3 * @copyright Copyright (C) 2020, Friendica
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Module\Settings\TwoFactor;
24 use BaconQrCode\Renderer\Image\SvgImageBackEnd;
25 use BaconQrCode\Renderer\ImageRenderer;
26 use BaconQrCode\Renderer\RendererStyle\RendererStyle;
27 use BaconQrCode\Writer;
28 use Friendica\Core\Renderer;
29 use Friendica\Core\Session;
31 use Friendica\Module\BaseSettings;
32 use Friendica\Module\Security\Login;
33 use PragmaRX\Google2FA\Google2FA;
36 * // Page 4: 2FA enabled but not verified, QR code and verification
38 * @package Friendica\Module\TwoFactor\Settings
40 class Verify extends BaseSettings
42 public static function init(array $parameters = [])
48 $secret = DI::pConfig()->get(local_user(), '2fa', 'secret');
49 $verified = DI::pConfig()->get(local_user(), '2fa', 'verified');
51 if ($secret && $verified) {
52 DI::baseUrl()->redirect('settings/2fa');
55 if (!self::checkFormSecurityToken('settings_2fa_password', 't')) {
56 notice(DI::l10n()->t('Please enter your password to access this page.'));
57 DI::baseUrl()->redirect('settings/2fa');
61 public static function post(array $parameters = [])
67 if (($_POST['action'] ?? '') == 'verify') {
68 self::checkFormSecurityTokenRedirectOnError('settings/2fa/verify', 'settings_2fa_verify');
70 $google2fa = new Google2FA();
72 $valid = $google2fa->verifyKey(DI::pConfig()->get(local_user(), '2fa', 'secret'), $_POST['verify_code'] ?? '');
75 DI::pConfig()->set(local_user(), '2fa', 'verified', true);
76 Session::set('2fa', true);
78 notice(DI::l10n()->t('Two-factor authentication successfully activated.'));
80 DI::baseUrl()->redirect('settings/2fa');
82 notice(DI::l10n()->t('Invalid code, please retry.'));
87 public static function content(array $parameters = [])
90 return Login::form('settings/2fa/verify');
93 parent::content($parameters);
95 $company = 'Friendica';
96 $holder = Session::get('my_address');
97 $secret = DI::pConfig()->get(local_user(), '2fa', 'secret');
99 $otpauthUrl = (new Google2FA())->getQRCodeUrl($company, $holder, $secret);
101 $renderer = (new \BaconQrCode\Renderer\Image\Svg())
105 $writer = new Writer($renderer);
107 $qrcode_image = str_replace('<?xml version="1.0" encoding="UTF-8"?>', '', $writer->writeString($otpauthUrl));
109 $shortOtpauthUrl = explode('?', $otpauthUrl)[0];
111 $manual_message = DI::l10n()->t('<p>Or you can submit the authentication settings manually:</p>
115 <dt>Account Name</dt>
121 <dt>Number of digits</dt>
123 <dt>Hashing algorithm</dt>
125 </dl>', $company, $holder, $secret);
127 return Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/twofactor/verify.tpl'), [
128 '$form_security_token' => self::getFormSecurityToken('settings_2fa_verify'),
129 '$password_security_token' => self::getFormSecurityToken('settings_2fa_password'),
131 '$title' => DI::l10n()->t('Two-factor code verification'),
132 '$help_label' => DI::l10n()->t('Help'),
133 '$message' => DI::l10n()->t('<p>Please scan this QR Code with your authenticator app and submit the provided code.</p>'),
134 '$qrcode_image' => $qrcode_image,
135 '$qrcode_url_message' => DI::l10n()->t('<p>Or you can open the following URL in your mobile device:</p><p><a href="%s">%s</a></p>', $otpauthUrl, $shortOtpauthUrl),
136 '$manual_message' => $manual_message,
137 '$company' => $company,
138 '$holder' => $holder,
139 '$secret' => $secret,
141 '$verify_code' => ['verify_code', DI::l10n()->t('Please enter a code from your authentication app'), '', '', 'required', 'autofocus placeholder="000000"'],
142 '$verify_label' => DI::l10n()->t('Verify code and enable two-factor authentication'),