Completed
Pull Request — master (#226)
by Lukas
18:43 queued 09:50
created

OccController::validateRequest()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 12
c 1
b 0
f 0
nc 5
nop 2
dl 0
loc 22
rs 8.6737
1
<?php
2
/**
3
 * @author Victor Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2016, ownCloud, Inc.
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace OC\Core\Controller;
23
24
use OCP\AppFramework\Controller;
25
use OCP\AppFramework\Http\JSONResponse;
26
use OC\Console\Application;
27
use OCP\IConfig;
28
use OCP\IRequest;
29
use Symfony\Component\Console\Input\ArrayInput;
30
use Symfony\Component\Console\Output\BufferedOutput;
31
32
class OccController extends Controller {
33
	
34
	/** @var array  */
35
	private $allowedCommands = [
36
		'app:disable',
37
		'app:enable',
38
		'app:getpath',
39
		'app:list',
40
		'check',
41
		'config:list',
42
		'maintenance:mode',
43
		'status',
44
		'upgrade'
45
	];
46
47
	/** @var IConfig */
48
	private $config;
49
	/** @var Application */
50
	private $console;
51
52
	/**
53
	 * OccController constructor.
54
	 *
55
	 * @param string $appName
56
	 * @param IRequest $request
57
	 * @param IConfig $config
58
	 * @param Application $console
59
	 */
60
	public function __construct($appName, IRequest $request,
61
								IConfig $config, Application $console) {
62
		parent::__construct($appName, $request);
63
		$this->config = $config;
64
		$this->console = $console;
65
	}
66
67
	/**
68
	 * @PublicPage
69
	 * @NoCSRFRequired
70
	 *
71
	 * Execute occ command
72
	 * Sample request
73
	 *	POST http://domain.tld/index.php/occ/status',
74
	 * 		{
75
	 *			'params': {
76
	 * 					'--no-warnings':'1',
77
	 *		 			'--output':'json'
78
	 * 			},
79
	 * 			'token': 'someToken'
80
	 * 		}
81
	 *
82
	 * @param string $command
83
	 * @param string $token
84
	 * @param array $params
85
	 *
86
	 * @return JSONResponse
87
	 * @throws \Exception
88
	 */
89
	public function execute($command, $token, $params = []) {
90
		try {
91
			$this->validateRequest($command, $token);
92
93
			$output = new BufferedOutput();
94
			$formatter = $output->getFormatter();
95
			$formatter->setDecorated(false);
96
			$this->console->setAutoExit(false);
97
			$this->console->loadCommands(new ArrayInput([]), $output);
98
99
			$inputArray = array_merge(['command' => $command], $params);
100
			$input = new ArrayInput($inputArray);
101
102
			$exitCode = $this->console->run($input, $output);
103
			$response = $output->fetch();
104
105
			$json = [
106
				'exitCode' => $exitCode,
107
				'response' => $response
108
			];
109
110
		} catch (\UnexpectedValueException $e){
111
			$json = [
112
				'exitCode' => 126,
113
				'response' => 'Not allowed',
114
				'details' => $e->getMessage()
115
			];
116
		}
117
		return new JSONResponse($json);
118
	}
119
120
	/**
121
	 * Check if command is allowed and has a valid security token
122
	 * @param $command
123
	 * @param $token
124
	 */
125
	protected function validateRequest($command, $token){
126
		if (!in_array($this->request->getRemoteAddress(), ['::1', '127.0.0.1', 'localhost'])) {
127
			throw new \UnexpectedValueException('Web executor is not allowed to run from a different host');
128
		}
129
130
		if (!in_array($command, $this->allowedCommands)) {
131
			throw new \UnexpectedValueException(sprintf('Command "%s" is not allowed to run via web request', $command));
132
		}
133
134
		$coreToken = $this->config->getSystemValue('updater.secret', '');
135
		if ($coreToken === '') {
136
			throw new \UnexpectedValueException(
137
				'updater.secret is undefined in config/config.php. Either browse the admin settings in your ownCloud and click "Open updater" or define a strong secret using <pre>php -r \'echo password_hash("MyStrongSecretDoUseYourOwn!", PASSWORD_DEFAULT)."\n";\'</pre> and set this in the config.php.'
138
			);
139
		}
140
141
		if (!password_verify($token, $coreToken)) {
142
			throw new \UnexpectedValueException(
143
				'updater.secret does not match the provided token'
144
			);
145
		}
146
	}
147
}
148