<?php
/**
 * Class SetupModuleController
 *
 * @author        Robin 'codeFareith' von den Bergen <robinvonberg@gmx.de>
 * @copyright (c) 2018-2019 by Robin von den Bergen
 * @license       http://opensource.org/licenses/gpl-license.php GNU Public License
 * @version       1.0.0
 *
 * @link          https://github.com/codeFareith/cf_google_authenticator
 * @see           https://www.fareith.de
 * @see           https://typo3.org
 */

namespace CodeFareith\CfGoogleAuthenticator\Controller\Backend;

use CodeFareith\CfGoogleAuthenticator\Utility\GoogleAuthenticatorUtility;
use CodeFareith\CfGoogleAuthenticator\Utility\PathUtility;
use TYPO3\CMS\Core\Exception;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Setup\Controller\SetupModuleController as T3SetupModuleController;

/**
 * Extension of the SetupModuleController
 *
 * To enable backend users to configure two-factor authentication for their account
 * via the User Settings module of the TYPO3 CMS backend without administrative rights,
 * the SetupModuleController has been extended. For this, the storeIncomingData method
 * was overloaded, so that the TOTP validation is carried out first.
 *
 * @package CodeFareith\CfGoogleAuthenticator\Controller\Backend
 * @since   1.1.4
 */
class SetupModuleController
    extends T3SetupModuleController
{
    /*─────────────────────────────────────────────────────────────────────────────*\
                Methods
    \*─────────────────────────────────────────────────────────────────────────────*/
    /**
     * @throws Exception
     */
    public function storeIncomingData(): void
    {
        $request = GeneralUtility::_POST('data');

        $enable = $request['tx_cfgoogleauthenticator_enabled'] === 'on';
        $secret = $request['tx_cfgoogleauthenticator_secret'];
        $otp = $request['tx_cfgoogleauthenticator_otp'];

        $isEnabled = (bool) $this->getBackendUser()->user['tx_cfgoogleauthenticator_enabled'];

        if ($isEnabled === true && $enable === false) {
            $oldSecret = $this->getBackendUser()->user['tx_cfgoogleauthenticator_secret'];

            if (GoogleAuthenticatorUtility::verifyOneTimePassword($oldSecret, $otp) === true) {
                $_POST['data']['tx_cfgoogleauthenticator_enabled'] = $enable;
                $_POST['data']['tx_cfgoogleauthenticator_secret'] = '';

                $this->addDisableSuccessMessage();
            } else {
                $_POST['data']['tx_cfgoogleauthenticator_enabled'] = true;
                $_POST['data']['tx_cfgoogleauthenticator_secret'] = $oldSecret;

                $this->addDisableErrorMessage();
            }
        } elseif ($isEnabled === false && $enable === true) {
            if (GoogleAuthenticatorUtility::verifyOneTimePassword($secret, $otp) === true) {
                $_POST['data']['tx_cfgoogleauthenticator_enabled'] = $enable;
                $_POST['data']['tx_cfgoogleauthenticator_secret'] = $secret;

                $this->addEnableSuccessMessage();
            } else {
                $_POST['data']['tx_cfgoogleauthenticator_enabled'] = false;
                $_POST['data']['tx_cfgoogleauthenticator_secret'] = '';

                $this->addEnableErrorMessage();
            }
        }

        $this->getBackendUser()
            ->uc['tx_cfgoogleauthenticator_enabled'] = $_POST['data']['tx_cfgoogleauthenticator_enabled'];
        $this->getBackendUser()
            ->uc['tx_cfgoogleauthenticator_secret'] = $_POST['data']['tx_cfgoogleauthenticator_secret'];

        parent::storeIncomingData();
    }

    /**
     * @throws Exception
     */
    protected function addFlashMessageLLL(string $messageKey, string $titleKey, int $severity = null): void
    {
        $severity = $severity ?? FlashMessage::OK;

        $flashMessage = GeneralUtility::makeInstance(
            FlashMessage::class,
            $this->getLanguageService()->sL(
                PathUtility::makeLocalLangLinkPath($messageKey, 'locallang_be.xlf')
            ),
            $this->getLanguageService()->sL(
                PathUtility::makeLocalLangLinkPath($titleKey, 'locallang_be.xlf')
            ),
            $severity
        );

        $this->enqueueFlashMessages([$flashMessage]);
    }

    /**
     * @throws Exception
     */
    private function addDisableSuccessMessage(): void
    {
        $this->addFlashMessageLLL(
            'setup.disable.success.body',
            'setup.disable.success.title',
            FlashMessage::OK
        );
    }

    /**
     * @throws Exception
     */
    private function addDisableErrorMessage(): void
    {
        $this->addFlashMessageLLL(
            'setup.disable.error.body',
            'setup.disable.error.title',
            FlashMessage::ERROR
        );
    }

    /**
     * @throws Exception
     */
    private function addEnableSuccessMessage(): void
    {
        $this->addFlashMessageLLL(
            'setup.enable.success.body',
            'setup.enable.success.title',
            FlashMessage::OK
        );
    }

    /**
     * @throws Exception
     */
    private function addEnableErrorMessage(): void
    {
        $this->addFlashMessageLLL(
            'setup.enable.error.body',
            'setup.enable.error.title',
            FlashMessage::ERROR
        );
    }
}

