You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
7.1 KiB

12 years ago
11 years ago
11 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
  1. <?php
  2. /**
  3. * @author Bernhard Posselt <dev@bernhard-posselt.com>
  4. * @author Björn Schießle <schiessle@owncloud.com>
  5. * @author Lukas Reschke <lukas@owncloud.com>
  6. * @author Morris Jobke <hey@morrisjobke.de>
  7. * @author Roeland Jago Douma <rullzer@owncloud.com>
  8. * @author Thomas Müller <thomas.mueller@tmit.eu>
  9. * @author Victor Dubiniuk <dubiniuk@owncloud.com>
  10. *
  11. * @copyright Copyright (c) 2016, ownCloud, Inc.
  12. * @license AGPL-3.0
  13. *
  14. * This code is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU Affero General Public License, version 3,
  16. * as published by the Free Software Foundation.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU Affero General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU Affero General Public License, version 3,
  24. * along with this program. If not, see <http://www.gnu.org/licenses/>
  25. *
  26. */
  27. namespace OC\Core\Controller;
  28. use \OCP\AppFramework\Controller;
  29. use \OCP\AppFramework\Http\TemplateResponse;
  30. use OCP\AppFramework\Utility\ITimeFactory;
  31. use \OCP\IURLGenerator;
  32. use \OCP\IRequest;
  33. use \OCP\IL10N;
  34. use \OCP\IConfig;
  35. use OCP\IUserManager;
  36. use OCP\Mail\IMailer;
  37. use OCP\Security\ISecureRandom;
  38. use \OC_Defaults;
  39. use OCP\Security\StringUtils;
  40. /**
  41. * Class LostController
  42. *
  43. * Successfully changing a password will emit the post_passwordReset hook.
  44. *
  45. * @package OC\Core\Controller
  46. */
  47. class LostController extends Controller {
  48. /** @var IURLGenerator */
  49. protected $urlGenerator;
  50. /** @var IUserManager */
  51. protected $userManager;
  52. // FIXME: Inject a non-static factory of OC_Defaults for better unit-testing
  53. /** @var OC_Defaults */
  54. protected $defaults;
  55. /** @var IL10N */
  56. protected $l10n;
  57. /** @var string */
  58. protected $from;
  59. /** @var bool */
  60. protected $isDataEncrypted;
  61. /** @var IConfig */
  62. protected $config;
  63. /** @var ISecureRandom */
  64. protected $secureRandom;
  65. /** @var IMailer */
  66. protected $mailer;
  67. /** @var ITimeFactory */
  68. protected $timeFactory;
  69. /**
  70. * @param string $appName
  71. * @param IRequest $request
  72. * @param IURLGenerator $urlGenerator
  73. * @param IUserManager $userManager
  74. * @param OC_Defaults $defaults
  75. * @param IL10N $l10n
  76. * @param IConfig $config
  77. * @param ISecureRandom $secureRandom
  78. * @param string $from
  79. * @param string $isDataEncrypted
  80. * @param IMailer $mailer
  81. * @param ITimeFactory $timeFactory
  82. */
  83. public function __construct($appName,
  84. IRequest $request,
  85. IURLGenerator $urlGenerator,
  86. IUserManager $userManager,
  87. OC_Defaults $defaults,
  88. IL10N $l10n,
  89. IConfig $config,
  90. ISecureRandom $secureRandom,
  91. $from,
  92. $isDataEncrypted,
  93. IMailer $mailer,
  94. ITimeFactory $timeFactory) {
  95. parent::__construct($appName, $request);
  96. $this->urlGenerator = $urlGenerator;
  97. $this->userManager = $userManager;
  98. $this->defaults = $defaults;
  99. $this->l10n = $l10n;
  100. $this->secureRandom = $secureRandom;
  101. $this->from = $from;
  102. $this->isDataEncrypted = $isDataEncrypted;
  103. $this->config = $config;
  104. $this->mailer = $mailer;
  105. $this->timeFactory = $timeFactory;
  106. }
  107. /**
  108. * Someone wants to reset their password:
  109. *
  110. * @PublicPage
  111. * @NoCSRFRequired
  112. *
  113. * @param string $token
  114. * @param string $userId
  115. * @return TemplateResponse
  116. */
  117. public function resetform($token, $userId) {
  118. return new TemplateResponse(
  119. 'core',
  120. 'lostpassword/resetpassword',
  121. array(
  122. 'link' => $this->urlGenerator->linkToRouteAbsolute('core.lost.setPassword', array('userId' => $userId, 'token' => $token)),
  123. ),
  124. 'guest'
  125. );
  126. }
  127. /**
  128. * @param $message
  129. * @param array $additional
  130. * @return array
  131. */
  132. private function error($message, array $additional=array()) {
  133. return array_merge(array('status' => 'error', 'msg' => $message), $additional);
  134. }
  135. /**
  136. * @return array
  137. */
  138. private function success() {
  139. return array('status'=>'success');
  140. }
  141. /**
  142. * @PublicPage
  143. *
  144. * @param string $user
  145. * @return array
  146. */
  147. public function email($user){
  148. // FIXME: use HTTP error codes
  149. try {
  150. $this->sendEmail($user);
  151. } catch (\Exception $e){
  152. return $this->error($e->getMessage());
  153. }
  154. return $this->success();
  155. }
  156. /**
  157. * @PublicPage
  158. * @param string $token
  159. * @param string $userId
  160. * @param string $password
  161. * @param boolean $proceed
  162. * @return array
  163. */
  164. public function setPassword($token, $userId, $password, $proceed) {
  165. if ($this->isDataEncrypted && !$proceed) {
  166. return $this->error('', array('encryption' => true));
  167. }
  168. try {
  169. $user = $this->userManager->get($userId);
  170. $splittedToken = explode(':', $this->config->getUserValue($userId, 'owncloud', 'lostpassword', null));
  171. if(count($splittedToken) !== 2) {
  172. throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
  173. }
  174. if ($splittedToken[0] < ($this->timeFactory->getTime() - 60*60*12) ||
  175. $user->getLastLogin() > $splittedToken[0]) {
  176. throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is expired'));
  177. }
  178. if (!StringUtils::equals($splittedToken[1], $token)) {
  179. throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
  180. }
  181. if (!$user->setPassword($password)) {
  182. throw new \Exception();
  183. }
  184. \OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'post_passwordReset', array('uid' => $userId, 'password' => $password));
  185. $this->config->deleteUserValue($userId, 'owncloud', 'lostpassword');
  186. @\OC_User::unsetMagicInCookie();
  187. } catch (\Exception $e){
  188. return $this->error($e->getMessage());
  189. }
  190. return $this->success();
  191. }
  192. /**
  193. * @param string $user
  194. * @throws \Exception
  195. */
  196. protected function sendEmail($user) {
  197. if (!$this->userManager->userExists($user)) {
  198. throw new \Exception($this->l10n->t('Couldn\'t send reset email. Please make sure your username is correct.'));
  199. }
  200. $userObject = $this->userManager->get($user);
  201. $email = $userObject->getEMailAddress();
  202. if (empty($email)) {
  203. throw new \Exception(
  204. $this->l10n->t('Could not send reset email because there is no email address for this username. Please contact your administrator.')
  205. );
  206. }
  207. $token = $this->secureRandom->generate(21,
  208. ISecureRandom::CHAR_DIGITS.
  209. ISecureRandom::CHAR_LOWER.
  210. ISecureRandom::CHAR_UPPER);
  211. $this->config->setUserValue($user, 'owncloud', 'lostpassword', $this->timeFactory->getTime() .':'. $token);
  212. $link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', array('userId' => $user, 'token' => $token));
  213. $tmpl = new \OC_Template('core', 'lostpassword/email');
  214. $tmpl->assign('link', $link);
  215. $msg = $tmpl->fetchPage();
  216. try {
  217. $message = $this->mailer->createMessage();
  218. $message->setTo([$email => $user]);
  219. $message->setSubject($this->l10n->t('%s password reset', [$this->defaults->getName()]));
  220. $message->setPlainBody($msg);
  221. $message->setFrom([$this->from => $this->defaults->getName()]);
  222. $this->mailer->send($message);
  223. } catch (\Exception $e) {
  224. throw new \Exception($this->l10n->t(
  225. 'Couldn\'t send reset email. Please contact your administrator.'
  226. ));
  227. }
  228. }
  229. }