Completed
Pull Request — master (#32569)
by Matthew
12:00
created

ResetPassword::hasValidEmailAddress()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Andreas Fischer <[email protected]>
4
 * @author Christopher Schäpers <[email protected]>
5
 * @author Clark Tomlinson <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Laurens Post <[email protected]>
8
 * @author Morris Jobke <[email protected]>
9
 * @author Thomas Müller <[email protected]>
10
 * @author Sujith Haridasan <[email protected]>
11
 *
12
 * @copyright Copyright (c) 2018, ownCloud GmbH
13
 * @license AGPL-3.0
14
 *
15
 * This code is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License, version 3,
17
 * as published by the Free Software Foundation.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License, version 3,
25
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
26
 *
27
 */
28
29
namespace OC\Core\Command\User;
30
31
use OC\Core\Controller\LostController;
32
use OC\Helper\EnvironmentHelper;
33
use OCP\AppFramework\Utility\ITimeFactory;
34
use OCP\IConfig;
35
use OCP\IL10N;
36
use OCP\IURLGenerator;
37
use OCP\IUserManager;
38
use OCP\Mail\IMailer;
39
use OCP\Security\ISecureRandom;
40
use OCP\Util;
41
use Symfony\Component\Console\Command\Command;
42
use Symfony\Component\Console\Input\InputInterface;
43
use Symfony\Component\Console\Input\InputArgument;
44
use Symfony\Component\Console\Input\InputOption;
45
use Symfony\Component\Console\Output\OutputInterface;
46
use Symfony\Component\Console\Question\Question;
47
use Zend\Validator\EmailAddress;
48
49
class ResetPassword extends Command {
50
51
	/** @var IUserManager */
52
	protected $userManager;
53
	/** @var IConfig  */
54
	private $config;
55
	/** @var ITimeFactory */
56
	private $timeFactory;
57
	/** @var EnvironmentHelper  */
58
	private $environmentHelper;
59
	/** @var LostController */
60
	private $lostController;
61
62
	public function __construct(IUserManager $userManager,
63
						IConfig $config,
64
						ITimeFactory $timeFactory,
65
						EnvironmentHelper $environmentHelper,
66
						LostController $lostController) {
67
		$this->userManager = $userManager;
68
		$this->config = $config;
69
		$this->timeFactory = $timeFactory;
70
		$this->environmentHelper = $environmentHelper;
71
		$this->lostController = $lostController;
72
		parent::__construct();
73
	}
74
75
	protected function configure() {
76
		$this
77
			->setName('user:resetpassword')
78
			->setDescription('Resets the password of the named user.')
79
			->addArgument(
80
				'user',
81
				InputArgument::REQUIRED,
82
				'The user\'s name.'
83
			)
84
			->addOption(
85
				'password-from-env',
86
				null,
87
				InputOption::VALUE_NONE,
88
				'Read the password from the OC_PASS environment variable.'
89
			)
90
			->addOption(
91
				'send-email',
92
				null,
93
				InputOption::VALUE_NONE,
94
				'The email-id set while creating the user, will be used to send link for password reset. This option will also display the link sent to user.'
95
			)
96
			->addOption(
97
				'output-link',
98
				null,
99
				InputOption::VALUE_NONE,
100
				'The link to reset the password will be displayed.'
101
			)
102
		;
103
	}
104
105
	protected function execute(InputInterface $input, OutputInterface $output) {
106
		$username = $input->getArgument('user');
107
		$emailLink = $input->getOption('send-email');
108
		$displayLink = $input->getOption('output-link');
109
110
		/** @var $user \OCP\IUser */
111
		$user = $this->userManager->get($username);
112
		if ($user === null) {
113
			$output->writeln('<error>User does not exist</error>');
114
			return 1;
115
		}
116
117
		if ($input->getOption('password-from-env')) {
118
			$password = $this->environmentHelper->getEnvVar('OC_PASS');
119
			if (!$password) {
120
				$output->writeln('<error>--password-from-env given, but OC_PASS is empty!</error>');
121
				return 1;
122
			}
123
		} elseif ($emailLink || $displayLink) {
124
			$userId = $user->getUID();
125
			list($link, $token) = $this->lostController->generateTokenAndLink($userId);
126
127
			if ($emailLink && $this->hasValidEmailAddress($user->getEMailAddress())) {
128
				try {
129
					$this->config->deleteUserValue($userId, 'owncloud', 'lostpassword');
130
					$this->lostController->sendEmail($userId, $token, $link);
131
				} catch (\Exception $e) {
132
					$output->writeln('<error>Can\'t send new user mail to ' . $user->getEMailAddress() . ': ' . $e->getMessage() . '</error>');
133
					return 1;
134
				}
135
			} else {
136
				if ($emailLink) {
137
					$output->writeln('<error>Email address is not set for the user ' . $user->getUID() . '</error>');
138
					return 1;
139
				}
140
			}
141
			$this->config->setUserValue($userId, 'owncloud', 'lostpassword', $this->timeFactory->getTime() . ':' . $token);
142
			$output->writeln('The password reset link is: ' . $link);
143
			return 0;
144
		} elseif ($input->isInteractive()) {
145
			/** @var $dialog \Symfony\Component\Console\Helper\QuestionHelper */
146
			$dialog = $this->getHelperSet()->get('question');
147
148
			if (\OCP\App::isEnabled('encryption')) {
149
				$output->writeln(
150
					'<error>Warning: Resetting the password when using encryption will result in data loss!</error>'
151
				);
152
				if (!$dialog->ask($input, $output, new Question('<question>Do you want to continue?</question>', true))) {
153
					return 1;
154
				}
155
			}
156
157
			$q = new Question('<question>Enter a new password: </question>', false);
158
			$q->setHidden(true);
159
			$password = $dialog->ask($input, $output, $q);
160
			if ($password === false) {
161
				// When user presses RETURN key or no password characters are entered,
162
				// $password gets a boolean value false.
163
				$output->writeln("<error>Password cannot be empty!</error>");
164
				return 1;
165
			}
166
			$q = new Question('<question>Confirm the new password: </question>', false);
167
			$q->setHidden(true);
168
			$confirm = $dialog->ask($input, $output, $q);
169
			if ($password !== $confirm) {
170
				$output->writeln("<error>Passwords did not match!</error>");
171
				return 1;
172
			}
173
		} else {
174
			$output->writeln("<error>Interactive input or --password-from-env is needed for entering a new password!</error>");
175
			return 1;
176
		}
177
178
		$success = $user->setPassword($password);
179
		if ($success) {
180
			$output->writeln("<info>Successfully reset password for " . $username . "</info>");
181
		} else {
182
			$output->writeln("<error>Error while resetting password!</error>");
183
			return 1;
184
		}
185
	}
186
187
	/**
188
	 * Determines if the user's email address is valid.
189
	 *
190
	 * @param string $emailAddress
191
	 * @return bool
192
	 */
193
	protected function hasValidEmailAddress($emailAddress) {
194
		return (new EmailAddress())->isValid($emailAddress);
195
	}
196
}
197