Passed
Push — master ( 514185...41ff00 )
by Roeland
28:32 queued 13:41
created

RemotePlugin::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 5
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2017 Arthur Schiwon <[email protected]>
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
namespace OC\Collaboration\Collaborators;
25
26
27
use OCP\Collaboration\Collaborators\ISearchPlugin;
28
use OCP\Collaboration\Collaborators\ISearchResult;
29
use OCP\Collaboration\Collaborators\SearchResultType;
30
use OCP\Contacts\IManager;
31
use OCP\Federation\ICloudIdManager;
32
use OCP\IConfig;
33
use OCP\IUserManager;
34
use OCP\IUserSession;
35
use OCP\Share;
36
37
class RemotePlugin implements ISearchPlugin {
38
	protected $shareeEnumeration;
39
40
	/** @var IManager */
41
	private $contactsManager;
42
	/** @var ICloudIdManager */
43
	private $cloudIdManager;
44
	/** @var IConfig */
45
	private $config;
46
	/** @var IUserManager */
47
	private $userManager;
48
	/** @var string */
49
	private $userId = '';
50
51
	public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) {
52
		$this->contactsManager = $contactsManager;
53
		$this->cloudIdManager = $cloudIdManager;
54
		$this->config = $config;
55
		$this->userManager = $userManager;
56
		$user = $userSession->getUser();
57
		if ($user !== null) {
58
			$this->userId = $user->getUID();
59
		}
60
		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
61
	}
62
63
	public function search($search, $limit, $offset, ISearchResult $searchResult) {
64
		$result = ['wide' => [], 'exact' => []];
65
		$resultType = new SearchResultType('remotes');
66
67
		// Search in contacts
68
		//@todo Pagination missing
69
		$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
70
		foreach ($addressBookContacts as $contact) {
71
			if (isset($contact['isLocalSystemBook'])) {
72
				continue;
73
			}
74
			if (isset($contact['CLOUD'])) {
75
				$cloudIds = $contact['CLOUD'];
76
				if (is_string($cloudIds)) {
77
					$cloudIds = [$cloudIds];
78
				}
79
				$lowerSearch = strtolower($search);
80
				foreach ($cloudIds as $cloudId) {
81
					$cloudIdType = '';
82
					if (\is_array($cloudId)) {
83
						$cloudIdData = $cloudId;
84
						$cloudId = $cloudIdData['value'];
85
						$cloudIdType = $cloudIdData['type'];
86
					}
87
					try {
88
						list($remoteUser, $serverUrl) = $this->splitUserRemote($cloudId);
89
					} catch (\InvalidArgumentException $e) {
90
						continue;
91
					}
92
93
					$localUser = $this->userManager->get($remoteUser);
94
					/**
95
					 * Add local share if remote cloud id matches a local user ones
96
					 */
97
					if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId() ) {
98
						$result['wide'][] = [
99
							'label' => $contact['FN'],
100
							'uuid' => $contact['UID'],
101
							'value' => [
102
								'shareType' => Share::SHARE_TYPE_USER,
103
								'shareWith' => $remoteUser
104
							]
105
						];
106
					}
107
108
					if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
109
						if (strtolower($cloudId) === $lowerSearch) {
110
							$searchResult->markExactIdMatch($resultType);
111
						}
112
						$result['exact'][] = [
113
							'label' => $contact['FN'] . " ($cloudId)",
114
							'uuid' => $contact['UID'],
115
							'name' => $contact['FN'],
116
							'type' => $cloudIdType,
117
							'value' => [
118
								'shareType' => Share::SHARE_TYPE_REMOTE,
119
								'shareWith' => $cloudId,
120
								'server' => $serverUrl,
121
							],
122
						];
123
					} else {
124
						$result['wide'][] = [
125
							'label' => $contact['FN'] . " ($cloudId)",
126
							'uuid' => $contact['UID'],
127
							'name' => $contact['FN'],
128
							'type' => $cloudIdType,
129
							'value' => [
130
								'shareType' => Share::SHARE_TYPE_REMOTE,
131
								'shareWith' => $cloudId,
132
								'server' => $serverUrl,
133
							],
134
						];
135
					}
136
				}
137
			}
138
		}
139
140
		if (!$this->shareeEnumeration) {
141
			$result['wide'] = [];
142
		} else {
143
			$result['wide'] = array_slice($result['wide'], $offset, $limit);
144
		}
145
146
		/**
147
		 * Add generic share with remote item for valid cloud ids that are not users of the local instance
148
		 */
149
		if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
150
			try {
151
				list($remoteUser, $serverUrl) = $this->splitUserRemote($search);
152
				$localUser = $this->userManager->get($remoteUser);
153
				if ($localUser === null || $search !== $localUser->getCloudId()) {
154
					$result['exact'][] = [
155
						'label' => $search,
156
						'value' => [
157
							'shareType' => Share::SHARE_TYPE_REMOTE,
158
							'shareWith' => $search,
159
						],
160
					];
161
				}
162
			} catch (\InvalidArgumentException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
163
			}
164
		}
165
166
		$searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
167
168
		return true;
169
	}
170
171
	/**
172
	 * split user and remote from federated cloud id
173
	 *
174
	 * @param string $address federated share address
175
	 * @return array [user, remoteURL]
176
	 * @throws \InvalidArgumentException
177
	 */
178
	public function splitUserRemote($address) {
179
		try {
180
			$cloudId = $this->cloudIdManager->resolveCloudId($address);
181
			return [$cloudId->getUser(), $cloudId->getRemote()];
182
		} catch (\InvalidArgumentException $e) {
183
			throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
184
		}
185
	}
186
}
187