Passed
Push — master ( b48a87...fd645d )
by Blizzz
16:00 queued 02:06
created
core/Controller/LostController.php 2 patches
Indentation   +259 added lines, -259 removed lines patch added patch discarded remove patch
@@ -71,263 +71,263 @@
 block discarded – undo
71 71
  * @package OC\Core\Controller
72 72
  */
73 73
 class LostController extends Controller {
74
-	protected IURLGenerator $urlGenerator;
75
-	protected IUserManager $userManager;
76
-	protected Defaults $defaults;
77
-	protected IL10N $l10n;
78
-	protected string $from;
79
-	protected IManager $encryptionManager;
80
-	protected IConfig $config;
81
-	protected IMailer $mailer;
82
-	private LoggerInterface $logger;
83
-	private Manager $twoFactorManager;
84
-	private IInitialState $initialState;
85
-	private IVerificationToken $verificationToken;
86
-	private IEventDispatcher $eventDispatcher;
87
-
88
-	public function __construct(
89
-		string $appName,
90
-		IRequest $request,
91
-		IURLGenerator $urlGenerator,
92
-		IUserManager $userManager,
93
-		Defaults $defaults,
94
-		IL10N $l10n,
95
-		IConfig $config,
96
-		string $defaultMailAddress,
97
-		IManager $encryptionManager,
98
-		IMailer $mailer,
99
-		LoggerInterface $logger,
100
-		Manager $twoFactorManager,
101
-		IInitialState $initialState,
102
-		IVerificationToken $verificationToken,
103
-		IEventDispatcher $eventDispatcher
104
-	) {
105
-		parent::__construct($appName, $request);
106
-		$this->urlGenerator = $urlGenerator;
107
-		$this->userManager = $userManager;
108
-		$this->defaults = $defaults;
109
-		$this->l10n = $l10n;
110
-		$this->from = $defaultMailAddress;
111
-		$this->encryptionManager = $encryptionManager;
112
-		$this->config = $config;
113
-		$this->mailer = $mailer;
114
-		$this->logger = $logger;
115
-		$this->twoFactorManager = $twoFactorManager;
116
-		$this->initialState = $initialState;
117
-		$this->verificationToken = $verificationToken;
118
-		$this->eventDispatcher = $eventDispatcher;
119
-	}
120
-
121
-	/**
122
-	 * Someone wants to reset their password:
123
-	 *
124
-	 * @PublicPage
125
-	 * @NoCSRFRequired
126
-	 */
127
-	public function resetform(string $token, string $userId): TemplateResponse {
128
-		try {
129
-			$this->checkPasswordResetToken($token, $userId);
130
-		} catch (Exception $e) {
131
-			if ($this->config->getSystemValue('lost_password_link', '') !== 'disabled'
132
-				|| ($e instanceof InvalidTokenException
133
-					&& !in_array($e->getCode(), [InvalidTokenException::TOKEN_NOT_FOUND, InvalidTokenException::USER_UNKNOWN]))
134
-			) {
135
-				return new TemplateResponse(
136
-					'core', 'error', [
137
-						"errors" => [["error" => $e->getMessage()]]
138
-					],
139
-					TemplateResponse::RENDER_AS_GUEST
140
-				);
141
-			}
142
-			return new TemplateResponse('core', 'error', [
143
-				'errors' => [['error' => $this->l10n->t('Password reset is disabled')]]
144
-			],
145
-				TemplateResponse::RENDER_AS_GUEST
146
-			);
147
-		}
148
-		$this->initialState->provideInitialState('resetPasswordUser', $userId);
149
-		$this->initialState->provideInitialState('resetPasswordTarget',
150
-			$this->urlGenerator->linkToRouteAbsolute('core.lost.setPassword', ['userId' => $userId, 'token' => $token])
151
-		);
152
-
153
-		return new TemplateResponse(
154
-			'core',
155
-			'login',
156
-			[],
157
-			'guest'
158
-		);
159
-	}
160
-
161
-	/**
162
-	 * @throws Exception
163
-	 */
164
-	protected function checkPasswordResetToken(string $token, string $userId): void {
165
-		try {
166
-			$user = $this->userManager->get($userId);
167
-			$this->verificationToken->check($token, $user, 'lostpassword', $user ? $user->getEMailAddress() : '', true);
168
-		} catch (InvalidTokenException $e) {
169
-			$error = $e->getCode() === InvalidTokenException::TOKEN_EXPIRED
170
-				? $this->l10n->t('Could not reset password because the token is expired')
171
-				: $this->l10n->t('Could not reset password because the token is invalid');
172
-			throw new Exception($error, (int)$e->getCode(), $e);
173
-		}
174
-	}
175
-
176
-	private function error(string $message, array $additional = []): array {
177
-		return array_merge(['status' => 'error', 'msg' => $message], $additional);
178
-	}
179
-
180
-	private function success(array $data = []): array {
181
-		return array_merge($data, ['status' => 'success']);
182
-	}
183
-
184
-	/**
185
-	 * @PublicPage
186
-	 * @BruteForceProtection(action=passwordResetEmail)
187
-	 * @AnonRateThrottle(limit=10, period=300)
188
-	 */
189
-	public function email(string $user): JSONResponse {
190
-		if ($this->config->getSystemValue('lost_password_link', '') !== '') {
191
-			return new JSONResponse($this->error($this->l10n->t('Password reset is disabled')));
192
-		}
193
-
194
-		\OCP\Util::emitHook(
195
-			'\OCA\Files_Sharing\API\Server2Server',
196
-			'preLoginNameUsedAsUserName',
197
-			['uid' => &$user]
198
-		);
199
-
200
-		// FIXME: use HTTP error codes
201
-		try {
202
-			$this->sendEmail($user);
203
-		} catch (ResetPasswordException $e) {
204
-			// Ignore the error since we do not want to leak this info
205
-			$this->logger->warning('Could not send password reset email: ' . $e->getMessage());
206
-		} catch (Exception $e) {
207
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
208
-		}
209
-
210
-		$response = new JSONResponse($this->success());
211
-		$response->throttle();
212
-		return $response;
213
-	}
214
-
215
-	/**
216
-	 * @PublicPage
217
-	 */
218
-	public function setPassword(string $token, string $userId, string $password, bool $proceed): array {
219
-		if ($this->encryptionManager->isEnabled() && !$proceed) {
220
-			$encryptionModules = $this->encryptionManager->getEncryptionModules();
221
-			foreach ($encryptionModules as $module) {
222
-				/** @var IEncryptionModule $instance */
223
-				$instance = call_user_func($module['callback']);
224
-				// this way we can find out whether per-user keys are used or a system wide encryption key
225
-				if ($instance->needDetailedAccessList()) {
226
-					return $this->error('', ['encryption' => true]);
227
-				}
228
-			}
229
-		}
230
-
231
-		try {
232
-			$this->checkPasswordResetToken($token, $userId);
233
-			$user = $this->userManager->get($userId);
234
-
235
-			$this->eventDispatcher->dispatchTyped(new BeforePasswordResetEvent($user, $password));
236
-			\OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'pre_passwordReset', ['uid' => $userId, 'password' => $password]);
237
-
238
-			if (!$user->setPassword($password)) {
239
-				throw new Exception();
240
-			}
241
-
242
-			$this->eventDispatcher->dispatchTyped(new PasswordResetEvent($user, $password));
243
-			\OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'post_passwordReset', ['uid' => $userId, 'password' => $password]);
244
-
245
-			$this->twoFactorManager->clearTwoFactorPending($userId);
246
-
247
-			$this->config->deleteUserValue($userId, 'core', 'lostpassword');
248
-			@\OC::$server->getUserSession()->unsetMagicInCookie();
249
-		} catch (HintException $e) {
250
-			return $this->error($e->getHint());
251
-		} catch (Exception $e) {
252
-			return $this->error($e->getMessage());
253
-		}
254
-
255
-		return $this->success(['user' => $userId]);
256
-	}
257
-
258
-	/**
259
-	 * @throws ResetPasswordException
260
-	 * @throws \OCP\PreConditionNotMetException
261
-	 */
262
-	protected function sendEmail(string $input): void {
263
-		$user = $this->findUserByIdOrMail($input);
264
-		$email = $user->getEMailAddress();
265
-
266
-		if (empty($email)) {
267
-			throw new ResetPasswordException('Could not send reset e-mail since there is no email for username ' . $input);
268
-		}
269
-
270
-		// Generate the token. It is stored encrypted in the database with the
271
-		// secret being the users' email address appended with the system secret.
272
-		// This makes the token automatically invalidate once the user changes
273
-		// their email address.
274
-		$token = $this->verificationToken->create($user, 'lostpassword', $email);
275
-
276
-		$link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', ['userId' => $user->getUID(), 'token' => $token]);
277
-
278
-		$emailTemplate = $this->mailer->createEMailTemplate('core.ResetPassword', [
279
-			'link' => $link,
280
-		]);
281
-
282
-		$emailTemplate->setSubject($this->l10n->t('%s password reset', [$this->defaults->getName()]));
283
-		$emailTemplate->addHeader();
284
-		$emailTemplate->addHeading($this->l10n->t('Password reset'));
285
-
286
-		$emailTemplate->addBodyText(
287
-			htmlspecialchars($this->l10n->t('Click the following button to reset your password. If you have not requested the password reset, then ignore this email.')),
288
-			$this->l10n->t('Click the following link to reset your password. If you have not requested the password reset, then ignore this email.')
289
-		);
290
-
291
-		$emailTemplate->addBodyButton(
292
-			htmlspecialchars($this->l10n->t('Reset your password')),
293
-			$link,
294
-			false
295
-		);
296
-		$emailTemplate->addFooter();
297
-
298
-		try {
299
-			$message = $this->mailer->createMessage();
300
-			$message->setTo([$email => $user->getDisplayName()]);
301
-			$message->setFrom([$this->from => $this->defaults->getName()]);
302
-			$message->useTemplate($emailTemplate);
303
-			$this->mailer->send($message);
304
-		} catch (Exception $e) {
305
-			// Log the exception and continue
306
-			$this->logger->error($e->getMessage(), ['app' => 'core', 'exception' => $e]);
307
-		}
308
-	}
309
-
310
-	/**
311
-	 * @throws ResetPasswordException
312
-	 */
313
-	protected function findUserByIdOrMail(string $input): IUser {
314
-		$user = $this->userManager->get($input);
315
-		if ($user instanceof IUser) {
316
-			if (!$user->isEnabled()) {
317
-				throw new ResetPasswordException('User ' . $user->getUID() . ' is disabled');
318
-			}
319
-
320
-			return $user;
321
-		}
322
-
323
-		$users = array_filter($this->userManager->getByEmail($input), function (IUser $user) {
324
-			return $user->isEnabled();
325
-		});
326
-
327
-		if (count($users) === 1) {
328
-			return reset($users);
329
-		}
330
-
331
-		throw new ResetPasswordException('Could not find user ' . $input);
332
-	}
74
+    protected IURLGenerator $urlGenerator;
75
+    protected IUserManager $userManager;
76
+    protected Defaults $defaults;
77
+    protected IL10N $l10n;
78
+    protected string $from;
79
+    protected IManager $encryptionManager;
80
+    protected IConfig $config;
81
+    protected IMailer $mailer;
82
+    private LoggerInterface $logger;
83
+    private Manager $twoFactorManager;
84
+    private IInitialState $initialState;
85
+    private IVerificationToken $verificationToken;
86
+    private IEventDispatcher $eventDispatcher;
87
+
88
+    public function __construct(
89
+        string $appName,
90
+        IRequest $request,
91
+        IURLGenerator $urlGenerator,
92
+        IUserManager $userManager,
93
+        Defaults $defaults,
94
+        IL10N $l10n,
95
+        IConfig $config,
96
+        string $defaultMailAddress,
97
+        IManager $encryptionManager,
98
+        IMailer $mailer,
99
+        LoggerInterface $logger,
100
+        Manager $twoFactorManager,
101
+        IInitialState $initialState,
102
+        IVerificationToken $verificationToken,
103
+        IEventDispatcher $eventDispatcher
104
+    ) {
105
+        parent::__construct($appName, $request);
106
+        $this->urlGenerator = $urlGenerator;
107
+        $this->userManager = $userManager;
108
+        $this->defaults = $defaults;
109
+        $this->l10n = $l10n;
110
+        $this->from = $defaultMailAddress;
111
+        $this->encryptionManager = $encryptionManager;
112
+        $this->config = $config;
113
+        $this->mailer = $mailer;
114
+        $this->logger = $logger;
115
+        $this->twoFactorManager = $twoFactorManager;
116
+        $this->initialState = $initialState;
117
+        $this->verificationToken = $verificationToken;
118
+        $this->eventDispatcher = $eventDispatcher;
119
+    }
120
+
121
+    /**
122
+     * Someone wants to reset their password:
123
+     *
124
+     * @PublicPage
125
+     * @NoCSRFRequired
126
+     */
127
+    public function resetform(string $token, string $userId): TemplateResponse {
128
+        try {
129
+            $this->checkPasswordResetToken($token, $userId);
130
+        } catch (Exception $e) {
131
+            if ($this->config->getSystemValue('lost_password_link', '') !== 'disabled'
132
+                || ($e instanceof InvalidTokenException
133
+                    && !in_array($e->getCode(), [InvalidTokenException::TOKEN_NOT_FOUND, InvalidTokenException::USER_UNKNOWN]))
134
+            ) {
135
+                return new TemplateResponse(
136
+                    'core', 'error', [
137
+                        "errors" => [["error" => $e->getMessage()]]
138
+                    ],
139
+                    TemplateResponse::RENDER_AS_GUEST
140
+                );
141
+            }
142
+            return new TemplateResponse('core', 'error', [
143
+                'errors' => [['error' => $this->l10n->t('Password reset is disabled')]]
144
+            ],
145
+                TemplateResponse::RENDER_AS_GUEST
146
+            );
147
+        }
148
+        $this->initialState->provideInitialState('resetPasswordUser', $userId);
149
+        $this->initialState->provideInitialState('resetPasswordTarget',
150
+            $this->urlGenerator->linkToRouteAbsolute('core.lost.setPassword', ['userId' => $userId, 'token' => $token])
151
+        );
152
+
153
+        return new TemplateResponse(
154
+            'core',
155
+            'login',
156
+            [],
157
+            'guest'
158
+        );
159
+    }
160
+
161
+    /**
162
+     * @throws Exception
163
+     */
164
+    protected function checkPasswordResetToken(string $token, string $userId): void {
165
+        try {
166
+            $user = $this->userManager->get($userId);
167
+            $this->verificationToken->check($token, $user, 'lostpassword', $user ? $user->getEMailAddress() : '', true);
168
+        } catch (InvalidTokenException $e) {
169
+            $error = $e->getCode() === InvalidTokenException::TOKEN_EXPIRED
170
+                ? $this->l10n->t('Could not reset password because the token is expired')
171
+                : $this->l10n->t('Could not reset password because the token is invalid');
172
+            throw new Exception($error, (int)$e->getCode(), $e);
173
+        }
174
+    }
175
+
176
+    private function error(string $message, array $additional = []): array {
177
+        return array_merge(['status' => 'error', 'msg' => $message], $additional);
178
+    }
179
+
180
+    private function success(array $data = []): array {
181
+        return array_merge($data, ['status' => 'success']);
182
+    }
183
+
184
+    /**
185
+     * @PublicPage
186
+     * @BruteForceProtection(action=passwordResetEmail)
187
+     * @AnonRateThrottle(limit=10, period=300)
188
+     */
189
+    public function email(string $user): JSONResponse {
190
+        if ($this->config->getSystemValue('lost_password_link', '') !== '') {
191
+            return new JSONResponse($this->error($this->l10n->t('Password reset is disabled')));
192
+        }
193
+
194
+        \OCP\Util::emitHook(
195
+            '\OCA\Files_Sharing\API\Server2Server',
196
+            'preLoginNameUsedAsUserName',
197
+            ['uid' => &$user]
198
+        );
199
+
200
+        // FIXME: use HTTP error codes
201
+        try {
202
+            $this->sendEmail($user);
203
+        } catch (ResetPasswordException $e) {
204
+            // Ignore the error since we do not want to leak this info
205
+            $this->logger->warning('Could not send password reset email: ' . $e->getMessage());
206
+        } catch (Exception $e) {
207
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
208
+        }
209
+
210
+        $response = new JSONResponse($this->success());
211
+        $response->throttle();
212
+        return $response;
213
+    }
214
+
215
+    /**
216
+     * @PublicPage
217
+     */
218
+    public function setPassword(string $token, string $userId, string $password, bool $proceed): array {
219
+        if ($this->encryptionManager->isEnabled() && !$proceed) {
220
+            $encryptionModules = $this->encryptionManager->getEncryptionModules();
221
+            foreach ($encryptionModules as $module) {
222
+                /** @var IEncryptionModule $instance */
223
+                $instance = call_user_func($module['callback']);
224
+                // this way we can find out whether per-user keys are used or a system wide encryption key
225
+                if ($instance->needDetailedAccessList()) {
226
+                    return $this->error('', ['encryption' => true]);
227
+                }
228
+            }
229
+        }
230
+
231
+        try {
232
+            $this->checkPasswordResetToken($token, $userId);
233
+            $user = $this->userManager->get($userId);
234
+
235
+            $this->eventDispatcher->dispatchTyped(new BeforePasswordResetEvent($user, $password));
236
+            \OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'pre_passwordReset', ['uid' => $userId, 'password' => $password]);
237
+
238
+            if (!$user->setPassword($password)) {
239
+                throw new Exception();
240
+            }
241
+
242
+            $this->eventDispatcher->dispatchTyped(new PasswordResetEvent($user, $password));
243
+            \OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'post_passwordReset', ['uid' => $userId, 'password' => $password]);
244
+
245
+            $this->twoFactorManager->clearTwoFactorPending($userId);
246
+
247
+            $this->config->deleteUserValue($userId, 'core', 'lostpassword');
248
+            @\OC::$server->getUserSession()->unsetMagicInCookie();
249
+        } catch (HintException $e) {
250
+            return $this->error($e->getHint());
251
+        } catch (Exception $e) {
252
+            return $this->error($e->getMessage());
253
+        }
254
+
255
+        return $this->success(['user' => $userId]);
256
+    }
257
+
258
+    /**
259
+     * @throws ResetPasswordException
260
+     * @throws \OCP\PreConditionNotMetException
261
+     */
262
+    protected function sendEmail(string $input): void {
263
+        $user = $this->findUserByIdOrMail($input);
264
+        $email = $user->getEMailAddress();
265
+
266
+        if (empty($email)) {
267
+            throw new ResetPasswordException('Could not send reset e-mail since there is no email for username ' . $input);
268
+        }
269
+
270
+        // Generate the token. It is stored encrypted in the database with the
271
+        // secret being the users' email address appended with the system secret.
272
+        // This makes the token automatically invalidate once the user changes
273
+        // their email address.
274
+        $token = $this->verificationToken->create($user, 'lostpassword', $email);
275
+
276
+        $link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', ['userId' => $user->getUID(), 'token' => $token]);
277
+
278
+        $emailTemplate = $this->mailer->createEMailTemplate('core.ResetPassword', [
279
+            'link' => $link,
280
+        ]);
281
+
282
+        $emailTemplate->setSubject($this->l10n->t('%s password reset', [$this->defaults->getName()]));
283
+        $emailTemplate->addHeader();
284
+        $emailTemplate->addHeading($this->l10n->t('Password reset'));
285
+
286
+        $emailTemplate->addBodyText(
287
+            htmlspecialchars($this->l10n->t('Click the following button to reset your password. If you have not requested the password reset, then ignore this email.')),
288
+            $this->l10n->t('Click the following link to reset your password. If you have not requested the password reset, then ignore this email.')
289
+        );
290
+
291
+        $emailTemplate->addBodyButton(
292
+            htmlspecialchars($this->l10n->t('Reset your password')),
293
+            $link,
294
+            false
295
+        );
296
+        $emailTemplate->addFooter();
297
+
298
+        try {
299
+            $message = $this->mailer->createMessage();
300
+            $message->setTo([$email => $user->getDisplayName()]);
301
+            $message->setFrom([$this->from => $this->defaults->getName()]);
302
+            $message->useTemplate($emailTemplate);
303
+            $this->mailer->send($message);
304
+        } catch (Exception $e) {
305
+            // Log the exception and continue
306
+            $this->logger->error($e->getMessage(), ['app' => 'core', 'exception' => $e]);
307
+        }
308
+    }
309
+
310
+    /**
311
+     * @throws ResetPasswordException
312
+     */
313
+    protected function findUserByIdOrMail(string $input): IUser {
314
+        $user = $this->userManager->get($input);
315
+        if ($user instanceof IUser) {
316
+            if (!$user->isEnabled()) {
317
+                throw new ResetPasswordException('User ' . $user->getUID() . ' is disabled');
318
+            }
319
+
320
+            return $user;
321
+        }
322
+
323
+        $users = array_filter($this->userManager->getByEmail($input), function (IUser $user) {
324
+            return $user->isEnabled();
325
+        });
326
+
327
+        if (count($users) === 1) {
328
+            return reset($users);
329
+        }
330
+
331
+        throw new ResetPasswordException('Could not find user ' . $input);
332
+    }
333 333
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -169,7 +169,7 @@  discard block
 block discarded – undo
169 169
 			$error = $e->getCode() === InvalidTokenException::TOKEN_EXPIRED
170 170
 				? $this->l10n->t('Could not reset password because the token is expired')
171 171
 				: $this->l10n->t('Could not reset password because the token is invalid');
172
-			throw new Exception($error, (int)$e->getCode(), $e);
172
+			throw new Exception($error, (int) $e->getCode(), $e);
173 173
 		}
174 174
 	}
175 175
 
@@ -202,7 +202,7 @@  discard block
 block discarded – undo
202 202
 			$this->sendEmail($user);
203 203
 		} catch (ResetPasswordException $e) {
204 204
 			// Ignore the error since we do not want to leak this info
205
-			$this->logger->warning('Could not send password reset email: ' . $e->getMessage());
205
+			$this->logger->warning('Could not send password reset email: '.$e->getMessage());
206 206
 		} catch (Exception $e) {
207 207
 			$this->logger->error($e->getMessage(), ['exception' => $e]);
208 208
 		}
@@ -264,7 +264,7 @@  discard block
 block discarded – undo
264 264
 		$email = $user->getEMailAddress();
265 265
 
266 266
 		if (empty($email)) {
267
-			throw new ResetPasswordException('Could not send reset e-mail since there is no email for username ' . $input);
267
+			throw new ResetPasswordException('Could not send reset e-mail since there is no email for username '.$input);
268 268
 		}
269 269
 
270 270
 		// Generate the token. It is stored encrypted in the database with the
@@ -314,13 +314,13 @@  discard block
 block discarded – undo
314 314
 		$user = $this->userManager->get($input);
315 315
 		if ($user instanceof IUser) {
316 316
 			if (!$user->isEnabled()) {
317
-				throw new ResetPasswordException('User ' . $user->getUID() . ' is disabled');
317
+				throw new ResetPasswordException('User '.$user->getUID().' is disabled');
318 318
 			}
319 319
 
320 320
 			return $user;
321 321
 		}
322 322
 
323
-		$users = array_filter($this->userManager->getByEmail($input), function (IUser $user) {
323
+		$users = array_filter($this->userManager->getByEmail($input), function(IUser $user) {
324 324
 			return $user->isEnabled();
325 325
 		});
326 326
 
@@ -328,6 +328,6 @@  discard block
 block discarded – undo
328 328
 			return reset($users);
329 329
 		}
330 330
 
331
-		throw new ResetPasswordException('Could not find user ' . $input);
331
+		throw new ResetPasswordException('Could not find user '.$input);
332 332
 	}
333 333
 }
Please login to merge, or discard this patch.