Passed
Push — master ( 2d76a7...48dbdd )
by
unknown
16:47
created

ResetPasswordController::getLanguageService()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace TYPO3\CMS\Backend\Controller;
19
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use TYPO3\CMS\Backend\Authentication\PasswordReset;
23
use TYPO3\CMS\Backend\Routing\UriBuilder;
24
use TYPO3\CMS\Backend\Template\ModuleTemplate;
25
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
26
use TYPO3\CMS\Backend\View\AuthenticationStyleInformation;
27
use TYPO3\CMS\Core\Configuration\Features;
28
use TYPO3\CMS\Core\Context\Context;
29
use TYPO3\CMS\Core\Http\HtmlResponse;
30
use TYPO3\CMS\Core\Http\PropagateResponseException;
31
use TYPO3\CMS\Core\Http\RedirectResponse;
32
use TYPO3\CMS\Core\Information\Typo3Information;
33
use TYPO3\CMS\Core\Localization\LanguageService;
34
use TYPO3\CMS\Core\Localization\Locales;
35
use TYPO3\CMS\Core\Page\PageRenderer;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
38
39
/**
40
 * Controller responsible for rendering and processing password reset requests
41
 *
42
 * @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
43
 */
44
class ResetPasswordController
45
{
46
    protected string $loginProvider = '';
47
    protected ?ViewInterface $view = null;
48
    protected ?ModuleTemplate $moduleTemplate = null;
49
50
    protected Context $context;
51
    protected Locales $locales;
52
    protected Features $features;
53
    protected UriBuilder $uriBuilder;
54
    protected PageRenderer $pageRenderer;
55
    protected PasswordReset $passwordReset;
56
    protected Typo3Information $typo3Information;
57
    protected ModuleTemplateFactory $moduleTemplateFactory;
58
    protected AuthenticationStyleInformation $authenticationStyleInformation;
59
60
    public function __construct(
61
        Context $context,
62
        Locales $locales,
63
        Features $features,
64
        UriBuilder $uriBuilder,
65
        PageRenderer $pageRenderer,
66
        PasswordReset $passwordReset,
67
        Typo3Information $typo3Information,
68
        ModuleTemplateFactory $moduleTemplateFactory,
69
        AuthenticationStyleInformation $authenticationStyleInformation
70
    ) {
71
        $this->context = $context;
72
        $this->locales = $locales;
73
        $this->features = $features;
74
        $this->uriBuilder = $uriBuilder;
75
        $this->pageRenderer = $pageRenderer;
76
        $this->passwordReset = $passwordReset;
77
        $this->typo3Information = $typo3Information;
78
        $this->moduleTemplateFactory = $moduleTemplateFactory;
79
        $this->authenticationStyleInformation = $authenticationStyleInformation;
80
    }
81
82
    /**
83
     * Show a form to enter an email address to request a password reset email.
84
     *
85
     * @param ServerRequestInterface $request
86
     * @return ResponseInterface
87
     */
88
    public function forgetPasswordFormAction(ServerRequestInterface $request): ResponseInterface
89
    {
90
        $this->initializeForgetPasswordView($request);
91
        $this->moduleTemplate->setContent($this->view->render());
0 ignored issues
show
Bug introduced by
The method render() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

91
        $this->moduleTemplate->setContent($this->view->/** @scrutinizer ignore-call */ render());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method setContent() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

91
        $this->moduleTemplate->/** @scrutinizer ignore-call */ 
92
                               setContent($this->view->render());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
92
        return new HtmlResponse($this->moduleTemplate->renderContent());
93
    }
94
95
    /**
96
     * Validate the email address.
97
     *
98
     * Restricted to POST method in Configuration/Backend/Routes.php
99
     *
100
     * @param ServerRequestInterface $request
101
     * @return ResponseInterface
102
     */
103
    public function initiatePasswordResetAction(ServerRequestInterface $request): ResponseInterface
104
    {
105
        $this->initializeForgetPasswordView($request);
106
        $emailAddress = $request->getParsedBody()['email'] ?? '';
107
        $this->view->assign('email', $emailAddress);
108
        if (!GeneralUtility::validEmail($emailAddress)) {
109
            $this->view->assign('invalidEmail', true);
110
        } else {
111
            $this->passwordReset->initiateReset($request, $this->context, $emailAddress);
112
            $this->view->assign('resetInitiated', true);
113
        }
114
        $this->moduleTemplate->setContent($this->view->render());
115
        // Prevent time based information disclosure by waiting a random time
116
        // before sending a response. This prevents that the response time
117
        // can be an indicator if the used email exists or not. Wait a random
118
        // time between 200 milliseconds and 3 seconds.
119
        usleep(random_int(200000, 3000000));
120
        return new HtmlResponse($this->moduleTemplate->renderContent());
121
    }
122
123
    /**
124
     * Validates the link and show a form to enter the new password.
125
     *
126
     * @param ServerRequestInterface $request
127
     * @return ResponseInterface
128
     */
129
    public function passwordResetAction(ServerRequestInterface $request): ResponseInterface
130
    {
131
        $this->initializeResetPasswordView($request);
132
        if (!$this->passwordReset->isValidResetTokenFromRequest($request)) {
133
            $this->view->assign('invalidToken', true);
134
        }
135
        $this->moduleTemplate->setContent($this->view->render());
136
        return new HtmlResponse($this->moduleTemplate->renderContent());
137
    }
138
139
    /**
140
     * Updates the password in the database.
141
     *
142
     * Restricted to POST method in Configuration/Backend/Routes.php
143
     *
144
     * @param ServerRequestInterface $request
145
     * @return ResponseInterface
146
     */
147
    public function passwordResetFinishAction(ServerRequestInterface $request): ResponseInterface
148
    {
149
        // Token is invalid
150
        if (!$this->passwordReset->isValidResetTokenFromRequest($request)) {
151
            return $this->passwordResetAction($request);
152
        }
153
        $this->initializeResetPasswordView($request);
154
        if ($this->passwordReset->resetPassword($request, $this->context)) {
155
            $this->view->assign('resetExecuted', true);
156
        } else {
157
            $this->view->assign('error', true);
158
        }
159
        $this->moduleTemplate->setContent($this->view->render());
160
        return new HtmlResponse($this->moduleTemplate->renderContent());
161
    }
162
163
    protected function initializeForgetPasswordView(ServerRequestInterface $request): void
164
    {
165
        $this->initialize($request);
166
        $this->view->setTemplate('Login/ForgetPasswordForm');
0 ignored issues
show
Bug introduced by
The method setTemplate() does not exist on TYPO3\CMS\Extbase\Mvc\View\ViewInterface. It seems like you code against a sub-type of TYPO3\CMS\Extbase\Mvc\View\ViewInterface such as TYPO3\CMS\Extbase\Mvc\View\EmptyView or TYPO3\CMS\Fluid\View\AbstractTemplateView or TYPO3\CMS\Extbase\Mvc\View\NotFoundView. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

166
        $this->view->/** @scrutinizer ignore-call */ 
167
                     setTemplate('Login/ForgetPasswordForm');
Loading history...
167
        $parameters = array_filter(['loginProvider' => $this->loginProvider]);
168
        $this->view->assignMultiple([
169
            'formUrl' => $this->uriBuilder->buildUriWithRedirectFromRequest('password_forget_initiate_reset', $parameters, $request),
170
            'returnUrl' => $this->uriBuilder->buildUriWithRedirectFromRequest('login', $parameters, $request)
171
        ]);
172
    }
173
174
    protected function initializeResetPasswordView(ServerRequestInterface $request): void
175
    {
176
        $this->initialize($request);
177
        $token = $request->getQueryParams()['t'] ?? '';
178
        $identity = $request->getQueryParams()['i'] ?? '';
179
        $expirationDate = $request->getQueryParams()['e'] ?? '';
180
        $parameters = array_filter(['loginProvider' => $this->loginProvider]);
181
        $formUrl = $this->uriBuilder->buildUriWithRedirectFromRequest(
182
            'password_reset_finish',
183
            array_filter(array_merge($parameters, [
184
               't' => $token,
185
               'i' => $identity,
186
               'e' => $expirationDate
187
            ])),
188
            $request
189
        );
190
        $this->view->setTemplate('Login/ResetPasswordForm');
191
        $this->view->assignMultiple([
192
            'token' => $token,
193
            'identity' => $identity,
194
            'expirationDate' => $expirationDate,
195
            'formUrl' => $formUrl,
196
            'restartUrl' => $this->uriBuilder->buildUriWithRedirectFromRequest('password_forget', $parameters, $request)
197
        ]);
198
    }
199
200
    protected function initialize(ServerRequestInterface $request): void
201
    {
202
        // Only allow to execute this if not logged in as a user right now
203
        if ($this->context->getAspect('backend.user')->isLoggedIn()) {
0 ignored issues
show
Bug introduced by
The method isLoggedIn() does not exist on TYPO3\CMS\Core\Context\AspectInterface. It seems like you code against a sub-type of TYPO3\CMS\Core\Context\AspectInterface such as TYPO3\CMS\Core\Context\UserAspect. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

203
        if ($this->context->getAspect('backend.user')->/** @scrutinizer ignore-call */ isLoggedIn()) {
Loading history...
204
            throw new PropagateResponseException(
205
                new RedirectResponse($this->uriBuilder->buildUriFromRoute('login'), 303),
206
                1618342858
207
            );
208
        }
209
210
        // Fetch login provider from the request
211
        $this->loginProvider = $request->getQueryParams()['loginProvider'] ?? '';
212
213
        // Try to get the preferred browser language
214
        $httpAcceptLanguage = $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'];
215
        $preferredBrowserLanguage = $this->locales->getPreferredClientLanguage($httpAcceptLanguage);
216
217
        // If we found a $preferredBrowserLanguage and it is not the default language
218
        // initialize $this->getLanguageService() again with $preferredBrowserLanguage
219
        if ($preferredBrowserLanguage !== 'default') {
220
            $this->getLanguageService()->init($preferredBrowserLanguage);
221
            $this->pageRenderer->setLanguage($preferredBrowserLanguage);
222
        }
223
224
        $this->getLanguageService()->includeLLFile('EXT:backend/Resources/Private/Language/locallang_login.xlf');
225
226
        $this->moduleTemplate = $this->moduleTemplateFactory->create($request);
227
        $this->moduleTemplate->setTitle('TYPO3 CMS Login: ' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ?? ''));
228
229
        $this->view = $this->moduleTemplate->getView();
230
        $this->view->getRequest()->setControllerExtensionName('Backend');
0 ignored issues
show
Bug introduced by
The method getRequest() does not exist on TYPO3\CMS\Extbase\Mvc\View\ViewInterface. It seems like you code against a sub-type of TYPO3\CMS\Extbase\Mvc\View\ViewInterface such as TYPO3\CMS\Extbase\Mvc\View\EmptyView or TYPO3\CMS\Extbase\Mvc\View\NotFoundView or TYPO3\CMS\Fluid\View\StandaloneView. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

230
        $this->view->/** @scrutinizer ignore-call */ 
231
                     getRequest()->setControllerExtensionName('Backend');
Loading history...
231
        $this->view->assignMultiple([
232
            'enablePasswordReset' => $this->passwordReset->isEnabled(),
233
            'referrerCheckEnabled' => $this->features->isFeatureEnabled('security.backend.enforceReferrer'),
234
            'loginUrl' => (string)$request->getUri(),
235
        ]);
236
237
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Login');
238
        $this->provideCustomLoginStyling();
239
    }
240
241
    protected function provideCustomLoginStyling(): void
242
    {
243
        if (($backgroundImageStyles = $this->authenticationStyleInformation->getBackgroundImageStyles()) !== '') {
244
            $this->pageRenderer->addCssInlineBlock('loginBackgroundImage', $backgroundImageStyles);
245
        }
246
        if (($footerNote = $this->authenticationStyleInformation->getFooterNote()) !== '') {
247
            $this->view->assign('loginFootnote', $footerNote);
248
        }
249
        if (($highlightColorStyles = $this->authenticationStyleInformation->getHighlightColorStyles()) !== '') {
250
            $this->pageRenderer->addCssInlineBlock('loginHighlightColor', $highlightColorStyles);
251
        }
252
        if (($logo = $this->authenticationStyleInformation->getLogo()) !== '') {
253
            $logoAlt = $this->authenticationStyleInformation->getLogoAlt();
254
        } else {
255
            $logo = $this->authenticationStyleInformation->getDefaultLogo();
256
            $logoAlt = $this->getLanguageService()->getLL('typo3.altText');
257
            $this->pageRenderer->addCssInlineBlock('loginLogo', $this->authenticationStyleInformation->getDefaultLogoStyles());
258
        }
259
        $this->view->assignMultiple([
260
            'logo' => $logo,
261
            'logoAlt' => $logoAlt,
262
            'images' => $this->authenticationStyleInformation->getSupportingImages(),
263
            'copyright' => $this->typo3Information->getCopyrightNotice(),
264
        ]);
265
    }
266
267
    protected function getLanguageService(): LanguageService
268
    {
269
        return $GLOBALS['LANG'];
270
    }
271
}
272