Passed
Push — master ( 55caf6...ad3735 )
by Roeland
26:40 queued 13s
created

AddAppPassword::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 14
rs 9.8666
1
<?php
2
/**
3
 * @copyright Copyright (c) 2020, NextCloud, Inc.
4
 *
5
 * @author Andreas Fischer <[email protected]>
6
 * @author Christopher Schäpers <[email protected]>
7
 * @author Clark Tomlinson <[email protected]>
8
 * @author Joas Schilling <[email protected]>
9
 * @author Laurens Post <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Roeland Jago Douma <[email protected]>
12
 * @author Sujith H <[email protected]>
13
 * @author Sean Molenaar <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program. If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
31
namespace OC\Core\Command\User;
32
33
use OC\Authentication\Token\IProvider;
34
use OC\Authentication\Token\IToken;
35
use OCP\IUserManager;
36
use OCP\Security\ICrypto;
37
use OCP\Security\ISecureRandom;
38
use Symfony\Component\Console\Command\Command;
39
use Symfony\Component\Console\Helper\QuestionHelper;
40
use Symfony\Component\Console\Input\InputArgument;
41
use Symfony\Component\Console\Input\InputInterface;
42
use Symfony\Component\Console\Input\InputOption;
43
use Symfony\Component\Console\Output\OutputInterface;
44
use Symfony\Component\Console\Question\Question;
45
46
class AddAppPassword extends Command {
47
48
	/** @var IUserManager */
49
	protected $userManager;
50
	/** @var IProvider */
51
	protected $tokenProvider;
52
	/** @var ISecureRandom */
53
	private $random;
54
	/** @var ICrypto */
55
	private $crypto;
56
57
	public function __construct(IUserManager $userManager,
58
								IProvider $tokenProvider,
59
								ISecureRandom $random,
60
								ICrypto $crypto) {
61
		$this->tokenProvider = $tokenProvider;
62
		$this->userManager = $userManager;
63
		$this->random = $random;
64
		$this->crypto = $crypto;
65
		parent::__construct();
66
	}
67
68
	protected function configure() {
69
		$this
70
			->setName('user:add-app-password')
71
			->setDescription('Add app password for the named user')
72
			->addArgument(
73
				'user',
74
				InputArgument::REQUIRED,
75
				'Username to add app password for'
76
			)
77
			->addOption(
78
				'password-from-env',
79
				null,
80
				InputOption::VALUE_NONE,
81
				'read password from environment variable NC_PASS/OC_PASS'
82
			)
83
		;
84
	}
85
86
	protected function execute(InputInterface $input, OutputInterface $output): int {
87
		$username = $input->getArgument('user');
88
89
		$user = $this->userManager->get($username);
90
		if (is_null($user)) {
91
			$output->writeln('<error>User does not exist</error>');
92
			return 1;
93
		}
94
95
		if ($input->getOption('password-from-env')) {
96
			$password = getenv('NC_PASS') ?? getenv('OC_PASS');
97
			if (!$password) {
98
				$output->writeln('<error>--password-from-env given, but NC_PASS is empty!</error>');
99
				return 1;
100
			}
101
		} elseif ($input->isInteractive()) {
102
			/** @var QuestionHelper $helper */
103
			$helper = $this->getHelper('question');
104
105
			$question = new Question('Enter the user password: ');
106
			$question->setHidden(true);
107
			$password = $helper->ask($input, $output, $question);
108
109
			if ($password === null) {
110
				$output->writeln("<error>Password cannot be empty!</error>");
111
				return 1;
112
			}
113
		} else {
114
			$output->writeln("<error>Interactive input or --password-from-env is needed for entering a new password!</error>");
115
			return 1;
116
		}
117
118
		$output->writeln('<info>The password is not validated so what you provide is what gets recorded in the token</info>');
119
120
121
		$token = $this->random->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
122
		$this->tokenProvider->generateToken(
123
			$token,
124
			$user->getUID(),
125
			$user->getDisplayName(),
126
			$password,
127
			'cli',
128
			IToken::PERMANENT_TOKEN,
129
			IToken::DO_NOT_REMEMBER
130
		);
131
132
		$output->writeln('app password:');
133
		$output->writeln($token);
134
135
		return 0;
136
	}
137
}
138