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