Completed
Pull Request — master (#4435)
by Lukas
16:16 queued 02:27
created
core/Controller/LostController.php 1 patch
Indentation   +283 added lines, -283 removed lines patch added patch discarded remove patch
@@ -56,287 +56,287 @@
 block discarded – undo
56 56
  */
57 57
 class LostController extends Controller {
58 58
 
59
-	/** @var IURLGenerator */
60
-	protected $urlGenerator;
61
-	/** @var IUserManager */
62
-	protected $userManager;
63
-	/** @var Defaults */
64
-	protected $defaults;
65
-	/** @var IL10N */
66
-	protected $l10n;
67
-	/** @var string */
68
-	protected $from;
69
-	/** @var IManager */
70
-	protected $encryptionManager;
71
-	/** @var IConfig */
72
-	protected $config;
73
-	/** @var ISecureRandom */
74
-	protected $secureRandom;
75
-	/** @var IMailer */
76
-	protected $mailer;
77
-	/** @var ITimeFactory */
78
-	protected $timeFactory;
79
-	/** @var ICrypto */
80
-	protected $crypto;
81
-
82
-	/**
83
-	 * @param string $appName
84
-	 * @param IRequest $request
85
-	 * @param IURLGenerator $urlGenerator
86
-	 * @param IUserManager $userManager
87
-	 * @param Defaults $defaults
88
-	 * @param IL10N $l10n
89
-	 * @param IConfig $config
90
-	 * @param ISecureRandom $secureRandom
91
-	 * @param string $defaultMailAddress
92
-	 * @param IManager $encryptionManager
93
-	 * @param IMailer $mailer
94
-	 * @param ITimeFactory $timeFactory
95
-	 * @param ICrypto $crypto
96
-	 */
97
-	public function __construct($appName,
98
-								IRequest $request,
99
-								IURLGenerator $urlGenerator,
100
-								IUserManager $userManager,
101
-								Defaults $defaults,
102
-								IL10N $l10n,
103
-								IConfig $config,
104
-								ISecureRandom $secureRandom,
105
-								$defaultMailAddress,
106
-								IManager $encryptionManager,
107
-								IMailer $mailer,
108
-								ITimeFactory $timeFactory,
109
-								ICrypto $crypto) {
110
-		parent::__construct($appName, $request);
111
-		$this->urlGenerator = $urlGenerator;
112
-		$this->userManager = $userManager;
113
-		$this->defaults = $defaults;
114
-		$this->l10n = $l10n;
115
-		$this->secureRandom = $secureRandom;
116
-		$this->from = $defaultMailAddress;
117
-		$this->encryptionManager = $encryptionManager;
118
-		$this->config = $config;
119
-		$this->mailer = $mailer;
120
-		$this->timeFactory = $timeFactory;
121
-		$this->crypto = $crypto;
122
-	}
123
-
124
-	/**
125
-	 * Someone wants to reset their password:
126
-	 *
127
-	 * @PublicPage
128
-	 * @NoCSRFRequired
129
-	 *
130
-	 * @param string $token
131
-	 * @param string $userId
132
-	 * @return TemplateResponse
133
-	 */
134
-	public function resetform($token, $userId) {
135
-		try {
136
-			$this->checkPasswordResetToken($token, $userId);
137
-		} catch (\Exception $e) {
138
-			return new TemplateResponse(
139
-				'core', 'error', [
140
-					"errors" => array(array("error" => $e->getMessage()))
141
-				],
142
-				'guest'
143
-			);
144
-		}
145
-
146
-		return new TemplateResponse(
147
-			'core',
148
-			'lostpassword/resetpassword',
149
-			array(
150
-				'link' => $this->urlGenerator->linkToRouteAbsolute('core.lost.setPassword', array('userId' => $userId, 'token' => $token)),
151
-			),
152
-			'guest'
153
-		);
154
-	}
155
-
156
-	/**
157
-	 * @param string $token
158
-	 * @param string $userId
159
-	 * @throws \Exception
160
-	 */
161
-	protected function checkPasswordResetToken($token, $userId) {
162
-		$user = $this->userManager->get($userId);
163
-		if($user === null) {
164
-			throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
165
-		}
166
-
167
-		try {
168
-			$encryptedToken = $this->config->getUserValue($userId, 'core', 'lostpassword', null);
169
-			$mailAddress = !is_null($user->getEMailAddress()) ? $user->getEMailAddress() : '';
170
-			$decryptedToken = $this->crypto->decrypt($encryptedToken, $mailAddress.$this->config->getSystemValue('secret'));
171
-		} catch (\Exception $e) {
172
-			throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
173
-		}
174
-
175
-		$splittedToken = explode(':', $decryptedToken);
176
-		if(count($splittedToken) !== 2) {
177
-			throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
178
-		}
179
-
180
-		if ($splittedToken[0] < ($this->timeFactory->getTime() - 60*60*12) ||
181
-			$user->getLastLogin() > $splittedToken[0]) {
182
-			throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is expired'));
183
-		}
184
-
185
-		if (!hash_equals($splittedToken[1], $token)) {
186
-			throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
187
-		}
188
-	}
189
-
190
-	/**
191
-	 * @param $message
192
-	 * @param array $additional
193
-	 * @return array
194
-	 */
195
-	private function error($message, array $additional=array()) {
196
-		return array_merge(array('status' => 'error', 'msg' => $message), $additional);
197
-	}
198
-
199
-	/**
200
-	 * @return array
201
-	 */
202
-	private function success() {
203
-		return array('status'=>'success');
204
-	}
205
-
206
-	/**
207
-	 * @PublicPage
208
-	 * @BruteForceProtection(action=passwordResetEmail)
209
-	 * @AnonRateThrottle(limit=10, period=300)
210
-	 *
211
-	 * @param string $user
212
-	 * @return JSONResponse
213
-	 */
214
-	public function email($user){
215
-		// FIXME: use HTTP error codes
216
-		try {
217
-			$this->sendEmail($user);
218
-		} catch (\Exception $e){
219
-			$response = new JSONResponse($this->error($e->getMessage()));
220
-			$response->throttle();
221
-			return $response;
222
-		}
223
-
224
-		$response = new JSONResponse($this->success());
225
-		$response->throttle();
226
-		return $response;
227
-	}
228
-
229
-	/**
230
-	 * @PublicPage
231
-	 * @param string $token
232
-	 * @param string $userId
233
-	 * @param string $password
234
-	 * @param boolean $proceed
235
-	 * @return array
236
-	 */
237
-	public function setPassword($token, $userId, $password, $proceed) {
238
-		if ($this->encryptionManager->isEnabled() && !$proceed) {
239
-			return $this->error('', array('encryption' => true));
240
-		}
241
-
242
-		try {
243
-			$this->checkPasswordResetToken($token, $userId);
244
-			$user = $this->userManager->get($userId);
245
-
246
-			\OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'pre_passwordReset', array('uid' => $userId, 'password' => $password));
247
-
248
-			if (!$user->setPassword($password)) {
249
-				throw new \Exception();
250
-			}
251
-
252
-			\OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'post_passwordReset', array('uid' => $userId, 'password' => $password));
253
-
254
-			$this->config->deleteUserValue($userId, 'core', 'lostpassword');
255
-			@\OC_User::unsetMagicInCookie();
256
-		} catch (\Exception $e){
257
-			return $this->error($e->getMessage());
258
-		}
259
-
260
-		return $this->success();
261
-	}
262
-
263
-	/**
264
-	 * @param string $input
265
-	 * @throws \Exception
266
-	 */
267
-	protected function sendEmail($input) {
268
-		$user = $this->findUserByIdOrMail($input);
269
-		$email = $user->getEMailAddress();
270
-
271
-		if (empty($email)) {
272
-			throw new \Exception(
273
-				$this->l10n->t('Could not send reset email because there is no email address for this username. Please contact your administrator.')
274
-			);
275
-		}
276
-
277
-		// Generate the token. It is stored encrypted in the database with the
278
-		// secret being the users' email address appended with the system secret.
279
-		// This makes the token automatically invalidate once the user changes
280
-		// their email address.
281
-		$token = $this->secureRandom->generate(
282
-			21,
283
-			ISecureRandom::CHAR_DIGITS.
284
-			ISecureRandom::CHAR_LOWER.
285
-			ISecureRandom::CHAR_UPPER
286
-		);
287
-		$tokenValue = $this->timeFactory->getTime() .':'. $token;
288
-		$encryptedValue = $this->crypto->encrypt($tokenValue, $email . $this->config->getSystemValue('secret'));
289
-		$this->config->setUserValue($user->getUID(), 'core', 'lostpassword', $encryptedValue);
290
-
291
-		$link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', array('userId' => $user->getUID(), 'token' => $token));
292
-
293
-		$emailTemplate = $this->mailer->createEMailTemplate();
294
-
295
-		$emailTemplate->addHeader();
296
-		$emailTemplate->addHeading($this->l10n->t('Password reset'));
297
-
298
-		$emailTemplate->addBodyText(
299
-			$this->l10n->t('Click the following button to reset your password. If you have not requested the password reset, then ignore this email.'),
300
-			$this->l10n->t('Click the following link to reset your password. If you have not requested the password reset, then ignore this email.')
301
-		);
302
-
303
-		$emailTemplate->addBodyButton(
304
-			$this->l10n->t('Reset your password'),
305
-			$link,
306
-			false
307
-		);
308
-		$emailTemplate->addFooter();
309
-
310
-		try {
311
-			$message = $this->mailer->createMessage();
312
-			$message->setTo([$email => $user->getUID()]);
313
-			$message->setSubject($this->l10n->t('%s password reset', [$this->defaults->getName()]));
314
-			$message->setPlainBody($emailTemplate->renderText());
315
-			$message->setHtmlBody($emailTemplate->renderHtml());
316
-			$message->setFrom([$this->from => $this->defaults->getName()]);
317
-			$this->mailer->send($message);
318
-		} catch (\Exception $e) {
319
-			throw new \Exception($this->l10n->t(
320
-				'Couldn\'t send reset email. Please contact your administrator.'
321
-			));
322
-		}
323
-	}
324
-
325
-	/**
326
-	 * @param string $input
327
-	 * @return IUser
328
-	 * @throws \Exception
329
-	 */
330
-	protected function findUserByIdOrMail($input) {
331
-		$user = $this->userManager->get($input);
332
-		if ($user instanceof IUser) {
333
-			return $user;
334
-		}
335
-		$users = $this->userManager->getByEmail($input);
336
-		if (count($users) === 1) {
337
-			return $users[0];
338
-		}
339
-
340
-		throw new \InvalidArgumentException($this->l10n->t('Couldn\'t send reset email. Please make sure your username is correct.'));
341
-	}
59
+    /** @var IURLGenerator */
60
+    protected $urlGenerator;
61
+    /** @var IUserManager */
62
+    protected $userManager;
63
+    /** @var Defaults */
64
+    protected $defaults;
65
+    /** @var IL10N */
66
+    protected $l10n;
67
+    /** @var string */
68
+    protected $from;
69
+    /** @var IManager */
70
+    protected $encryptionManager;
71
+    /** @var IConfig */
72
+    protected $config;
73
+    /** @var ISecureRandom */
74
+    protected $secureRandom;
75
+    /** @var IMailer */
76
+    protected $mailer;
77
+    /** @var ITimeFactory */
78
+    protected $timeFactory;
79
+    /** @var ICrypto */
80
+    protected $crypto;
81
+
82
+    /**
83
+     * @param string $appName
84
+     * @param IRequest $request
85
+     * @param IURLGenerator $urlGenerator
86
+     * @param IUserManager $userManager
87
+     * @param Defaults $defaults
88
+     * @param IL10N $l10n
89
+     * @param IConfig $config
90
+     * @param ISecureRandom $secureRandom
91
+     * @param string $defaultMailAddress
92
+     * @param IManager $encryptionManager
93
+     * @param IMailer $mailer
94
+     * @param ITimeFactory $timeFactory
95
+     * @param ICrypto $crypto
96
+     */
97
+    public function __construct($appName,
98
+                                IRequest $request,
99
+                                IURLGenerator $urlGenerator,
100
+                                IUserManager $userManager,
101
+                                Defaults $defaults,
102
+                                IL10N $l10n,
103
+                                IConfig $config,
104
+                                ISecureRandom $secureRandom,
105
+                                $defaultMailAddress,
106
+                                IManager $encryptionManager,
107
+                                IMailer $mailer,
108
+                                ITimeFactory $timeFactory,
109
+                                ICrypto $crypto) {
110
+        parent::__construct($appName, $request);
111
+        $this->urlGenerator = $urlGenerator;
112
+        $this->userManager = $userManager;
113
+        $this->defaults = $defaults;
114
+        $this->l10n = $l10n;
115
+        $this->secureRandom = $secureRandom;
116
+        $this->from = $defaultMailAddress;
117
+        $this->encryptionManager = $encryptionManager;
118
+        $this->config = $config;
119
+        $this->mailer = $mailer;
120
+        $this->timeFactory = $timeFactory;
121
+        $this->crypto = $crypto;
122
+    }
123
+
124
+    /**
125
+     * Someone wants to reset their password:
126
+     *
127
+     * @PublicPage
128
+     * @NoCSRFRequired
129
+     *
130
+     * @param string $token
131
+     * @param string $userId
132
+     * @return TemplateResponse
133
+     */
134
+    public function resetform($token, $userId) {
135
+        try {
136
+            $this->checkPasswordResetToken($token, $userId);
137
+        } catch (\Exception $e) {
138
+            return new TemplateResponse(
139
+                'core', 'error', [
140
+                    "errors" => array(array("error" => $e->getMessage()))
141
+                ],
142
+                'guest'
143
+            );
144
+        }
145
+
146
+        return new TemplateResponse(
147
+            'core',
148
+            'lostpassword/resetpassword',
149
+            array(
150
+                'link' => $this->urlGenerator->linkToRouteAbsolute('core.lost.setPassword', array('userId' => $userId, 'token' => $token)),
151
+            ),
152
+            'guest'
153
+        );
154
+    }
155
+
156
+    /**
157
+     * @param string $token
158
+     * @param string $userId
159
+     * @throws \Exception
160
+     */
161
+    protected function checkPasswordResetToken($token, $userId) {
162
+        $user = $this->userManager->get($userId);
163
+        if($user === null) {
164
+            throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
165
+        }
166
+
167
+        try {
168
+            $encryptedToken = $this->config->getUserValue($userId, 'core', 'lostpassword', null);
169
+            $mailAddress = !is_null($user->getEMailAddress()) ? $user->getEMailAddress() : '';
170
+            $decryptedToken = $this->crypto->decrypt($encryptedToken, $mailAddress.$this->config->getSystemValue('secret'));
171
+        } catch (\Exception $e) {
172
+            throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
173
+        }
174
+
175
+        $splittedToken = explode(':', $decryptedToken);
176
+        if(count($splittedToken) !== 2) {
177
+            throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
178
+        }
179
+
180
+        if ($splittedToken[0] < ($this->timeFactory->getTime() - 60*60*12) ||
181
+            $user->getLastLogin() > $splittedToken[0]) {
182
+            throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is expired'));
183
+        }
184
+
185
+        if (!hash_equals($splittedToken[1], $token)) {
186
+            throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
187
+        }
188
+    }
189
+
190
+    /**
191
+     * @param $message
192
+     * @param array $additional
193
+     * @return array
194
+     */
195
+    private function error($message, array $additional=array()) {
196
+        return array_merge(array('status' => 'error', 'msg' => $message), $additional);
197
+    }
198
+
199
+    /**
200
+     * @return array
201
+     */
202
+    private function success() {
203
+        return array('status'=>'success');
204
+    }
205
+
206
+    /**
207
+     * @PublicPage
208
+     * @BruteForceProtection(action=passwordResetEmail)
209
+     * @AnonRateThrottle(limit=10, period=300)
210
+     *
211
+     * @param string $user
212
+     * @return JSONResponse
213
+     */
214
+    public function email($user){
215
+        // FIXME: use HTTP error codes
216
+        try {
217
+            $this->sendEmail($user);
218
+        } catch (\Exception $e){
219
+            $response = new JSONResponse($this->error($e->getMessage()));
220
+            $response->throttle();
221
+            return $response;
222
+        }
223
+
224
+        $response = new JSONResponse($this->success());
225
+        $response->throttle();
226
+        return $response;
227
+    }
228
+
229
+    /**
230
+     * @PublicPage
231
+     * @param string $token
232
+     * @param string $userId
233
+     * @param string $password
234
+     * @param boolean $proceed
235
+     * @return array
236
+     */
237
+    public function setPassword($token, $userId, $password, $proceed) {
238
+        if ($this->encryptionManager->isEnabled() && !$proceed) {
239
+            return $this->error('', array('encryption' => true));
240
+        }
241
+
242
+        try {
243
+            $this->checkPasswordResetToken($token, $userId);
244
+            $user = $this->userManager->get($userId);
245
+
246
+            \OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'pre_passwordReset', array('uid' => $userId, 'password' => $password));
247
+
248
+            if (!$user->setPassword($password)) {
249
+                throw new \Exception();
250
+            }
251
+
252
+            \OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'post_passwordReset', array('uid' => $userId, 'password' => $password));
253
+
254
+            $this->config->deleteUserValue($userId, 'core', 'lostpassword');
255
+            @\OC_User::unsetMagicInCookie();
256
+        } catch (\Exception $e){
257
+            return $this->error($e->getMessage());
258
+        }
259
+
260
+        return $this->success();
261
+    }
262
+
263
+    /**
264
+     * @param string $input
265
+     * @throws \Exception
266
+     */
267
+    protected function sendEmail($input) {
268
+        $user = $this->findUserByIdOrMail($input);
269
+        $email = $user->getEMailAddress();
270
+
271
+        if (empty($email)) {
272
+            throw new \Exception(
273
+                $this->l10n->t('Could not send reset email because there is no email address for this username. Please contact your administrator.')
274
+            );
275
+        }
276
+
277
+        // Generate the token. It is stored encrypted in the database with the
278
+        // secret being the users' email address appended with the system secret.
279
+        // This makes the token automatically invalidate once the user changes
280
+        // their email address.
281
+        $token = $this->secureRandom->generate(
282
+            21,
283
+            ISecureRandom::CHAR_DIGITS.
284
+            ISecureRandom::CHAR_LOWER.
285
+            ISecureRandom::CHAR_UPPER
286
+        );
287
+        $tokenValue = $this->timeFactory->getTime() .':'. $token;
288
+        $encryptedValue = $this->crypto->encrypt($tokenValue, $email . $this->config->getSystemValue('secret'));
289
+        $this->config->setUserValue($user->getUID(), 'core', 'lostpassword', $encryptedValue);
290
+
291
+        $link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', array('userId' => $user->getUID(), 'token' => $token));
292
+
293
+        $emailTemplate = $this->mailer->createEMailTemplate();
294
+
295
+        $emailTemplate->addHeader();
296
+        $emailTemplate->addHeading($this->l10n->t('Password reset'));
297
+
298
+        $emailTemplate->addBodyText(
299
+            $this->l10n->t('Click the following button to reset your password. If you have not requested the password reset, then ignore this email.'),
300
+            $this->l10n->t('Click the following link to reset your password. If you have not requested the password reset, then ignore this email.')
301
+        );
302
+
303
+        $emailTemplate->addBodyButton(
304
+            $this->l10n->t('Reset your password'),
305
+            $link,
306
+            false
307
+        );
308
+        $emailTemplate->addFooter();
309
+
310
+        try {
311
+            $message = $this->mailer->createMessage();
312
+            $message->setTo([$email => $user->getUID()]);
313
+            $message->setSubject($this->l10n->t('%s password reset', [$this->defaults->getName()]));
314
+            $message->setPlainBody($emailTemplate->renderText());
315
+            $message->setHtmlBody($emailTemplate->renderHtml());
316
+            $message->setFrom([$this->from => $this->defaults->getName()]);
317
+            $this->mailer->send($message);
318
+        } catch (\Exception $e) {
319
+            throw new \Exception($this->l10n->t(
320
+                'Couldn\'t send reset email. Please contact your administrator.'
321
+            ));
322
+        }
323
+    }
324
+
325
+    /**
326
+     * @param string $input
327
+     * @return IUser
328
+     * @throws \Exception
329
+     */
330
+    protected function findUserByIdOrMail($input) {
331
+        $user = $this->userManager->get($input);
332
+        if ($user instanceof IUser) {
333
+            return $user;
334
+        }
335
+        $users = $this->userManager->getByEmail($input);
336
+        if (count($users) === 1) {
337
+            return $users[0];
338
+        }
339
+
340
+        throw new \InvalidArgumentException($this->l10n->t('Couldn\'t send reset email. Please make sure your username is correct.'));
341
+    }
342 342
 }
Please login to merge, or discard this patch.