Skip to content

Commit c559e14

Browse files
author
gcompagnon
committed
Activate and choose new Password Form
1 parent fcd5fc6 commit c559e14

File tree

9 files changed

+482
-25
lines changed

9 files changed

+482
-25
lines changed

config/config.sample.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@
5454
*/
5555
'passwordsalt' => '',
5656

57+
/**
58+
* The adminitsrator email provides a place to personalize a support email to
59+
* display in all messages errors
60+
*
61+
* 'administrator_email' => '[email protected]',
62+
*/
63+
'administrator_email' => 'your administrator email',
64+
5765
/**
5866
* Your list of trusted domains that users can log into. Specifying trusted
5967
* domains prevents host header poisoning. Do not remove this, as it performs

core/Controller/LostController.php

Lines changed: 173 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232
namespace OC\Core\Controller;
3333

3434
use OC\Authentication\TwoFactorAuth\Manager;
35+
use OC\Security\Bruteforce\Throttler;
3536
use OC\HintException;
3637
use \OCP\AppFramework\Controller;
38+
use OCP\AppFramework\Http;
3739
use OCP\AppFramework\Http\JSONResponse;
3840
use \OCP\AppFramework\Http\TemplateResponse;
3941
use OCP\AppFramework\Utility\ITimeFactory;
@@ -47,6 +49,8 @@
4749
use \OCP\IConfig;
4850
use OCP\IUser;
4951
use OCP\IUserManager;
52+
use OCP\ISession;
53+
use OCP\Util;
5054
use OCP\Mail\IMailer;
5155
use OCP\Security\ICrypto;
5256
use OCP\Security\ISecureRandom;
@@ -73,6 +77,8 @@ class LostController extends Controller {
7377
protected $encryptionManager;
7478
/** @var IConfig */
7579
protected $config;
80+
/** @var ISession */
81+
protected $session;
7682
/** @var ISecureRandom */
7783
protected $secureRandom;
7884
/** @var IMailer */
@@ -85,6 +91,9 @@ class LostController extends Controller {
8591
private $logger;
8692
/** @var Manager */
8793
private $twoFactorManager;
94+
/** @var Throttler */
95+
private $throttler;
96+
8897

8998
/**
9099
* @param string $appName
@@ -94,6 +103,7 @@ class LostController extends Controller {
94103
* @param Defaults $defaults
95104
* @param IL10N $l10n
96105
* @param IConfig $config
106+
* @param ISession $session
97107
* @param ISecureRandom $secureRandom
98108
* @param string $defaultMailAddress
99109
* @param IManager $encryptionManager
@@ -108,14 +118,16 @@ public function __construct($appName,
108118
Defaults $defaults,
109119
IL10N $l10n,
110120
IConfig $config,
121+
ISession $session,
111122
ISecureRandom $secureRandom,
112123
$defaultMailAddress,
113124
IManager $encryptionManager,
114125
IMailer $mailer,
115126
ITimeFactory $timeFactory,
116127
ICrypto $crypto,
117128
ILogger $logger,
118-
Manager $twoFactorManager) {
129+
Manager $twoFactorManager,
130+
Throttler $throttler) {
119131
parent::__construct($appName, $request);
120132
$this->urlGenerator = $urlGenerator;
121133
$this->userManager = $userManager;
@@ -125,11 +137,13 @@ public function __construct($appName,
125137
$this->from = $defaultMailAddress;
126138
$this->encryptionManager = $encryptionManager;
127139
$this->config = $config;
140+
$this->session = $session;
128141
$this->mailer = $mailer;
129142
$this->timeFactory = $timeFactory;
130143
$this->crypto = $crypto;
131144
$this->logger = $logger;
132145
$this->twoFactorManager = $twoFactorManager;
146+
$this->throttler = $throttler;
133147
}
134148

135149
/**
@@ -171,6 +185,95 @@ public function resetform($token, $userId) {
171185
'guest'
172186
);
173187
}
188+
/**
189+
* @PublicPage
190+
* @NoCSRFRequired
191+
* @BruteForceProtection(action=passwordResetEmail)
192+
* @AnonRateThrottle(limit=10, period=300)
193+
* @UseSession
194+
*
195+
* @param string $userId
196+
*
197+
* @return TemplateResponse
198+
*/
199+
public function showPasswordEmailForm($userId) : Http\Response {
200+
return $this->showNewPasswordForm($userId);
201+
}
202+
/**
203+
* @PublicPage
204+
* @NoCSRFRequired
205+
* @BruteForceProtection(action=passwordResetEmail)
206+
* @AnonRateThrottle(limit=10, period=300)
207+
* @UseSession
208+
*
209+
* @param string $user
210+
*
211+
* @return TemplateResponse
212+
*/
213+
public function showNewPasswordForm($user = null) : Http\Response {
214+
215+
$parameters = [];
216+
$renewPasswordMessages = $this->session->get('loginMessages');
217+
$errors = [];
218+
$messages = [];
219+
220+
if (is_array($renewPasswordMessages)) {
221+
list($errors, $messages) = $renewPasswordMessages;
222+
}
223+
$this->session->remove('loginMessages');
224+
foreach ($errors as $value) {
225+
$parameters[$value] = true;
226+
}
227+
$parameters['messages'] = $messages;
228+
229+
$parameters['resetPasswordLink'] = $this->config
230+
->getSystemValue('lost_password_link', '');
231+
232+
// disable the form if setting 'password reset' is disabled
233+
if ($parameters['resetPasswordLink'] !== '') {
234+
return new TemplateResponse('core', 'error', [
235+
'errors' => [['error' => $this->l10n->t('Password reset is disabled')]]
236+
],
237+
'guest'
238+
);
239+
}
240+
241+
$userObj = null;
242+
if ($user !== null && $user !== '') {
243+
try {
244+
$userObj = $this->findUserByIdOrMail($user);
245+
$parameters['displayName'] = $userObj->getDisplayName();
246+
$parameters['loginName'] = $userObj->getEMailAddress();
247+
//the timestamp of the user's last login or 0 if the user did never
248+
$parameters['last_login'] = $userObj->getLastLogin();
249+
$parameters['user_autofocus'] = false;
250+
} catch(\InvalidArgumentException $exception){
251+
// $user parameter is unknown or desactivated
252+
$parameters['messages'][] = $user . ' :' . $this->l10n->t('unknown text');
253+
$parameters['loginName'] = null;
254+
$parameters['displayName'] = null;
255+
$parameters['last_login'] = null;
256+
$parameters['user_autofocus'] = true;
257+
}
258+
}
259+
260+
$parameters = $this->setPasswordResetParameters($userObj, $parameters);
261+
$parameters['administrator_email'] = $this->config->getSystemValue('administrator_email');
262+
$parameters['login_form_autocomplete'] = 'on';
263+
$parameters['throttle_delay'] = $this->throttler->getDelay($this->request->getRemoteAddress());
264+
265+
// OpenGraph Support: http://ogp.me/
266+
Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
267+
Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
268+
Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
269+
Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
270+
Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
271+
Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-touch.png'))]);
272+
273+
return new TemplateResponse(
274+
$this->appName, 'lostpassword/newpassword', $parameters, 'guest'
275+
);
276+
}
174277

175278
/**
176279
* @param string $token
@@ -229,9 +332,10 @@ private function success($data = []) {
229332
* @AnonRateThrottle(limit=10, period=300)
230333
*
231334
* @param string $user
335+
* @param string $action optional
232336
* @return JSONResponse
233337
*/
234-
public function email($user){
338+
public function email($user,$action=null){
235339
if ($this->config->getSystemValue('lost_password_link', '') !== '') {
236340
return new JSONResponse($this->error($this->l10n->t('Password reset is disabled')));
237341
}
@@ -244,7 +348,7 @@ public function email($user){
244348

245349
// FIXME: use HTTP error codes
246350
try {
247-
$this->sendEmail($user);
351+
$this->sendEmail($user,$action);
248352
} catch (\Exception $e) {
249353
// Ignore the error since we do not want to leak this info
250354
$this->logger->logException($e, [
@@ -309,9 +413,10 @@ public function setPassword($token, $userId, $password, $proceed) {
309413

310414
/**
311415
* @param string $input
416+
* @param string $action
312417
* @throws \Exception
313418
*/
314-
protected function sendEmail($input) {
419+
protected function sendEmail($input,$action=null) {
315420
$user = $this->findUserByIdOrMail($input);
316421
$email = $user->getEMailAddress();
317422

@@ -341,22 +446,44 @@ protected function sendEmail($input) {
341446
'link' => $link,
342447
]);
343448

344-
$emailTemplate->setSubject($this->l10n->t('%s password reset', [$this->defaults->getName()]));
345-
$emailTemplate->addHeader();
346-
$emailTemplate->addHeading($this->l10n->t('Password reset'));
449+
if((empty($action)) || ($action == 'RESET')) {
450+
$emailTemplate->setSubject($this->l10n->t('%s password reset', [$this->defaults->getName()]));
451+
$emailTemplate->addHeader();
452+
$emailTemplate->addHeading($this->l10n->t('Password reset'));
347453

348-
$emailTemplate->addBodyText(
349-
htmlspecialchars($this->l10n->t('Click the following button to reset your password. If you have not requested the password reset, then ignore this email.')),
350-
$this->l10n->t('Click the following link to reset your password. If you have not requested the password reset, then ignore this email.')
351-
);
454+
$emailTemplate->addBodyText(
455+
htmlspecialchars($this->l10n->t('Click the following button to reset your password. If you have not requested the password reset, then ignore this email.')),
456+
$this->l10n->t('Click the following link to reset your password. If you have not requested the password reset, then ignore this email.')
457+
);
352458

353-
$emailTemplate->addBodyButton(
354-
htmlspecialchars($this->l10n->t('Reset your password')),
355-
$link,
356-
false
357-
);
358-
$emailTemplate->addFooter();
459+
$emailTemplate->addBodyButton(
460+
htmlspecialchars($this->l10n->t('Reset your password')),
461+
$link,
462+
false
463+
);
464+
} else if($action == 'NEW'){
465+
$emailTemplate->setSubject($this->l10n->t('%s activate and choose a password', [$this->defaults->getName()]));
466+
$emailTemplate->addHeader();
467+
$emailTemplate->addHeading($this->l10n->t('Activate and choose a password'));
468+
469+
$emailTemplate->addBodyText(
470+
htmlspecialchars($this->l10n->t('Click the following button to activate and choose a new password. If you have not requested the new password, then ignore this email.')),
471+
$this->l10n->t('Click the following link to activate and choose a new password. If you have not requested the new password, then ignore this email.')
472+
);
473+
474+
$emailTemplate->addBodyButton(
475+
htmlspecialchars($this->l10n->t('Activate and choose your new password')),
476+
$link,
477+
false
478+
);
479+
480+
} else {
481+
throw new \Exception($this->l10n->t(
482+
'Couldn\'t send reset email. Please contact your administrator.'
483+
));
484+
}
359485

486+
$emailTemplate->addFooter();
360487
try {
361488
$message = $this->mailer->createMessage();
362489
$message->setTo([$email => $user->getUID()]);
@@ -394,9 +521,37 @@ protected function findUserByIdOrMail($input) {
394521
});
395522

396523
if (\count($users) === 1) {
397-
return $users[0];
524+
return $users[1];
398525
}
399526

400527
throw $userNotFound;
401528
}
529+
530+
/**
531+
* Sets the password reset params.
532+
*
533+
* Users may not change their passwords if:
534+
* - The account is disabled
535+
* - The backend doesn't support password resets
536+
* - The password reset function is disabled
537+
*
538+
* @param IUser $userObj
539+
* @param array $parameters
540+
* @return array
541+
*/
542+
protected function setPasswordResetParameters(
543+
$userObj = null, array $parameters): array {
544+
545+
if ($parameters['resetPasswordLink'] === 'disabled') {
546+
$parameters['canResetPassword'] = false;
547+
} else if (!$parameters['resetPasswordLink'] && $userObj !== null) {
548+
$parameters['canResetPassword'] = $userObj->canChangePassword();
549+
} else if ($userObj !== null && $userObj->isEnabled() === false) {
550+
$parameters['canResetPassword'] = false;
551+
} else {
552+
$parameters['canResetPassword'] = true;
553+
}
554+
555+
return $parameters;
556+
}
402557
}

core/js/lostpassword.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ OC.Lostpassword = {
134134

135135
getSendStatusNode : function(){
136136
if (!$('#lost-password').length){
137-
$('<p id="lost-password"></p>').insertBefore($('#remember_login'));
137+
$('<p id="lost-password"></p>').insertBefore($('#lost-password-back'));
138138
} else {
139139
$('#lost-password').replaceWith($('<p id="lost-password"></p>'));
140140
}

0 commit comments

Comments
 (0)