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

ResetPasswordController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 20
rs 9.9666
cc 1
nc 1
nop 9

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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