3 namespace Friendica\Module\Settings\TwoFactor;
5 use BaconQrCode\Renderer\Image\SvgImageBackEnd;
6 use BaconQrCode\Renderer\ImageRenderer;
7 use BaconQrCode\Renderer\RendererStyle\RendererStyle;
8 use BaconQrCode\Writer;
9 use Friendica\Core\L10n;
10 use Friendica\Core\Renderer;
11 use Friendica\Core\Session;
13 use Friendica\Module\BaseSettingsModule;
14 use Friendica\Module\Security\Login;
15 use PragmaRX\Google2FA\Google2FA;
18 * // Page 4: 2FA enabled but not verified, QR code and verification
20 * @package Friendica\Module\TwoFactor\Settings
22 class Verify extends BaseSettingsModule
24 public static function init(array $parameters = [])
30 $secret = DI::pConfig()->get(local_user(), '2fa', 'secret');
31 $verified = DI::pConfig()->get(local_user(), '2fa', 'verified');
33 if ($secret && $verified) {
34 DI::baseUrl()->redirect('settings/2fa');
37 if (!self::checkFormSecurityToken('settings_2fa_password', 't')) {
38 notice(DI::l10n()->t('Please enter your password to access this page.'));
39 DI::baseUrl()->redirect('settings/2fa');
43 public static function post(array $parameters = [])
49 if (($_POST['action'] ?? '') == 'verify') {
50 self::checkFormSecurityTokenRedirectOnError('settings/2fa/verify', 'settings_2fa_verify');
52 $google2fa = new Google2FA();
54 $valid = $google2fa->verifyKey(DI::pConfig()->get(local_user(), '2fa', 'secret'), $_POST['verify_code'] ?? '');
57 DI::pConfig()->set(local_user(), '2fa', 'verified', true);
58 Session::set('2fa', true);
60 notice(DI::l10n()->t('Two-factor authentication successfully activated.'));
62 DI::baseUrl()->redirect('settings/2fa');
64 notice(DI::l10n()->t('Invalid code, please retry.'));
69 public static function content(array $parameters = [])
72 return Login::form('settings/2fa/verify');
75 parent::content($parameters);
77 $company = 'Friendica';
78 $holder = Session::get('my_address');
79 $secret = DI::pConfig()->get(local_user(), '2fa', 'secret');
81 $otpauthUrl = (new Google2FA())->getQRCodeUrl($company, $holder, $secret);
83 $renderer = (new \BaconQrCode\Renderer\Image\Svg())
87 $writer = new Writer($renderer);
89 $qrcode_image = str_replace('<?xml version="1.0" encoding="UTF-8"?>', '', $writer->writeString($otpauthUrl));
91 $shortOtpauthUrl = explode('?', $otpauthUrl)[0];
93 $manual_message = DI::l10n()->t('<p>Or you can submit the authentication settings manually:</p>
103 <dt>Number of digits</dt>
105 <dt>Hashing algorithm</dt>
107 </dl>', $company, $holder, $secret);
109 return Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/twofactor/verify.tpl'), [
110 '$form_security_token' => self::getFormSecurityToken('settings_2fa_verify'),
111 '$password_security_token' => self::getFormSecurityToken('settings_2fa_password'),
113 '$title' => DI::l10n()->t('Two-factor code verification'),
114 '$help_label' => DI::l10n()->t('Help'),
115 '$message' => DI::l10n()->t('<p>Please scan this QR Code with your authenticator app and submit the provided code.</p>'),
116 '$qrcode_image' => $qrcode_image,
117 '$qrcode_url_message' => DI::l10n()->t('<p>Or you can open the following URL in your mobile devicde:</p><p><a href="%s">%s</a></p>', $otpauthUrl, $shortOtpauthUrl),
118 '$manual_message' => $manual_message,
119 '$company' => $company,
120 '$holder' => $holder,
121 '$secret' => $secret,
123 '$verify_code' => ['verify_code', DI::l10n()->t('Please enter a code from your authentication app'), '', '', 'required', 'autofocus placeholder="000000"'],
124 '$verify_label' => DI::l10n()->t('Verify code and enable two-factor authentication'),