Passed
Push — master ( 6a3321...65b6b4 )
by Christoph
13:21 queued 14s
created
apps/dav/lib/Connector/Sabre/Principal.php 2 patches
Indentation   +496 added lines, -496 removed lines patch added patch discarded remove patch
@@ -55,500 +55,500 @@
 block discarded – undo
55 55
 
56 56
 class Principal implements BackendInterface {
57 57
 
58
-	/** @var IUserManager */
59
-	private $userManager;
60
-
61
-	/** @var IGroupManager */
62
-	private $groupManager;
63
-
64
-	/** @var IShareManager */
65
-	private $shareManager;
66
-
67
-	/** @var IUserSession */
68
-	private $userSession;
69
-
70
-	/** @var IAppManager */
71
-	private $appManager;
72
-
73
-	/** @var string */
74
-	private $principalPrefix;
75
-
76
-	/** @var bool */
77
-	private $hasGroups;
78
-
79
-	/** @var bool */
80
-	private $hasCircles;
81
-
82
-	/** @var ProxyMapper */
83
-	private $proxyMapper;
84
-
85
-	/** @var IConfig */
86
-	private $config;
87
-
88
-	/**
89
-	 * Principal constructor.
90
-	 *
91
-	 * @param IUserManager $userManager
92
-	 * @param IGroupManager $groupManager
93
-	 * @param IShareManager $shareManager
94
-	 * @param IUserSession $userSession
95
-	 * @param IAppManager $appManager
96
-	 * @param ProxyMapper $proxyMapper
97
-	 * @param IConfig $config
98
-	 * @param string $principalPrefix
99
-	 */
100
-	public function __construct(IUserManager $userManager,
101
-								IGroupManager $groupManager,
102
-								IShareManager $shareManager,
103
-								IUserSession $userSession,
104
-								IAppManager $appManager,
105
-								ProxyMapper $proxyMapper,
106
-								IConfig $config,
107
-								string $principalPrefix = 'principals/users/') {
108
-		$this->userManager = $userManager;
109
-		$this->groupManager = $groupManager;
110
-		$this->shareManager = $shareManager;
111
-		$this->userSession = $userSession;
112
-		$this->appManager = $appManager;
113
-		$this->principalPrefix = trim($principalPrefix, '/');
114
-		$this->hasGroups = $this->hasCircles = ($principalPrefix === 'principals/users/');
115
-		$this->proxyMapper = $proxyMapper;
116
-		$this->config = $config;
117
-	}
118
-
119
-	use PrincipalProxyTrait {
120
-		getGroupMembership as protected traitGetGroupMembership;
121
-	}
122
-
123
-	/**
124
-	 * Returns a list of principals based on a prefix.
125
-	 *
126
-	 * This prefix will often contain something like 'principals'. You are only
127
-	 * expected to return principals that are in this base path.
128
-	 *
129
-	 * You are expected to return at least a 'uri' for every user, you can
130
-	 * return any additional properties if you wish so. Common properties are:
131
-	 *   {DAV:}displayname
132
-	 *
133
-	 * @param string $prefixPath
134
-	 * @return string[]
135
-	 */
136
-	public function getPrincipalsByPrefix($prefixPath) {
137
-		$principals = [];
138
-
139
-		if ($prefixPath === $this->principalPrefix) {
140
-			foreach ($this->userManager->search('') as $user) {
141
-				$principals[] = $this->userToPrincipal($user);
142
-			}
143
-		}
144
-
145
-		return $principals;
146
-	}
147
-
148
-	/**
149
-	 * Returns a specific principal, specified by it's path.
150
-	 * The returned structure should be the exact same as from
151
-	 * getPrincipalsByPrefix.
152
-	 *
153
-	 * @param string $path
154
-	 * @return array
155
-	 */
156
-	public function getPrincipalByPath($path) {
157
-		list($prefix, $name) = \Sabre\Uri\split($path);
158
-		$decodedName = urldecode($name);
159
-
160
-		if ($name === 'calendar-proxy-write' || $name === 'calendar-proxy-read') {
161
-			list($prefix2, $name2) = \Sabre\Uri\split($prefix);
162
-
163
-			if ($prefix2 === $this->principalPrefix) {
164
-				$user = $this->userManager->get($name2);
165
-
166
-				if ($user !== null) {
167
-					return [
168
-						'uri' => 'principals/users/' . $user->getUID() . '/' . $name,
169
-					];
170
-				}
171
-				return null;
172
-			}
173
-		}
174
-
175
-		if ($prefix === $this->principalPrefix) {
176
-			// Depending on where it is called, it may happen that this function
177
-			// is called either with a urlencoded version of the name or with a non-urlencoded one.
178
-			// The urldecode function replaces %## and +, both of which are forbidden in usernames.
179
-			// Hence there can be no ambiguity here and it is safe to call urldecode on all usernames
180
-			$user = $this->userManager->get($decodedName);
181
-
182
-			if ($user !== null) {
183
-				return $this->userToPrincipal($user);
184
-			}
185
-		} elseif ($prefix === 'principals/circles') {
186
-			if ($this->userSession->getUser() !== null) {
187
-				// At the time of writing - 2021-01-19 — a mixed state is possible.
188
-				// The second condition can be removed when this is fixed.
189
-				return $this->circleToPrincipal($decodedName)
190
-					?: $this->circleToPrincipal($name);
191
-			}
192
-		} elseif ($prefix === 'principals/groups') {
193
-			// At the time of writing - 2021-01-19 — a mixed state is possible.
194
-			// The second condition can be removed when this is fixed.
195
-			$group = $this->groupManager->get($decodedName)
196
-				?: $this->groupManager->get($name);
197
-			if ($group instanceof IGroup) {
198
-				return [
199
-					'uri' => 'principals/groups/' . $name,
200
-					'{DAV:}displayname' => $group->getDisplayName(),
201
-				];
202
-			}
203
-		}
204
-		return null;
205
-	}
206
-
207
-	/**
208
-	 * Returns the list of groups a principal is a member of
209
-	 *
210
-	 * @param string $principal
211
-	 * @param bool $needGroups
212
-	 * @return array
213
-	 * @throws Exception
214
-	 */
215
-	public function getGroupMembership($principal, $needGroups = false) {
216
-		list($prefix, $name) = \Sabre\Uri\split($principal);
217
-
218
-		if ($prefix !== $this->principalPrefix) {
219
-			return [];
220
-		}
221
-
222
-		$user = $this->userManager->get($name);
223
-		if (!$user) {
224
-			throw new Exception('Principal not found');
225
-		}
226
-
227
-		$groups = [];
228
-
229
-		if ($this->hasGroups || $needGroups) {
230
-			$userGroups = $this->groupManager->getUserGroups($user);
231
-			foreach ($userGroups as $userGroup) {
232
-				$groups[] = 'principals/groups/' . urlencode($userGroup->getGID());
233
-			}
234
-		}
235
-
236
-		$groups = array_unique(array_merge(
237
-			$groups,
238
-			$this->traitGetGroupMembership($principal, $needGroups)
239
-		));
240
-
241
-		return $groups;
242
-	}
243
-
244
-	/**
245
-	 * @param string $path
246
-	 * @param PropPatch $propPatch
247
-	 * @return int
248
-	 */
249
-	public function updatePrincipal($path, PropPatch $propPatch) {
250
-		return 0;
251
-	}
252
-
253
-	/**
254
-	 * Search user principals
255
-	 *
256
-	 * @param array $searchProperties
257
-	 * @param string $test
258
-	 * @return array
259
-	 */
260
-	protected function searchUserPrincipals(array $searchProperties, $test = 'allof') {
261
-		$results = [];
262
-
263
-		// If sharing is disabled, return the empty array
264
-		$shareAPIEnabled = $this->shareManager->shareApiEnabled();
265
-		if (!$shareAPIEnabled) {
266
-			return [];
267
-		}
268
-
269
-		$allowEnumeration = $this->shareManager->allowEnumeration();
270
-		$limitEnumeration = $this->shareManager->limitEnumerationToGroups();
271
-
272
-		// If sharing is restricted to group members only,
273
-		// return only members that have groups in common
274
-		$restrictGroups = false;
275
-		if ($this->shareManager->shareWithGroupMembersOnly()) {
276
-			$user = $this->userSession->getUser();
277
-			if (!$user) {
278
-				return [];
279
-			}
280
-
281
-			$restrictGroups = $this->groupManager->getUserGroupIds($user);
282
-		}
283
-
284
-		$currentUserGroups = [];
285
-		if ($limitEnumeration) {
286
-			$currentUser = $this->userSession->getUser();
287
-			if ($currentUser) {
288
-				$currentUserGroups = $this->groupManager->getUserGroupIds($currentUser);
289
-			}
290
-		}
291
-
292
-		$searchLimit = $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT);
293
-		if ($searchLimit <= 0) {
294
-			$searchLimit = null;
295
-		}
296
-		foreach ($searchProperties as $prop => $value) {
297
-			switch ($prop) {
298
-				case '{http://sabredav.org/ns}email-address':
299
-					$users = $this->userManager->getByEmail($value);
300
-
301
-					if (!$allowEnumeration) {
302
-						$users = \array_filter($users, static function (IUser $user) use ($value) {
303
-							return $user->getEMailAddress() === $value;
304
-						});
305
-					}
306
-
307
-					if ($limitEnumeration) {
308
-						$users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
309
-							return !empty(array_intersect(
310
-									$this->groupManager->getUserGroupIds($user),
311
-									$currentUserGroups
312
-								)) || $user->getEMailAddress() === $value;
313
-						});
314
-					}
315
-
316
-					$results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
317
-						// is sharing restricted to groups only?
318
-						if ($restrictGroups !== false) {
319
-							$userGroups = $this->groupManager->getUserGroupIds($user);
320
-							if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
321
-								return $carry;
322
-							}
323
-						}
324
-
325
-						$carry[] = $this->principalPrefix . '/' . $user->getUID();
326
-						return $carry;
327
-					}, []);
328
-					break;
329
-
330
-				case '{DAV:}displayname':
331
-					$users = $this->userManager->searchDisplayName($value, $searchLimit);
332
-
333
-					if (!$allowEnumeration) {
334
-						$users = \array_filter($users, static function (IUser $user) use ($value) {
335
-							return $user->getDisplayName() === $value;
336
-						});
337
-					}
338
-
339
-					if ($limitEnumeration) {
340
-						$users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
341
-							return !empty(array_intersect(
342
-									$this->groupManager->getUserGroupIds($user),
343
-									$currentUserGroups
344
-								)) || $user->getDisplayName() === $value;
345
-						});
346
-					}
347
-
348
-					$results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
349
-						// is sharing restricted to groups only?
350
-						if ($restrictGroups !== false) {
351
-							$userGroups = $this->groupManager->getUserGroupIds($user);
352
-							if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
353
-								return $carry;
354
-							}
355
-						}
356
-
357
-						$carry[] = $this->principalPrefix . '/' . $user->getUID();
358
-						return $carry;
359
-					}, []);
360
-					break;
361
-
362
-				case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
363
-					// If you add support for more search properties that qualify as a user-address,
364
-					// please also add them to the array below
365
-					$results[] = $this->searchUserPrincipals([
366
-						// In theory this should also search for principal:principals/users/...
367
-						// but that's used internally only anyway and i don't know of any client querying that
368
-						'{http://sabredav.org/ns}email-address' => $value,
369
-					], 'anyof');
370
-					break;
371
-
372
-				default:
373
-					$results[] = [];
374
-					break;
375
-			}
376
-		}
377
-
378
-		// results is an array of arrays, so this is not the first search result
379
-		// but the results of the first searchProperty
380
-		if (count($results) === 1) {
381
-			return $results[0];
382
-		}
383
-
384
-		switch ($test) {
385
-			case 'anyof':
386
-				return array_values(array_unique(array_merge(...$results)));
387
-
388
-			case 'allof':
389
-			default:
390
-				return array_values(array_intersect(...$results));
391
-		}
392
-	}
393
-
394
-	/**
395
-	 * @param string $prefixPath
396
-	 * @param array $searchProperties
397
-	 * @param string $test
398
-	 * @return array
399
-	 */
400
-	public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
401
-		if (count($searchProperties) === 0) {
402
-			return [];
403
-		}
404
-
405
-		switch ($prefixPath) {
406
-			case 'principals/users':
407
-				return $this->searchUserPrincipals($searchProperties, $test);
408
-
409
-			default:
410
-				return [];
411
-		}
412
-	}
413
-
414
-	/**
415
-	 * @param string $uri
416
-	 * @param string $principalPrefix
417
-	 * @return string
418
-	 */
419
-	public function findByUri($uri, $principalPrefix) {
420
-		// If sharing is disabled, return the empty array
421
-		$shareAPIEnabled = $this->shareManager->shareApiEnabled();
422
-		if (!$shareAPIEnabled) {
423
-			return null;
424
-		}
425
-
426
-		// If sharing is restricted to group members only,
427
-		// return only members that have groups in common
428
-		$restrictGroups = false;
429
-		if ($this->shareManager->shareWithGroupMembersOnly()) {
430
-			$user = $this->userSession->getUser();
431
-			if (!$user) {
432
-				return null;
433
-			}
434
-
435
-			$restrictGroups = $this->groupManager->getUserGroupIds($user);
436
-		}
437
-
438
-		if (strpos($uri, 'mailto:') === 0) {
439
-			if ($principalPrefix === 'principals/users') {
440
-				$users = $this->userManager->getByEmail(substr($uri, 7));
441
-				if (count($users) !== 1) {
442
-					return null;
443
-				}
444
-				$user = $users[0];
445
-
446
-				if ($restrictGroups !== false) {
447
-					$userGroups = $this->groupManager->getUserGroupIds($user);
448
-					if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
449
-						return null;
450
-					}
451
-				}
452
-
453
-				return $this->principalPrefix . '/' . $user->getUID();
454
-			}
455
-		}
456
-		if (substr($uri, 0, 10) === 'principal:') {
457
-			$principal = substr($uri, 10);
458
-			$principal = $this->getPrincipalByPath($principal);
459
-			if ($principal !== null) {
460
-				return $principal['uri'];
461
-			}
462
-		}
463
-
464
-		return null;
465
-	}
466
-
467
-	/**
468
-	 * @param IUser $user
469
-	 * @return array
470
-	 */
471
-	protected function userToPrincipal($user) {
472
-		$userId = $user->getUID();
473
-		$displayName = $user->getDisplayName();
474
-		$principal = [
475
-			'uri' => $this->principalPrefix . '/' . $userId,
476
-			'{DAV:}displayname' => is_null($displayName) ? $userId : $displayName,
477
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
478
-		];
479
-
480
-		$email = $user->getEMailAddress();
481
-		if (!empty($email)) {
482
-			$principal['{http://sabredav.org/ns}email-address'] = $email;
483
-		}
484
-
485
-		return $principal;
486
-	}
487
-
488
-	public function getPrincipalPrefix() {
489
-		return $this->principalPrefix;
490
-	}
491
-
492
-	/**
493
-	 * @param string $circleUniqueId
494
-	 * @return array|null
495
-	 */
496
-	protected function circleToPrincipal($circleUniqueId) {
497
-		if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
498
-			return null;
499
-		}
500
-
501
-		try {
502
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($circleUniqueId, true);
503
-		} catch (QueryException $ex) {
504
-			return null;
505
-		} catch (CircleDoesNotExistException $ex) {
506
-			return null;
507
-		}
508
-
509
-		if (!$circle) {
510
-			return null;
511
-		}
512
-
513
-		$principal = [
514
-			'uri' => 'principals/circles/' . $circleUniqueId,
515
-			'{DAV:}displayname' => $circle->getName(),
516
-		];
517
-
518
-		return $principal;
519
-	}
520
-
521
-	/**
522
-	 * Returns the list of circles a principal is a member of
523
-	 *
524
-	 * @param string $principal
525
-	 * @return array
526
-	 * @throws Exception
527
-	 * @throws \OCP\AppFramework\QueryException
528
-	 * @suppress PhanUndeclaredClassMethod
529
-	 */
530
-	public function getCircleMembership($principal):array {
531
-		if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
532
-			return [];
533
-		}
534
-
535
-		list($prefix, $name) = \Sabre\Uri\split($principal);
536
-		if ($this->hasCircles && $prefix === $this->principalPrefix) {
537
-			$user = $this->userManager->get($name);
538
-			if (!$user) {
539
-				throw new Exception('Principal not found');
540
-			}
541
-
542
-			$circles = \OCA\Circles\Api\v1\Circles::joinedCircles($name, true);
543
-
544
-			$circles = array_map(function ($circle) {
545
-				/** @var \OCA\Circles\Model\Circle $circle */
546
-				return 'principals/circles/' . urlencode($circle->getUniqueId());
547
-			}, $circles);
548
-
549
-			return $circles;
550
-		}
551
-
552
-		return [];
553
-	}
58
+    /** @var IUserManager */
59
+    private $userManager;
60
+
61
+    /** @var IGroupManager */
62
+    private $groupManager;
63
+
64
+    /** @var IShareManager */
65
+    private $shareManager;
66
+
67
+    /** @var IUserSession */
68
+    private $userSession;
69
+
70
+    /** @var IAppManager */
71
+    private $appManager;
72
+
73
+    /** @var string */
74
+    private $principalPrefix;
75
+
76
+    /** @var bool */
77
+    private $hasGroups;
78
+
79
+    /** @var bool */
80
+    private $hasCircles;
81
+
82
+    /** @var ProxyMapper */
83
+    private $proxyMapper;
84
+
85
+    /** @var IConfig */
86
+    private $config;
87
+
88
+    /**
89
+     * Principal constructor.
90
+     *
91
+     * @param IUserManager $userManager
92
+     * @param IGroupManager $groupManager
93
+     * @param IShareManager $shareManager
94
+     * @param IUserSession $userSession
95
+     * @param IAppManager $appManager
96
+     * @param ProxyMapper $proxyMapper
97
+     * @param IConfig $config
98
+     * @param string $principalPrefix
99
+     */
100
+    public function __construct(IUserManager $userManager,
101
+                                IGroupManager $groupManager,
102
+                                IShareManager $shareManager,
103
+                                IUserSession $userSession,
104
+                                IAppManager $appManager,
105
+                                ProxyMapper $proxyMapper,
106
+                                IConfig $config,
107
+                                string $principalPrefix = 'principals/users/') {
108
+        $this->userManager = $userManager;
109
+        $this->groupManager = $groupManager;
110
+        $this->shareManager = $shareManager;
111
+        $this->userSession = $userSession;
112
+        $this->appManager = $appManager;
113
+        $this->principalPrefix = trim($principalPrefix, '/');
114
+        $this->hasGroups = $this->hasCircles = ($principalPrefix === 'principals/users/');
115
+        $this->proxyMapper = $proxyMapper;
116
+        $this->config = $config;
117
+    }
118
+
119
+    use PrincipalProxyTrait {
120
+        getGroupMembership as protected traitGetGroupMembership;
121
+    }
122
+
123
+    /**
124
+     * Returns a list of principals based on a prefix.
125
+     *
126
+     * This prefix will often contain something like 'principals'. You are only
127
+     * expected to return principals that are in this base path.
128
+     *
129
+     * You are expected to return at least a 'uri' for every user, you can
130
+     * return any additional properties if you wish so. Common properties are:
131
+     *   {DAV:}displayname
132
+     *
133
+     * @param string $prefixPath
134
+     * @return string[]
135
+     */
136
+    public function getPrincipalsByPrefix($prefixPath) {
137
+        $principals = [];
138
+
139
+        if ($prefixPath === $this->principalPrefix) {
140
+            foreach ($this->userManager->search('') as $user) {
141
+                $principals[] = $this->userToPrincipal($user);
142
+            }
143
+        }
144
+
145
+        return $principals;
146
+    }
147
+
148
+    /**
149
+     * Returns a specific principal, specified by it's path.
150
+     * The returned structure should be the exact same as from
151
+     * getPrincipalsByPrefix.
152
+     *
153
+     * @param string $path
154
+     * @return array
155
+     */
156
+    public function getPrincipalByPath($path) {
157
+        list($prefix, $name) = \Sabre\Uri\split($path);
158
+        $decodedName = urldecode($name);
159
+
160
+        if ($name === 'calendar-proxy-write' || $name === 'calendar-proxy-read') {
161
+            list($prefix2, $name2) = \Sabre\Uri\split($prefix);
162
+
163
+            if ($prefix2 === $this->principalPrefix) {
164
+                $user = $this->userManager->get($name2);
165
+
166
+                if ($user !== null) {
167
+                    return [
168
+                        'uri' => 'principals/users/' . $user->getUID() . '/' . $name,
169
+                    ];
170
+                }
171
+                return null;
172
+            }
173
+        }
174
+
175
+        if ($prefix === $this->principalPrefix) {
176
+            // Depending on where it is called, it may happen that this function
177
+            // is called either with a urlencoded version of the name or with a non-urlencoded one.
178
+            // The urldecode function replaces %## and +, both of which are forbidden in usernames.
179
+            // Hence there can be no ambiguity here and it is safe to call urldecode on all usernames
180
+            $user = $this->userManager->get($decodedName);
181
+
182
+            if ($user !== null) {
183
+                return $this->userToPrincipal($user);
184
+            }
185
+        } elseif ($prefix === 'principals/circles') {
186
+            if ($this->userSession->getUser() !== null) {
187
+                // At the time of writing - 2021-01-19 — a mixed state is possible.
188
+                // The second condition can be removed when this is fixed.
189
+                return $this->circleToPrincipal($decodedName)
190
+                    ?: $this->circleToPrincipal($name);
191
+            }
192
+        } elseif ($prefix === 'principals/groups') {
193
+            // At the time of writing - 2021-01-19 — a mixed state is possible.
194
+            // The second condition can be removed when this is fixed.
195
+            $group = $this->groupManager->get($decodedName)
196
+                ?: $this->groupManager->get($name);
197
+            if ($group instanceof IGroup) {
198
+                return [
199
+                    'uri' => 'principals/groups/' . $name,
200
+                    '{DAV:}displayname' => $group->getDisplayName(),
201
+                ];
202
+            }
203
+        }
204
+        return null;
205
+    }
206
+
207
+    /**
208
+     * Returns the list of groups a principal is a member of
209
+     *
210
+     * @param string $principal
211
+     * @param bool $needGroups
212
+     * @return array
213
+     * @throws Exception
214
+     */
215
+    public function getGroupMembership($principal, $needGroups = false) {
216
+        list($prefix, $name) = \Sabre\Uri\split($principal);
217
+
218
+        if ($prefix !== $this->principalPrefix) {
219
+            return [];
220
+        }
221
+
222
+        $user = $this->userManager->get($name);
223
+        if (!$user) {
224
+            throw new Exception('Principal not found');
225
+        }
226
+
227
+        $groups = [];
228
+
229
+        if ($this->hasGroups || $needGroups) {
230
+            $userGroups = $this->groupManager->getUserGroups($user);
231
+            foreach ($userGroups as $userGroup) {
232
+                $groups[] = 'principals/groups/' . urlencode($userGroup->getGID());
233
+            }
234
+        }
235
+
236
+        $groups = array_unique(array_merge(
237
+            $groups,
238
+            $this->traitGetGroupMembership($principal, $needGroups)
239
+        ));
240
+
241
+        return $groups;
242
+    }
243
+
244
+    /**
245
+     * @param string $path
246
+     * @param PropPatch $propPatch
247
+     * @return int
248
+     */
249
+    public function updatePrincipal($path, PropPatch $propPatch) {
250
+        return 0;
251
+    }
252
+
253
+    /**
254
+     * Search user principals
255
+     *
256
+     * @param array $searchProperties
257
+     * @param string $test
258
+     * @return array
259
+     */
260
+    protected function searchUserPrincipals(array $searchProperties, $test = 'allof') {
261
+        $results = [];
262
+
263
+        // If sharing is disabled, return the empty array
264
+        $shareAPIEnabled = $this->shareManager->shareApiEnabled();
265
+        if (!$shareAPIEnabled) {
266
+            return [];
267
+        }
268
+
269
+        $allowEnumeration = $this->shareManager->allowEnumeration();
270
+        $limitEnumeration = $this->shareManager->limitEnumerationToGroups();
271
+
272
+        // If sharing is restricted to group members only,
273
+        // return only members that have groups in common
274
+        $restrictGroups = false;
275
+        if ($this->shareManager->shareWithGroupMembersOnly()) {
276
+            $user = $this->userSession->getUser();
277
+            if (!$user) {
278
+                return [];
279
+            }
280
+
281
+            $restrictGroups = $this->groupManager->getUserGroupIds($user);
282
+        }
283
+
284
+        $currentUserGroups = [];
285
+        if ($limitEnumeration) {
286
+            $currentUser = $this->userSession->getUser();
287
+            if ($currentUser) {
288
+                $currentUserGroups = $this->groupManager->getUserGroupIds($currentUser);
289
+            }
290
+        }
291
+
292
+        $searchLimit = $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT);
293
+        if ($searchLimit <= 0) {
294
+            $searchLimit = null;
295
+        }
296
+        foreach ($searchProperties as $prop => $value) {
297
+            switch ($prop) {
298
+                case '{http://sabredav.org/ns}email-address':
299
+                    $users = $this->userManager->getByEmail($value);
300
+
301
+                    if (!$allowEnumeration) {
302
+                        $users = \array_filter($users, static function (IUser $user) use ($value) {
303
+                            return $user->getEMailAddress() === $value;
304
+                        });
305
+                    }
306
+
307
+                    if ($limitEnumeration) {
308
+                        $users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
309
+                            return !empty(array_intersect(
310
+                                    $this->groupManager->getUserGroupIds($user),
311
+                                    $currentUserGroups
312
+                                )) || $user->getEMailAddress() === $value;
313
+                        });
314
+                    }
315
+
316
+                    $results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
317
+                        // is sharing restricted to groups only?
318
+                        if ($restrictGroups !== false) {
319
+                            $userGroups = $this->groupManager->getUserGroupIds($user);
320
+                            if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
321
+                                return $carry;
322
+                            }
323
+                        }
324
+
325
+                        $carry[] = $this->principalPrefix . '/' . $user->getUID();
326
+                        return $carry;
327
+                    }, []);
328
+                    break;
329
+
330
+                case '{DAV:}displayname':
331
+                    $users = $this->userManager->searchDisplayName($value, $searchLimit);
332
+
333
+                    if (!$allowEnumeration) {
334
+                        $users = \array_filter($users, static function (IUser $user) use ($value) {
335
+                            return $user->getDisplayName() === $value;
336
+                        });
337
+                    }
338
+
339
+                    if ($limitEnumeration) {
340
+                        $users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
341
+                            return !empty(array_intersect(
342
+                                    $this->groupManager->getUserGroupIds($user),
343
+                                    $currentUserGroups
344
+                                )) || $user->getDisplayName() === $value;
345
+                        });
346
+                    }
347
+
348
+                    $results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
349
+                        // is sharing restricted to groups only?
350
+                        if ($restrictGroups !== false) {
351
+                            $userGroups = $this->groupManager->getUserGroupIds($user);
352
+                            if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
353
+                                return $carry;
354
+                            }
355
+                        }
356
+
357
+                        $carry[] = $this->principalPrefix . '/' . $user->getUID();
358
+                        return $carry;
359
+                    }, []);
360
+                    break;
361
+
362
+                case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
363
+                    // If you add support for more search properties that qualify as a user-address,
364
+                    // please also add them to the array below
365
+                    $results[] = $this->searchUserPrincipals([
366
+                        // In theory this should also search for principal:principals/users/...
367
+                        // but that's used internally only anyway and i don't know of any client querying that
368
+                        '{http://sabredav.org/ns}email-address' => $value,
369
+                    ], 'anyof');
370
+                    break;
371
+
372
+                default:
373
+                    $results[] = [];
374
+                    break;
375
+            }
376
+        }
377
+
378
+        // results is an array of arrays, so this is not the first search result
379
+        // but the results of the first searchProperty
380
+        if (count($results) === 1) {
381
+            return $results[0];
382
+        }
383
+
384
+        switch ($test) {
385
+            case 'anyof':
386
+                return array_values(array_unique(array_merge(...$results)));
387
+
388
+            case 'allof':
389
+            default:
390
+                return array_values(array_intersect(...$results));
391
+        }
392
+    }
393
+
394
+    /**
395
+     * @param string $prefixPath
396
+     * @param array $searchProperties
397
+     * @param string $test
398
+     * @return array
399
+     */
400
+    public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
401
+        if (count($searchProperties) === 0) {
402
+            return [];
403
+        }
404
+
405
+        switch ($prefixPath) {
406
+            case 'principals/users':
407
+                return $this->searchUserPrincipals($searchProperties, $test);
408
+
409
+            default:
410
+                return [];
411
+        }
412
+    }
413
+
414
+    /**
415
+     * @param string $uri
416
+     * @param string $principalPrefix
417
+     * @return string
418
+     */
419
+    public function findByUri($uri, $principalPrefix) {
420
+        // If sharing is disabled, return the empty array
421
+        $shareAPIEnabled = $this->shareManager->shareApiEnabled();
422
+        if (!$shareAPIEnabled) {
423
+            return null;
424
+        }
425
+
426
+        // If sharing is restricted to group members only,
427
+        // return only members that have groups in common
428
+        $restrictGroups = false;
429
+        if ($this->shareManager->shareWithGroupMembersOnly()) {
430
+            $user = $this->userSession->getUser();
431
+            if (!$user) {
432
+                return null;
433
+            }
434
+
435
+            $restrictGroups = $this->groupManager->getUserGroupIds($user);
436
+        }
437
+
438
+        if (strpos($uri, 'mailto:') === 0) {
439
+            if ($principalPrefix === 'principals/users') {
440
+                $users = $this->userManager->getByEmail(substr($uri, 7));
441
+                if (count($users) !== 1) {
442
+                    return null;
443
+                }
444
+                $user = $users[0];
445
+
446
+                if ($restrictGroups !== false) {
447
+                    $userGroups = $this->groupManager->getUserGroupIds($user);
448
+                    if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
449
+                        return null;
450
+                    }
451
+                }
452
+
453
+                return $this->principalPrefix . '/' . $user->getUID();
454
+            }
455
+        }
456
+        if (substr($uri, 0, 10) === 'principal:') {
457
+            $principal = substr($uri, 10);
458
+            $principal = $this->getPrincipalByPath($principal);
459
+            if ($principal !== null) {
460
+                return $principal['uri'];
461
+            }
462
+        }
463
+
464
+        return null;
465
+    }
466
+
467
+    /**
468
+     * @param IUser $user
469
+     * @return array
470
+     */
471
+    protected function userToPrincipal($user) {
472
+        $userId = $user->getUID();
473
+        $displayName = $user->getDisplayName();
474
+        $principal = [
475
+            'uri' => $this->principalPrefix . '/' . $userId,
476
+            '{DAV:}displayname' => is_null($displayName) ? $userId : $displayName,
477
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
478
+        ];
479
+
480
+        $email = $user->getEMailAddress();
481
+        if (!empty($email)) {
482
+            $principal['{http://sabredav.org/ns}email-address'] = $email;
483
+        }
484
+
485
+        return $principal;
486
+    }
487
+
488
+    public function getPrincipalPrefix() {
489
+        return $this->principalPrefix;
490
+    }
491
+
492
+    /**
493
+     * @param string $circleUniqueId
494
+     * @return array|null
495
+     */
496
+    protected function circleToPrincipal($circleUniqueId) {
497
+        if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
498
+            return null;
499
+        }
500
+
501
+        try {
502
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($circleUniqueId, true);
503
+        } catch (QueryException $ex) {
504
+            return null;
505
+        } catch (CircleDoesNotExistException $ex) {
506
+            return null;
507
+        }
508
+
509
+        if (!$circle) {
510
+            return null;
511
+        }
512
+
513
+        $principal = [
514
+            'uri' => 'principals/circles/' . $circleUniqueId,
515
+            '{DAV:}displayname' => $circle->getName(),
516
+        ];
517
+
518
+        return $principal;
519
+    }
520
+
521
+    /**
522
+     * Returns the list of circles a principal is a member of
523
+     *
524
+     * @param string $principal
525
+     * @return array
526
+     * @throws Exception
527
+     * @throws \OCP\AppFramework\QueryException
528
+     * @suppress PhanUndeclaredClassMethod
529
+     */
530
+    public function getCircleMembership($principal):array {
531
+        if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
532
+            return [];
533
+        }
534
+
535
+        list($prefix, $name) = \Sabre\Uri\split($principal);
536
+        if ($this->hasCircles && $prefix === $this->principalPrefix) {
537
+            $user = $this->userManager->get($name);
538
+            if (!$user) {
539
+                throw new Exception('Principal not found');
540
+            }
541
+
542
+            $circles = \OCA\Circles\Api\v1\Circles::joinedCircles($name, true);
543
+
544
+            $circles = array_map(function ($circle) {
545
+                /** @var \OCA\Circles\Model\Circle $circle */
546
+                return 'principals/circles/' . urlencode($circle->getUniqueId());
547
+            }, $circles);
548
+
549
+            return $circles;
550
+        }
551
+
552
+        return [];
553
+    }
554 554
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -165,7 +165,7 @@  discard block
 block discarded – undo
165 165
 
166 166
 				if ($user !== null) {
167 167
 					return [
168
-						'uri' => 'principals/users/' . $user->getUID() . '/' . $name,
168
+						'uri' => 'principals/users/'.$user->getUID().'/'.$name,
169 169
 					];
170 170
 				}
171 171
 				return null;
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
 				?: $this->groupManager->get($name);
197 197
 			if ($group instanceof IGroup) {
198 198
 				return [
199
-					'uri' => 'principals/groups/' . $name,
199
+					'uri' => 'principals/groups/'.$name,
200 200
 					'{DAV:}displayname' => $group->getDisplayName(),
201 201
 				];
202 202
 			}
@@ -229,7 +229,7 @@  discard block
 block discarded – undo
229 229
 		if ($this->hasGroups || $needGroups) {
230 230
 			$userGroups = $this->groupManager->getUserGroups($user);
231 231
 			foreach ($userGroups as $userGroup) {
232
-				$groups[] = 'principals/groups/' . urlencode($userGroup->getGID());
232
+				$groups[] = 'principals/groups/'.urlencode($userGroup->getGID());
233 233
 			}
234 234
 		}
235 235
 
@@ -299,13 +299,13 @@  discard block
 block discarded – undo
299 299
 					$users = $this->userManager->getByEmail($value);
300 300
 
301 301
 					if (!$allowEnumeration) {
302
-						$users = \array_filter($users, static function (IUser $user) use ($value) {
302
+						$users = \array_filter($users, static function(IUser $user) use ($value) {
303 303
 							return $user->getEMailAddress() === $value;
304 304
 						});
305 305
 					}
306 306
 
307 307
 					if ($limitEnumeration) {
308
-						$users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
308
+						$users = \array_filter($users, function(IUser $user) use ($currentUserGroups, $value) {
309 309
 							return !empty(array_intersect(
310 310
 									$this->groupManager->getUserGroupIds($user),
311 311
 									$currentUserGroups
@@ -313,7 +313,7 @@  discard block
 block discarded – undo
313 313
 						});
314 314
 					}
315 315
 
316
-					$results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
316
+					$results[] = array_reduce($users, function(array $carry, IUser $user) use ($restrictGroups) {
317 317
 						// is sharing restricted to groups only?
318 318
 						if ($restrictGroups !== false) {
319 319
 							$userGroups = $this->groupManager->getUserGroupIds($user);
@@ -322,7 +322,7 @@  discard block
 block discarded – undo
322 322
 							}
323 323
 						}
324 324
 
325
-						$carry[] = $this->principalPrefix . '/' . $user->getUID();
325
+						$carry[] = $this->principalPrefix.'/'.$user->getUID();
326 326
 						return $carry;
327 327
 					}, []);
328 328
 					break;
@@ -331,13 +331,13 @@  discard block
 block discarded – undo
331 331
 					$users = $this->userManager->searchDisplayName($value, $searchLimit);
332 332
 
333 333
 					if (!$allowEnumeration) {
334
-						$users = \array_filter($users, static function (IUser $user) use ($value) {
334
+						$users = \array_filter($users, static function(IUser $user) use ($value) {
335 335
 							return $user->getDisplayName() === $value;
336 336
 						});
337 337
 					}
338 338
 
339 339
 					if ($limitEnumeration) {
340
-						$users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
340
+						$users = \array_filter($users, function(IUser $user) use ($currentUserGroups, $value) {
341 341
 							return !empty(array_intersect(
342 342
 									$this->groupManager->getUserGroupIds($user),
343 343
 									$currentUserGroups
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
 						});
346 346
 					}
347 347
 
348
-					$results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
348
+					$results[] = array_reduce($users, function(array $carry, IUser $user) use ($restrictGroups) {
349 349
 						// is sharing restricted to groups only?
350 350
 						if ($restrictGroups !== false) {
351 351
 							$userGroups = $this->groupManager->getUserGroupIds($user);
@@ -354,7 +354,7 @@  discard block
 block discarded – undo
354 354
 							}
355 355
 						}
356 356
 
357
-						$carry[] = $this->principalPrefix . '/' . $user->getUID();
357
+						$carry[] = $this->principalPrefix.'/'.$user->getUID();
358 358
 						return $carry;
359 359
 					}, []);
360 360
 					break;
@@ -450,7 +450,7 @@  discard block
 block discarded – undo
450 450
 					}
451 451
 				}
452 452
 
453
-				return $this->principalPrefix . '/' . $user->getUID();
453
+				return $this->principalPrefix.'/'.$user->getUID();
454 454
 			}
455 455
 		}
456 456
 		if (substr($uri, 0, 10) === 'principal:') {
@@ -472,7 +472,7 @@  discard block
 block discarded – undo
472 472
 		$userId = $user->getUID();
473 473
 		$displayName = $user->getDisplayName();
474 474
 		$principal = [
475
-			'uri' => $this->principalPrefix . '/' . $userId,
475
+			'uri' => $this->principalPrefix.'/'.$userId,
476 476
 			'{DAV:}displayname' => is_null($displayName) ? $userId : $displayName,
477 477
 			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
478 478
 		];
@@ -511,7 +511,7 @@  discard block
 block discarded – undo
511 511
 		}
512 512
 
513 513
 		$principal = [
514
-			'uri' => 'principals/circles/' . $circleUniqueId,
514
+			'uri' => 'principals/circles/'.$circleUniqueId,
515 515
 			'{DAV:}displayname' => $circle->getName(),
516 516
 		];
517 517
 
@@ -541,9 +541,9 @@  discard block
 block discarded – undo
541 541
 
542 542
 			$circles = \OCA\Circles\Api\v1\Circles::joinedCircles($name, true);
543 543
 
544
-			$circles = array_map(function ($circle) {
544
+			$circles = array_map(function($circle) {
545 545
 				/** @var \OCA\Circles\Model\Circle $circle */
546
-				return 'principals/circles/' . urlencode($circle->getUniqueId());
546
+				return 'principals/circles/'.urlencode($circle->getUniqueId());
547 547
 			}, $circles);
548 548
 
549 549
 			return $circles;
Please login to merge, or discard this patch.