]> git.mxchange.org Git - friendica.git/blob - src/Module/Settings/TwoFactor/Index.php
Merge branch 'friendica:2023.09-rc' into Leftovers-from-PR-#13339
[friendica.git] / src / Module / Settings / TwoFactor / Index.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
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.
11  *
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.
16  *
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/>.
19  *
20  */
21
22 namespace Friendica\Module\Settings\TwoFactor;
23
24 use Friendica\App;
25 use Friendica\Core\L10n;
26 use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
27 use Friendica\Core\Renderer;
28 use Friendica\Core\Session\Capability\IHandleUserSessions;
29 use Friendica\Module\Response;
30 use Friendica\Navigation\SystemMessages;
31 use Friendica\Network\HTTPException\FoundException;
32 use Friendica\Security\TwoFactor\Model\AppSpecificPassword;
33 use Friendica\Security\TwoFactor\Model\RecoveryCode;
34 use Friendica\Model\User;
35 use Friendica\Module\BaseSettings;
36 use Friendica\Module\Security\Login;
37 use Friendica\Util\Profiler;
38 use PragmaRX\Google2FA\Google2FA;
39 use Psr\Log\LoggerInterface;
40
41 class Index extends BaseSettings
42 {
43         /** @var IManagePersonalConfigValues */
44         protected $pConfig;
45         /** @var SystemMessages */
46         protected $systemMessages;
47
48         public function __construct(SystemMessages $systemMessages, IManagePersonalConfigValues $pConfig, IHandleUserSessions $session, App\Page $page, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
49         {
50                 parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
51
52                 $this->pConfig        = $pConfig;
53                 $this->systemMessages = $systemMessages;
54         }
55
56         protected function post(array $request = [])
57         {
58                 if (!$this->session->getLocalUserId()) {
59                         return;
60                 }
61
62                 self::checkFormSecurityTokenRedirectOnError('settings/2fa', 'settings_2fa');
63
64                 try {
65                         User::getIdFromPasswordAuthentication($this->session->getLocalUserId(), $request['password'] ?? '');
66
67                         $has_secret = (bool)$this->pConfig->get($this->session->getLocalUserId(), '2fa', 'secret');
68                         $verified   = $this->pConfig->get($this->session->getLocalUserId(), '2fa', 'verified');
69
70                         switch ($request['action'] ?? '') {
71                                 case 'enable':
72                                         if (!$has_secret && !$verified) {
73                                                 $Google2FA = new Google2FA();
74
75                                                 $this->pConfig->set($this->session->getLocalUserId(), '2fa', 'secret', $Google2FA->generateSecretKey(32));
76
77                                                 $this->baseUrl
78                                                   ->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password'));
79                                         }
80                                         break;
81                                 case 'disable':
82                                         if ($has_secret) {
83                                                 RecoveryCode::deleteForUser($this->session->getLocalUserId());
84                                                 $this->pConfig->delete($this->session->getLocalUserId(), '2fa', 'secret');
85                                                 $this->pConfig->delete($this->session->getLocalUserId(), '2fa', 'verified');
86                                                 $this->session->remove('2fa');
87
88                                                 $this->systemMessages->addInfo($this->t('Two-factor authentication successfully disabled.'));
89                                                 $this->baseUrl->redirect('settings/2fa');
90                                         }
91                                         break;
92                                 case 'recovery':
93                                         if ($has_secret) {
94                                                 $this->baseUrl
95                                                   ->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password'));
96                                         }
97                                         break;
98                                 case 'app_specific':
99                                         if ($has_secret) {
100                                                 $this->baseUrl
101                                                   ->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password'));
102                                         }
103                                         break;
104                                 case 'trusted':
105                                         if ($has_secret) {
106                                                 $this->baseUrl
107                                                   ->redirect('settings/2fa/trusted?t=' . self::getFormSecurityToken('settings_2fa_password'));
108                                         }
109                                         break;
110                                 case 'configure':
111                                         if (!$verified) {
112                                                 $this->baseUrl
113                                                   ->redirect('settings/2fa/verify?t=' . self::getFormSecurityToken('settings_2fa_password'));
114                                         }
115                                         break;
116                         }
117                 } catch (FoundException $exception) {
118                         // Redirection, passing along
119                         throw $exception;
120                 } catch (\Exception $e) {
121                         $this->systemMessages->addNotice($this->t($e->getMessage()));
122                 }
123         }
124
125         protected function content(array $request = []): string
126         {
127                 if (!$this->session->getLocalUserId()) {
128                         return Login::form('settings/2fa');
129                 }
130
131                 parent::content();
132
133                 $has_secret = (bool) $this->pConfig->get($this->session->getLocalUserId(), '2fa', 'secret');
134                 $verified = $this->pConfig->get($this->session->getLocalUserId(), '2fa', 'verified');
135
136                 return Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/twofactor/index.tpl'), [
137                         '$form_security_token' => self::getFormSecurityToken('settings_2fa'),
138                         '$title'               => $this->t('Two-factor authentication'),
139                         '$help_label'          => $this->t('Help'),
140                         '$status_title'        => $this->t('Status'),
141                         '$message'             => $this->t('<p>Use an application on a mobile device to get two-factor authentication codes when prompted on login.</p>'),
142                         '$has_secret'          => $has_secret,
143                         '$verified'            => $verified,
144
145                         '$auth_app_label'         => $this->t('Authenticator app'),
146                         '$app_status'             => $has_secret ? $verified ? $this->t('Configured') : $this->t('Not Configured') : $this->t('Disabled'),
147                         '$not_configured_message' => $this->t('<p>You haven\'t finished configuring your authenticator app.</p>'),
148                         '$configured_message'     => $this->t('<p>Your authenticator app is correctly configured.</p>'),
149
150                         '$recovery_codes_title'     => $this->t('Recovery codes'),
151                         '$recovery_codes_remaining' => $this->t('Remaining valid codes'),
152                         '$recovery_codes_count'     => RecoveryCode::countValidForUser($this->session->getLocalUserId()),
153                         '$recovery_codes_message'   => $this->t('<p>These one-use codes can replace an authenticator app code in case you have lost access to it.</p>'),
154
155                         '$app_specific_passwords_title'     => $this->t('App-specific passwords'),
156                         '$app_specific_passwords_remaining' => $this->t('Generated app-specific passwords'),
157                         '$app_specific_passwords_count'     => AppSpecificPassword::countForUser($this->session->getLocalUserId()),
158                         '$app_specific_passwords_message'   => $this->t('<p>These randomly generated passwords allow you to authenticate on apps not supporting two-factor authentication.</p>'),
159
160                         '$action_title'         => $this->t('Actions'),
161                         '$password'             => ['password', $this->t('Current password:'), '', $this->t('You need to provide your current password to change two-factor authentication settings.'), $this->t('Required'), 'autofocus'],
162                         '$enable_label'         => $this->t('Enable two-factor authentication'),
163                         '$disable_label'        => $this->t('Disable two-factor authentication'),
164                         '$recovery_codes_label' => $this->t('Show recovery codes'),
165                         '$app_specific_passwords_label' => $this->t('Manage app-specific passwords'),
166                         '$trusted_browsers_label' => $this->t('Manage trusted browsers'),
167                         '$configure_label'      => $this->t('Finish app configuration'),
168                 ]);
169         }
170 }