From 23ed038a27901b947b75413b966d4beab21cd2bc Mon Sep 17 00:00:00 2001 From: Victor Dubiniuk Date: Tue, 25 Mar 2014 01:38:11 +0300 Subject: [PATCH 01/16] Basics --- core/js/lostpassword.js | 134 +++++++++++++++++++ core/lostpassword/ajaxcontroller.php | 45 +++++++ core/lostpassword/controller.php | 62 ++++----- core/lostpassword/encrypteddataexception.php | 14 ++ core/lostpassword/templates/lostpassword.php | 2 +- core/routes.php | 13 +- core/templates/login.php | 6 +- 7 files changed, 228 insertions(+), 48 deletions(-) create mode 100644 core/js/lostpassword.js create mode 100644 core/lostpassword/ajaxcontroller.php create mode 100644 core/lostpassword/encrypteddataexception.php diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js new file mode 100644 index 0000000000..00dfe71be6 --- /dev/null +++ b/core/js/lostpassword.js @@ -0,0 +1,134 @@ + +OC.Lostpassword = { + sendErrorMsg : t('core', 'Couldn’t send reset email. Please contact your administrator.'), + + sendSuccessMsg : t('core', 'The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator.'), + + encryptedMsg : t('core', "Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.
If you are not sure what to do, please contact your administrator before you continue.
Do you really want to continue?") + + ('
') + + '
' + + '' + + t('core', 'Reset password') + + '', + + resetErrorMsg : t('core', 'Password can not be changed. Please contact your administrator.'), + + init : function() { + if ($('#lost-password-encryption').length){ + $('#lost-password-encryption').click(OC.Lostpassword.sendLink); + } else { + $('#lost-password').click(OC.Lostpassword.sendLink); + } + $('#reset-password #submit').click(OC.Lostpassword.resetPassword); + }, + + sendLink : function(event){ + event.preventDefault(); + if (!$('#user').val().length){ + $('#submit').trigger('click'); + } else { + $.post( + OC.filePath('core', 'ajax', 'password/lost'), + { + user : $('#user').val(), + proceed: $('#encrypted-continue').attr('checked') ? 'Yes' : 'No' + }, + OC.Lostpassword.sendLinkDone + ); + } + }, + + sendLinkDone : function(result){ + if (result && result.status === 'success'){ + OC.Lostpassword.sendLinkSuccess(); + } else { + if (result && result.msg){ + var sendErrorMsg = result.msg; + } else if (result && result.encryption) { + var sendErrorMsg = OC.Lostpassword.encryptedMsg; + } else { + var sendErrorMsg = OC.Lostpassword.sendErrorMsg; + } + OC.Lostpassword.sendLinkError(sendErrorMsg); + } + }, + + sendLinkSuccess : function(msg){ + var node = OC.Lostpassword.getSendStatusNode(); + node.addClass('success').css({width:'auto'}); + node.html(OC.Lostpassword.sendSuccessMsg); + }, + + sendLinkError : function(msg){ + var node = OC.Lostpassword.getSendStatusNode(); + node.addClass('warning'); + node.html(msg); + OC.Lostpassword.init(); + }, + + getSendStatusNode : function(){ + if (!$('#lost-password').length){ + $('

').insertBefore($('#remember_login')); + } else { + $('#lost-password').replaceWith($('

')); + } + return $('#lost-password'); + }, + + resetPassword : function(event){ + event.preventDefault(); + if ($('#password').val()){ + $.post( + $('#password').parents('form').attr('action'), + { + password : $('#password').val() + }, + OC.Lostpassword.resetDone + ); + } + }, + + resetDone : function(result){ + if (result && result.status === 'success'){ + $.post( + OC.webroot + '/', + { + user : window.location.href.split('/').pop(), + password : $('#password').val() + }, + OC.Lostpassword.redirect + ); + } else { + if (result && result.msg){ + var resetErrorMsg = result.msg; + } else { + var resetErrorMsg = OC.Lostpassword.resetErrorMsg; + } + OC.Lostpassword.resetError(resetErrorMsg); + } + }, + + redirect : function(msg){ + window.location = OC.webroot; + }, + + resetError : function(msg){ + var node = OC.Lostpassword.getResetStatusNode(); + node.addClass('warning'); + node.html(msg); + }, + + getResetStatusNode : function (){ + if (!$('#lost-password').length){ + $('

').insertAfter($('#submit')); + } else { + $('#lost-password').replaceWith($('

')); + } + return $('#lost-password'); + } + +}; + +$(document).ready(OC.Lostpassword.init); diff --git a/core/lostpassword/ajaxcontroller.php b/core/lostpassword/ajaxcontroller.php new file mode 100644 index 0000000000..3722681308 --- /dev/null +++ b/core/lostpassword/ajaxcontroller.php @@ -0,0 +1,45 @@ + '1') + ); + } catch (\Exception $e){ + \OCP\JSON::error( + array('msg'=> $e->getMessage()) + ); + } + + exit(); + } + + public static function resetPassword($args) { + \OCP\JSON::callCheck(); + try { + Controller::resetPassword($args); + \OCP\JSON::success(); + } catch (Exception $e){ + \OCP\JSON::error( + array('msg'=> $e->getMessage()) + ); + } + exit(); + } +} diff --git a/core/lostpassword/controller.php b/core/lostpassword/controller.php index c858696885..0c6ada4edc 100644 --- a/core/lostpassword/controller.php +++ b/core/lostpassword/controller.php @@ -36,47 +36,37 @@ class Controller { return \OC_Preferences::getValue($user, 'owncloud', 'lostpassword') === hash('sha256', $token); } - public static function index($args) { - self::displayLostPasswordPage(false, false); - } - - public static function sendEmail($args) { - + public static function sendEmail($user, $proceed) { + $l = \OC_L10N::get('core'); $isEncrypted = \OC_App::isEnabled('files_encryption'); - if(!$isEncrypted || isset($_POST['continue'])) { - $continue = true; - } else { - $continue = false; + if ($isEncrypted && $proceed !== 'Yes'){ + throw new EncryptedDataException(); } - if (\OC_User::userExists($_POST['user']) && $continue) { - $token = hash('sha256', \OC_Util::generateRandomBytes(30).\OC_Config::getValue('passwordsalt', '')); - \OC_Preferences::setValue($_POST['user'], 'owncloud', 'lostpassword', - hash('sha256', $token)); // Hash the token again to prevent timing attacks - $email = \OC_Preferences::getValue($_POST['user'], 'settings', 'email', ''); - if (!empty($email)) { - $link = \OC_Helper::linkToRoute('core_lostpassword_reset', - array('user' => $_POST['user'], 'token' => $token)); - $link = \OC_Helper::makeURLAbsolute($link); + if (!\OC_User::userExists($user)) { + throw new \Exception($l->t('Couldn’t send reset email. Please make sure your username is correct.')); + } + $token = hash('sha256', \OC_Util::generateRandomBytes(30).\OC_Config::getValue('passwordsalt', '')); + \OC_Preferences::setValue($user, 'owncloud', 'lostpassword', + hash('sha256', $token)); // Hash the token again to prevent timing attacks + $email = \OC_Preferences::getValue($user, 'settings', 'email', ''); + if (empty($email)) { + throw new \Exception($l->t('Couldn’t send reset email because there is no email address for this username. Please contact your administrator.')); + } + $link = \OC_Helper::linkToRoute('core_lostpassword_reset', + array('user' => $user, 'token' => $token)); + $link = \OC_Helper::makeURLAbsolute($link); - $tmpl = new \OC_Template('core/lostpassword', 'email'); - $tmpl->assign('link', $link, false); - $msg = $tmpl->fetchPage(); - $l = \OC_L10N::get('core'); - $from = \OCP\Util::getDefaultEmailAddress('lostpassword-noreply'); - try { - $defaults = new \OC_Defaults(); - \OC_Mail::send($email, $_POST['user'], $l->t('%s password reset', array($defaults->getName())), $msg, $from, $defaults->getName()); - } catch (Exception $e) { - \OC_Template::printErrorPage( $l->t('A problem has occurred whilst sending the email, please contact your administrator.') ); - } - self::displayLostPasswordPage(false, true); - } else { - self::displayLostPasswordPage(true, false); - } - } else { - self::displayLostPasswordPage(true, false); + $tmpl = new \OC_Template('core/lostpassword', 'email'); + $tmpl->assign('link', $link, false); + $msg = $tmpl->fetchPage(); + $from = \OCP\Util::getDefaultEmailAddress('lostpassword-noreply'); + try { + $defaults = new \OC_Defaults(); + \OC_Mail::send($email, $user, $l->t('%s password reset', array($defaults->getName())), $msg, $from, $defaults->getName()); + } catch (\Exception $e) { + throw new \Exception( $l->t('Couldn’t send reset email. Please contact your administrator.')); } } diff --git a/core/lostpassword/encrypteddataexception.php b/core/lostpassword/encrypteddataexception.php new file mode 100644 index 0000000000..99d19445b6 --- /dev/null +++ b/core/lostpassword/encrypteddataexception.php @@ -0,0 +1,14 @@ +

-
+

diff --git a/core/routes.php b/core/routes.php index 5368fd4564..fbbbdee81f 100644 --- a/core/routes.php +++ b/core/routes.php @@ -70,18 +70,15 @@ $this->create('core_ajax_preview', '/core/preview') ->actionInclude('core/ajax/preview.php'); $this->create('core_ajax_preview', '/core/preview.png') ->actionInclude('core/ajax/preview.php'); -$this->create('core_lostpassword_index', '/lostpassword/') - ->get() - ->action('OC\Core\LostPassword\Controller', 'index'); -$this->create('core_lostpassword_send_email', '/lostpassword/') +$this->create('core_ajax_password_lost', '/core/ajax/password/lost') ->post() - ->action('OC\Core\LostPassword\Controller', 'sendEmail'); + ->action('OC\Core\Lostpassword\AjaxController', 'lost'); +$this->create('core_ajax_password_reset', '/core/ajax/password/reset/{token}/{user}') + ->post() + ->action('OC\Core\LostPassword\AjaxController', 'resetPassword'); $this->create('core_lostpassword_reset', '/lostpassword/reset/{token}/{user}') ->get() ->action('OC\Core\LostPassword\Controller', 'reset'); -$this->create('core_lostpassword_reset_password', '/lostpassword/reset/{token}/{user}') - ->post() - ->action('OC\Core\LostPassword\Controller', 'resetPassword'); // Avatar routes $this->create('core_avatar_get_tmp', '/avatar/tmp') diff --git a/core/templates/login.php b/core/templates/login.php index 6af3d76969..951ba3b4f6 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -46,8 +46,8 @@

- - t('Lost your password?')); ?> + + t('Forgot your password? Reset it!')); ?> @@ -74,4 +74,4 @@ Date: Wed, 28 May 2014 00:09:08 +0300 Subject: [PATCH 02/16] Use appframework --- core/js/lostpassword.js | 4 +- core/lostpassword/ajaxcontroller.php | 45 -------- core/lostpassword/controller.php | 101 ------------------ .../controller/ajaxcontroller.php | 101 ++++++++++++++++++ .../controller/lostcontroller.php | 66 ++++++++++++ core/lostpassword/templates/lostpassword.php | 45 +++----- core/lostpassword/templates/resetpassword.php | 19 ++-- core/routes.php | 48 +++++++-- 8 files changed, 229 insertions(+), 200 deletions(-) delete mode 100644 core/lostpassword/ajaxcontroller.php delete mode 100644 core/lostpassword/controller.php create mode 100644 core/lostpassword/controller/ajaxcontroller.php create mode 100644 core/lostpassword/controller/lostcontroller.php diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js index 00dfe71be6..0c50f858ec 100644 --- a/core/js/lostpassword.js +++ b/core/js/lostpassword.js @@ -46,8 +46,6 @@ OC.Lostpassword = { } else { if (result && result.msg){ var sendErrorMsg = result.msg; - } else if (result && result.encryption) { - var sendErrorMsg = OC.Lostpassword.encryptedMsg; } else { var sendErrorMsg = OC.Lostpassword.sendErrorMsg; } @@ -103,6 +101,8 @@ OC.Lostpassword = { } else { if (result && result.msg){ var resetErrorMsg = result.msg; + } else if (result && result.encryption) { + var sendErrorMsg = OC.Lostpassword.encryptedMsg; } else { var resetErrorMsg = OC.Lostpassword.resetErrorMsg; } diff --git a/core/lostpassword/ajaxcontroller.php b/core/lostpassword/ajaxcontroller.php deleted file mode 100644 index 3722681308..0000000000 --- a/core/lostpassword/ajaxcontroller.php +++ /dev/null @@ -1,45 +0,0 @@ - '1') - ); - } catch (\Exception $e){ - \OCP\JSON::error( - array('msg'=> $e->getMessage()) - ); - } - - exit(); - } - - public static function resetPassword($args) { - \OCP\JSON::callCheck(); - try { - Controller::resetPassword($args); - \OCP\JSON::success(); - } catch (Exception $e){ - \OCP\JSON::error( - array('msg'=> $e->getMessage()) - ); - } - exit(); - } -} diff --git a/core/lostpassword/controller.php b/core/lostpassword/controller.php deleted file mode 100644 index 0c6ada4edc..0000000000 --- a/core/lostpassword/controller.php +++ /dev/null @@ -1,101 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ -namespace OC\Core\LostPassword; - -class Controller { - - /** - * @param boolean $error - * @param boolean $requested - */ - protected static function displayLostPasswordPage($error, $requested) { - $isEncrypted = \OC_App::isEnabled('files_encryption'); - \OC_Template::printGuestPage('core/lostpassword', 'lostpassword', - array('error' => $error, - 'requested' => $requested, - 'isEncrypted' => $isEncrypted)); - } - - /** - * @param boolean $success - */ - protected static function displayResetPasswordPage($success, $args) { - $route_args = array(); - $route_args['token'] = $args['token']; - $route_args['user'] = $args['user']; - \OC_Template::printGuestPage('core/lostpassword', 'resetpassword', - array('success' => $success, 'args' => $route_args)); - } - - protected static function checkToken($user, $token) { - return \OC_Preferences::getValue($user, 'owncloud', 'lostpassword') === hash('sha256', $token); - } - - public static function sendEmail($user, $proceed) { - $l = \OC_L10N::get('core'); - $isEncrypted = \OC_App::isEnabled('files_encryption'); - - if ($isEncrypted && $proceed !== 'Yes'){ - throw new EncryptedDataException(); - } - - if (!\OC_User::userExists($user)) { - throw new \Exception($l->t('Couldn’t send reset email. Please make sure your username is correct.')); - } - $token = hash('sha256', \OC_Util::generateRandomBytes(30).\OC_Config::getValue('passwordsalt', '')); - \OC_Preferences::setValue($user, 'owncloud', 'lostpassword', - hash('sha256', $token)); // Hash the token again to prevent timing attacks - $email = \OC_Preferences::getValue($user, 'settings', 'email', ''); - if (empty($email)) { - throw new \Exception($l->t('Couldn’t send reset email because there is no email address for this username. Please contact your administrator.')); - } - $link = \OC_Helper::linkToRoute('core_lostpassword_reset', - array('user' => $user, 'token' => $token)); - $link = \OC_Helper::makeURLAbsolute($link); - - $tmpl = new \OC_Template('core/lostpassword', 'email'); - $tmpl->assign('link', $link, false); - $msg = $tmpl->fetchPage(); - $from = \OCP\Util::getDefaultEmailAddress('lostpassword-noreply'); - try { - $defaults = new \OC_Defaults(); - \OC_Mail::send($email, $user, $l->t('%s password reset', array($defaults->getName())), $msg, $from, $defaults->getName()); - } catch (\Exception $e) { - throw new \Exception( $l->t('Couldn’t send reset email. Please contact your administrator.')); - } - } - - public static function reset($args) { - // Someone wants to reset their password: - if(self::checkToken($args['user'], $args['token'])) { - self::displayResetPasswordPage(false, $args); - } else { - // Someone lost their password - self::displayLostPasswordPage(false, false); - } - } - - public static function resetPassword($args) { - if (self::checkToken($args['user'], $args['token'])) { - if (isset($_POST['password'])) { - if (\OC_User::setPassword($args['user'], $_POST['password'])) { - \OC_Preferences::deleteKey($args['user'], 'owncloud', 'lostpassword'); - \OC_User::unsetMagicInCookie(); - self::displayResetPasswordPage(true, $args); - } else { - self::displayResetPasswordPage(false, $args); - } - } else { - self::reset($args); - } - } else { - // Someone lost their password - self::displayLostPasswordPage(false, false); - } - } -} diff --git a/core/lostpassword/controller/ajaxcontroller.php b/core/lostpassword/controller/ajaxcontroller.php new file mode 100644 index 0000000000..22fa0ce912 --- /dev/null +++ b/core/lostpassword/controller/ajaxcontroller.php @@ -0,0 +1,101 @@ +'success')); + try { + $this->sendEmail($this->params('user', ''), $this->params('proceed', '')); + } catch (EncryptedDataException $e){ + $response->setData(array( + 'status' => 'error', + 'encryption' => '1' + )); + } catch (\Exception $e){ + $response->setData(array( + 'status' => 'error', + 'msg' => $e->getMessage() + )); + } + + return $response; + } + + /** + * @PublicPage + */ + public function resetPassword() { + $response = new JSONResponse(array('status'=>'success')); + try { + $user = $this->params('user'); + $newPassword = $this->params('password'); + if (!$this->checkToken()) { + throw new \RuntimeException(''); + } + if (!\OC_User::setPassword($user, $newPassword)) { + throw new \RuntimeException(''); + } + \OC_Preferences::deleteKey($user, 'owncloud', 'lostpassword'); + \OC_User::unsetMagicInCookie(); + } catch (Exception $e){ + $response->setData(array( + 'status' => 'error', + 'msg' => $e->getMessage() + )); + } + return $response; + } + + protected function sendEmail($user, $proceed) { + $l = \OC_L10N::get('core'); + $isEncrypted = \OC_App::isEnabled('files_encryption'); + + if ($isEncrypted && $proceed !== 'Yes'){ + throw new EncryptedDataException(); + } + + if (!\OC_User::userExists($user)) { + throw new \Exception($l->t('Couldn’t send reset email. Please make sure your username is correct.')); + } + $token = hash('sha256', \OC_Util::generateRandomBytes(30).\OC_Config::getValue('passwordsalt', '')); + \OC_Preferences::setValue($user, 'owncloud', 'lostpassword', + hash('sha256', $token)); // Hash the token again to prevent timing attacks + $email = \OC_Preferences::getValue($user, 'settings', 'email', ''); + if (empty($email)) { + throw new \Exception($l->t('Couldn’t send reset email because there is no email address for this username. Please contact your administrator.')); + } + + $parameters = array('token' => $token, 'user' => $user); + $link = $this->urlGenerator->linkToRoute('core.lost.reset', $parameters); + $link = $this->urlGenerator->getAbsoluteUrl($link); + + $tmpl = new \OC_Template('core/lostpassword', 'email'); + $tmpl->assign('link', $link, false); + $msg = $tmpl->fetchPage(); + echo $link; + $from = \OCP\Util::getDefaultEmailAddress('lostpassword-noreply'); + try { + $defaults = new \OC_Defaults(); + \OC_Mail::send($email, $user, $l->t('%s password reset', array($defaults->getName())), $msg, $from, $defaults->getName()); + } catch (\Exception $e) { + throw new \Exception( $l->t('Couldn’t send reset email. Please contact your administrator.')); + } + } + +} diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php new file mode 100644 index 0000000000..0a28779259 --- /dev/null +++ b/core/lostpassword/controller/lostcontroller.php @@ -0,0 +1,66 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Core\LostPassword\Controller; + +use \OCP\AppFramework\Controller; +use \OCP\AppFramework\Http\TemplateResponse; + +class LostController extends Controller { + + protected $urlGenerator; + + public function __construct($appName, IRequest $request, IURLGenerator $urlGenerator) { + parent::__construct($appName, $request); + $this->urlGenerator = $urlGenerator; + } + + /** + * @PublicPage + * @NoCSRFRequired + */ + public function reset() { + // Someone wants to reset their password: + if($this->checkToken()) { + return new TemplateResponse( + 'core/lostpassword', + 'resetpassword', + array( + 'link' => $link + ), + 'guest' + ); + } else { + // Someone lost their password + $isEncrypted = \OC_App::isEnabled('files_encryption'); + return new TemplateResponse( + 'core/lostpassword', + 'lostpassword', + array( + 'isEncrypted' => $isEncrypted, + 'link' => $this->getResetPasswordLink() + ), + 'guest' + ); + } + } + + protected function getResetPasswordLink(){ + $parameters = array( + 'token' => $this->params('token'), + 'user' => $this->params('user') + ); + $link = $this->urlGenerator->linkToRoute('core.ajax.reset', $parameters); + return $this->urlGenerator->getAbsoluteUrl($link); + } + + protected function checkToken() { + $user = $this->params('user'); + $token = $this->params('token'); + return \OC_Preferences::getValue($user, 'owncloud', 'lostpassword') === hash('sha256', $token); + } +} diff --git a/core/lostpassword/templates/lostpassword.php b/core/lostpassword/templates/lostpassword.php index 0c2c72b40c..7548b4787e 100644 --- a/core/lostpassword/templates/lostpassword.php +++ b/core/lostpassword/templates/lostpassword.php @@ -1,35 +1,20 @@ -

- t('The link to reset your password has been sent to your email.
If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator .')); - ?> -

- - -
- -

- t('Request failed!
Did you make sure your email/username was right?')); ?> -

- -
t('You will receive a link to reset your password via Email.')); ?>
-

- - - - +OCP\Util::addStyle('lostpassword', 'lostpassword'); ?> + +

+
t('You will receive a link to reset your password via Email.')); ?>
+

+ + + +

t("Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset. If you are not sure what to do, please contact your administrator before you continue. Do you really want to continue?")); ?>
- t('Yes, I really want to reset my password now')); ?>

- -

- -
- - + t('Yes, I really want to reset my password now')); ?>

+ +

+ +
+ diff --git a/core/lostpassword/templates/resetpassword.php b/core/lostpassword/templates/resetpassword.php index 11dce9f112..3f2cade08c 100644 --- a/core/lostpassword/templates/resetpassword.php +++ b/core/lostpassword/templates/resetpassword.php @@ -1,16 +1,9 @@ -
+
- -

t('Your password was reset')); ?>

-

t('To login page')); ?>

- -

- - -

- - +

+ + +

+
diff --git a/core/routes.php b/core/routes.php index fbbbdee81f..3ee5fcaa62 100644 --- a/core/routes.php +++ b/core/routes.php @@ -6,6 +6,45 @@ * See the COPYING-README file. */ +use \OCP\AppFramework\App; +use OC\Core\LostPassword\Controller\LostController; +use OC\Core\LostPassword\Controller\AjaxController; + +class Application extends App { + public function __construct(array $urlParams=array()){ + parent::__construct('core', $urlParams); + + $container = $this->getContainer(); + + /** + * Controllers + */ + $container->registerService('LostController', function($c) { + return new LostController( + $c->query('AppName'), + $c->query('ServerContainer')->getRequest(), + $c->query('ServerContainer')->getURLGenerator() + ); + }); + $container->registerService('AjaxController', function($c) { + return new AjaxController( + $c->query('AppName'), + $c->query('ServerContainer')->getRequest(), + $c->query('ServerContainer')->getURLGenerator() + ); + }); + } +} + +$application = new Application(); +$application->registerRoutes($this, array('routes' => array( + array('name' => 'ajax#lost', 'url' => '/core/ajax/password/lost', 'verb' => 'POST'), + array('name' => 'ajax#reset', 'url' => '/core/ajax/password/reset/{token}/{user}', 'verb' => 'POST'), + array('name' => 'lost#reset', 'url' => '/lostpassword/reset/{token}/{user}', 'verb' => 'GET'), + ) +)); + + // Post installation check /** @var $this OCP\Route\IRouter */ @@ -70,15 +109,6 @@ $this->create('core_ajax_preview', '/core/preview') ->actionInclude('core/ajax/preview.php'); $this->create('core_ajax_preview', '/core/preview.png') ->actionInclude('core/ajax/preview.php'); -$this->create('core_ajax_password_lost', '/core/ajax/password/lost') - ->post() - ->action('OC\Core\Lostpassword\AjaxController', 'lost'); -$this->create('core_ajax_password_reset', '/core/ajax/password/reset/{token}/{user}') - ->post() - ->action('OC\Core\LostPassword\AjaxController', 'resetPassword'); -$this->create('core_lostpassword_reset', '/lostpassword/reset/{token}/{user}') - ->get() - ->action('OC\Core\LostPassword\Controller', 'reset'); // Avatar routes $this->create('core_avatar_get_tmp', '/avatar/tmp') From 218d0add36f873e7cdfdd32608883ea431eb2af9 Mon Sep 17 00:00:00 2001 From: Victor Dubiniuk Date: Wed, 28 May 2014 20:13:07 +0300 Subject: [PATCH 03/16] Changes according to review --- core/js/lostpassword.js | 21 ++-- core/lostpassword/application.php | 38 ++++++ .../controller/ajaxcontroller.php | 101 ---------------- .../controller/lostcontroller.php | 113 ++++++++++++++++-- core/routes.php | 37 +----- 5 files changed, 154 insertions(+), 156 deletions(-) create mode 100644 core/lostpassword/application.php delete mode 100644 core/lostpassword/controller/ajaxcontroller.php diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js index 0c50f858ec..cfce4564f8 100644 --- a/core/js/lostpassword.js +++ b/core/js/lostpassword.js @@ -30,24 +30,26 @@ OC.Lostpassword = { $('#submit').trigger('click'); } else { $.post( - OC.filePath('core', 'ajax', 'password/lost'), - { + OC.filePath('core', 'ajax', 'password/lost'), + { user : $('#user').val(), proceed: $('#encrypted-continue').attr('checked') ? 'Yes' : 'No' - }, + }, OC.Lostpassword.sendLinkDone ); } }, sendLinkDone : function(result){ + var sendErrorMsg; + if (result && result.status === 'success'){ OC.Lostpassword.sendLinkSuccess(); } else { if (result && result.msg){ - var sendErrorMsg = result.msg; + sendErrorMsg = result.msg; } else { - var sendErrorMsg = OC.Lostpassword.sendErrorMsg; + sendErrorMsg = OC.Lostpassword.sendErrorMsg; } OC.Lostpassword.sendLinkError(sendErrorMsg); } @@ -80,7 +82,7 @@ OC.Lostpassword = { if ($('#password').val()){ $.post( $('#password').parents('form').attr('action'), - { + { password : $('#password').val() }, OC.Lostpassword.resetDone @@ -89,6 +91,7 @@ OC.Lostpassword = { }, resetDone : function(result){ + var resetErrorMsg; if (result && result.status === 'success'){ $.post( OC.webroot + '/', @@ -100,11 +103,11 @@ OC.Lostpassword = { ); } else { if (result && result.msg){ - var resetErrorMsg = result.msg; + resetErrorMsg = result.msg; } else if (result && result.encryption) { - var sendErrorMsg = OC.Lostpassword.encryptedMsg; + resetErrorMsg = OC.Lostpassword.encryptedMsg; } else { - var resetErrorMsg = OC.Lostpassword.resetErrorMsg; + resetErrorMsg = OC.Lostpassword.resetErrorMsg; } OC.Lostpassword.resetError(resetErrorMsg); } diff --git a/core/lostpassword/application.php b/core/lostpassword/application.php new file mode 100644 index 0000000000..1d22af5f61 --- /dev/null +++ b/core/lostpassword/application.php @@ -0,0 +1,38 @@ +getContainer(); + + /** + * Controllers + */ + $container->registerService('LostController', function($c) { + return new LostController( + $c->query('AppName'), + $c->query('ServerContainer')->getRequest(), + $c->query('ServerContainer')->getURLGenerator(), + $c->query('ServerContainer')->getUserManager(), + new \OC_Defaults(), + $c->query('ServerContainer')->getL10N('core'), + \OCP\Util::getDefaultEmailAddress('lostpassword-noreply'), + \OC_App::isEnabled('files_encryption') + ); + }); + } +} diff --git a/core/lostpassword/controller/ajaxcontroller.php b/core/lostpassword/controller/ajaxcontroller.php deleted file mode 100644 index 22fa0ce912..0000000000 --- a/core/lostpassword/controller/ajaxcontroller.php +++ /dev/null @@ -1,101 +0,0 @@ -'success')); - try { - $this->sendEmail($this->params('user', ''), $this->params('proceed', '')); - } catch (EncryptedDataException $e){ - $response->setData(array( - 'status' => 'error', - 'encryption' => '1' - )); - } catch (\Exception $e){ - $response->setData(array( - 'status' => 'error', - 'msg' => $e->getMessage() - )); - } - - return $response; - } - - /** - * @PublicPage - */ - public function resetPassword() { - $response = new JSONResponse(array('status'=>'success')); - try { - $user = $this->params('user'); - $newPassword = $this->params('password'); - if (!$this->checkToken()) { - throw new \RuntimeException(''); - } - if (!\OC_User::setPassword($user, $newPassword)) { - throw new \RuntimeException(''); - } - \OC_Preferences::deleteKey($user, 'owncloud', 'lostpassword'); - \OC_User::unsetMagicInCookie(); - } catch (Exception $e){ - $response->setData(array( - 'status' => 'error', - 'msg' => $e->getMessage() - )); - } - return $response; - } - - protected function sendEmail($user, $proceed) { - $l = \OC_L10N::get('core'); - $isEncrypted = \OC_App::isEnabled('files_encryption'); - - if ($isEncrypted && $proceed !== 'Yes'){ - throw new EncryptedDataException(); - } - - if (!\OC_User::userExists($user)) { - throw new \Exception($l->t('Couldn’t send reset email. Please make sure your username is correct.')); - } - $token = hash('sha256', \OC_Util::generateRandomBytes(30).\OC_Config::getValue('passwordsalt', '')); - \OC_Preferences::setValue($user, 'owncloud', 'lostpassword', - hash('sha256', $token)); // Hash the token again to prevent timing attacks - $email = \OC_Preferences::getValue($user, 'settings', 'email', ''); - if (empty($email)) { - throw new \Exception($l->t('Couldn’t send reset email because there is no email address for this username. Please contact your administrator.')); - } - - $parameters = array('token' => $token, 'user' => $user); - $link = $this->urlGenerator->linkToRoute('core.lost.reset', $parameters); - $link = $this->urlGenerator->getAbsoluteUrl($link); - - $tmpl = new \OC_Template('core/lostpassword', 'email'); - $tmpl->assign('link', $link, false); - $msg = $tmpl->fetchPage(); - echo $link; - $from = \OCP\Util::getDefaultEmailAddress('lostpassword-noreply'); - try { - $defaults = new \OC_Defaults(); - \OC_Mail::send($email, $user, $l->t('%s password reset', array($defaults->getName())), $msg, $from, $defaults->getName()); - } catch (\Exception $e) { - throw new \Exception( $l->t('Couldn’t send reset email. Please contact your administrator.')); - } - } - -} diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php index 0a28779259..0f188b8e85 100644 --- a/core/lostpassword/controller/lostcontroller.php +++ b/core/lostpassword/controller/lostcontroller.php @@ -5,27 +5,43 @@ * later. * See the COPYING-README file. */ + namespace OC\Core\LostPassword\Controller; use \OCP\AppFramework\Controller; +use \OCP\AppFramework\Http\JSONResponse; use \OCP\AppFramework\Http\TemplateResponse; class LostController extends Controller { protected $urlGenerator; + protected $userManager; + protected $defaults; + protected $l10n; + protected $from; + protected $isDataEncrypted; - public function __construct($appName, IRequest $request, IURLGenerator $urlGenerator) { + public function __construct($appName, IRequest $request, IURLGenerator $urlGenerator, $userManager, + $defaults, $l10n, $from, $isDataEncrypted) { parent::__construct($appName, $request); $this->urlGenerator = $urlGenerator; + $this->userManager = $userManager; + $this->defaults = $defaults; + $this->l10n = $l10n; + $this->from = $from; + $this->isDataEncrypted = $isDataEncrypted; } /** * @PublicPage * @NoCSRFRequired + * + * @param string $token + * @param string $uid */ - public function reset() { + public function reset($token, $uid) { // Someone wants to reset their password: - if($this->checkToken()) { + if($this->checkToken($uid, $token)) { return new TemplateResponse( 'core/lostpassword', 'resetpassword', @@ -36,31 +52,102 @@ class LostController extends Controller { ); } else { // Someone lost their password - $isEncrypted = \OC_App::isEnabled('files_encryption'); return new TemplateResponse( 'core/lostpassword', 'lostpassword', array( - 'isEncrypted' => $isEncrypted, - 'link' => $this->getResetPasswordLink() + 'isEncrypted' => $this->isDataEncrypted, + 'link' => $this->getResetPasswordLink($uid, $token) ), 'guest' ); } } + + /** + * @PublicPage + * + * @param bool $proceed + */ + public function lost($user, $proceed){ + $response = new JSONResponse(array('status'=>'success')); + try { + $this->sendEmail($user, $proceed); + } catch (EncryptedDataException $e){ + $response->setData(array( + 'status' => 'error', + 'encryption' => '1' + )); + } catch (\Exception $e){ + $response->setData(array( + 'status' => 'error', + 'msg' => $e->getMessage() + )); + } + + return $response; + } + + /** + * @PublicPage + */ + public function resetPassword($user, $password, $token) { + $response = new JSONResponse(array('status'=>'success')); + try { + if (!$this->checkToken($user, $token)) { + throw new \RuntimeException(''); + } + if (!$this->userManager->setPassword($user, $newPassword)) { + throw new \RuntimeException(''); + } + \OC_Preferences::deleteKey($user, 'owncloud', 'lostpassword'); + $this->userManager->unsetMagicInCookie(); + } catch (Exception $e){ + $response->setData(array( + 'status' => 'error', + 'msg' => $e->getMessage() + )); + } + return $response; + } + + protected function sendEmail($user, $proceed) { + if ($this->isDataEncrypted && $proceed !== 'Yes'){ + throw new EncryptedDataException(); + } - protected function getResetPasswordLink(){ + if (!$this->userManager->userExists($user)) { + throw new \Exception($this->l10n->t('Couldn’t send reset email. Please make sure your username is correct.')); + } + $token = hash('sha256', \OC_Util::generateRandomBytes(30)); + \OC_Preferences::setValue($user, 'owncloud', 'lostpassword', hash('sha256', $token)); // Hash the token again to prevent timing attacks + $email = \OC_Preferences::getValue($user, 'settings', 'email', ''); + if (empty($email)) { + throw new \Exception($this->l10n->t('Couldn’t send reset email because there is no email address for this username. Please contact your administrator.')); + } + + $link = $this->getResetPasswordLink($user, $token); + echo $link; + $tmpl = new \OC_Template('core/lostpassword', 'email'); + $tmpl->assign('link', $link, false); + $msg = $tmpl->fetchPage(); + try { + \OC_Mail::send($email, $user, $this->l10n->t('%s password reset', array($this->defaults->getName())), $msg, $this->from, $this->defaults->getName()); + } catch (\Exception $e) { + throw new \Exception( $this->l10n->t('Couldn’t send reset email. Please contact your administrator.')); + } + } + + protected function getResetPasswordLink($user, $token){ $parameters = array( - 'token' => $this->params('token'), - 'user' => $this->params('user') + 'token' => $token, + 'uid' => $user ); - $link = $this->urlGenerator->linkToRoute('core.ajax.reset', $parameters); + $link = $this->urlGenerator->linkToRoute('core.lost.reset', $parameters); return $this->urlGenerator->getAbsoluteUrl($link); } - protected function checkToken() { - $user = $this->params('user'); - $token = $this->params('token'); + protected function checkToken($user, $token) { return \OC_Preferences::getValue($user, 'owncloud', 'lostpassword') === hash('sha256', $token); } } diff --git a/core/routes.php b/core/routes.php index 3ee5fcaa62..0a67585e0b 100644 --- a/core/routes.php +++ b/core/routes.php @@ -6,45 +6,16 @@ * See the COPYING-README file. */ -use \OCP\AppFramework\App; -use OC\Core\LostPassword\Controller\LostController; -use OC\Core\LostPassword\Controller\AjaxController; - -class Application extends App { - public function __construct(array $urlParams=array()){ - parent::__construct('core', $urlParams); - - $container = $this->getContainer(); - - /** - * Controllers - */ - $container->registerService('LostController', function($c) { - return new LostController( - $c->query('AppName'), - $c->query('ServerContainer')->getRequest(), - $c->query('ServerContainer')->getURLGenerator() - ); - }); - $container->registerService('AjaxController', function($c) { - return new AjaxController( - $c->query('AppName'), - $c->query('ServerContainer')->getRequest(), - $c->query('ServerContainer')->getURLGenerator() - ); - }); - } -} +use OC\Core\LostPassword\Application; $application = new Application(); $application->registerRoutes($this, array('routes' => array( - array('name' => 'ajax#lost', 'url' => '/core/ajax/password/lost', 'verb' => 'POST'), - array('name' => 'ajax#reset', 'url' => '/core/ajax/password/reset/{token}/{user}', 'verb' => 'POST'), - array('name' => 'lost#reset', 'url' => '/lostpassword/reset/{token}/{user}', 'verb' => 'GET'), + array('name' => 'lost#lost', 'url' => '/core/ajax/password/lost', 'verb' => 'POST'), + array('name' => 'lost#reset', 'url' => '/lostpassword/reset/{token}/{uid}', 'verb' => 'GET'), + array('name' => 'lost#resetPassword', 'url' => '/core/ajax/password/reset/{token}/{user}', 'verb' => 'POST'), ) )); - // Post installation check /** @var $this OCP\Route\IRouter */ From 4b359ad20c504caaab737514185863a2af0df53e Mon Sep 17 00:00:00 2001 From: Victor Dubiniuk Date: Tue, 3 Jun 2014 01:24:27 +0300 Subject: [PATCH 04/16] Change routes. Update templates --- core/js/lostpassword.js | 2 +- core/lostpassword/application.php | 4 +-- .../controller/lostcontroller.php | 36 ++++++++++--------- core/lostpassword/templates/resetpassword.php | 3 +- core/routes.php | 6 ++-- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js index cfce4564f8..19e2cf5a4b 100644 --- a/core/js/lostpassword.js +++ b/core/js/lostpassword.js @@ -30,7 +30,7 @@ OC.Lostpassword = { $('#submit').trigger('click'); } else { $.post( - OC.filePath('core', 'ajax', 'password/lost'), + OC.generateUrl('/lostpassword/email'), { user : $('#user').val(), proceed: $('#encrypted-continue').attr('checked') ? 'Yes' : 'No' diff --git a/core/lostpassword/application.php b/core/lostpassword/application.php index 1d22af5f61..f39f8aee75 100644 --- a/core/lostpassword/application.php +++ b/core/lostpassword/application.php @@ -25,9 +25,9 @@ class Application extends App { $container->registerService('LostController', function($c) { return new LostController( $c->query('AppName'), - $c->query('ServerContainer')->getRequest(), + $c->query('Request'), $c->query('ServerContainer')->getURLGenerator(), - $c->query('ServerContainer')->getUserManager(), + '\OC_User', new \OC_Defaults(), $c->query('ServerContainer')->getL10N('core'), \OCP\Util::getDefaultEmailAddress('lostpassword-noreply'), diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php index 0f188b8e85..40a86e9813 100644 --- a/core/lostpassword/controller/lostcontroller.php +++ b/core/lostpassword/controller/lostcontroller.php @@ -15,17 +15,17 @@ use \OCP\AppFramework\Http\TemplateResponse; class LostController extends Controller { protected $urlGenerator; - protected $userManager; + protected $userClass; protected $defaults; protected $l10n; protected $from; protected $isDataEncrypted; - public function __construct($appName, IRequest $request, IURLGenerator $urlGenerator, $userManager, + public function __construct($appName, IRequest $request, IURLGenerator $urlGenerator, $userClass, $defaults, $l10n, $from, $isDataEncrypted) { parent::__construct($appName, $request); $this->urlGenerator = $urlGenerator; - $this->userManager = $userManager; + $this->userClass = $userClass; $this->defaults = $defaults; $this->l10n = $l10n; $this->from = $from; @@ -39,14 +39,15 @@ class LostController extends Controller { * @param string $token * @param string $uid */ - public function reset($token, $uid) { + public function resetform($token, $uid) { // Someone wants to reset their password: if($this->checkToken($uid, $token)) { return new TemplateResponse( 'core/lostpassword', 'resetpassword', array( - 'link' => $link + 'link' => $this->getLink('core.lost.setPassword', $uid, $token), + 'isEncrypted' => $this->isDataEncrypted, ), 'guest' ); @@ -56,8 +57,8 @@ class LostController extends Controller { 'core/lostpassword', 'lostpassword', array( - 'isEncrypted' => $this->isDataEncrypted, - 'link' => $this->getResetPasswordLink($uid, $token) + 'isEncrypted' => $this->isDataEncrypted, + 'link' => $this->getLink('core.lost.setPassword', $uid, $token) ), 'guest' ); @@ -69,7 +70,7 @@ class LostController extends Controller { * * @param bool $proceed */ - public function lost($user, $proceed){ + public function email($user, $proceed){ $response = new JSONResponse(array('status'=>'success')); try { $this->sendEmail($user, $proceed); @@ -91,17 +92,18 @@ class LostController extends Controller { /** * @PublicPage */ - public function resetPassword($user, $password, $token) { + public function setPassword($token, $uid, $password) { $response = new JSONResponse(array('status'=>'success')); try { - if (!$this->checkToken($user, $token)) { + if (!$this->checkToken($uid, $token)) { throw new \RuntimeException(''); } - if (!$this->userManager->setPassword($user, $newPassword)) { + $userClass = $this->userClass; + if (!$userClass::setPassword($uid, $password)) { throw new \RuntimeException(''); } - \OC_Preferences::deleteKey($user, 'owncloud', 'lostpassword'); - $this->userManager->unsetMagicInCookie(); + \OC_Preferences::deleteKey($uid, 'owncloud', 'lostpassword'); + $userClass::unsetMagicInCookie(); } catch (Exception $e){ $response->setData(array( 'status' => 'error', @@ -116,7 +118,7 @@ class LostController extends Controller { throw new EncryptedDataException(); } - if (!$this->userManager->userExists($user)) { + if (!$this->userClass->userExists($user)) { throw new \Exception($this->l10n->t('Couldn’t send reset email. Please make sure your username is correct.')); } $token = hash('sha256', \OC_Util::generateRandomBytes(30)); @@ -126,7 +128,7 @@ class LostController extends Controller { throw new \Exception($this->l10n->t('Couldn’t send reset email because there is no email address for this username. Please contact your administrator.')); } - $link = $this->getResetPasswordLink($user, $token); + $link = $this->getLink('core.lost.resetform', $user, $token); echo $link; $tmpl = new \OC_Template('core/lostpassword', 'email'); $tmpl->assign('link', $link, false); @@ -138,12 +140,12 @@ class LostController extends Controller { } } - protected function getResetPasswordLink($user, $token){ + protected function getLink($route, $user, $token){ $parameters = array( 'token' => $token, 'uid' => $user ); - $link = $this->urlGenerator->linkToRoute('core.lost.reset', $parameters); + $link = $this->urlGenerator->linkToRoute($route, $parameters); return $this->urlGenerator->getAbsoluteUrl($link); } diff --git a/core/lostpassword/templates/resetpassword.php b/core/lostpassword/templates/resetpassword.php index 3f2cade08c..0184ace8d1 100644 --- a/core/lostpassword/templates/resetpassword.php +++ b/core/lostpassword/templates/resetpassword.php @@ -1,4 +1,4 @@ -
+

@@ -7,3 +7,4 @@

+ diff --git a/core/routes.php b/core/routes.php index 0a67585e0b..ce0103e3ee 100644 --- a/core/routes.php +++ b/core/routes.php @@ -10,9 +10,9 @@ use OC\Core\LostPassword\Application; $application = new Application(); $application->registerRoutes($this, array('routes' => array( - array('name' => 'lost#lost', 'url' => '/core/ajax/password/lost', 'verb' => 'POST'), - array('name' => 'lost#reset', 'url' => '/lostpassword/reset/{token}/{uid}', 'verb' => 'GET'), - array('name' => 'lost#resetPassword', 'url' => '/core/ajax/password/reset/{token}/{user}', 'verb' => 'POST'), + array('name' => 'lost#email', 'url' => '/lostpassword/email', 'verb' => 'POST'), + array('name' => 'lost#resetform', 'url' => '/lostpassword/reset/form/{token}/{uid}', 'verb' => 'GET'), + array('name' => 'lost#setPassword', 'url' => '/lostpassword/set/{token}/{uid}', 'verb' => 'POST'), ) )); From 47c6fd0c855bf173e2ebc04a1552c8d8fb6bfb09 Mon Sep 17 00:00:00 2001 From: Victor Dubiniuk Date: Tue, 3 Jun 2014 18:47:09 +0300 Subject: [PATCH 05/16] Remove debug output --- core/lostpassword/controller/lostcontroller.php | 1 - 1 file changed, 1 deletion(-) diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php index 40a86e9813..45a8d23c93 100644 --- a/core/lostpassword/controller/lostcontroller.php +++ b/core/lostpassword/controller/lostcontroller.php @@ -129,7 +129,6 @@ class LostController extends Controller { } $link = $this->getLink('core.lost.resetform', $user, $token); - echo $link; $tmpl = new \OC_Template('core/lostpassword', 'email'); $tmpl->assign('link', $link, false); $msg = $tmpl->fetchPage(); From 59ff71f7815557794fc9195cfa34ad16c241ab61 Mon Sep 17 00:00:00 2001 From: Victor Dubiniuk Date: Tue, 3 Jun 2014 23:32:19 +0300 Subject: [PATCH 06/16] Fix check for user existence --- core/lostpassword/controller/lostcontroller.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php index 45a8d23c93..0739410252 100644 --- a/core/lostpassword/controller/lostcontroller.php +++ b/core/lostpassword/controller/lostcontroller.php @@ -118,7 +118,8 @@ class LostController extends Controller { throw new EncryptedDataException(); } - if (!$this->userClass->userExists($user)) { + $userClass = $this->userClass; + if (!$userClass::userExists($user)) { throw new \Exception($this->l10n->t('Couldn’t send reset email. Please make sure your username is correct.')); } $token = hash('sha256', \OC_Util::generateRandomBytes(30)); From e026b1dc19e7ad50901efe4544fa701a6a1bd341 Mon Sep 17 00:00:00 2001 From: Victor Dubiniuk Date: Thu, 5 Jun 2014 17:48:14 +0300 Subject: [PATCH 07/16] Add missing use --- core/lostpassword/controller/lostcontroller.php | 1 + 1 file changed, 1 insertion(+) diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php index 0739410252..2055e0a6eb 100644 --- a/core/lostpassword/controller/lostcontroller.php +++ b/core/lostpassword/controller/lostcontroller.php @@ -11,6 +11,7 @@ namespace OC\Core\LostPassword\Controller; use \OCP\AppFramework\Controller; use \OCP\AppFramework\Http\JSONResponse; use \OCP\AppFramework\Http\TemplateResponse; +use \OC\Core\LostPassword\EncryptedDataException; class LostController extends Controller { From a6e45a8d0e1f3060b4e3ffa09270c791010f2459 Mon Sep 17 00:00:00 2001 From: Bernhard Posselt Date: Fri, 6 Jun 2014 16:36:10 +0200 Subject: [PATCH 08/16] use more stuff from core :) --- core/lostpassword/application.php | 8 +- .../controller/lostcontroller.php | 169 +++++++++++------- core/lostpassword/templates/lostpassword.php | 12 +- 3 files changed, 113 insertions(+), 76 deletions(-) diff --git a/core/lostpassword/application.php b/core/lostpassword/application.php index f39f8aee75..ba2f3fc633 100644 --- a/core/lostpassword/application.php +++ b/core/lostpassword/application.php @@ -14,6 +14,8 @@ use \OCP\AppFramework\App; use OC\Core\LostPassword\Controller\LostController; class Application extends App { + + public function __construct(array $urlParams=array()){ parent::__construct('core', $urlParams); @@ -27,12 +29,16 @@ class Application extends App { $c->query('AppName'), $c->query('Request'), $c->query('ServerContainer')->getURLGenerator(), - '\OC_User', + $c->query('ServerContainer')->getUserManager(), new \OC_Defaults(), $c->query('ServerContainer')->getL10N('core'), + $c->query('ServerContainer')->getConfig(), + $c->query('ServerContainer')->getUserSession(), \OCP\Util::getDefaultEmailAddress('lostpassword-noreply'), \OC_App::isEnabled('files_encryption') ); }); } + + } diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php index 2055e0a6eb..6635f8dcde 100644 --- a/core/lostpassword/controller/lostcontroller.php +++ b/core/lostpassword/controller/lostcontroller.php @@ -11,146 +11,177 @@ namespace OC\Core\LostPassword\Controller; use \OCP\AppFramework\Controller; use \OCP\AppFramework\Http\JSONResponse; use \OCP\AppFramework\Http\TemplateResponse; +use \OCP\IURLGenerator; +use \OCP\IRequest; +use \OCP\IL10N; +use \OCP\IConfig; +use \OCP\IUserSession; use \OC\Core\LostPassword\EncryptedDataException; class LostController extends Controller { - + protected $urlGenerator; - protected $userClass; + protected $userManager; protected $defaults; protected $l10n; protected $from; protected $isDataEncrypted; - - public function __construct($appName, IRequest $request, IURLGenerator $urlGenerator, $userClass, - $defaults, $l10n, $from, $isDataEncrypted) { + protected $config; + protected $userSession; + + public function __construct($appName, + IRequest $request, + IURLGenerator $urlGenerator, + $userManager, + $defaults, + IL10N $l10n, + IConfig $config, + IUserSession $userSession, + $from, + $isDataEncrypted) { parent::__construct($appName, $request); $this->urlGenerator = $urlGenerator; - $this->userClass = $userClass; + $this->userManager = $userManager; $this->defaults = $defaults; $this->l10n = $l10n; $this->from = $from; $this->isDataEncrypted = $isDataEncrypted; + $this->config = $config; + $this->userSession = $userSession; } /** + * Someone wants to reset their password: + * * @PublicPage * @NoCSRFRequired - * + * * @param string $token * @param string $uid */ public function resetform($token, $uid) { - // Someone wants to reset their password: - if($this->checkToken($uid, $token)) { - return new TemplateResponse( - 'core/lostpassword', - 'resetpassword', - array( - 'link' => $this->getLink('core.lost.setPassword', $uid, $token), - 'isEncrypted' => $this->isDataEncrypted, - ), - 'guest' - ); - } else { - // Someone lost their password - return new TemplateResponse( - 'core/lostpassword', - 'lostpassword', - array( - 'isEncrypted' => $this->isDataEncrypted, - 'link' => $this->getLink('core.lost.setPassword', $uid, $token) - ), - 'guest' - ); - } + return new TemplateResponse( + 'core/lostpassword', + 'resetpassword', + array( + 'isEncrypted' => $this->isDataEncrypted, + 'link' => $this->getLink('core.lost.setPassword', $uid, $token), + ), + 'guest' + ); } - + /** * @PublicPage - * + * + * @param string $user * @param bool $proceed */ public function email($user, $proceed){ - $response = new JSONResponse(array('status'=>'success')); + // FIXME: use HTTP error codes try { $this->sendEmail($user, $proceed); } catch (EncryptedDataException $e){ - $response->setData(array( - 'status' => 'error', - 'encryption' => '1' - )); + array('status' => 'error', 'encryption' => '1'); } catch (\Exception $e){ - $response->setData(array( - 'status' => 'error', - 'msg' => $e->getMessage() - )); + return array('status' => 'error', 'msg' => $e->getMessage()); } - - return $response; + + return array('status'=>'success'); } - + + /** * @PublicPage */ public function setPassword($token, $uid, $password) { - $response = new JSONResponse(array('status'=>'success')); try { if (!$this->checkToken($uid, $token)) { - throw new \RuntimeException(''); + throw new \Exception(); } - $userClass = $this->userClass; - if (!$userClass::setPassword($uid, $password)) { - throw new \RuntimeException(''); + + $user = $this->userManager->get($uid); + if (!$user->setPassword($uid, $password)) { + + throw new \Exception(); } + + // FIXME: should be added to the all config at some point \OC_Preferences::deleteKey($uid, 'owncloud', 'lostpassword'); - $userClass::unsetMagicInCookie(); - } catch (Exception $e){ - $response->setData(array( - 'status' => 'error', - 'msg' => $e->getMessage() - )); + $this->userSession->unsetMagicInCookie(); + + } catch (\Exception $e){ + return array('status' => 'error','msg' => $e->getMessage()); } - return $response; + + return array('status'=>'success'); } - + + protected function sendEmail($user, $proceed) { - if ($this->isDataEncrypted && $proceed !== 'Yes'){ + if ($this->isDataEncrypted && !$proceed){ throw new EncryptedDataException(); } - $userClass = $this->userClass; - if (!$userClass::userExists($user)) { - throw new \Exception($this->l10n->t('Couldn’t send reset email. Please make sure your username is correct.')); + if (!$this->userManager->userExists($user)) { + throw new \Exception( + $this->l10n->t('Couldn’t send reset email. Please make sure '. + 'your username is correct.')); } + $token = hash('sha256', \OC_Util::generateRandomBytes(30)); - \OC_Preferences::setValue($user, 'owncloud', 'lostpassword', hash('sha256', $token)); // Hash the token again to prevent timing attacks - $email = \OC_Preferences::getValue($user, 'settings', 'email', ''); + + // Hash the token again to prevent timing attacks + $this->config->setUserValue( + $user, 'owncloud', 'lostpassword', hash('sha256', $token) + ); + + $email = $this->config->getUserValue($user, 'settings', 'email'); + if (empty($email)) { - throw new \Exception($this->l10n->t('Couldn’t send reset email because there is no email address for this username. Please contact your administrator.')); + throw new \Exception( + $this->l10n->t('Couldn’t send reset email because there is no '. + 'email address for this username. Please ' . + 'contact your administrator.') + ); } - + $link = $this->getLink('core.lost.resetform', $user, $token); + $tmpl = new \OC_Template('core/lostpassword', 'email'); $tmpl->assign('link', $link, false); $msg = $tmpl->fetchPage(); + try { - \OC_Mail::send($email, $user, $this->l10n->t('%s password reset', array($this->defaults->getName())), $msg, $this->from, $this->defaults->getName()); + \OC_Mail::send($email, $user, $this->l10n->t( + '%s password reset', + array( + $this->defaults->getName())), + $msg, + $this->from, + $this->defaults->getName() + )); } catch (\Exception $e) { - throw new \Exception( $this->l10n->t('Couldn’t send reset email. Please contact your administrator.')); + throw new \Exception($this->l10n->t('Couldn’t send reset email. ' . + 'Please contact your administrator.')); } } + protected function getLink($route, $user, $token){ $parameters = array( - 'token' => $token, + 'token' => $token, 'uid' => $user ); $link = $this->urlGenerator->linkToRoute($route, $parameters); return $this->urlGenerator->getAbsoluteUrl($link); } + protected function checkToken($user, $token) { - return \OC_Preferences::getValue($user, 'owncloud', 'lostpassword') === hash('sha256', $token); + return $this->config->getUserValue( + $user, 'owncloud', 'lostpassword' + ) === hash('sha256', $token); } + } diff --git a/core/lostpassword/templates/lostpassword.php b/core/lostpassword/templates/lostpassword.php index 7548b4787e..00dd139e71 100644 --- a/core/lostpassword/templates/lostpassword.php +++ b/core/lostpassword/templates/lostpassword.php @@ -3,18 +3,18 @@ OCP\Util::addStyle('lostpassword', 'lostpassword'); ?>
-
t('You will receive a link to reset your password via Email.')); ?>
+
t('You will receive a link to reset your password via Email.')); ?>

- - + +
-

t("Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset. If you are not sure what to do, please contact your administrator before you continue. Do you really want to continue?")); ?>
+

t("Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset. If you are not sure what to do, please contact your administrator before you continue. Do you really want to continue?")); ?>
- t('Yes, I really want to reset my password now')); ?>

+ t('Yes, I really want to reset my password now')); ?>

- +
From 2b2b1b487c6b74d442a70ebb0468a8990c26d08d Mon Sep 17 00:00:00 2001 From: Bernhard Posselt Date: Fri, 6 Jun 2014 16:51:58 +0200 Subject: [PATCH 09/16] more style fixes --- .../controller/lostcontroller.php | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php index 6635f8dcde..c140499015 100644 --- a/core/lostpassword/controller/lostcontroller.php +++ b/core/lostpassword/controller/lostcontroller.php @@ -71,6 +71,14 @@ class LostController extends Controller { ); } + private function error($message, array $additional=array()) { + return array_combine(array('status' => 'error', 'msg' => $message), $additional); + } + + private function success() { + return array('status'=>'success'); + } + /** * @PublicPage * @@ -82,39 +90,36 @@ class LostController extends Controller { try { $this->sendEmail($user, $proceed); } catch (EncryptedDataException $e){ - array('status' => 'error', 'encryption' => '1'); + return $this->error('', array('encryption' => '1')); } catch (\Exception $e){ - return array('status' => 'error', 'msg' => $e->getMessage()); + return $this->error($e->getMessage()); } - return array('status'=>'success'); + return $this->success(); } /** * @PublicPage */ - public function setPassword($token, $uid, $password) { + public function setPassword($token, $userId, $password) { try { - if (!$this->checkToken($uid, $token)) { - throw new \Exception(); - } - - $user = $this->userManager->get($uid); - if (!$user->setPassword($uid, $password)) { + $user = $this->userManager->get($userId); + if (!$this->checkToken($userId, $token) || + !$user->setPassword($userId, $password)) { throw new \Exception(); } // FIXME: should be added to the all config at some point - \OC_Preferences::deleteKey($uid, 'owncloud', 'lostpassword'); + \OC_Preferences::deleteKey($userId, 'owncloud', 'lostpassword'); $this->userSession->unsetMagicInCookie(); } catch (\Exception $e){ - return array('status' => 'error','msg' => $e->getMessage()); + return $this->error($e->getMessage()); } - return array('status'=>'success'); + return $this->success(); } @@ -153,6 +158,7 @@ class LostController extends Controller { $msg = $tmpl->fetchPage(); try { + // FIXME: should be added to the container and injected in here \OC_Mail::send($email, $user, $this->l10n->t( '%s password reset', array( @@ -162,8 +168,9 @@ class LostController extends Controller { $this->defaults->getName() )); } catch (\Exception $e) { - throw new \Exception($this->l10n->t('Couldn’t send reset email. ' . - 'Please contact your administrator.')); + throw new \Exception($this->l10n->t( + 'Couldn’t send reset email. Please contact your administrator.' + )); } } @@ -174,6 +181,7 @@ class LostController extends Controller { 'uid' => $user ); $link = $this->urlGenerator->linkToRoute($route, $parameters); + return $this->urlGenerator->getAbsoluteUrl($link); } @@ -184,4 +192,5 @@ class LostController extends Controller { ) === hash('sha256', $token); } + } From d0b71dffca8754f9a2633586b35772b862bbe1d2 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 13 Jun 2014 15:39:44 +0200 Subject: [PATCH 10/16] reformat method call and fix paranthesis mismatch --- core/lostpassword/controller/lostcontroller.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php index c140499015..a13d6a26d5 100644 --- a/core/lostpassword/controller/lostcontroller.php +++ b/core/lostpassword/controller/lostcontroller.php @@ -159,14 +159,14 @@ class LostController extends Controller { try { // FIXME: should be added to the container and injected in here - \OC_Mail::send($email, $user, $this->l10n->t( - '%s password reset', - array( - $this->defaults->getName())), - $msg, - $this->from, - $this->defaults->getName() - )); + \OC_Mail::send( + $email, + $user, + $this->l10n->t('%s password reset', array($this->defaults->getName())), + $msg, + $this->from, + $this->defaults->getName() + ); } catch (\Exception $e) { throw new \Exception($this->l10n->t( 'Couldn’t send reset email. Please contact your administrator.' From cedca03ef524376135e9fa232879bd1df0da0c9d Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 13 Jun 2014 15:54:09 +0200 Subject: [PATCH 11/16] Remove infield label, add password icon, fix layout --- core/js/lostpassword.js | 3 ++- core/lostpassword/css/resetpassword.css | 7 +++++++ core/lostpassword/templates/resetpassword.php | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 core/lostpassword/css/resetpassword.css diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js index 19e2cf5a4b..b0bd0e01b7 100644 --- a/core/js/lostpassword.js +++ b/core/js/lostpassword.js @@ -57,7 +57,8 @@ OC.Lostpassword = { sendLinkSuccess : function(msg){ var node = OC.Lostpassword.getSendStatusNode(); - node.addClass('success').css({width:'auto'}); + // update is the better success message styling + node.addClass('update').css({width:'auto'}); node.html(OC.Lostpassword.sendSuccessMsg); }, diff --git a/core/lostpassword/css/resetpassword.css b/core/lostpassword/css/resetpassword.css new file mode 100644 index 0000000000..012af672d9 --- /dev/null +++ b/core/lostpassword/css/resetpassword.css @@ -0,0 +1,7 @@ +#reset-password p { + position: relative; +} + +#password-icon { + top: 20px; +} diff --git a/core/lostpassword/templates/resetpassword.php b/core/lostpassword/templates/resetpassword.php index 0184ace8d1..118fe78711 100644 --- a/core/lostpassword/templates/resetpassword.php +++ b/core/lostpassword/templates/resetpassword.php @@ -1,8 +1,10 @@ +

- + +

From a53cfcb9d1ca3f77dcebac9bd584bb1992aac815 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 13 Jun 2014 16:02:41 +0200 Subject: [PATCH 12/16] =?UTF-8?q?Migrate=20=C2=B4=20to=20'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/js/lostpassword.js | 4 ++-- core/lostpassword/controller/lostcontroller.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js index b0bd0e01b7..bec4f98b9f 100644 --- a/core/js/lostpassword.js +++ b/core/js/lostpassword.js @@ -1,7 +1,7 @@ OC.Lostpassword = { - sendErrorMsg : t('core', 'Couldn’t send reset email. Please contact your administrator.'), - + sendErrorMsg : t('core', 'Couldn\'t send reset email. Please contact your administrator.'), + sendSuccessMsg : t('core', 'The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator.'), encryptedMsg : t('core', "Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.
If you are not sure what to do, please contact your administrator before you continue.
Do you really want to continue?") diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php index a13d6a26d5..db94eeadea 100644 --- a/core/lostpassword/controller/lostcontroller.php +++ b/core/lostpassword/controller/lostcontroller.php @@ -130,7 +130,7 @@ class LostController extends Controller { if (!$this->userManager->userExists($user)) { throw new \Exception( - $this->l10n->t('Couldn’t send reset email. Please make sure '. + $this->l10n->t('Couldn\'t send reset email. Please make sure '. 'your username is correct.')); } @@ -145,7 +145,7 @@ class LostController extends Controller { if (empty($email)) { throw new \Exception( - $this->l10n->t('Couldn’t send reset email because there is no '. + $this->l10n->t('Couldn\'t send reset email because there is no '. 'email address for this username. Please ' . 'contact your administrator.') ); @@ -169,7 +169,7 @@ class LostController extends Controller { ); } catch (\Exception $e) { throw new \Exception($this->l10n->t( - 'Couldn’t send reset email. Please contact your administrator.' + 'Couldn\'t send reset email. Please contact your administrator.' )); } } From ebbf2283099215ca06914b0c4c62423de2ceb2e2 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 13 Jun 2014 16:03:13 +0200 Subject: [PATCH 13/16] remove whitespace at end of line --- core/js/lostpassword.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js index bec4f98b9f..ad221cb30f 100644 --- a/core/js/lostpassword.js +++ b/core/js/lostpassword.js @@ -3,7 +3,7 @@ OC.Lostpassword = { sendErrorMsg : t('core', 'Couldn\'t send reset email. Please contact your administrator.'), sendSuccessMsg : t('core', 'The link to reset your password has been sent to your email. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator.'), - + encryptedMsg : t('core', "Your files are encrypted. If you haven't enabled the recovery key, there will be no way to get your data back after your password is reset.
If you are not sure what to do, please contact your administrator before you continue.
Do you really want to continue?") + ('
') + '