Passed
Push — master ( 45ff17...c44188 )
by Pauli
02:46
created

SettingController::addUserKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Morris Jobke <[email protected]>
10
 * @author Pauli Järvinen <[email protected]>
11
 * @copyright Morris Jobke 2013, 2014
12
 * @copyright Pauli Järvinen 2017 - 2022
13
 */
14
15
namespace OCA\Music\Controller;
16
17
use OCP\AppFramework\Controller;
18
use OCP\AppFramework\Http;
19
use OCP\AppFramework\Http\JSONResponse;
20
use OCP\IRequest;
21
use OCP\IURLGenerator;
22
use OCP\Security\ISecureRandom;
23
24
use OCA\Music\AppFramework\Core\Logger;
25
use OCA\Music\Db\AmpacheUserMapper;
26
use OCA\Music\Http\ErrorResponse;
27
use OCA\Music\Utility\AppInfo;
28
use OCA\Music\Utility\LibrarySettings;
29
use OCA\Music\Utility\Scanner;
30
use OCA\Music\Utility\Util;
31
32
class SettingController extends Controller {
33
	const DEFAULT_PASSWORD_LENGTH = 10;
34
35
	private $ampacheUserMapper;
36
	private $scanner;
37
	private $userId;
38
	private $librarySettings;
39
	private $secureRandom;
40
	private $urlGenerator;
41
	private $logger;
42
43
	public function __construct(string $appName,
44
								IRequest $request,
45
								AmpacheUserMapper $ampacheUserMapper,
46
								Scanner $scanner,
47
								?string $userId,
48
								LibrarySettings $librarySettings,
49
								ISecureRandom $secureRandom,
50
								IURLGenerator $urlGenerator,
51
								Logger $logger) {
52
		parent::__construct($appName, $request);
53
54
		$this->ampacheUserMapper = $ampacheUserMapper;
55
		$this->scanner = $scanner;
56
		$this->userId = $userId ?? ''; // ensure non-null to satisfy Scrutinizer; the null case should happen only when the user has already logged out
57
		$this->librarySettings = $librarySettings;
58
		$this->secureRandom = $secureRandom;
59
		$this->urlGenerator = $urlGenerator;
60
		$this->logger = $logger;
61
	}
62
63
	/**
64
	 * @NoAdminRequired
65
	 * @UseSession to keep the session reserved while execution in progress
66
	 */
67
	public function userPath(string $value) {
68
		$prevPath = $this->librarySettings->getPath($this->userId);
69
		$success = $this->librarySettings->setPath($this->userId, $value);
70
71
		if ($success) {
72
			$this->scanner->updatePath($prevPath, $value, $this->userId);
73
		}
74
75
		return new JSONResponse(['success' => $success]);
76
	}
77
78
	/**
79
	 * @NoAdminRequired
80
	 */
81
	public function userExcludedPaths(array $value) {
82
		$success = $this->librarySettings->setExcludedPaths($this->userId, $value);
83
		return new JSONResponse(['success' => $success]);
84
	}
85
86
	/**
87
	 * @NoAdminRequired
88
	 */
89
	public function enableScanMetadata(bool $value) {
90
		$this->librarySettings->setScanMetadataEnabled($this->userId, $value);
91
		return new JSONResponse(['success' => true]);
92
	}
93
94
	/**
95
	 * @NoAdminRequired
96
	 */
97
	public function ignoredArticles(array $value) {
98
		$this->librarySettings->setIgnoredArticles($this->userId, $value);
99
		return new JSONResponse(['success' => true]);
100
	}
101
102
	/**
103
	 * @NoAdminRequired
104
	 */
105
	public function getAll() {
106
		return [
107
			'path' => $this->librarySettings->getPath($this->userId),
108
			'excludedPaths' => $this->librarySettings->getExcludedPaths($this->userId),
109
			'scanMetadata' => $this->librarySettings->getScanMetadataEnabled($this->userId),
110
			'ignoredArticles' => $this->librarySettings->getIgnoredArticles($this->userId),
111
			'ampacheUrl' => $this->getAmpacheUrl(),
112
			'subsonicUrl' => $this->getSubsonicUrl(),
113
			'ampacheKeys' => $this->getAmpacheKeys(),
114
			'appVersion' => AppInfo::getVersion(),
115
			'user' => $this->userId
116
		];
117
	}
118
119
	private function getAmpacheUrl() {
120
		return \str_replace('/server/xml.server.php', '',
121
				$this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('music.ampache.xmlApi')));
122
	}
123
124
	private function getSubsonicUrl() {
125
		return \str_replace('/rest/dummy', '',
126
				$this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute(
127
						'music.subsonic.handleRequest', ['method' => 'dummy'])));
128
	}
129
130
	private function getAmpacheKeys() {
131
		return $this->ampacheUserMapper->getAll($this->userId);
132
	}
133
134
	private function storeUserKey($description, $password) {
135
		$hash = \hash('sha256', $password);
136
		$description = Util::truncate($description, 64); // some DB setups can't truncate automatically to column max size
137
		return $this->ampacheUserMapper->addUserKey($this->userId, $hash, $description);
138
	}
139
140
	/**
141
	 * @NoAdminRequired
142
	 */
143
	public function addUserKey($description, $password) {
144
		$id = $this->storeUserKey($description, $password);
145
		$success = ($id !== null);
146
		return new JSONResponse(['success' => $success, 'id' => $id]);
147
	}
148
149
	/**
150
	 * @NoAdminRequired
151
	 * @NoCSRFRequired
152
	 * @CORS
153
	 */
154
	public function generateUserKey($length, $description) {
155
		if ($description == null) {
156
			return new ErrorResponse(Http::STATUS_BAD_REQUEST, 'Please provide a description');
157
		}
158
159
		if ($length == null || $length < self::DEFAULT_PASSWORD_LENGTH) {
160
			$length = self::DEFAULT_PASSWORD_LENGTH;
161
		}
162
163
		$password = $this->secureRandom->generate(
164
			$length,
165
			ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
166
167
		$id = $this->storeUserKey($description, $password);
168
169
		if ($id === null) {
170
			return new ErrorResponse(Http::STATUS_INTERNAL_SERVER_ERROR, 'Error while saving the credentials');
171
		}
172
173
		return new JSONResponse(['id' => $id, 'password' => $password, 'description' => $description], Http::STATUS_CREATED);
174
	}
175
176
	/**
177
	 * @NoAdminRequired
178
	 */
179
	public function removeUserKey($id) {
180
		$this->ampacheUserMapper->removeUserKey($this->userId, (int)$id);
181
		return new JSONResponse(['success' => true]);
182
	}
183
}
184