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.

241 lines
6.5 KiB

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