Completed
Push — master ( ba9b17...94004c )
by Lukas
05:19 queued 04:59
created

ShareesAPIController::getLookup()   B

Complexity

Conditions 4
Paths 7

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 21
c 0
b 0
f 0
nc 7
nop 1
dl 0
loc 33
rs 8.5806
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Björn Schießle <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Roeland Jago Douma <[email protected]>
8
 * @author Thomas Müller <[email protected]>
9
 *
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
namespace OCA\Files_Sharing\Controller;
26
27
use OCP\AppFramework\Http;
28
use OCP\AppFramework\OCS\OCSBadRequestException;
29
use OCP\AppFramework\OCSController;
30
use OCP\Contacts\IManager;
31
use OCP\Http\Client\IClientService;
32
use OCP\IGroup;
33
use OCP\IGroupManager;
34
use OCP\ILogger;
35
use OCP\IRequest;
36
use OCP\IUser;
37
use OCP\IUserManager;
38
use OCP\IConfig;
39
use OCP\IUserSession;
40
use OCP\IURLGenerator;
41
use OCP\Share;
42
43
class ShareesAPIController extends OCSController {
44
45
	/** @var IGroupManager */
46
	protected $groupManager;
47
48
	/** @var IUserManager */
49
	protected $userManager;
50
51
	/** @var IManager */
52
	protected $contactsManager;
53
54
	/** @var IConfig */
55
	protected $config;
56
57
	/** @var IUserSession */
58
	protected $userSession;
59
60
	/** @var IURLGenerator */
61
	protected $urlGenerator;
62
63
	/** @var ILogger */
64
	protected $logger;
65
66
	/** @var \OCP\Share\IManager */
67
	protected $shareManager;
68
69
	/** @var IClientService */
70
	protected $clientService;
71
72
	/** @var bool */
73
	protected $shareWithGroupOnly = false;
74
75
	/** @var bool */
76
	protected $shareeEnumeration = true;
77
78
	/** @var int */
79
	protected $offset = 0;
80
81
	/** @var int */
82
	protected $limit = 10;
83
84
	/** @var array */
85
	protected $result = [
86
		'exact' => [
87
			'users' => [],
88
			'groups' => [],
89
			'remotes' => [],
90
			'emails' => [],
91
		],
92
		'users' => [],
93
		'groups' => [],
94
		'remotes' => [],
95
		'emails' => [],
96
		'lookup' => [],
97
	];
98
99
	protected $reachedEndFor = [];
100
101
	/**
102
	 * @param string $appName
103
	 * @param IRequest $request
104
	 * @param IGroupManager $groupManager
105
	 * @param IUserManager $userManager
106
	 * @param IManager $contactsManager
107
	 * @param IConfig $config
108
	 * @param IUserSession $userSession
109
	 * @param IURLGenerator $urlGenerator
110
	 * @param ILogger $logger
111
	 * @param \OCP\Share\IManager $shareManager
112
	 * @param IClientService $clientService
113
	 */
114
	public function __construct($appName,
115
								IRequest $request,
116
								IGroupManager $groupManager,
117
								IUserManager $userManager,
118
								IManager $contactsManager,
119
								IConfig $config,
120
								IUserSession $userSession,
121
								IURLGenerator $urlGenerator,
122
								ILogger $logger,
123
								\OCP\Share\IManager $shareManager,
124
								IClientService $clientService) {
125
		parent::__construct($appName, $request);
126
127
		$this->groupManager = $groupManager;
128
		$this->userManager = $userManager;
129
		$this->contactsManager = $contactsManager;
130
		$this->config = $config;
131
		$this->userSession = $userSession;
132
		$this->urlGenerator = $urlGenerator;
133
		$this->logger = $logger;
134
		$this->shareManager = $shareManager;
135
		$this->clientService = $clientService;
136
	}
137
138
	/**
139
	 * @param string $search
140
	 */
141
	protected function getUsers($search) {
142
		$this->result['users'] = $this->result['exact']['users'] = $users = [];
143
144
		$userGroups = [];
145
		if ($this->shareWithGroupOnly) {
146
			// Search in all the groups this user is part of
147
			$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
0 ignored issues
show
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, getUserGroupIds() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
148
			foreach ($userGroups as $userGroup) {
149
				$usersTmp = $this->groupManager->displayNamesInGroup($userGroup, $search, $this->limit, $this->offset);
150
				foreach ($usersTmp as $uid => $userDisplayName) {
151
					$users[$uid] = $userDisplayName;
152
				}
153
			}
154
		} else {
155
			// Search in all users
156
			$usersTmp = $this->userManager->searchDisplayName($search, $this->limit, $this->offset);
157
158
			foreach ($usersTmp as $user) {
159
				$users[$user->getUID()] = $user->getDisplayName();
160
			}
161
		}
162
163 View Code Duplication
		if (!$this->shareeEnumeration || sizeof($users) < $this->limit) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164
			$this->reachedEndFor[] = 'users';
165
		}
166
167
		$foundUserById = false;
168
		foreach ($users as $uid => $userDisplayName) {
169
			if (strtolower($uid) === strtolower($search) || strtolower($userDisplayName) === strtolower($search)) {
170
				if (strtolower($uid) === strtolower($search)) {
171
					$foundUserById = true;
172
				}
173
				$this->result['exact']['users'][] = [
174
					'label' => $userDisplayName,
175
					'value' => [
176
						'shareType' => Share::SHARE_TYPE_USER,
177
						'shareWith' => $uid,
178
					],
179
				];
180 View Code Duplication
			} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
				$this->result['users'][] = [
182
					'label' => $userDisplayName,
183
					'value' => [
184
						'shareType' => Share::SHARE_TYPE_USER,
185
						'shareWith' => $uid,
186
					],
187
				];
188
			}
189
		}
190
191
		if ($this->offset === 0 && !$foundUserById) {
192
			// On page one we try if the search result has a direct hit on the
193
			// user id and if so, we add that to the exact match list
194
			$user = $this->userManager->get($search);
195
			if ($user instanceof IUser) {
196
				$addUser = true;
197
198
				if ($this->shareWithGroupOnly) {
199
					// Only add, if we have a common group
200
					$commonGroups = array_intersect($userGroups, $this->groupManager->getUserGroupIds($user));
201
					$addUser = !empty($commonGroups);
202
				}
203
204
				if ($addUser) {
205
					array_push($this->result['exact']['users'], [
206
						'label' => $user->getDisplayName(),
207
						'value' => [
208
							'shareType' => Share::SHARE_TYPE_USER,
209
							'shareWith' => $user->getUID(),
210
						],
211
					]);
212
				}
213
			}
214
		}
215
216
		if (!$this->shareeEnumeration) {
217
			$this->result['users'] = [];
218
		}
219
	}
220
221
	/**
222
	 * @param string $search
223
	 */
224
	protected function getGroups($search) {
225
		$this->result['groups'] = $this->result['exact']['groups'] = [];
226
227
		$groups = $this->groupManager->search($search, $this->limit, $this->offset);
228
		$groups = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
229
230 View Code Duplication
		if (!$this->shareeEnumeration || sizeof($groups) < $this->limit) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
231
			$this->reachedEndFor[] = 'groups';
232
		}
233
234
		$userGroups =  [];
235
		if (!empty($groups) && $this->shareWithGroupOnly) {
236
			// Intersect all the groups that match with the groups this user is a member of
237
			$userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
238
			$userGroups = array_map(function (IGroup $group) { return $group->getGID(); }, $userGroups);
239
			$groups = array_intersect($groups, $userGroups);
240
		}
241
242
		foreach ($groups as $gid) {
243
			if (strtolower($gid) === strtolower($search)) {
244
				$this->result['exact']['groups'][] = [
245
					'label' => $gid,
246
					'value' => [
247
						'shareType' => Share::SHARE_TYPE_GROUP,
248
						'shareWith' => $gid,
249
					],
250
				];
251 View Code Duplication
			} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
252
				$this->result['groups'][] = [
253
					'label' => $gid,
254
					'value' => [
255
						'shareType' => Share::SHARE_TYPE_GROUP,
256
						'shareWith' => $gid,
257
					],
258
				];
259
			}
260
		}
261
262
		if ($this->offset === 0 && empty($this->result['exact']['groups'])) {
263
			// On page one we try if the search result has a direct hit on the
264
			// user id and if so, we add that to the exact match list
265
			$group = $this->groupManager->get($search);
266
			if ($group instanceof IGroup && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups))) {
267
				array_push($this->result['exact']['groups'], [
268
					'label' => $group->getGID(),
269
					'value' => [
270
						'shareType' => Share::SHARE_TYPE_GROUP,
271
						'shareWith' => $group->getGID(),
272
					],
273
				]);
274
			}
275
		}
276
277
		if (!$this->shareeEnumeration) {
278
			$this->result['groups'] = [];
279
		}
280
	}
281
282
	/**
283
	 * @param string $search
284
	 * @return array
285
	 */
286
	protected function getRemote($search) {
287
		$result = ['results' => [], 'exact' => []];
288
289
		// Search in contacts
290
		//@todo Pagination missing
291
		$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
292
		$result['exactIdMatch'] = false;
293
		foreach ($addressBookContacts as $contact) {
294
			if (isset($contact['isLocalSystemBook'])) {
295
				continue;
296
			}
297
			if (isset($contact['CLOUD'])) {
298
				$cloudIds = $contact['CLOUD'];
299
				if (!is_array($cloudIds)) {
300
					$cloudIds = [$cloudIds];
301
				}
302
				foreach ($cloudIds as $cloudId) {
303
					list(, $serverUrl) = $this->splitUserRemote($cloudId);
304
					if (strtolower($contact['FN']) === strtolower($search) || strtolower($cloudId) === strtolower($search)) {
305
						if (strtolower($cloudId) === strtolower($search)) {
306
							$result['exactIdMatch'] = true;
307
						}
308
						$result['exact'][] = [
309
							'label' => $contact['FN'] . " ($cloudId)",
310
							'value' => [
311
								'shareType' => Share::SHARE_TYPE_REMOTE,
312
								'shareWith' => $cloudId,
313
								'server' => $serverUrl,
314
							],
315
						];
316 View Code Duplication
					} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
317
						$result['results'][] = [
318
							'label' => $contact['FN'] . " ($cloudId)",
319
							'value' => [
320
								'shareType' => Share::SHARE_TYPE_REMOTE,
321
								'shareWith' => $cloudId,
322
								'server' => $serverUrl,
323
							],
324
						];
325
					}
326
				}
327
			}
328
		}
329
330
		if (!$this->shareeEnumeration) {
331
			$result['results'] = [];
332
		}
333
334
		if (!$result['exactIdMatch'] && substr_count($search, '@') >= 1 && $this->offset === 0) {
335
			$result['exact'][] = [
336
				'label' => $search,
337
				'value' => [
338
					'shareType' => Share::SHARE_TYPE_REMOTE,
339
					'shareWith' => $search,
340
				],
341
			];
342
		}
343
344
		$this->reachedEndFor[] = 'remotes';
345
346
		return $result;
347
	}
348
349
	/**
350
	 * split user and remote from federated cloud id
351
	 *
352
	 * @param string $address federated share address
353
	 * @return array [user, remoteURL]
354
	 * @throws \Exception
355
	 */
356
	public function splitUserRemote($address) {
357
		if (strpos($address, '@') === false) {
358
			throw new \Exception('Invalid Federated Cloud ID');
359
		}
360
361
		// Find the first character that is not allowed in user names
362
		$id = str_replace('\\', '/', $address);
363
		$posSlash = strpos($id, '/');
364
		$posColon = strpos($id, ':');
365
366 View Code Duplication
		if ($posSlash === false && $posColon === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
367
			$invalidPos = strlen($id);
368
		} else if ($posSlash === false) {
369
			$invalidPos = $posColon;
370
		} else if ($posColon === false) {
371
			$invalidPos = $posSlash;
372
		} else {
373
			$invalidPos = min($posSlash, $posColon);
374
		}
375
376
		// Find the last @ before $invalidPos
377
		$pos = $lastAtPos = 0;
378 View Code Duplication
		while ($lastAtPos !== false && $lastAtPos <= $invalidPos) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
379
			$pos = $lastAtPos;
380
			$lastAtPos = strpos($id, '@', $pos + 1);
381
		}
382
383 View Code Duplication
		if ($pos !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
384
			$user = substr($id, 0, $pos);
385
			$remote = substr($id, $pos + 1);
386
			$remote = $this->fixRemoteURL($remote);
387
			if (!empty($user) && !empty($remote)) {
388
				return array($user, $remote);
389
			}
390
		}
391
392
		throw new \Exception('Invalid Federated Cloud ID');
393
	}
394
395
	/**
396
	 * Strips away a potential file names and trailing slashes:
397
	 * - http://localhost
398
	 * - http://localhost/
399
	 * - http://localhost/index.php
400
	 * - http://localhost/index.php/s/{shareToken}
401
	 *
402
	 * all return: http://localhost
403
	 *
404
	 * @param string $remote
405
	 * @return string
406
	 */
407 View Code Duplication
	protected function fixRemoteURL($remote) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
408
		$remote = str_replace('\\', '/', $remote);
409
		if ($fileNamePosition = strpos($remote, '/index.php')) {
410
			$remote = substr($remote, 0, $fileNamePosition);
411
		}
412
		$remote = rtrim($remote, '/');
413
414
		return $remote;
415
	}
416
417
	/**
418
	 * @NoAdminRequired
419
	 *
420
	 * @param string $search
421
	 * @param string $itemType
422
	 * @param int $page
423
	 * @param int $perPage
424
	 * @param int|int[] $shareType
425
	 * @param bool $lookup
426
	 * @return Http\DataResponse
427
	 * @throws OCSBadRequestException
428
	 */
429
	public function search($search = '', $itemType = null, $page = 1, $perPage = 200, $shareType = null, $lookup = true) {
430
		if ($perPage <= 0) {
431
			throw new OCSBadRequestException('Invalid perPage argument');
432
		}
433
		if ($page <= 0) {
434
			throw new OCSBadRequestException('Invalid page');
435
		}
436
437
		$shareTypes = [
438
			Share::SHARE_TYPE_USER,
439
		];
440
441
		if ($itemType === 'file' || $itemType === 'folder') {
442
			if ($this->shareManager->allowGroupSharing()) {
443
				$shareTypes[] = Share::SHARE_TYPE_GROUP;
444
			}
445
446
			if ($this->isRemoteSharingAllowed($itemType)) {
447
				$shareTypes[] = Share::SHARE_TYPE_REMOTE;
448
			}
449
450
			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
451
				$shareTypes[] = Share::SHARE_TYPE_EMAIL;
452
			}
453
		} else {
454
			$shareTypes[] = Share::SHARE_TYPE_GROUP;
455
			$shareTypes[] = Share::SHARE_TYPE_EMAIL;
456
		}
457
458
		if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
459
			$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
460
			sort($shareTypes);
461
		} else if (is_numeric($shareType)) {
462
			$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
463
			sort($shareTypes);
464
		}
465
466
		$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
467
		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
468
		$this->limit = (int) $perPage;
469
		$this->offset = $perPage * ($page - 1);
470
471
		return $this->searchSharees($search, $itemType, $shareTypes, $page, $perPage, $lookup);
472
	}
473
474
	/**
475
	 * Method to get out the static call for better testing
476
	 *
477
	 * @param string $itemType
478
	 * @return bool
479
	 */
480
	protected function isRemoteSharingAllowed($itemType) {
481
		try {
482
			$backend = Share::getBackend($itemType);
483
			return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
484
		} catch (\Exception $e) {
485
			return false;
486
		}
487
	}
488
489
	/**
490
	 * Testable search function that does not need globals
491
	 *
492
	 * @param string $search
493
	 * @param string $itemType
494
	 * @param array $shareTypes
495
	 * @param int $page
496
	 * @param int $perPage
497
	 * @param bool $lookup
498
	 * @return Http\DataResponse
499
	 * @throws OCSBadRequestException
500
	 */
501
	protected function searchSharees($search, $itemType, array $shareTypes, $page, $perPage, $lookup) {
502
		// Verify arguments
503
		if ($itemType === null) {
504
			throw new OCSBadRequestException('Missing itemType');
505
		}
506
507
		// Get users
508
		if (in_array(Share::SHARE_TYPE_USER, $shareTypes)) {
509
			$this->getUsers($search);
510
		}
511
512
		// Get groups
513
		if (in_array(Share::SHARE_TYPE_GROUP, $shareTypes)) {
514
			$this->getGroups($search);
515
		}
516
517
		// Get remote
518
		$remoteResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
519
		if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes)) {
520
			$remoteResults = $this->getRemote($search);
521
		}
522
523
		// Get emails
524
		$mailResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
525
		if (in_array(Share::SHARE_TYPE_EMAIL, $shareTypes)) {
526
			$mailResults = $this->getEmail($search);
527
		}
528
529
		// Get from lookup server
530
		if ($lookup) {
531
			$this->getLookup($search);
532
		}
533
534
		// if we have a exact match, either for the federated cloud id or for the
535
		// email address we only return the exact match. It is highly unlikely
536
		// that the exact same email address and federated cloud id exists
537
		if ($mailResults['exactIdMatch'] && !$remoteResults['exactIdMatch']) {
538
			$this->result['emails'] = $mailResults['results'];
539
			$this->result['exact']['emails'] = $mailResults['exact'];
540
		} else if (!$mailResults['exactIdMatch'] && $remoteResults['exactIdMatch']) {
541
			$this->result['remotes'] = $remoteResults['results'];
542
			$this->result['exact']['remotes'] = $remoteResults['exact'];
543
		} else {
544
			$this->result['remotes'] = $remoteResults['results'];
545
			$this->result['exact']['remotes'] = $remoteResults['exact'];
546
			$this->result['emails'] = $mailResults['results'];
547
			$this->result['exact']['emails'] = $mailResults['exact'];
548
		}
549
550
		$response = new Http\DataResponse($this->result);
551
552
		if (sizeof($this->reachedEndFor) < 3) {
553
			$response->addHeader('Link', $this->getPaginationLink($page, [
554
				'search' => $search,
555
				'itemType' => $itemType,
556
				'shareType' => $shareTypes,
557
				'perPage' => $perPage,
558
			]));
559
		}
560
561
		return $response;
562
	}
563
564
	/**
565
	 * @param string $search
566
	 * @return array
567
	 */
568
	protected function getEmail($search) {
569
		$result = ['results' => [], 'exact' => []];
570
571
		// Search in contacts
572
		//@todo Pagination missing
573
		$addressBookContacts = $this->contactsManager->search($search, ['EMAIL', 'FN']);
574
		$result['exactIdMatch'] = false;
575
		foreach ($addressBookContacts as $contact) {
576
			if (isset($contact['isLocalSystemBook'])) {
577
				continue;
578
			}
579
			if (isset($contact['EMAIL'])) {
580
				$emailAddresses = $contact['EMAIL'];
581
				if (!is_array($emailAddresses)) {
582
					$emailAddresses = [$emailAddresses];
583
				}
584
				foreach ($emailAddresses as $emailAddress) {
585
					if (strtolower($contact['FN']) === strtolower($search) || strtolower($emailAddress) === strtolower($search)) {
586
						if (strtolower($emailAddress) === strtolower($search)) {
587
							$result['exactIdMatch'] = true;
588
						}
589
						$result['exact'][] = [
590
							'label' => $contact['FN'] . " ($emailAddress)",
591
							'value' => [
592
								'shareType' => Share::SHARE_TYPE_EMAIL,
593
								'shareWith' => $emailAddress,
594
							],
595
						];
596 View Code Duplication
					} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
597
						$result['results'][] = [
598
							'label' => $contact['FN'] . " ($emailAddress)",
599
							'value' => [
600
								'shareType' => Share::SHARE_TYPE_EMAIL,
601
								'shareWith' => $emailAddress,
602
							],
603
						];
604
					}
605
				}
606
			}
607
		}
608
609
		if (!$this->shareeEnumeration) {
610
			$result['results'] = [];
611
		}
612
613
		if (!$result['exactIdMatch'] && filter_var($search, FILTER_VALIDATE_EMAIL)) {
614
			$result['exact'][] = [
615
				'label' => $search,
616
				'value' => [
617
					'shareType' => Share::SHARE_TYPE_EMAIL,
618
					'shareWith' => $search,
619
				],
620
			];
621
		}
622
623
		$this->reachedEndFor[] = 'emails';
624
625
		return $result;
626
	}
627
628
	protected function getLookup($search) {
629
		$isEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
630
		$result = [];
631
632
		if($isEnabled === 'yes') {
633
			try {
634
				$client = $this->clientService->newClient();
635
				$response = $client->get(
636
					'https://lookup.nextcloud.com/users?search=' . urlencode($search),
637
					[
638
						'timeout' => 10,
639
						'connect_timeout' => 3,
640
					]
641
				);
642
643
				$body = json_decode($response->getBody(), true);
644
645
				$result = [];
646
				foreach ($body as $lookup) {
647
					$result[] = [
648
						'label' => $lookup['federationId'],
649
						'value' => [
650
							'shareType' => Share::SHARE_TYPE_REMOTE,
651
							'shareWith' => $lookup['federationId'],
652
						],
653
						'extra' => $lookup,
654
					];
655
				}
656
			} catch (\Exception $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
657
		}
658
659
		$this->result['lookup'] = $result;
660
	}
661
662
	/**
663
	 * Generates a bunch of pagination links for the current page
664
	 *
665
	 * @param int $page Current page
666
	 * @param array $params Parameters for the URL
667
	 * @return string
668
	 */
669
	protected function getPaginationLink($page, array $params) {
670
		if ($this->isV2()) {
671
			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
672
		} else {
673
			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
674
		}
675
		$params['page'] = $page + 1;
676
		$link = '<' . $url . http_build_query($params) . '>; rel="next"';
677
678
		return $link;
679
	}
680
681
	/**
682
	 * @return bool
683
	 */
684
	protected function isV2() {
685
		return $this->request->getScriptName() === '/ocs/v2.php';
686
	}
687
}
688