Passed
Push — master ( 9002ff...62782a )
by Marcel
04:34
created

ShareService::create()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
nc 2
nop 3
dl 0
loc 8
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * Analytics
4
 *
5
 * SPDX-FileCopyrightText: 2019-2022 Marcel Scherello
6
 * SPDX-License-Identifier: AGPL-3.0-or-later
7
 */
8
9
namespace OCA\Analytics\Service;
10
11
use OCA\Analytics\Activity\ActivityManager;
12
use OCA\Analytics\Db\ShareMapper;
13
use OCA\Analytics\Db\ReportMapper;
14
use OCP\DB\Exception;
0 ignored issues
show
Bug introduced by
The type OCP\DB\Exception was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use OCP\IGroupManager;
0 ignored issues
show
Bug introduced by
The type OCP\IGroupManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use OCP\IUserManager;
0 ignored issues
show
Bug introduced by
The type OCP\IUserManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use OCP\IUserSession;
0 ignored issues
show
Bug introduced by
The type OCP\IUserSession was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use OCP\Security\ISecureRandom;
0 ignored issues
show
Bug introduced by
The type OCP\Security\ISecureRandom was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use Psr\Log\LoggerInterface;
0 ignored issues
show
Bug introduced by
The type Psr\Log\LoggerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
21
class ShareService {
22
	const SHARE_TYPE_USER = 0;
23
	const SHARE_TYPE_GROUP = 1;
24
	const SHARE_TYPE_USERGROUP = 2; // obsolete
25
	const SHARE_TYPE_LINK = 3;
26
	const SHARE_TYPE_ROOM = 10;
27
28
	/** @var IUserSession */
29
	private $userSession;
30
	/** @var LoggerInterface */
31
	private $logger;
32
	/** @var ShareMapper */
33
	private $ShareMapper;
34
	private $ReportMapper;
35
	private $secureRandom;
36
	private $ActivityManager;
37
	/** @var IGroupManager */
38
	private $groupManager;
39
	/** @var IUserManager */
40
	private $userManager;
41
	private $VariableService;
42
43
	public function __construct(
44
		IUserSession    $userSession,
45
		LoggerInterface $logger,
46
		ShareMapper     $ShareMapper,
47
		ReportMapper    $ReportMapper,
48
		ActivityManager $ActivityManager,
49
		IGroupManager   $groupManager,
50
		ISecureRandom   $secureRandom,
51
		IUserManager    $userManager,
52
		VariableService $VariableService
53
	) {
54
		$this->userSession = $userSession;
55
		$this->logger = $logger;
56
		$this->ShareMapper = $ShareMapper;
57
		$this->ReportMapper = $ReportMapper;
58
		$this->secureRandom = $secureRandom;
59
		$this->groupManager = $groupManager;
60
		$this->ActivityManager = $ActivityManager;
61
		$this->userManager = $userManager;
62
		$this->VariableService = $VariableService;
63
	}
64
65
	/**
66
	 * create a new share
67
	 *
68
	 * @param $reportId
69
	 * @param $type
70
	 * @param $user
71
	 * @return bool
72
	 * @throws \OCP\DB\Exception
73
	 */
74
	public function create($reportId, $type, $user) {
75
		$token = null;
76
		if ((int)$type === self::SHARE_TYPE_LINK) {
77
			$token = $this->generateToken();
78
		}
79
		$this->ShareMapper->createShare($reportId, $type, $user, $token);
80
		$this->ActivityManager->triggerEvent($reportId, ActivityManager::OBJECT_REPORT, ActivityManager::SUBJECT_REPORT_SHARE);
81
		return true;
82
	}
83
84
	/**
85
	 * get all shares for a report
86
	 *
87
	 * @param $reportId
88
	 * @return array
89
	 * @throws Exception
90
	 */
91
	public function read($reportId) {
92
93
		$shares = $this->ShareMapper->getShares($reportId);
94
		foreach ($shares as $key => $share) {
95
			if ((int)$share['type'] === self::SHARE_TYPE_USER) {
96
				if (!$this->userManager->userExists($share['uid_owner'])) {
97
					$this->ShareMapper->deleteShare($share['id']);
98
					unset($shares[$key]);
99
					continue;
100
				}
101
				$shares[$key]['displayName'] = $this->userManager->get($share['uid_owner'])->getDisplayName();
102
			}
103
			$shares[$key]['pass'] = $share['pass'] !== null;
104
		}
105
		return $shares;
106
	}
107
108
	/**
109
	 * get all report by token
110
	 *
111
	 * @param $token
112
	 * @return array
113
	 */
114
	public function getReportByToken($token) {
115
		$reportId = $this->ShareMapper->getReportByToken($token);
116
		return $this->VariableService->replaceTextVariables($reportId);
117
	}
118
119
	/**
120
	 * verify password hahes
121
	 *
122
	 * @param $password
123
	 * @param $sharePassword
124
	 * @return bool
125
	 */
126
	public function verifyPassword($password, $sharePassword) {
127
		return password_verify($password, $sharePassword);
128
	}
129
130
	/**
131
	 * get all reports or shared panoramas shared with user
132
	 *
133
	 * @throws Exception
134
	 */
135
	public function getSharedReports($getPanoramas = null) {
136
		if ($getPanoramas === true) {
137
			$sharedReports = $this->ShareMapper->getAllSharedPanoramas();
138
		} else {
139
			$sharedReports = $this->ShareMapper->getAllSharedReports();
140
		}
141
		$groupsOfUser = $this->groupManager->getUserGroups($this->userSession->getUser());
142
		$reports = array();
143
144
		foreach ($sharedReports as $sharedReport) {
145
			// shared with a group?
146
			if ((int)$sharedReport['shareType'] === self::SHARE_TYPE_GROUP) {
147
				// is the current user part of this group?
148
				$this->logger->debug('Shareservice: is group share');
149
				if (array_key_exists($sharedReport['shareUid_owner'], $groupsOfUser)) {
150
					// was the report not yet added to the result?
151
					if (!in_array($sharedReport["id"], array_column($reports, "id"))) {
152
						unset($sharedReport['shareType']);
153
						unset($sharedReport['shareUid_owner']);
154
						$sharedReport['isShare'] = self::SHARE_TYPE_GROUP;
155
						$reports[] = $sharedReport;
156
					}
157
				}
158
				// shared with a user directly?
159
			} elseif ((int)$sharedReport['shareType'] === self::SHARE_TYPE_USER) {
160
				// current user matching?
161
				$this->logger->debug('Shareservice: is user share; check against current user: ' . $this->userSession->getUser()
162
																													 ->getUID());
163
				if ($this->userSession->getUser()->getUID() === $sharedReport['shareUid_owner']) {
164
					// was the report not yet added to the result?
165
					$this->logger->debug('Shareservice: Share belongs to current user');
166
					if (!in_array($sharedReport["id"], array_column($reports, "id"))) {
167
						$this->logger->debug('Shareservice: Share added to output');
168
						unset($sharedReport['shareType']);
169
						unset($sharedReport['shareUid_owner']);
170
						$sharedReport['isShare'] = self::SHARE_TYPE_USER;
171
						$reports[] = $sharedReport;
172
					}
173
				}
174
			}
175
		}
176
177
		// no groupings of shares exist for panoramas
178
		if ($getPanoramas === null) {
179
			foreach ($reports as $report) {
180
				// if it is a shared group, get all reports below
181
				if ((int)$report['type'] === ReportService::REPORT_TYPE_GROUP) {
182
					$subreport = $this->ReportMapper->getReportsByGroup($report['id']);
183
					$subreport = array_map(function ($report) {
184
						$report['isShare'] = self::SHARE_TYPE_GROUP;
185
						return $report;
186
					}, $subreport);
187
188
					$reports = array_merge($reports, $subreport);
189
				}
190
			}
191
		}
192
		return $reports;
193
	}
194
195
	/**
196
	 * get metadata of a report, shared with current user
197
	 * used to check if user is allowed to execute current report
198
	 *
199
	 * @param $reportId
200
	 * @return array
201
	 * @throws Exception
202
	 */
203
	public function getSharedReport($reportId) {
204
		$sharedReport = $this->getSharedReports();
205
		if (in_array($reportId, array_column($sharedReport, "id"))) {
206
			$key = array_search($reportId, array_column($sharedReport, 'id'));
207
			return $sharedReport[$key];
208
		} else {
209
			return [];
210
		}
211
	}
212
213
	/**
214
	 * get metadata of a report, shared with current user as part of a panorama
215
	 * used to check if user is allowed to execute current report
216
	 *
217
	 * @param $reportId
218
	 * @return array
219
	 * @throws Exception
220
	 */
221
	public function getSharedPanoramaReport($reportId) {
222
		$foundReportId = 0;
223
		$panoramaOwner = null;
224
		$sharedPanoramas = $this->getSharedReports(true);
225
		foreach ($sharedPanoramas as $sharedPanorama) {
226
			$panoramaOwner = $sharedPanorama['user_id'];
227
			$pages = json_decode($sharedPanorama['pages'], true);
228
			foreach ($pages as $page) {
229
				$reports = $page['reports'];
230
				foreach ($reports as $report) {
231
					// only use report type 0 = report; not text or image
232
					if ($report['type'] === 0 && $report['value'] === $reportId) {
233
						$foundReportId = $reportId;
234
						break 3;
235
					}
236
				}
237
			}
238
		}
239
240
		if ($foundReportId !== 0) {
0 ignored issues
show
introduced by
The condition $foundReportId !== 0 is always false.
Loading history...
241
			$report = $this->ReportMapper->read($foundReportId);
242
			// check against the original owner of the panorama
243
			// This is needed to prevent getting other reports by modifying the panorama properties
244
			if ($report['user_id'] === $panoramaOwner) {
245
				return $report;
246
			} else {
247
				return [];
248
			}
249
		} else {
250
			return [];
251
		}
252
	}
253
254
	/**
255
	 * Delete an own share (sharee or receiver)
256
	 *
257
	 * @param $shareId
258
	 * @return bool
259
	 * @throws Exception
260
	 */
261
	public function delete($shareId) {
262
		$this->ShareMapper->deleteShare($shareId);
263
		return true;
264
	}
265
266
	/**
267
	 * delete all shares for a report
268
	 *
269
	 * @param $reportId
270
	 * @return bool
271
	 */
272
	public function deleteShareByReport($reportId) {
273
		return $this->ShareMapper->deleteShareByReport($reportId);
274
	}
275
276
	/**
277
	 * delete all shares when a share-receiving-user is deleted
278
	 *
279
	 * @param $userId
280
	 * @return bool
281
	 */
282
	public function deleteByUser($userId) {
283
		return $this->ShareMapper->deleteByUser($userId);
284
	}
285
286
	/**
287
	 * update/set share password
288
	 *
289
	 * @param $shareId
290
	 * @param string|null $password
291
	 * @param string|null $canEdit
292
	 * @param string|null $domain
293
	 * @return bool
294
	 */
295
	public function update($shareId, $password = null, $canEdit = null, $domain = null) {
296
		if ($password !== null) {
297
			$password = password_hash($password, PASSWORD_DEFAULT);
298
			return $this->ShareMapper->updateSharePassword($shareId, $password);
299
		}
300
		if ($domain !== null) {
301
			return $this->ShareMapper->updateShareDomain($shareId, $domain);
302
		}
303
		if ($canEdit !== null) {
304
			$canEdit === true ? $canEdit = \OCP\Constants::PERMISSION_UPDATE : $canEdit = \OCP\Constants::PERMISSION_READ;
0 ignored issues
show
introduced by
The condition $canEdit === true is always false.
Loading history...
Bug introduced by
The type OCP\Constants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
305
			return $this->ShareMapper->updateSharePermissions($shareId, $canEdit);
306
		}
307
	}
308
309
	/**
310
	 * generate to token used to authenticate federated shares
311
	 *
312
	 * @return string
313
	 */
314
	private function generateToken() {
315
		$token = $this->secureRandom->generate(15, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
316
		return $token;
317
	}
318
}