Completed
Push — master ( a89f9a...3036b1 )
by Morris
29:19 queued 12:13
created
apps/federatedfilesharing/lib/FederatedShareProvider.php 2 patches
Indentation   +1030 added lines, -1030 removed lines patch added patch discarded remove patch
@@ -55,1044 +55,1044 @@
 block discarded – undo
55 55
  */
56 56
 class FederatedShareProvider implements IShareProvider {
57 57
 
58
-	const SHARE_TYPE_REMOTE = 6;
59
-
60
-	/** @var IDBConnection */
61
-	private $dbConnection;
62
-
63
-	/** @var AddressHandler */
64
-	private $addressHandler;
65
-
66
-	/** @var Notifications */
67
-	private $notifications;
68
-
69
-	/** @var TokenHandler */
70
-	private $tokenHandler;
71
-
72
-	/** @var IL10N */
73
-	private $l;
74
-
75
-	/** @var ILogger */
76
-	private $logger;
77
-
78
-	/** @var IRootFolder */
79
-	private $rootFolder;
80
-
81
-	/** @var IConfig */
82
-	private $config;
83
-
84
-	/** @var string */
85
-	private $externalShareTable = 'share_external';
86
-
87
-	/** @var IUserManager */
88
-	private $userManager;
89
-
90
-	/** @var ICloudIdManager */
91
-	private $cloudIdManager;
92
-
93
-	/** @var \OCP\GlobalScale\IConfig */
94
-	private $gsConfig;
95
-
96
-	/** @var ICloudFederationProviderManager */
97
-	private $cloudFederationProviderManager;
98
-
99
-	/** @var array list of supported share types */
100
-	private $supportedShareType = [\OCP\Share::SHARE_TYPE_REMOTE_GROUP, \OCP\Share::SHARE_TYPE_REMOTE];
101
-
102
-	/**
103
-	 * DefaultShareProvider constructor.
104
-	 *
105
-	 * @param IDBConnection $connection
106
-	 * @param AddressHandler $addressHandler
107
-	 * @param Notifications $notifications
108
-	 * @param TokenHandler $tokenHandler
109
-	 * @param IL10N $l10n
110
-	 * @param ILogger $logger
111
-	 * @param IRootFolder $rootFolder
112
-	 * @param IConfig $config
113
-	 * @param IUserManager $userManager
114
-	 * @param ICloudIdManager $cloudIdManager
115
-	 * @param \OCP\GlobalScale\IConfig $globalScaleConfig
116
-	 * @param ICloudFederationProviderManager $cloudFederationProviderManager
117
-	 */
118
-	public function __construct(
119
-			IDBConnection $connection,
120
-			AddressHandler $addressHandler,
121
-			Notifications $notifications,
122
-			TokenHandler $tokenHandler,
123
-			IL10N $l10n,
124
-			ILogger $logger,
125
-			IRootFolder $rootFolder,
126
-			IConfig $config,
127
-			IUserManager $userManager,
128
-			ICloudIdManager $cloudIdManager,
129
-			\OCP\GlobalScale\IConfig $globalScaleConfig,
130
-			ICloudFederationProviderManager $cloudFederationProviderManager
131
-	) {
132
-		$this->dbConnection = $connection;
133
-		$this->addressHandler = $addressHandler;
134
-		$this->notifications = $notifications;
135
-		$this->tokenHandler = $tokenHandler;
136
-		$this->l = $l10n;
137
-		$this->logger = $logger;
138
-		$this->rootFolder = $rootFolder;
139
-		$this->config = $config;
140
-		$this->userManager = $userManager;
141
-		$this->cloudIdManager = $cloudIdManager;
142
-		$this->gsConfig = $globalScaleConfig;
143
-		$this->cloudFederationProviderManager = $cloudFederationProviderManager;
144
-	}
145
-
146
-	/**
147
-	 * Return the identifier of this provider.
148
-	 *
149
-	 * @return string Containing only [a-zA-Z0-9]
150
-	 */
151
-	public function identifier() {
152
-		return 'ocFederatedSharing';
153
-	}
154
-
155
-	/**
156
-	 * Share a path
157
-	 *
158
-	 * @param IShare $share
159
-	 * @return IShare The share object
160
-	 * @throws ShareNotFound
161
-	 * @throws \Exception
162
-	 */
163
-	public function create(IShare $share) {
164
-
165
-		$shareWith = $share->getSharedWith();
166
-		$itemSource = $share->getNodeId();
167
-		$itemType = $share->getNodeType();
168
-		$permissions = $share->getPermissions();
169
-		$sharedBy = $share->getSharedBy();
170
-		$shareType = $share->getShareType();
171
-
172
-		if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE_GROUP &&
173
-			!$this->isOutgoingServer2serverGroupShareEnabled()
174
-		) {
175
-			$message = 'It is not allowed to send federated group shares from this server.';
176
-			$message_t = $this->l->t('It is not allowed to send federated group shares from this server.');
177
-			$this->logger->debug($message, ['app' => 'Federated File Sharing']);
178
-			throw new \Exception($message_t);
179
-		}
180
-
181
-		/*
58
+    const SHARE_TYPE_REMOTE = 6;
59
+
60
+    /** @var IDBConnection */
61
+    private $dbConnection;
62
+
63
+    /** @var AddressHandler */
64
+    private $addressHandler;
65
+
66
+    /** @var Notifications */
67
+    private $notifications;
68
+
69
+    /** @var TokenHandler */
70
+    private $tokenHandler;
71
+
72
+    /** @var IL10N */
73
+    private $l;
74
+
75
+    /** @var ILogger */
76
+    private $logger;
77
+
78
+    /** @var IRootFolder */
79
+    private $rootFolder;
80
+
81
+    /** @var IConfig */
82
+    private $config;
83
+
84
+    /** @var string */
85
+    private $externalShareTable = 'share_external';
86
+
87
+    /** @var IUserManager */
88
+    private $userManager;
89
+
90
+    /** @var ICloudIdManager */
91
+    private $cloudIdManager;
92
+
93
+    /** @var \OCP\GlobalScale\IConfig */
94
+    private $gsConfig;
95
+
96
+    /** @var ICloudFederationProviderManager */
97
+    private $cloudFederationProviderManager;
98
+
99
+    /** @var array list of supported share types */
100
+    private $supportedShareType = [\OCP\Share::SHARE_TYPE_REMOTE_GROUP, \OCP\Share::SHARE_TYPE_REMOTE];
101
+
102
+    /**
103
+     * DefaultShareProvider constructor.
104
+     *
105
+     * @param IDBConnection $connection
106
+     * @param AddressHandler $addressHandler
107
+     * @param Notifications $notifications
108
+     * @param TokenHandler $tokenHandler
109
+     * @param IL10N $l10n
110
+     * @param ILogger $logger
111
+     * @param IRootFolder $rootFolder
112
+     * @param IConfig $config
113
+     * @param IUserManager $userManager
114
+     * @param ICloudIdManager $cloudIdManager
115
+     * @param \OCP\GlobalScale\IConfig $globalScaleConfig
116
+     * @param ICloudFederationProviderManager $cloudFederationProviderManager
117
+     */
118
+    public function __construct(
119
+            IDBConnection $connection,
120
+            AddressHandler $addressHandler,
121
+            Notifications $notifications,
122
+            TokenHandler $tokenHandler,
123
+            IL10N $l10n,
124
+            ILogger $logger,
125
+            IRootFolder $rootFolder,
126
+            IConfig $config,
127
+            IUserManager $userManager,
128
+            ICloudIdManager $cloudIdManager,
129
+            \OCP\GlobalScale\IConfig $globalScaleConfig,
130
+            ICloudFederationProviderManager $cloudFederationProviderManager
131
+    ) {
132
+        $this->dbConnection = $connection;
133
+        $this->addressHandler = $addressHandler;
134
+        $this->notifications = $notifications;
135
+        $this->tokenHandler = $tokenHandler;
136
+        $this->l = $l10n;
137
+        $this->logger = $logger;
138
+        $this->rootFolder = $rootFolder;
139
+        $this->config = $config;
140
+        $this->userManager = $userManager;
141
+        $this->cloudIdManager = $cloudIdManager;
142
+        $this->gsConfig = $globalScaleConfig;
143
+        $this->cloudFederationProviderManager = $cloudFederationProviderManager;
144
+    }
145
+
146
+    /**
147
+     * Return the identifier of this provider.
148
+     *
149
+     * @return string Containing only [a-zA-Z0-9]
150
+     */
151
+    public function identifier() {
152
+        return 'ocFederatedSharing';
153
+    }
154
+
155
+    /**
156
+     * Share a path
157
+     *
158
+     * @param IShare $share
159
+     * @return IShare The share object
160
+     * @throws ShareNotFound
161
+     * @throws \Exception
162
+     */
163
+    public function create(IShare $share) {
164
+
165
+        $shareWith = $share->getSharedWith();
166
+        $itemSource = $share->getNodeId();
167
+        $itemType = $share->getNodeType();
168
+        $permissions = $share->getPermissions();
169
+        $sharedBy = $share->getSharedBy();
170
+        $shareType = $share->getShareType();
171
+
172
+        if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE_GROUP &&
173
+            !$this->isOutgoingServer2serverGroupShareEnabled()
174
+        ) {
175
+            $message = 'It is not allowed to send federated group shares from this server.';
176
+            $message_t = $this->l->t('It is not allowed to send federated group shares from this server.');
177
+            $this->logger->debug($message, ['app' => 'Federated File Sharing']);
178
+            throw new \Exception($message_t);
179
+        }
180
+
181
+        /*
182 182
 		 * Check if file is not already shared with the remote user
183 183
 		 */
184
-		$alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0);
185
-		$alreadySharedGroup = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE_GROUP, $share->getNode(), 1, 0);
186
-		if (!empty($alreadyShared) || !empty($alreadySharedGroup)) {
187
-			$message = 'Sharing %s failed, because this item is already shared with %s';
188
-			$message_t = $this->l->t('Sharing %s failed, because this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
189
-			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
190
-			throw new \Exception($message_t);
191
-		}
192
-
193
-
194
-		// don't allow federated shares if source and target server are the same
195
-		$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
196
-		$currentServer = $this->addressHandler->generateRemoteURL();
197
-		$currentUser = $sharedBy;
198
-		if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
199
-			$message = 'Not allowed to create a federated share with the same user.';
200
-			$message_t = $this->l->t('Not allowed to create a federated share with the same user');
201
-			$this->logger->debug($message, ['app' => 'Federated File Sharing']);
202
-			throw new \Exception($message_t);
203
-		}
204
-
205
-
206
-		$share->setSharedWith($cloudId->getId());
207
-
208
-		try {
209
-			$remoteShare = $this->getShareFromExternalShareTable($share);
210
-		} catch (ShareNotFound $e) {
211
-			$remoteShare = null;
212
-		}
213
-
214
-		if ($remoteShare) {
215
-			try {
216
-				$ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
217
-				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType);
218
-				$share->setId($shareId);
219
-				list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
220
-				// remote share was create successfully if we get a valid token as return
221
-				$send = is_string($token) && $token !== '';
222
-			} catch (\Exception $e) {
223
-				// fall back to old re-share behavior if the remote server
224
-				// doesn't support flat re-shares (was introduced with Nextcloud 9.1)
225
-				$this->removeShareFromTable($share);
226
-				$shareId = $this->createFederatedShare($share);
227
-			}
228
-			if ($send) {
229
-				$this->updateSuccessfulReshare($shareId, $token);
230
-				$this->storeRemoteId($shareId, $remoteId);
231
-			} else {
232
-				$this->removeShareFromTable($share);
233
-				$message_t = $this->l->t('File is already shared with %s', [$shareWith]);
234
-				throw new \Exception($message_t);
235
-			}
236
-
237
-		} else {
238
-			$shareId = $this->createFederatedShare($share);
239
-		}
240
-
241
-		$data = $this->getRawShare($shareId);
242
-		return $this->createShareObject($data);
243
-	}
244
-
245
-	/**
246
-	 * create federated share and inform the recipient
247
-	 *
248
-	 * @param IShare $share
249
-	 * @return int
250
-	 * @throws ShareNotFound
251
-	 * @throws \Exception
252
-	 */
253
-	protected function createFederatedShare(IShare $share) {
254
-		$token = $this->tokenHandler->generateToken();
255
-		$shareId = $this->addShareToDB(
256
-			$share->getNodeId(),
257
-			$share->getNodeType(),
258
-			$share->getSharedWith(),
259
-			$share->getSharedBy(),
260
-			$share->getShareOwner(),
261
-			$share->getPermissions(),
262
-			$token,
263
-			$share->getShareType()
264
-		);
265
-
266
-		$failure = false;
267
-
268
-		try {
269
-			$sharedByFederatedId = $share->getSharedBy();
270
-			if ($this->userManager->userExists($sharedByFederatedId)) {
271
-				$cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
272
-				$sharedByFederatedId = $cloudId->getId();
273
-			}
274
-			$ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
275
-			$send = $this->notifications->sendRemoteShare(
276
-				$token,
277
-				$share->getSharedWith(),
278
-				$share->getNode()->getName(),
279
-				$shareId,
280
-				$share->getShareOwner(),
281
-				$ownerCloudId->getId(),
282
-				$share->getSharedBy(),
283
-				$sharedByFederatedId,
284
-				$share->getShareType()
285
-			);
286
-
287
-			if ($send === false) {
288
-				$failure = true;
289
-			}
290
-		} catch (\Exception $e) {
291
-			$this->logger->logException($e, [
292
-				'message' => 'Failed to notify remote server of federated share, removing share.',
293
-				'level' => ILogger::ERROR,
294
-				'app' => 'federatedfilesharing',
295
-			]);
296
-			$failure = true;
297
-		}
298
-
299
-		if($failure) {
300
-			$this->removeShareFromTableById($shareId);
301
-			$message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable or uses a self-signed certificate.',
302
-				[$share->getNode()->getName(), $share->getSharedWith()]);
303
-			throw new \Exception($message_t);
304
-		}
305
-
306
-		return $shareId;
307
-
308
-	}
309
-
310
-	/**
311
-	 * @param string $shareWith
312
-	 * @param IShare $share
313
-	 * @param string $shareId internal share Id
314
-	 * @return array
315
-	 * @throws \Exception
316
-	 */
317
-	protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
318
-
319
-		$remoteShare = $this->getShareFromExternalShareTable($share);
320
-		$token = $remoteShare['share_token'];
321
-		$remoteId = $remoteShare['remote_id'];
322
-		$remote = $remoteShare['remote'];
323
-
324
-		list($token, $remoteId) = $this->notifications->requestReShare(
325
-			$token,
326
-			$remoteId,
327
-			$shareId,
328
-			$remote,
329
-			$shareWith,
330
-			$share->getPermissions(),
331
-			$share->getNode()->getName()
332
-		);
333
-
334
-		return [$token, $remoteId];
335
-	}
336
-
337
-	/**
338
-	 * get federated share from the share_external table but exclude mounted link shares
339
-	 *
340
-	 * @param IShare $share
341
-	 * @return array
342
-	 * @throws ShareNotFound
343
-	 */
344
-	protected function getShareFromExternalShareTable(IShare $share) {
345
-		$query = $this->dbConnection->getQueryBuilder();
346
-		$query->select('*')->from($this->externalShareTable)
347
-			->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
348
-			->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
349
-		$result = $query->execute()->fetchAll();
350
-
351
-		if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
352
-			return $result[0];
353
-		}
354
-
355
-		throw new ShareNotFound('share not found in share_external table');
356
-	}
357
-
358
-	/**
359
-	 * add share to the database and return the ID
360
-	 *
361
-	 * @param int $itemSource
362
-	 * @param string $itemType
363
-	 * @param string $shareWith
364
-	 * @param string $sharedBy
365
-	 * @param string $uidOwner
366
-	 * @param int $permissions
367
-	 * @param string $token
368
-	 * @param int $shareType
369
-	 * @return int
370
-	 */
371
-	private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType) {
372
-		$qb = $this->dbConnection->getQueryBuilder();
373
-		$qb->insert('share')
374
-			->setValue('share_type', $qb->createNamedParameter($shareType))
375
-			->setValue('item_type', $qb->createNamedParameter($itemType))
376
-			->setValue('item_source', $qb->createNamedParameter($itemSource))
377
-			->setValue('file_source', $qb->createNamedParameter($itemSource))
378
-			->setValue('share_with', $qb->createNamedParameter($shareWith))
379
-			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
380
-			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
381
-			->setValue('permissions', $qb->createNamedParameter($permissions))
382
-			->setValue('token', $qb->createNamedParameter($token))
383
-			->setValue('stime', $qb->createNamedParameter(time()));
384
-
385
-		/*
184
+        $alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0);
185
+        $alreadySharedGroup = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE_GROUP, $share->getNode(), 1, 0);
186
+        if (!empty($alreadyShared) || !empty($alreadySharedGroup)) {
187
+            $message = 'Sharing %s failed, because this item is already shared with %s';
188
+            $message_t = $this->l->t('Sharing %s failed, because this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
189
+            $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
190
+            throw new \Exception($message_t);
191
+        }
192
+
193
+
194
+        // don't allow federated shares if source and target server are the same
195
+        $cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
196
+        $currentServer = $this->addressHandler->generateRemoteURL();
197
+        $currentUser = $sharedBy;
198
+        if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
199
+            $message = 'Not allowed to create a federated share with the same user.';
200
+            $message_t = $this->l->t('Not allowed to create a federated share with the same user');
201
+            $this->logger->debug($message, ['app' => 'Federated File Sharing']);
202
+            throw new \Exception($message_t);
203
+        }
204
+
205
+
206
+        $share->setSharedWith($cloudId->getId());
207
+
208
+        try {
209
+            $remoteShare = $this->getShareFromExternalShareTable($share);
210
+        } catch (ShareNotFound $e) {
211
+            $remoteShare = null;
212
+        }
213
+
214
+        if ($remoteShare) {
215
+            try {
216
+                $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
217
+                $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType);
218
+                $share->setId($shareId);
219
+                list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
220
+                // remote share was create successfully if we get a valid token as return
221
+                $send = is_string($token) && $token !== '';
222
+            } catch (\Exception $e) {
223
+                // fall back to old re-share behavior if the remote server
224
+                // doesn't support flat re-shares (was introduced with Nextcloud 9.1)
225
+                $this->removeShareFromTable($share);
226
+                $shareId = $this->createFederatedShare($share);
227
+            }
228
+            if ($send) {
229
+                $this->updateSuccessfulReshare($shareId, $token);
230
+                $this->storeRemoteId($shareId, $remoteId);
231
+            } else {
232
+                $this->removeShareFromTable($share);
233
+                $message_t = $this->l->t('File is already shared with %s', [$shareWith]);
234
+                throw new \Exception($message_t);
235
+            }
236
+
237
+        } else {
238
+            $shareId = $this->createFederatedShare($share);
239
+        }
240
+
241
+        $data = $this->getRawShare($shareId);
242
+        return $this->createShareObject($data);
243
+    }
244
+
245
+    /**
246
+     * create federated share and inform the recipient
247
+     *
248
+     * @param IShare $share
249
+     * @return int
250
+     * @throws ShareNotFound
251
+     * @throws \Exception
252
+     */
253
+    protected function createFederatedShare(IShare $share) {
254
+        $token = $this->tokenHandler->generateToken();
255
+        $shareId = $this->addShareToDB(
256
+            $share->getNodeId(),
257
+            $share->getNodeType(),
258
+            $share->getSharedWith(),
259
+            $share->getSharedBy(),
260
+            $share->getShareOwner(),
261
+            $share->getPermissions(),
262
+            $token,
263
+            $share->getShareType()
264
+        );
265
+
266
+        $failure = false;
267
+
268
+        try {
269
+            $sharedByFederatedId = $share->getSharedBy();
270
+            if ($this->userManager->userExists($sharedByFederatedId)) {
271
+                $cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
272
+                $sharedByFederatedId = $cloudId->getId();
273
+            }
274
+            $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
275
+            $send = $this->notifications->sendRemoteShare(
276
+                $token,
277
+                $share->getSharedWith(),
278
+                $share->getNode()->getName(),
279
+                $shareId,
280
+                $share->getShareOwner(),
281
+                $ownerCloudId->getId(),
282
+                $share->getSharedBy(),
283
+                $sharedByFederatedId,
284
+                $share->getShareType()
285
+            );
286
+
287
+            if ($send === false) {
288
+                $failure = true;
289
+            }
290
+        } catch (\Exception $e) {
291
+            $this->logger->logException($e, [
292
+                'message' => 'Failed to notify remote server of federated share, removing share.',
293
+                'level' => ILogger::ERROR,
294
+                'app' => 'federatedfilesharing',
295
+            ]);
296
+            $failure = true;
297
+        }
298
+
299
+        if($failure) {
300
+            $this->removeShareFromTableById($shareId);
301
+            $message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable or uses a self-signed certificate.',
302
+                [$share->getNode()->getName(), $share->getSharedWith()]);
303
+            throw new \Exception($message_t);
304
+        }
305
+
306
+        return $shareId;
307
+
308
+    }
309
+
310
+    /**
311
+     * @param string $shareWith
312
+     * @param IShare $share
313
+     * @param string $shareId internal share Id
314
+     * @return array
315
+     * @throws \Exception
316
+     */
317
+    protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
318
+
319
+        $remoteShare = $this->getShareFromExternalShareTable($share);
320
+        $token = $remoteShare['share_token'];
321
+        $remoteId = $remoteShare['remote_id'];
322
+        $remote = $remoteShare['remote'];
323
+
324
+        list($token, $remoteId) = $this->notifications->requestReShare(
325
+            $token,
326
+            $remoteId,
327
+            $shareId,
328
+            $remote,
329
+            $shareWith,
330
+            $share->getPermissions(),
331
+            $share->getNode()->getName()
332
+        );
333
+
334
+        return [$token, $remoteId];
335
+    }
336
+
337
+    /**
338
+     * get federated share from the share_external table but exclude mounted link shares
339
+     *
340
+     * @param IShare $share
341
+     * @return array
342
+     * @throws ShareNotFound
343
+     */
344
+    protected function getShareFromExternalShareTable(IShare $share) {
345
+        $query = $this->dbConnection->getQueryBuilder();
346
+        $query->select('*')->from($this->externalShareTable)
347
+            ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
348
+            ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
349
+        $result = $query->execute()->fetchAll();
350
+
351
+        if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
352
+            return $result[0];
353
+        }
354
+
355
+        throw new ShareNotFound('share not found in share_external table');
356
+    }
357
+
358
+    /**
359
+     * add share to the database and return the ID
360
+     *
361
+     * @param int $itemSource
362
+     * @param string $itemType
363
+     * @param string $shareWith
364
+     * @param string $sharedBy
365
+     * @param string $uidOwner
366
+     * @param int $permissions
367
+     * @param string $token
368
+     * @param int $shareType
369
+     * @return int
370
+     */
371
+    private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType) {
372
+        $qb = $this->dbConnection->getQueryBuilder();
373
+        $qb->insert('share')
374
+            ->setValue('share_type', $qb->createNamedParameter($shareType))
375
+            ->setValue('item_type', $qb->createNamedParameter($itemType))
376
+            ->setValue('item_source', $qb->createNamedParameter($itemSource))
377
+            ->setValue('file_source', $qb->createNamedParameter($itemSource))
378
+            ->setValue('share_with', $qb->createNamedParameter($shareWith))
379
+            ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
380
+            ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
381
+            ->setValue('permissions', $qb->createNamedParameter($permissions))
382
+            ->setValue('token', $qb->createNamedParameter($token))
383
+            ->setValue('stime', $qb->createNamedParameter(time()));
384
+
385
+        /*
386 386
 		 * Added to fix https://github.com/owncloud/core/issues/22215
387 387
 		 * Can be removed once we get rid of ajax/share.php
388 388
 		 */
389
-		$qb->setValue('file_target', $qb->createNamedParameter(''));
390
-
391
-		$qb->execute();
392
-		$id = $qb->getLastInsertId();
393
-
394
-		return (int)$id;
395
-	}
396
-
397
-	/**
398
-	 * Update a share
399
-	 *
400
-	 * @param IShare $share
401
-	 * @return IShare The share object
402
-	 */
403
-	public function update(IShare $share) {
404
-		/*
389
+        $qb->setValue('file_target', $qb->createNamedParameter(''));
390
+
391
+        $qb->execute();
392
+        $id = $qb->getLastInsertId();
393
+
394
+        return (int)$id;
395
+    }
396
+
397
+    /**
398
+     * Update a share
399
+     *
400
+     * @param IShare $share
401
+     * @return IShare The share object
402
+     */
403
+    public function update(IShare $share) {
404
+        /*
405 405
 		 * We allow updating the permissions of federated shares
406 406
 		 */
407
-		$qb = $this->dbConnection->getQueryBuilder();
408
-			$qb->update('share')
409
-				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
410
-				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
411
-				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
412
-				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
413
-				->execute();
414
-
415
-		// send the updated permission to the owner/initiator, if they are not the same
416
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
417
-			$this->sendPermissionUpdate($share);
418
-		}
419
-
420
-		return $share;
421
-	}
422
-
423
-	/**
424
-	 * send the updated permission to the owner/initiator, if they are not the same
425
-	 *
426
-	 * @param IShare $share
427
-	 * @throws ShareNotFound
428
-	 * @throws \OC\HintException
429
-	 */
430
-	protected function sendPermissionUpdate(IShare $share) {
431
-		$remoteId = $this->getRemoteId($share);
432
-		// if the local user is the owner we send the permission change to the initiator
433
-		if ($this->userManager->userExists($share->getShareOwner())) {
434
-			list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
435
-		} else { // ... if not we send the permission change to the owner
436
-			list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
437
-		}
438
-		$this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
439
-	}
440
-
441
-
442
-	/**
443
-	 * update successful reShare with the correct token
444
-	 *
445
-	 * @param int $shareId
446
-	 * @param string $token
447
-	 */
448
-	protected function updateSuccessfulReShare($shareId, $token) {
449
-		$query = $this->dbConnection->getQueryBuilder();
450
-		$query->update('share')
451
-			->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
452
-			->set('token', $query->createNamedParameter($token))
453
-			->execute();
454
-	}
455
-
456
-	/**
457
-	 * store remote ID in federated reShare table
458
-	 *
459
-	 * @param $shareId
460
-	 * @param $remoteId
461
-	 */
462
-	public function storeRemoteId($shareId, $remoteId) {
463
-		$query = $this->dbConnection->getQueryBuilder();
464
-		$query->insert('federated_reshares')
465
-			->values(
466
-				[
467
-					'share_id' =>  $query->createNamedParameter($shareId),
468
-					'remote_id' => $query->createNamedParameter($remoteId),
469
-				]
470
-			);
471
-		$query->execute();
472
-	}
473
-
474
-	/**
475
-	 * get share ID on remote server for federated re-shares
476
-	 *
477
-	 * @param IShare $share
478
-	 * @return int
479
-	 * @throws ShareNotFound
480
-	 */
481
-	public function getRemoteId(IShare $share) {
482
-		$query = $this->dbConnection->getQueryBuilder();
483
-		$query->select('remote_id')->from('federated_reshares')
484
-			->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
485
-		$data = $query->execute()->fetch();
486
-
487
-		if (!is_array($data) || !isset($data['remote_id'])) {
488
-			throw new ShareNotFound();
489
-		}
490
-
491
-		return (int)$data['remote_id'];
492
-	}
493
-
494
-	/**
495
-	 * @inheritdoc
496
-	 */
497
-	public function move(IShare $share, $recipient) {
498
-		/*
407
+        $qb = $this->dbConnection->getQueryBuilder();
408
+            $qb->update('share')
409
+                ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
410
+                ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
411
+                ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
412
+                ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
413
+                ->execute();
414
+
415
+        // send the updated permission to the owner/initiator, if they are not the same
416
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
417
+            $this->sendPermissionUpdate($share);
418
+        }
419
+
420
+        return $share;
421
+    }
422
+
423
+    /**
424
+     * send the updated permission to the owner/initiator, if they are not the same
425
+     *
426
+     * @param IShare $share
427
+     * @throws ShareNotFound
428
+     * @throws \OC\HintException
429
+     */
430
+    protected function sendPermissionUpdate(IShare $share) {
431
+        $remoteId = $this->getRemoteId($share);
432
+        // if the local user is the owner we send the permission change to the initiator
433
+        if ($this->userManager->userExists($share->getShareOwner())) {
434
+            list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
435
+        } else { // ... if not we send the permission change to the owner
436
+            list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
437
+        }
438
+        $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
439
+    }
440
+
441
+
442
+    /**
443
+     * update successful reShare with the correct token
444
+     *
445
+     * @param int $shareId
446
+     * @param string $token
447
+     */
448
+    protected function updateSuccessfulReShare($shareId, $token) {
449
+        $query = $this->dbConnection->getQueryBuilder();
450
+        $query->update('share')
451
+            ->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
452
+            ->set('token', $query->createNamedParameter($token))
453
+            ->execute();
454
+    }
455
+
456
+    /**
457
+     * store remote ID in federated reShare table
458
+     *
459
+     * @param $shareId
460
+     * @param $remoteId
461
+     */
462
+    public function storeRemoteId($shareId, $remoteId) {
463
+        $query = $this->dbConnection->getQueryBuilder();
464
+        $query->insert('federated_reshares')
465
+            ->values(
466
+                [
467
+                    'share_id' =>  $query->createNamedParameter($shareId),
468
+                    'remote_id' => $query->createNamedParameter($remoteId),
469
+                ]
470
+            );
471
+        $query->execute();
472
+    }
473
+
474
+    /**
475
+     * get share ID on remote server for federated re-shares
476
+     *
477
+     * @param IShare $share
478
+     * @return int
479
+     * @throws ShareNotFound
480
+     */
481
+    public function getRemoteId(IShare $share) {
482
+        $query = $this->dbConnection->getQueryBuilder();
483
+        $query->select('remote_id')->from('federated_reshares')
484
+            ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
485
+        $data = $query->execute()->fetch();
486
+
487
+        if (!is_array($data) || !isset($data['remote_id'])) {
488
+            throw new ShareNotFound();
489
+        }
490
+
491
+        return (int)$data['remote_id'];
492
+    }
493
+
494
+    /**
495
+     * @inheritdoc
496
+     */
497
+    public function move(IShare $share, $recipient) {
498
+        /*
499 499
 		 * This function does nothing yet as it is just for outgoing
500 500
 		 * federated shares.
501 501
 		 */
502
-		return $share;
503
-	}
504
-
505
-	/**
506
-	 * Get all children of this share
507
-	 *
508
-	 * @param IShare $parent
509
-	 * @return IShare[]
510
-	 */
511
-	public function getChildren(IShare $parent) {
512
-		$children = [];
513
-
514
-		$qb = $this->dbConnection->getQueryBuilder();
515
-		$qb->select('*')
516
-			->from('share')
517
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
518
-			->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
519
-			->orderBy('id');
520
-
521
-		$cursor = $qb->execute();
522
-		while($data = $cursor->fetch()) {
523
-			$children[] = $this->createShareObject($data);
524
-		}
525
-		$cursor->closeCursor();
526
-
527
-		return $children;
528
-	}
529
-
530
-	/**
531
-	 * Delete a share (owner unShares the file)
532
-	 *
533
-	 * @param IShare $share
534
-	 * @throws ShareNotFound
535
-	 * @throws \OC\HintException
536
-	 */
537
-	public function delete(IShare $share) {
538
-
539
-		list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith());
540
-
541
-		// if the local user is the owner we can send the unShare request directly...
542
-		if ($this->userManager->userExists($share->getShareOwner())) {
543
-			$this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
544
-			$this->revokeShare($share, true);
545
-		} else { // ... if not we need to correct ID for the unShare request
546
-			$remoteId = $this->getRemoteId($share);
547
-			$this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
548
-			$this->revokeShare($share, false);
549
-		}
550
-
551
-		// only remove the share when all messages are send to not lose information
552
-		// about the share to early
553
-		$this->removeShareFromTable($share);
554
-	}
555
-
556
-	/**
557
-	 * in case of a re-share we need to send the other use (initiator or owner)
558
-	 * a message that the file was unshared
559
-	 *
560
-	 * @param IShare $share
561
-	 * @param bool $isOwner the user can either be the owner or the user who re-sahred it
562
-	 * @throws ShareNotFound
563
-	 * @throws \OC\HintException
564
-	 */
565
-	protected function revokeShare($share, $isOwner) {
566
-		// also send a unShare request to the initiator, if this is a different user than the owner
567
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
568
-			if ($isOwner) {
569
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
570
-			} else {
571
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
572
-			}
573
-			$remoteId = $this->getRemoteId($share);
574
-			$this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
575
-		}
576
-	}
577
-
578
-	/**
579
-	 * remove share from table
580
-	 *
581
-	 * @param IShare $share
582
-	 */
583
-	public function removeShareFromTable(IShare $share) {
584
-		$this->removeShareFromTableById($share->getId());
585
-	}
586
-
587
-	/**
588
-	 * remove share from table
589
-	 *
590
-	 * @param string $shareId
591
-	 */
592
-	private function removeShareFromTableById($shareId) {
593
-		$qb = $this->dbConnection->getQueryBuilder();
594
-		$qb->delete('share')
595
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
596
-		$qb->execute();
597
-
598
-		$qb->delete('federated_reshares')
599
-			->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
600
-		$qb->execute();
601
-	}
602
-
603
-	/**
604
-	 * @inheritdoc
605
-	 */
606
-	public function deleteFromSelf(IShare $share, $recipient) {
607
-		// nothing to do here. Technically deleteFromSelf in the context of federated
608
-		// shares is a umount of a external storage. This is handled here
609
-		// apps/files_sharing/lib/external/manager.php
610
-		// TODO move this code over to this app
611
-	}
612
-
613
-	public function restore(IShare $share, string $recipient): IShare {
614
-		throw new GenericShareException('not implemented');
615
-	}
616
-
617
-
618
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
619
-		$qb = $this->dbConnection->getQueryBuilder();
620
-		$qb->select('*')
621
-			->from('share', 's')
622
-			->andWhere($qb->expr()->orX(
623
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
624
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
625
-			))
626
-			->andWhere(
627
-				$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))
628
-			);
629
-
630
-		/**
631
-		 * Reshares for this user are shares where they are the owner.
632
-		 */
633
-		if ($reshares === false) {
634
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
635
-		} else {
636
-			$qb->andWhere(
637
-				$qb->expr()->orX(
638
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
639
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
640
-				)
641
-			);
642
-		}
643
-
644
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
645
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
646
-
647
-		$qb->orderBy('id');
648
-
649
-		$cursor = $qb->execute();
650
-		$shares = [];
651
-		while ($data = $cursor->fetch()) {
652
-			$shares[$data['fileid']][] = $this->createShareObject($data);
653
-		}
654
-		$cursor->closeCursor();
655
-
656
-		return $shares;
657
-	}
658
-
659
-	/**
660
-	 * @inheritdoc
661
-	 */
662
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
663
-		$qb = $this->dbConnection->getQueryBuilder();
664
-		$qb->select('*')
665
-			->from('share');
666
-
667
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
668
-
669
-		/**
670
-		 * Reshares for this user are shares where they are the owner.
671
-		 */
672
-		if ($reshares === false) {
673
-			//Special case for old shares created via the web UI
674
-			$or1 = $qb->expr()->andX(
675
-				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
676
-				$qb->expr()->isNull('uid_initiator')
677
-			);
678
-
679
-			$qb->andWhere(
680
-				$qb->expr()->orX(
681
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
682
-					$or1
683
-				)
684
-			);
685
-		} else {
686
-			$qb->andWhere(
687
-				$qb->expr()->orX(
688
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
689
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
690
-				)
691
-			);
692
-		}
693
-
694
-		if ($node !== null) {
695
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
696
-		}
697
-
698
-		if ($limit !== -1) {
699
-			$qb->setMaxResults($limit);
700
-		}
701
-
702
-		$qb->setFirstResult($offset);
703
-		$qb->orderBy('id');
704
-
705
-		$cursor = $qb->execute();
706
-		$shares = [];
707
-		while($data = $cursor->fetch()) {
708
-			$shares[] = $this->createShareObject($data);
709
-		}
710
-		$cursor->closeCursor();
711
-
712
-		return $shares;
713
-	}
714
-
715
-	/**
716
-	 * @inheritdoc
717
-	 */
718
-	public function getShareById($id, $recipientId = null) {
719
-		$qb = $this->dbConnection->getQueryBuilder();
720
-
721
-		$qb->select('*')
722
-			->from('share')
723
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
724
-			->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
725
-
726
-		$cursor = $qb->execute();
727
-		$data = $cursor->fetch();
728
-		$cursor->closeCursor();
729
-
730
-		if ($data === false) {
731
-			throw new ShareNotFound('Can not find share with ID: ' . $id);
732
-		}
733
-
734
-		try {
735
-			$share = $this->createShareObject($data);
736
-		} catch (InvalidShare $e) {
737
-			throw new ShareNotFound();
738
-		}
739
-
740
-		return $share;
741
-	}
742
-
743
-	/**
744
-	 * Get shares for a given path
745
-	 *
746
-	 * @param \OCP\Files\Node $path
747
-	 * @return IShare[]
748
-	 */
749
-	public function getSharesByPath(Node $path) {
750
-		$qb = $this->dbConnection->getQueryBuilder();
751
-
752
-		// get federated user shares
753
-		$cursor = $qb->select('*')
754
-			->from('share')
755
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
756
-			->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
757
-			->execute();
758
-
759
-		$shares = [];
760
-		while($data = $cursor->fetch()) {
761
-			$shares[] = $this->createShareObject($data);
762
-		}
763
-		$cursor->closeCursor();
764
-
765
-		return $shares;
766
-	}
767
-
768
-	/**
769
-	 * @inheritdoc
770
-	 */
771
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
772
-		/** @var IShare[] $shares */
773
-		$shares = [];
774
-
775
-		//Get shares directly with this user
776
-		$qb = $this->dbConnection->getQueryBuilder();
777
-		$qb->select('*')
778
-			->from('share');
779
-
780
-		// Order by id
781
-		$qb->orderBy('id');
782
-
783
-		// Set limit and offset
784
-		if ($limit !== -1) {
785
-			$qb->setMaxResults($limit);
786
-		}
787
-		$qb->setFirstResult($offset);
788
-
789
-		$qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
790
-		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
791
-
792
-		// Filter by node if provided
793
-		if ($node !== null) {
794
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
795
-		}
796
-
797
-		$cursor = $qb->execute();
798
-
799
-		while($data = $cursor->fetch()) {
800
-			$shares[] = $this->createShareObject($data);
801
-		}
802
-		$cursor->closeCursor();
803
-
804
-
805
-		return $shares;
806
-	}
807
-
808
-	/**
809
-	 * Get a share by token
810
-	 *
811
-	 * @param string $token
812
-	 * @return IShare
813
-	 * @throws ShareNotFound
814
-	 */
815
-	public function getShareByToken($token) {
816
-		$qb = $this->dbConnection->getQueryBuilder();
817
-
818
-		$cursor = $qb->select('*')
819
-			->from('share')
820
-			->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
821
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
822
-			->execute();
823
-
824
-		$data = $cursor->fetch();
825
-
826
-		if ($data === false) {
827
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
828
-		}
829
-
830
-		try {
831
-			$share = $this->createShareObject($data);
832
-		} catch (InvalidShare $e) {
833
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
834
-		}
835
-
836
-		return $share;
837
-	}
838
-
839
-	/**
840
-	 * get database row of a give share
841
-	 *
842
-	 * @param $id
843
-	 * @return array
844
-	 * @throws ShareNotFound
845
-	 */
846
-	private function getRawShare($id) {
847
-
848
-		// Now fetch the inserted share and create a complete share object
849
-		$qb = $this->dbConnection->getQueryBuilder();
850
-		$qb->select('*')
851
-			->from('share')
852
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
853
-
854
-		$cursor = $qb->execute();
855
-		$data = $cursor->fetch();
856
-		$cursor->closeCursor();
857
-
858
-		if ($data === false) {
859
-			throw new ShareNotFound;
860
-		}
861
-
862
-		return $data;
863
-	}
864
-
865
-	/**
866
-	 * Create a share object from an database row
867
-	 *
868
-	 * @param array $data
869
-	 * @return IShare
870
-	 * @throws InvalidShare
871
-	 * @throws ShareNotFound
872
-	 */
873
-	private function createShareObject($data) {
874
-
875
-		$share = new Share($this->rootFolder, $this->userManager);
876
-		$share->setId((int)$data['id'])
877
-			->setShareType((int)$data['share_type'])
878
-			->setPermissions((int)$data['permissions'])
879
-			->setTarget($data['file_target'])
880
-			->setMailSend((bool)$data['mail_send'])
881
-			->setToken($data['token']);
882
-
883
-		$shareTime = new \DateTime();
884
-		$shareTime->setTimestamp((int)$data['stime']);
885
-		$share->setShareTime($shareTime);
886
-		$share->setSharedWith($data['share_with']);
887
-
888
-		if ($data['uid_initiator'] !== null) {
889
-			$share->setShareOwner($data['uid_owner']);
890
-			$share->setSharedBy($data['uid_initiator']);
891
-		} else {
892
-			//OLD SHARE
893
-			$share->setSharedBy($data['uid_owner']);
894
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
895
-
896
-			$owner = $path->getOwner();
897
-			$share->setShareOwner($owner->getUID());
898
-		}
899
-
900
-		$share->setNodeId((int)$data['file_source']);
901
-		$share->setNodeType($data['item_type']);
902
-
903
-		$share->setProviderId($this->identifier());
904
-
905
-		return $share;
906
-	}
907
-
908
-	/**
909
-	 * Get the node with file $id for $user
910
-	 *
911
-	 * @param string $userId
912
-	 * @param int $id
913
-	 * @return \OCP\Files\File|\OCP\Files\Folder
914
-	 * @throws InvalidShare
915
-	 */
916
-	private function getNode($userId, $id) {
917
-		try {
918
-			$userFolder = $this->rootFolder->getUserFolder($userId);
919
-		} catch (NotFoundException $e) {
920
-			throw new InvalidShare();
921
-		}
922
-
923
-		$nodes = $userFolder->getById($id);
924
-
925
-		if (empty($nodes)) {
926
-			throw new InvalidShare();
927
-		}
928
-
929
-		return $nodes[0];
930
-	}
931
-
932
-	/**
933
-	 * A user is deleted from the system
934
-	 * So clean up the relevant shares.
935
-	 *
936
-	 * @param string $uid
937
-	 * @param int $shareType
938
-	 */
939
-	public function userDeleted($uid, $shareType) {
940
-		//TODO: probabaly a good idea to send unshare info to remote servers
941
-
942
-		$qb = $this->dbConnection->getQueryBuilder();
943
-
944
-		$qb->delete('share')
945
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
946
-			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
947
-			->execute();
948
-	}
949
-
950
-	/**
951
-	 * This provider does not handle groups
952
-	 *
953
-	 * @param string $gid
954
-	 */
955
-	public function groupDeleted($gid) {
956
-		// We don't handle groups here
957
-	}
958
-
959
-	/**
960
-	 * This provider does not handle groups
961
-	 *
962
-	 * @param string $uid
963
-	 * @param string $gid
964
-	 */
965
-	public function userDeletedFromGroup($uid, $gid) {
966
-		// We don't handle groups here
967
-	}
968
-
969
-	/**
970
-	 * check if users from other Nextcloud instances are allowed to mount public links share by this instance
971
-	 *
972
-	 * @return bool
973
-	 */
974
-	public function isOutgoingServer2serverShareEnabled() {
975
-		if ($this->gsConfig->onlyInternalFederation()) {
976
-			return false;
977
-		}
978
-		$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
979
-		return ($result === 'yes');
980
-	}
981
-
982
-	/**
983
-	 * check if users are allowed to mount public links from other Nextclouds
984
-	 *
985
-	 * @return bool
986
-	 */
987
-	public function isIncomingServer2serverShareEnabled() {
988
-		if ($this->gsConfig->onlyInternalFederation()) {
989
-			return false;
990
-		}
991
-		$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
992
-		return ($result === 'yes');
993
-	}
994
-
995
-
996
-	/**
997
-	 * check if users from other Nextcloud instances are allowed to send federated group shares
998
-	 *
999
-	 * @return bool
1000
-	 */
1001
-	public function isOutgoingServer2serverGroupShareEnabled() {
1002
-		if ($this->gsConfig->onlyInternalFederation()) {
1003
-			return false;
1004
-		}
1005
-		$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no');
1006
-		return ($result === 'yes');
1007
-	}
1008
-
1009
-	/**
1010
-	 * check if users are allowed to receive federated group shares
1011
-	 *
1012
-	 * @return bool
1013
-	 */
1014
-	public function isIncomingServer2serverGroupShareEnabled() {
1015
-		if ($this->gsConfig->onlyInternalFederation()) {
1016
-			return false;
1017
-		}
1018
-		$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no');
1019
-		return ($result === 'yes');
1020
-	}
1021
-
1022
-	/**
1023
-	 * check if federated group sharing is supported, therefore the OCM API need to be enabled
1024
-	 *
1025
-	 * @return bool
1026
-	 */
1027
-	public function isFederatedGroupSharingSupported() {
1028
-		return $this->cloudFederationProviderManager->isReady();
1029
-	}
1030
-
1031
-	/**
1032
-	 * Check if querying sharees on the lookup server is enabled
1033
-	 *
1034
-	 * @return bool
1035
-	 */
1036
-	public function isLookupServerQueriesEnabled() {
1037
-		// in a global scale setup we should always query the lookup server
1038
-		if ($this->gsConfig->isGlobalScaleEnabled()) {
1039
-			return true;
1040
-		}
1041
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
1042
-		return ($result === 'yes');
1043
-	}
1044
-
1045
-
1046
-	/**
1047
-	 * Check if it is allowed to publish user specific data to the lookup server
1048
-	 *
1049
-	 * @return bool
1050
-	 */
1051
-	public function isLookupServerUploadEnabled() {
1052
-		// in a global scale setup the admin is responsible to keep the lookup server up-to-date
1053
-		if ($this->gsConfig->isGlobalScaleEnabled()) {
1054
-			return false;
1055
-		}
1056
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
1057
-		return ($result === 'yes');
1058
-	}
1059
-
1060
-	/**
1061
-	 * @inheritdoc
1062
-	 */
1063
-	public function getAccessList($nodes, $currentAccess) {
1064
-		$ids = [];
1065
-		foreach ($nodes as $node) {
1066
-			$ids[] = $node->getId();
1067
-		}
1068
-
1069
-		$qb = $this->dbConnection->getQueryBuilder();
1070
-		$qb->select('share_with', 'token', 'file_source')
1071
-			->from('share')
1072
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
1073
-			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1074
-			->andWhere($qb->expr()->orX(
1075
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1076
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1077
-			));
1078
-		$cursor = $qb->execute();
1079
-
1080
-		if ($currentAccess === false) {
1081
-			$remote = $cursor->fetch() !== false;
1082
-			$cursor->closeCursor();
1083
-
1084
-			return ['remote' => $remote];
1085
-		}
1086
-
1087
-		$remote = [];
1088
-		while ($row = $cursor->fetch()) {
1089
-			$remote[$row['share_with']] = [
1090
-				'node_id' => $row['file_source'],
1091
-				'token' => $row['token'],
1092
-			];
1093
-		}
1094
-		$cursor->closeCursor();
1095
-
1096
-		return ['remote' => $remote];
1097
-	}
502
+        return $share;
503
+    }
504
+
505
+    /**
506
+     * Get all children of this share
507
+     *
508
+     * @param IShare $parent
509
+     * @return IShare[]
510
+     */
511
+    public function getChildren(IShare $parent) {
512
+        $children = [];
513
+
514
+        $qb = $this->dbConnection->getQueryBuilder();
515
+        $qb->select('*')
516
+            ->from('share')
517
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
518
+            ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
519
+            ->orderBy('id');
520
+
521
+        $cursor = $qb->execute();
522
+        while($data = $cursor->fetch()) {
523
+            $children[] = $this->createShareObject($data);
524
+        }
525
+        $cursor->closeCursor();
526
+
527
+        return $children;
528
+    }
529
+
530
+    /**
531
+     * Delete a share (owner unShares the file)
532
+     *
533
+     * @param IShare $share
534
+     * @throws ShareNotFound
535
+     * @throws \OC\HintException
536
+     */
537
+    public function delete(IShare $share) {
538
+
539
+        list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith());
540
+
541
+        // if the local user is the owner we can send the unShare request directly...
542
+        if ($this->userManager->userExists($share->getShareOwner())) {
543
+            $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
544
+            $this->revokeShare($share, true);
545
+        } else { // ... if not we need to correct ID for the unShare request
546
+            $remoteId = $this->getRemoteId($share);
547
+            $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
548
+            $this->revokeShare($share, false);
549
+        }
550
+
551
+        // only remove the share when all messages are send to not lose information
552
+        // about the share to early
553
+        $this->removeShareFromTable($share);
554
+    }
555
+
556
+    /**
557
+     * in case of a re-share we need to send the other use (initiator or owner)
558
+     * a message that the file was unshared
559
+     *
560
+     * @param IShare $share
561
+     * @param bool $isOwner the user can either be the owner or the user who re-sahred it
562
+     * @throws ShareNotFound
563
+     * @throws \OC\HintException
564
+     */
565
+    protected function revokeShare($share, $isOwner) {
566
+        // also send a unShare request to the initiator, if this is a different user than the owner
567
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
568
+            if ($isOwner) {
569
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
570
+            } else {
571
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
572
+            }
573
+            $remoteId = $this->getRemoteId($share);
574
+            $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
575
+        }
576
+    }
577
+
578
+    /**
579
+     * remove share from table
580
+     *
581
+     * @param IShare $share
582
+     */
583
+    public function removeShareFromTable(IShare $share) {
584
+        $this->removeShareFromTableById($share->getId());
585
+    }
586
+
587
+    /**
588
+     * remove share from table
589
+     *
590
+     * @param string $shareId
591
+     */
592
+    private function removeShareFromTableById($shareId) {
593
+        $qb = $this->dbConnection->getQueryBuilder();
594
+        $qb->delete('share')
595
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
596
+        $qb->execute();
597
+
598
+        $qb->delete('federated_reshares')
599
+            ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
600
+        $qb->execute();
601
+    }
602
+
603
+    /**
604
+     * @inheritdoc
605
+     */
606
+    public function deleteFromSelf(IShare $share, $recipient) {
607
+        // nothing to do here. Technically deleteFromSelf in the context of federated
608
+        // shares is a umount of a external storage. This is handled here
609
+        // apps/files_sharing/lib/external/manager.php
610
+        // TODO move this code over to this app
611
+    }
612
+
613
+    public function restore(IShare $share, string $recipient): IShare {
614
+        throw new GenericShareException('not implemented');
615
+    }
616
+
617
+
618
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
619
+        $qb = $this->dbConnection->getQueryBuilder();
620
+        $qb->select('*')
621
+            ->from('share', 's')
622
+            ->andWhere($qb->expr()->orX(
623
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
624
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
625
+            ))
626
+            ->andWhere(
627
+                $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))
628
+            );
629
+
630
+        /**
631
+         * Reshares for this user are shares where they are the owner.
632
+         */
633
+        if ($reshares === false) {
634
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
635
+        } else {
636
+            $qb->andWhere(
637
+                $qb->expr()->orX(
638
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
639
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
640
+                )
641
+            );
642
+        }
643
+
644
+        $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
645
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
646
+
647
+        $qb->orderBy('id');
648
+
649
+        $cursor = $qb->execute();
650
+        $shares = [];
651
+        while ($data = $cursor->fetch()) {
652
+            $shares[$data['fileid']][] = $this->createShareObject($data);
653
+        }
654
+        $cursor->closeCursor();
655
+
656
+        return $shares;
657
+    }
658
+
659
+    /**
660
+     * @inheritdoc
661
+     */
662
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
663
+        $qb = $this->dbConnection->getQueryBuilder();
664
+        $qb->select('*')
665
+            ->from('share');
666
+
667
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
668
+
669
+        /**
670
+         * Reshares for this user are shares where they are the owner.
671
+         */
672
+        if ($reshares === false) {
673
+            //Special case for old shares created via the web UI
674
+            $or1 = $qb->expr()->andX(
675
+                $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
676
+                $qb->expr()->isNull('uid_initiator')
677
+            );
678
+
679
+            $qb->andWhere(
680
+                $qb->expr()->orX(
681
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
682
+                    $or1
683
+                )
684
+            );
685
+        } else {
686
+            $qb->andWhere(
687
+                $qb->expr()->orX(
688
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
689
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
690
+                )
691
+            );
692
+        }
693
+
694
+        if ($node !== null) {
695
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
696
+        }
697
+
698
+        if ($limit !== -1) {
699
+            $qb->setMaxResults($limit);
700
+        }
701
+
702
+        $qb->setFirstResult($offset);
703
+        $qb->orderBy('id');
704
+
705
+        $cursor = $qb->execute();
706
+        $shares = [];
707
+        while($data = $cursor->fetch()) {
708
+            $shares[] = $this->createShareObject($data);
709
+        }
710
+        $cursor->closeCursor();
711
+
712
+        return $shares;
713
+    }
714
+
715
+    /**
716
+     * @inheritdoc
717
+     */
718
+    public function getShareById($id, $recipientId = null) {
719
+        $qb = $this->dbConnection->getQueryBuilder();
720
+
721
+        $qb->select('*')
722
+            ->from('share')
723
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
724
+            ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
725
+
726
+        $cursor = $qb->execute();
727
+        $data = $cursor->fetch();
728
+        $cursor->closeCursor();
729
+
730
+        if ($data === false) {
731
+            throw new ShareNotFound('Can not find share with ID: ' . $id);
732
+        }
733
+
734
+        try {
735
+            $share = $this->createShareObject($data);
736
+        } catch (InvalidShare $e) {
737
+            throw new ShareNotFound();
738
+        }
739
+
740
+        return $share;
741
+    }
742
+
743
+    /**
744
+     * Get shares for a given path
745
+     *
746
+     * @param \OCP\Files\Node $path
747
+     * @return IShare[]
748
+     */
749
+    public function getSharesByPath(Node $path) {
750
+        $qb = $this->dbConnection->getQueryBuilder();
751
+
752
+        // get federated user shares
753
+        $cursor = $qb->select('*')
754
+            ->from('share')
755
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
756
+            ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
757
+            ->execute();
758
+
759
+        $shares = [];
760
+        while($data = $cursor->fetch()) {
761
+            $shares[] = $this->createShareObject($data);
762
+        }
763
+        $cursor->closeCursor();
764
+
765
+        return $shares;
766
+    }
767
+
768
+    /**
769
+     * @inheritdoc
770
+     */
771
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
772
+        /** @var IShare[] $shares */
773
+        $shares = [];
774
+
775
+        //Get shares directly with this user
776
+        $qb = $this->dbConnection->getQueryBuilder();
777
+        $qb->select('*')
778
+            ->from('share');
779
+
780
+        // Order by id
781
+        $qb->orderBy('id');
782
+
783
+        // Set limit and offset
784
+        if ($limit !== -1) {
785
+            $qb->setMaxResults($limit);
786
+        }
787
+        $qb->setFirstResult($offset);
788
+
789
+        $qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
790
+        $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
791
+
792
+        // Filter by node if provided
793
+        if ($node !== null) {
794
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
795
+        }
796
+
797
+        $cursor = $qb->execute();
798
+
799
+        while($data = $cursor->fetch()) {
800
+            $shares[] = $this->createShareObject($data);
801
+        }
802
+        $cursor->closeCursor();
803
+
804
+
805
+        return $shares;
806
+    }
807
+
808
+    /**
809
+     * Get a share by token
810
+     *
811
+     * @param string $token
812
+     * @return IShare
813
+     * @throws ShareNotFound
814
+     */
815
+    public function getShareByToken($token) {
816
+        $qb = $this->dbConnection->getQueryBuilder();
817
+
818
+        $cursor = $qb->select('*')
819
+            ->from('share')
820
+            ->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
821
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
822
+            ->execute();
823
+
824
+        $data = $cursor->fetch();
825
+
826
+        if ($data === false) {
827
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
828
+        }
829
+
830
+        try {
831
+            $share = $this->createShareObject($data);
832
+        } catch (InvalidShare $e) {
833
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
834
+        }
835
+
836
+        return $share;
837
+    }
838
+
839
+    /**
840
+     * get database row of a give share
841
+     *
842
+     * @param $id
843
+     * @return array
844
+     * @throws ShareNotFound
845
+     */
846
+    private function getRawShare($id) {
847
+
848
+        // Now fetch the inserted share and create a complete share object
849
+        $qb = $this->dbConnection->getQueryBuilder();
850
+        $qb->select('*')
851
+            ->from('share')
852
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
853
+
854
+        $cursor = $qb->execute();
855
+        $data = $cursor->fetch();
856
+        $cursor->closeCursor();
857
+
858
+        if ($data === false) {
859
+            throw new ShareNotFound;
860
+        }
861
+
862
+        return $data;
863
+    }
864
+
865
+    /**
866
+     * Create a share object from an database row
867
+     *
868
+     * @param array $data
869
+     * @return IShare
870
+     * @throws InvalidShare
871
+     * @throws ShareNotFound
872
+     */
873
+    private function createShareObject($data) {
874
+
875
+        $share = new Share($this->rootFolder, $this->userManager);
876
+        $share->setId((int)$data['id'])
877
+            ->setShareType((int)$data['share_type'])
878
+            ->setPermissions((int)$data['permissions'])
879
+            ->setTarget($data['file_target'])
880
+            ->setMailSend((bool)$data['mail_send'])
881
+            ->setToken($data['token']);
882
+
883
+        $shareTime = new \DateTime();
884
+        $shareTime->setTimestamp((int)$data['stime']);
885
+        $share->setShareTime($shareTime);
886
+        $share->setSharedWith($data['share_with']);
887
+
888
+        if ($data['uid_initiator'] !== null) {
889
+            $share->setShareOwner($data['uid_owner']);
890
+            $share->setSharedBy($data['uid_initiator']);
891
+        } else {
892
+            //OLD SHARE
893
+            $share->setSharedBy($data['uid_owner']);
894
+            $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
895
+
896
+            $owner = $path->getOwner();
897
+            $share->setShareOwner($owner->getUID());
898
+        }
899
+
900
+        $share->setNodeId((int)$data['file_source']);
901
+        $share->setNodeType($data['item_type']);
902
+
903
+        $share->setProviderId($this->identifier());
904
+
905
+        return $share;
906
+    }
907
+
908
+    /**
909
+     * Get the node with file $id for $user
910
+     *
911
+     * @param string $userId
912
+     * @param int $id
913
+     * @return \OCP\Files\File|\OCP\Files\Folder
914
+     * @throws InvalidShare
915
+     */
916
+    private function getNode($userId, $id) {
917
+        try {
918
+            $userFolder = $this->rootFolder->getUserFolder($userId);
919
+        } catch (NotFoundException $e) {
920
+            throw new InvalidShare();
921
+        }
922
+
923
+        $nodes = $userFolder->getById($id);
924
+
925
+        if (empty($nodes)) {
926
+            throw new InvalidShare();
927
+        }
928
+
929
+        return $nodes[0];
930
+    }
931
+
932
+    /**
933
+     * A user is deleted from the system
934
+     * So clean up the relevant shares.
935
+     *
936
+     * @param string $uid
937
+     * @param int $shareType
938
+     */
939
+    public function userDeleted($uid, $shareType) {
940
+        //TODO: probabaly a good idea to send unshare info to remote servers
941
+
942
+        $qb = $this->dbConnection->getQueryBuilder();
943
+
944
+        $qb->delete('share')
945
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
946
+            ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
947
+            ->execute();
948
+    }
949
+
950
+    /**
951
+     * This provider does not handle groups
952
+     *
953
+     * @param string $gid
954
+     */
955
+    public function groupDeleted($gid) {
956
+        // We don't handle groups here
957
+    }
958
+
959
+    /**
960
+     * This provider does not handle groups
961
+     *
962
+     * @param string $uid
963
+     * @param string $gid
964
+     */
965
+    public function userDeletedFromGroup($uid, $gid) {
966
+        // We don't handle groups here
967
+    }
968
+
969
+    /**
970
+     * check if users from other Nextcloud instances are allowed to mount public links share by this instance
971
+     *
972
+     * @return bool
973
+     */
974
+    public function isOutgoingServer2serverShareEnabled() {
975
+        if ($this->gsConfig->onlyInternalFederation()) {
976
+            return false;
977
+        }
978
+        $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
979
+        return ($result === 'yes');
980
+    }
981
+
982
+    /**
983
+     * check if users are allowed to mount public links from other Nextclouds
984
+     *
985
+     * @return bool
986
+     */
987
+    public function isIncomingServer2serverShareEnabled() {
988
+        if ($this->gsConfig->onlyInternalFederation()) {
989
+            return false;
990
+        }
991
+        $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
992
+        return ($result === 'yes');
993
+    }
994
+
995
+
996
+    /**
997
+     * check if users from other Nextcloud instances are allowed to send federated group shares
998
+     *
999
+     * @return bool
1000
+     */
1001
+    public function isOutgoingServer2serverGroupShareEnabled() {
1002
+        if ($this->gsConfig->onlyInternalFederation()) {
1003
+            return false;
1004
+        }
1005
+        $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no');
1006
+        return ($result === 'yes');
1007
+    }
1008
+
1009
+    /**
1010
+     * check if users are allowed to receive federated group shares
1011
+     *
1012
+     * @return bool
1013
+     */
1014
+    public function isIncomingServer2serverGroupShareEnabled() {
1015
+        if ($this->gsConfig->onlyInternalFederation()) {
1016
+            return false;
1017
+        }
1018
+        $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no');
1019
+        return ($result === 'yes');
1020
+    }
1021
+
1022
+    /**
1023
+     * check if federated group sharing is supported, therefore the OCM API need to be enabled
1024
+     *
1025
+     * @return bool
1026
+     */
1027
+    public function isFederatedGroupSharingSupported() {
1028
+        return $this->cloudFederationProviderManager->isReady();
1029
+    }
1030
+
1031
+    /**
1032
+     * Check if querying sharees on the lookup server is enabled
1033
+     *
1034
+     * @return bool
1035
+     */
1036
+    public function isLookupServerQueriesEnabled() {
1037
+        // in a global scale setup we should always query the lookup server
1038
+        if ($this->gsConfig->isGlobalScaleEnabled()) {
1039
+            return true;
1040
+        }
1041
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
1042
+        return ($result === 'yes');
1043
+    }
1044
+
1045
+
1046
+    /**
1047
+     * Check if it is allowed to publish user specific data to the lookup server
1048
+     *
1049
+     * @return bool
1050
+     */
1051
+    public function isLookupServerUploadEnabled() {
1052
+        // in a global scale setup the admin is responsible to keep the lookup server up-to-date
1053
+        if ($this->gsConfig->isGlobalScaleEnabled()) {
1054
+            return false;
1055
+        }
1056
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
1057
+        return ($result === 'yes');
1058
+    }
1059
+
1060
+    /**
1061
+     * @inheritdoc
1062
+     */
1063
+    public function getAccessList($nodes, $currentAccess) {
1064
+        $ids = [];
1065
+        foreach ($nodes as $node) {
1066
+            $ids[] = $node->getId();
1067
+        }
1068
+
1069
+        $qb = $this->dbConnection->getQueryBuilder();
1070
+        $qb->select('share_with', 'token', 'file_source')
1071
+            ->from('share')
1072
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
1073
+            ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1074
+            ->andWhere($qb->expr()->orX(
1075
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1076
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1077
+            ));
1078
+        $cursor = $qb->execute();
1079
+
1080
+        if ($currentAccess === false) {
1081
+            $remote = $cursor->fetch() !== false;
1082
+            $cursor->closeCursor();
1083
+
1084
+            return ['remote' => $remote];
1085
+        }
1086
+
1087
+        $remote = [];
1088
+        while ($row = $cursor->fetch()) {
1089
+            $remote[$row['share_with']] = [
1090
+                'node_id' => $row['file_source'],
1091
+                'token' => $row['token'],
1092
+            ];
1093
+        }
1094
+        $cursor->closeCursor();
1095
+
1096
+        return ['remote' => $remote];
1097
+    }
1098 1098
 }
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -214,7 +214,7 @@  discard block
 block discarded – undo
214 214
 		if ($remoteShare) {
215 215
 			try {
216 216
 				$ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
217
-				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType);
217
+				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_'.time(), $shareType);
218 218
 				$share->setId($shareId);
219 219
 				list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
220 220
 				// remote share was create successfully if we get a valid token as return
@@ -296,7 +296,7 @@  discard block
 block discarded – undo
296 296
 			$failure = true;
297 297
 		}
298 298
 
299
-		if($failure) {
299
+		if ($failure) {
300 300
 			$this->removeShareFromTableById($shareId);
301 301
 			$message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable or uses a self-signed certificate.',
302 302
 				[$share->getNode()->getName(), $share->getSharedWith()]);
@@ -348,7 +348,7 @@  discard block
 block discarded – undo
348 348
 			->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
349 349
 		$result = $query->execute()->fetchAll();
350 350
 
351
-		if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
351
+		if (isset($result[0]) && (int) $result[0]['remote_id'] > 0) {
352 352
 			return $result[0];
353 353
 		}
354 354
 
@@ -391,7 +391,7 @@  discard block
 block discarded – undo
391 391
 		$qb->execute();
392 392
 		$id = $qb->getLastInsertId();
393 393
 
394
-		return (int)$id;
394
+		return (int) $id;
395 395
 	}
396 396
 
397 397
 	/**
@@ -481,14 +481,14 @@  discard block
 block discarded – undo
481 481
 	public function getRemoteId(IShare $share) {
482 482
 		$query = $this->dbConnection->getQueryBuilder();
483 483
 		$query->select('remote_id')->from('federated_reshares')
484
-			->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
484
+			->where($query->expr()->eq('share_id', $query->createNamedParameter((int) $share->getId())));
485 485
 		$data = $query->execute()->fetch();
486 486
 
487 487
 		if (!is_array($data) || !isset($data['remote_id'])) {
488 488
 			throw new ShareNotFound();
489 489
 		}
490 490
 
491
-		return (int)$data['remote_id'];
491
+		return (int) $data['remote_id'];
492 492
 	}
493 493
 
494 494
 	/**
@@ -519,7 +519,7 @@  discard block
 block discarded – undo
519 519
 			->orderBy('id');
520 520
 
521 521
 		$cursor = $qb->execute();
522
-		while($data = $cursor->fetch()) {
522
+		while ($data = $cursor->fetch()) {
523 523
 			$children[] = $this->createShareObject($data);
524 524
 		}
525 525
 		$cursor->closeCursor();
@@ -641,7 +641,7 @@  discard block
 block discarded – undo
641 641
 			);
642 642
 		}
643 643
 
644
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
644
+		$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
645 645
 		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
646 646
 
647 647
 		$qb->orderBy('id');
@@ -704,7 +704,7 @@  discard block
 block discarded – undo
704 704
 
705 705
 		$cursor = $qb->execute();
706 706
 		$shares = [];
707
-		while($data = $cursor->fetch()) {
707
+		while ($data = $cursor->fetch()) {
708 708
 			$shares[] = $this->createShareObject($data);
709 709
 		}
710 710
 		$cursor->closeCursor();
@@ -728,7 +728,7 @@  discard block
 block discarded – undo
728 728
 		$cursor->closeCursor();
729 729
 
730 730
 		if ($data === false) {
731
-			throw new ShareNotFound('Can not find share with ID: ' . $id);
731
+			throw new ShareNotFound('Can not find share with ID: '.$id);
732 732
 		}
733 733
 
734 734
 		try {
@@ -757,7 +757,7 @@  discard block
 block discarded – undo
757 757
 			->execute();
758 758
 
759 759
 		$shares = [];
760
-		while($data = $cursor->fetch()) {
760
+		while ($data = $cursor->fetch()) {
761 761
 			$shares[] = $this->createShareObject($data);
762 762
 		}
763 763
 		$cursor->closeCursor();
@@ -796,7 +796,7 @@  discard block
 block discarded – undo
796 796
 
797 797
 		$cursor = $qb->execute();
798 798
 
799
-		while($data = $cursor->fetch()) {
799
+		while ($data = $cursor->fetch()) {
800 800
 			$shares[] = $this->createShareObject($data);
801 801
 		}
802 802
 		$cursor->closeCursor();
@@ -873,15 +873,15 @@  discard block
 block discarded – undo
873 873
 	private function createShareObject($data) {
874 874
 
875 875
 		$share = new Share($this->rootFolder, $this->userManager);
876
-		$share->setId((int)$data['id'])
877
-			->setShareType((int)$data['share_type'])
878
-			->setPermissions((int)$data['permissions'])
876
+		$share->setId((int) $data['id'])
877
+			->setShareType((int) $data['share_type'])
878
+			->setPermissions((int) $data['permissions'])
879 879
 			->setTarget($data['file_target'])
880
-			->setMailSend((bool)$data['mail_send'])
880
+			->setMailSend((bool) $data['mail_send'])
881 881
 			->setToken($data['token']);
882 882
 
883 883
 		$shareTime = new \DateTime();
884
-		$shareTime->setTimestamp((int)$data['stime']);
884
+		$shareTime->setTimestamp((int) $data['stime']);
885 885
 		$share->setShareTime($shareTime);
886 886
 		$share->setSharedWith($data['share_with']);
887 887
 
@@ -891,13 +891,13 @@  discard block
 block discarded – undo
891 891
 		} else {
892 892
 			//OLD SHARE
893 893
 			$share->setSharedBy($data['uid_owner']);
894
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
894
+			$path = $this->getNode($share->getSharedBy(), (int) $data['file_source']);
895 895
 
896 896
 			$owner = $path->getOwner();
897 897
 			$share->setShareOwner($owner->getUID());
898 898
 		}
899 899
 
900
-		$share->setNodeId((int)$data['file_source']);
900
+		$share->setNodeId((int) $data['file_source']);
901 901
 		$share->setNodeType($data['item_type']);
902 902
 
903 903
 		$share->setProviderId($this->identifier());
Please login to merge, or discard this patch.
apps/federatedfilesharing/lib/Notifications.php 1 patch
Indentation   +409 added lines, -409 removed lines patch added patch discarded remove patch
@@ -33,413 +33,413 @@
 block discarded – undo
33 33
 use OCP\OCS\IDiscoveryService;
34 34
 
35 35
 class Notifications {
36
-	const RESPONSE_FORMAT = 'json'; // default response format for ocs calls
37
-
38
-	/** @var AddressHandler */
39
-	private $addressHandler;
40
-
41
-	/** @var IClientService */
42
-	private $httpClientService;
43
-
44
-	/** @var IDiscoveryService */
45
-	private $discoveryService;
46
-
47
-	/** @var IJobList  */
48
-	private $jobList;
49
-
50
-	/** @var ICloudFederationProviderManager */
51
-	private $federationProviderManager;
52
-
53
-	/** @var ICloudFederationFactory */
54
-	private $cloudFederationFactory;
55
-
56
-	/**
57
-	 * @param AddressHandler $addressHandler
58
-	 * @param IClientService $httpClientService
59
-	 * @param IDiscoveryService $discoveryService
60
-	 * @param IJobList $jobList
61
-	 * @param ICloudFederationProviderManager $federationProviderManager
62
-	 * @param ICloudFederationFactory $cloudFederationFactory
63
-	 */
64
-	public function __construct(
65
-		AddressHandler $addressHandler,
66
-		IClientService $httpClientService,
67
-		IDiscoveryService $discoveryService,
68
-		IJobList $jobList,
69
-		ICloudFederationProviderManager $federationProviderManager,
70
-		ICloudFederationFactory $cloudFederationFactory
71
-	) {
72
-		$this->addressHandler = $addressHandler;
73
-		$this->httpClientService = $httpClientService;
74
-		$this->discoveryService = $discoveryService;
75
-		$this->jobList = $jobList;
76
-		$this->federationProviderManager = $federationProviderManager;
77
-		$this->cloudFederationFactory = $cloudFederationFactory;
78
-	}
79
-
80
-	/**
81
-	 * send server-to-server share to remote server
82
-	 *
83
-	 * @param string $token
84
-	 * @param string $shareWith
85
-	 * @param string $name
86
-	 * @param int $remote_id
87
-	 * @param string $owner
88
-	 * @param string $ownerFederatedId
89
-	 * @param string $sharedBy
90
-	 * @param string $sharedByFederatedId
91
-	 * @param int $shareType (can be a remote user or group share)
92
-	 * @return bool
93
-	 * @throws \OC\HintException
94
-	 * @throws \OC\ServerNotAvailableException
95
-	 */
96
-	public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId, $shareType) {
97
-
98
-		list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith);
99
-
100
-		if ($user && $remote) {
101
-			$local = $this->addressHandler->generateRemoteURL();
102
-
103
-			$fields = array(
104
-				'shareWith' => $user,
105
-				'token' => $token,
106
-				'name' => $name,
107
-				'remoteId' => $remote_id,
108
-				'owner' => $owner,
109
-				'ownerFederatedId' => $ownerFederatedId,
110
-				'sharedBy' => $sharedBy,
111
-				'sharedByFederatedId' => $sharedByFederatedId,
112
-				'remote' => $local,
113
-				'shareType' => $shareType
114
-			);
115
-
116
-			$result = $this->tryHttpPostToShareEndpoint($remote, '', $fields);
117
-			$status = json_decode($result['result'], true);
118
-
119
-			$ocsStatus = isset($status['ocs']);
120
-			$ocsSuccess = $ocsStatus && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200);
121
-
122
-			if ($result['success'] && (!$ocsStatus ||$ocsSuccess)) {
123
-				\OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
124
-				return true;
125
-			}
126
-
127
-		}
128
-
129
-		return false;
130
-	}
131
-
132
-	/**
133
-	 * ask owner to re-share the file with the given user
134
-	 *
135
-	 * @param string $token
136
-	 * @param int $id remote Id
137
-	 * @param int $shareId internal share Id
138
-	 * @param string $remote remote address of the owner
139
-	 * @param string $shareWith
140
-	 * @param int $permission
141
-	 * @param string $filename
142
-	 * @return bool
143
-	 * @throws \OC\HintException
144
-	 * @throws \OC\ServerNotAvailableException
145
-	 */
146
-	public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission, $filename) {
147
-
148
-		$fields = array(
149
-			'shareWith' => $shareWith,
150
-			'token' => $token,
151
-			'permission' => $permission,
152
-			'remoteId' => $shareId,
153
-		);
154
-
155
-		$ocmFields = $fields;
156
-		$ocmFields['remoteId'] = $id;
157
-		$ocmFields['localId'] = $shareId;
158
-		$ocmFields['name'] = $filename;
159
-
160
-		$ocmResult = $this->tryOCMEndPoint($remote, $ocmFields, 'reshare');
161
-		if (is_array($ocmResult) && isset($ocmResult['token']) && isset($ocmResult['providerId'])) {
162
-			return [$ocmResult['token'], $ocmResult['providerId']];
163
-		}
164
-
165
-		$result = $this->tryLegacyEndPoint(rtrim($remote, '/'), '/' . $id . '/reshare', $fields);
166
-		$status = json_decode($result['result'], true);
167
-
168
-		$httpRequestSuccessful = $result['success'];
169
-		$ocsCallSuccessful = $status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200;
170
-		$validToken = isset($status['ocs']['data']['token']) && is_string($status['ocs']['data']['token']);
171
-		$validRemoteId = isset($status['ocs']['data']['remoteId']);
172
-
173
-		if ($httpRequestSuccessful && $ocsCallSuccessful && $validToken && $validRemoteId) {
174
-			return [
175
-				$status['ocs']['data']['token'],
176
-				(int)$status['ocs']['data']['remoteId']
177
-			];
178
-		}
179
-
180
-		return false;
181
-	}
182
-
183
-	/**
184
-	 * send server-to-server unshare to remote server
185
-	 *
186
-	 * @param string $remote url
187
-	 * @param int $id share id
188
-	 * @param string $token
189
-	 * @return bool
190
-	 */
191
-	public function sendRemoteUnShare($remote, $id, $token) {
192
-		$this->sendUpdateToRemote($remote, $id, $token, 'unshare');
193
-	}
194
-
195
-	/**
196
-	 * send server-to-server unshare to remote server
197
-	 *
198
-	 * @param string $remote url
199
-	 * @param int $id share id
200
-	 * @param string $token
201
-	 * @return bool
202
-	 */
203
-	public function sendRevokeShare($remote, $id, $token) {
204
-		$this->sendUpdateToRemote($remote, $id, $token, 'reshare_undo');
205
-	}
206
-
207
-	/**
208
-	 * send notification to remote server if the permissions was changed
209
-	 *
210
-	 * @param string $remote
211
-	 * @param int $remoteId
212
-	 * @param string $token
213
-	 * @param int $permissions
214
-	 * @return bool
215
-	 */
216
-	public function sendPermissionChange($remote, $remoteId, $token, $permissions) {
217
-		$this->sendUpdateToRemote($remote, $remoteId, $token, 'permissions', ['permissions' => $permissions]);
218
-	}
219
-
220
-	/**
221
-	 * forward accept reShare to remote server
222
-	 *
223
-	 * @param string $remote
224
-	 * @param int $remoteId
225
-	 * @param string $token
226
-	 */
227
-	public function sendAcceptShare($remote, $remoteId, $token) {
228
-		$this->sendUpdateToRemote($remote, $remoteId, $token, 'accept');
229
-	}
230
-
231
-	/**
232
-	 * forward decline reShare to remote server
233
-	 *
234
-	 * @param string $remote
235
-	 * @param int $remoteId
236
-	 * @param string $token
237
-	 */
238
-	public function sendDeclineShare($remote, $remoteId, $token) {
239
-		$this->sendUpdateToRemote($remote, $remoteId, $token, 'decline');
240
-	}
241
-
242
-	/**
243
-	 * inform remote server whether server-to-server share was accepted/declined
244
-	 *
245
-	 * @param string $remote
246
-	 * @param string $token
247
-	 * @param int $remoteId Share id on the remote host
248
-	 * @param string $action possible actions: accept, decline, unshare, revoke, permissions
249
-	 * @param array $data
250
-	 * @param int $try
251
-	 * @return boolean
252
-	 */
253
-	public function sendUpdateToRemote($remote, $remoteId, $token, $action, $data = [], $try = 0) {
254
-
255
-		$fields = [
256
-			'token' => $token,
257
-			'remoteId' => $remoteId
258
-			];
259
-		foreach ($data as $key => $value) {
260
-			$fields[$key] = $value;
261
-		}
262
-
263
-		$result = $this->tryHttpPostToShareEndpoint(rtrim($remote, '/'), '/' . $remoteId . '/' . $action, $fields, $action);
264
-		$status = json_decode($result['result'], true);
265
-
266
-		if ($result['success'] &&
267
-			($status['ocs']['meta']['statuscode'] === 100 ||
268
-				$status['ocs']['meta']['statuscode'] === 200
269
-			)
270
-		) {
271
-			return true;
272
-		} elseif ($try === 0) {
273
-			// only add new job on first try
274
-			$this->jobList->add('OCA\FederatedFileSharing\BackgroundJob\RetryJob',
275
-				[
276
-					'remote' => $remote,
277
-					'remoteId' => $remoteId,
278
-					'token' => $token,
279
-					'action' => $action,
280
-					'data' => json_encode($data),
281
-					'try' => $try,
282
-					'lastRun' => $this->getTimestamp()
283
-				]
284
-			);
285
-		}
286
-
287
-		return false;
288
-	}
289
-
290
-
291
-	/**
292
-	 * return current timestamp
293
-	 *
294
-	 * @return int
295
-	 */
296
-	protected function getTimestamp() {
297
-		return time();
298
-	}
299
-
300
-	/**
301
-	 * try http post with the given protocol, if no protocol is given we pick
302
-	 * the secure one (https)
303
-	 *
304
-	 * @param string $remoteDomain
305
-	 * @param string $urlSuffix
306
-	 * @param array $fields post parameters
307
-	 * @param string $action define the action (possible values: share, reshare, accept, decline, unshare, revoke, permissions)
308
-	 * @return array
309
-	 * @throws \Exception
310
-	 */
311
-	protected function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields, $action="share") {
312
-
313
-		if ($this->addressHandler->urlContainProtocol($remoteDomain) === false) {
314
-			$remoteDomain = 'https://' . $remoteDomain;
315
-		}
316
-
317
-		$result = [
318
-			'success' => false,
319
-			'result' => '',
320
-		];
321
-
322
-		// if possible we use the new OCM API
323
-		$ocmResult = $this->tryOCMEndPoint($remoteDomain, $fields, $action);
324
-		if (is_array($ocmResult)) {
325
-			$result['success'] = true;
326
-			$result['result'] = json_encode([
327
-				'ocs' => ['meta' => ['statuscode' => 200]]]);
328
-			return $result;
329
-		}
330
-
331
-		return $this->tryLegacyEndPoint($remoteDomain, $urlSuffix, $fields);
332
-	}
333
-
334
-	/**
335
-	 * try old federated sharing API if the OCM api doesn't work
336
-	 *
337
-	 * @param $remoteDomain
338
-	 * @param $urlSuffix
339
-	 * @param array $fields
340
-	 * @return mixed
341
-	 * @throws \Exception
342
-	 */
343
-	protected function tryLegacyEndPoint($remoteDomain, $urlSuffix, array $fields) {
344
-
345
-		$result = [
346
-			'success' => false,
347
-			'result' => '',
348
-		];
349
-
350
-		// Fall back to old API
351
-		$client = $this->httpClientService->newClient();
352
-		$federationEndpoints = $this->discoveryService->discover($remoteDomain, 'FEDERATED_SHARING');
353
-		$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
354
-		try {
355
-			$response = $client->post($remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, [
356
-				'body' => $fields,
357
-				'timeout' => 10,
358
-				'connect_timeout' => 10,
359
-			]);
360
-			$result['result'] = $response->getBody();
361
-			$result['success'] = true;
362
-		} catch (\Exception $e) {
363
-			// if flat re-sharing is not supported by the remote server
364
-			// we re-throw the exception and fall back to the old behaviour.
365
-			// (flat re-shares has been introduced in Nextcloud 9.1)
366
-			if ($e->getCode() === Http::STATUS_INTERNAL_SERVER_ERROR) {
367
-				throw $e;
368
-			}
369
-		}
370
-
371
-		return $result;
372
-
373
-	}
374
-
375
-	/**
376
-	 * send action regarding federated sharing to the remote server using the OCM API
377
-	 *
378
-	 * @param $remoteDomain
379
-	 * @param $fields
380
-	 * @param $action
381
-	 *
382
-	 * @return bool
383
-	 */
384
-	protected function tryOCMEndPoint($remoteDomain, $fields, $action) {
385
-		switch ($action) {
386
-			case 'share':
387
-				$share = $this->cloudFederationFactory->getCloudFederationShare(
388
-					$fields['shareWith'] . '@' . $remoteDomain,
389
-					$fields['name'],
390
-					'',
391
-					$fields['remoteId'],
392
-					$fields['ownerFederatedId'],
393
-					$fields['owner'],
394
-					$fields['sharedByFederatedId'],
395
-					$fields['sharedBy'],
396
-					$fields['token'],
397
-					$fields['shareType'],
398
-					'file'
399
-				);
400
-				return $this->federationProviderManager->sendShare($share);
401
-			case 'reshare':
402
-				// ask owner to reshare a file
403
-				$notification = $this->cloudFederationFactory->getCloudFederationNotification();
404
-				$notification->setMessage('REQUEST_RESHARE',
405
-					'file',
406
-					$fields['remoteId'],
407
-					[
408
-						'sharedSecret' => $fields['token'],
409
-						'shareWith' => $fields['shareWith'],
410
-						'senderId' => $fields['localId'],
411
-						'shareType' => $fields['shareType'],
412
-						'message' => 'Ask owner to reshare the file'
413
-					]
414
-				);
415
-				return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
416
-			case 'unshare':
417
-				//owner unshares the file from the recipient again
418
-				$notification = $this->cloudFederationFactory->getCloudFederationNotification();
419
-				$notification->setMessage('SHARE_UNSHARED',
420
-					'file',
421
-					$fields['remoteId'],
422
-					[
423
-						'sharedSecret' => $fields['token'],
424
-						'messgage' => 'file is no longer shared with you'
425
-					]
426
-				);
427
-				return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
428
-			case 'reshare_undo':
429
-				// if a reshare was unshared we send the information to the initiator/owner
430
-				$notification = $this->cloudFederationFactory->getCloudFederationNotification();
431
-				$notification->setMessage('RESHARE_UNDO',
432
-					'file',
433
-					$fields['remoteId'],
434
-					[
435
-						'sharedSecret' => $fields['token'],
436
-						'message' => 'reshare was revoked'
437
-					]
438
-				);
439
-				return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
440
-		}
441
-
442
-		return false;
443
-
444
-	}
36
+    const RESPONSE_FORMAT = 'json'; // default response format for ocs calls
37
+
38
+    /** @var AddressHandler */
39
+    private $addressHandler;
40
+
41
+    /** @var IClientService */
42
+    private $httpClientService;
43
+
44
+    /** @var IDiscoveryService */
45
+    private $discoveryService;
46
+
47
+    /** @var IJobList  */
48
+    private $jobList;
49
+
50
+    /** @var ICloudFederationProviderManager */
51
+    private $federationProviderManager;
52
+
53
+    /** @var ICloudFederationFactory */
54
+    private $cloudFederationFactory;
55
+
56
+    /**
57
+     * @param AddressHandler $addressHandler
58
+     * @param IClientService $httpClientService
59
+     * @param IDiscoveryService $discoveryService
60
+     * @param IJobList $jobList
61
+     * @param ICloudFederationProviderManager $federationProviderManager
62
+     * @param ICloudFederationFactory $cloudFederationFactory
63
+     */
64
+    public function __construct(
65
+        AddressHandler $addressHandler,
66
+        IClientService $httpClientService,
67
+        IDiscoveryService $discoveryService,
68
+        IJobList $jobList,
69
+        ICloudFederationProviderManager $federationProviderManager,
70
+        ICloudFederationFactory $cloudFederationFactory
71
+    ) {
72
+        $this->addressHandler = $addressHandler;
73
+        $this->httpClientService = $httpClientService;
74
+        $this->discoveryService = $discoveryService;
75
+        $this->jobList = $jobList;
76
+        $this->federationProviderManager = $federationProviderManager;
77
+        $this->cloudFederationFactory = $cloudFederationFactory;
78
+    }
79
+
80
+    /**
81
+     * send server-to-server share to remote server
82
+     *
83
+     * @param string $token
84
+     * @param string $shareWith
85
+     * @param string $name
86
+     * @param int $remote_id
87
+     * @param string $owner
88
+     * @param string $ownerFederatedId
89
+     * @param string $sharedBy
90
+     * @param string $sharedByFederatedId
91
+     * @param int $shareType (can be a remote user or group share)
92
+     * @return bool
93
+     * @throws \OC\HintException
94
+     * @throws \OC\ServerNotAvailableException
95
+     */
96
+    public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId, $shareType) {
97
+
98
+        list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith);
99
+
100
+        if ($user && $remote) {
101
+            $local = $this->addressHandler->generateRemoteURL();
102
+
103
+            $fields = array(
104
+                'shareWith' => $user,
105
+                'token' => $token,
106
+                'name' => $name,
107
+                'remoteId' => $remote_id,
108
+                'owner' => $owner,
109
+                'ownerFederatedId' => $ownerFederatedId,
110
+                'sharedBy' => $sharedBy,
111
+                'sharedByFederatedId' => $sharedByFederatedId,
112
+                'remote' => $local,
113
+                'shareType' => $shareType
114
+            );
115
+
116
+            $result = $this->tryHttpPostToShareEndpoint($remote, '', $fields);
117
+            $status = json_decode($result['result'], true);
118
+
119
+            $ocsStatus = isset($status['ocs']);
120
+            $ocsSuccess = $ocsStatus && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200);
121
+
122
+            if ($result['success'] && (!$ocsStatus ||$ocsSuccess)) {
123
+                \OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
124
+                return true;
125
+            }
126
+
127
+        }
128
+
129
+        return false;
130
+    }
131
+
132
+    /**
133
+     * ask owner to re-share the file with the given user
134
+     *
135
+     * @param string $token
136
+     * @param int $id remote Id
137
+     * @param int $shareId internal share Id
138
+     * @param string $remote remote address of the owner
139
+     * @param string $shareWith
140
+     * @param int $permission
141
+     * @param string $filename
142
+     * @return bool
143
+     * @throws \OC\HintException
144
+     * @throws \OC\ServerNotAvailableException
145
+     */
146
+    public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission, $filename) {
147
+
148
+        $fields = array(
149
+            'shareWith' => $shareWith,
150
+            'token' => $token,
151
+            'permission' => $permission,
152
+            'remoteId' => $shareId,
153
+        );
154
+
155
+        $ocmFields = $fields;
156
+        $ocmFields['remoteId'] = $id;
157
+        $ocmFields['localId'] = $shareId;
158
+        $ocmFields['name'] = $filename;
159
+
160
+        $ocmResult = $this->tryOCMEndPoint($remote, $ocmFields, 'reshare');
161
+        if (is_array($ocmResult) && isset($ocmResult['token']) && isset($ocmResult['providerId'])) {
162
+            return [$ocmResult['token'], $ocmResult['providerId']];
163
+        }
164
+
165
+        $result = $this->tryLegacyEndPoint(rtrim($remote, '/'), '/' . $id . '/reshare', $fields);
166
+        $status = json_decode($result['result'], true);
167
+
168
+        $httpRequestSuccessful = $result['success'];
169
+        $ocsCallSuccessful = $status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200;
170
+        $validToken = isset($status['ocs']['data']['token']) && is_string($status['ocs']['data']['token']);
171
+        $validRemoteId = isset($status['ocs']['data']['remoteId']);
172
+
173
+        if ($httpRequestSuccessful && $ocsCallSuccessful && $validToken && $validRemoteId) {
174
+            return [
175
+                $status['ocs']['data']['token'],
176
+                (int)$status['ocs']['data']['remoteId']
177
+            ];
178
+        }
179
+
180
+        return false;
181
+    }
182
+
183
+    /**
184
+     * send server-to-server unshare to remote server
185
+     *
186
+     * @param string $remote url
187
+     * @param int $id share id
188
+     * @param string $token
189
+     * @return bool
190
+     */
191
+    public function sendRemoteUnShare($remote, $id, $token) {
192
+        $this->sendUpdateToRemote($remote, $id, $token, 'unshare');
193
+    }
194
+
195
+    /**
196
+     * send server-to-server unshare to remote server
197
+     *
198
+     * @param string $remote url
199
+     * @param int $id share id
200
+     * @param string $token
201
+     * @return bool
202
+     */
203
+    public function sendRevokeShare($remote, $id, $token) {
204
+        $this->sendUpdateToRemote($remote, $id, $token, 'reshare_undo');
205
+    }
206
+
207
+    /**
208
+     * send notification to remote server if the permissions was changed
209
+     *
210
+     * @param string $remote
211
+     * @param int $remoteId
212
+     * @param string $token
213
+     * @param int $permissions
214
+     * @return bool
215
+     */
216
+    public function sendPermissionChange($remote, $remoteId, $token, $permissions) {
217
+        $this->sendUpdateToRemote($remote, $remoteId, $token, 'permissions', ['permissions' => $permissions]);
218
+    }
219
+
220
+    /**
221
+     * forward accept reShare to remote server
222
+     *
223
+     * @param string $remote
224
+     * @param int $remoteId
225
+     * @param string $token
226
+     */
227
+    public function sendAcceptShare($remote, $remoteId, $token) {
228
+        $this->sendUpdateToRemote($remote, $remoteId, $token, 'accept');
229
+    }
230
+
231
+    /**
232
+     * forward decline reShare to remote server
233
+     *
234
+     * @param string $remote
235
+     * @param int $remoteId
236
+     * @param string $token
237
+     */
238
+    public function sendDeclineShare($remote, $remoteId, $token) {
239
+        $this->sendUpdateToRemote($remote, $remoteId, $token, 'decline');
240
+    }
241
+
242
+    /**
243
+     * inform remote server whether server-to-server share was accepted/declined
244
+     *
245
+     * @param string $remote
246
+     * @param string $token
247
+     * @param int $remoteId Share id on the remote host
248
+     * @param string $action possible actions: accept, decline, unshare, revoke, permissions
249
+     * @param array $data
250
+     * @param int $try
251
+     * @return boolean
252
+     */
253
+    public function sendUpdateToRemote($remote, $remoteId, $token, $action, $data = [], $try = 0) {
254
+
255
+        $fields = [
256
+            'token' => $token,
257
+            'remoteId' => $remoteId
258
+            ];
259
+        foreach ($data as $key => $value) {
260
+            $fields[$key] = $value;
261
+        }
262
+
263
+        $result = $this->tryHttpPostToShareEndpoint(rtrim($remote, '/'), '/' . $remoteId . '/' . $action, $fields, $action);
264
+        $status = json_decode($result['result'], true);
265
+
266
+        if ($result['success'] &&
267
+            ($status['ocs']['meta']['statuscode'] === 100 ||
268
+                $status['ocs']['meta']['statuscode'] === 200
269
+            )
270
+        ) {
271
+            return true;
272
+        } elseif ($try === 0) {
273
+            // only add new job on first try
274
+            $this->jobList->add('OCA\FederatedFileSharing\BackgroundJob\RetryJob',
275
+                [
276
+                    'remote' => $remote,
277
+                    'remoteId' => $remoteId,
278
+                    'token' => $token,
279
+                    'action' => $action,
280
+                    'data' => json_encode($data),
281
+                    'try' => $try,
282
+                    'lastRun' => $this->getTimestamp()
283
+                ]
284
+            );
285
+        }
286
+
287
+        return false;
288
+    }
289
+
290
+
291
+    /**
292
+     * return current timestamp
293
+     *
294
+     * @return int
295
+     */
296
+    protected function getTimestamp() {
297
+        return time();
298
+    }
299
+
300
+    /**
301
+     * try http post with the given protocol, if no protocol is given we pick
302
+     * the secure one (https)
303
+     *
304
+     * @param string $remoteDomain
305
+     * @param string $urlSuffix
306
+     * @param array $fields post parameters
307
+     * @param string $action define the action (possible values: share, reshare, accept, decline, unshare, revoke, permissions)
308
+     * @return array
309
+     * @throws \Exception
310
+     */
311
+    protected function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields, $action="share") {
312
+
313
+        if ($this->addressHandler->urlContainProtocol($remoteDomain) === false) {
314
+            $remoteDomain = 'https://' . $remoteDomain;
315
+        }
316
+
317
+        $result = [
318
+            'success' => false,
319
+            'result' => '',
320
+        ];
321
+
322
+        // if possible we use the new OCM API
323
+        $ocmResult = $this->tryOCMEndPoint($remoteDomain, $fields, $action);
324
+        if (is_array($ocmResult)) {
325
+            $result['success'] = true;
326
+            $result['result'] = json_encode([
327
+                'ocs' => ['meta' => ['statuscode' => 200]]]);
328
+            return $result;
329
+        }
330
+
331
+        return $this->tryLegacyEndPoint($remoteDomain, $urlSuffix, $fields);
332
+    }
333
+
334
+    /**
335
+     * try old federated sharing API if the OCM api doesn't work
336
+     *
337
+     * @param $remoteDomain
338
+     * @param $urlSuffix
339
+     * @param array $fields
340
+     * @return mixed
341
+     * @throws \Exception
342
+     */
343
+    protected function tryLegacyEndPoint($remoteDomain, $urlSuffix, array $fields) {
344
+
345
+        $result = [
346
+            'success' => false,
347
+            'result' => '',
348
+        ];
349
+
350
+        // Fall back to old API
351
+        $client = $this->httpClientService->newClient();
352
+        $federationEndpoints = $this->discoveryService->discover($remoteDomain, 'FEDERATED_SHARING');
353
+        $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
354
+        try {
355
+            $response = $client->post($remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, [
356
+                'body' => $fields,
357
+                'timeout' => 10,
358
+                'connect_timeout' => 10,
359
+            ]);
360
+            $result['result'] = $response->getBody();
361
+            $result['success'] = true;
362
+        } catch (\Exception $e) {
363
+            // if flat re-sharing is not supported by the remote server
364
+            // we re-throw the exception and fall back to the old behaviour.
365
+            // (flat re-shares has been introduced in Nextcloud 9.1)
366
+            if ($e->getCode() === Http::STATUS_INTERNAL_SERVER_ERROR) {
367
+                throw $e;
368
+            }
369
+        }
370
+
371
+        return $result;
372
+
373
+    }
374
+
375
+    /**
376
+     * send action regarding federated sharing to the remote server using the OCM API
377
+     *
378
+     * @param $remoteDomain
379
+     * @param $fields
380
+     * @param $action
381
+     *
382
+     * @return bool
383
+     */
384
+    protected function tryOCMEndPoint($remoteDomain, $fields, $action) {
385
+        switch ($action) {
386
+            case 'share':
387
+                $share = $this->cloudFederationFactory->getCloudFederationShare(
388
+                    $fields['shareWith'] . '@' . $remoteDomain,
389
+                    $fields['name'],
390
+                    '',
391
+                    $fields['remoteId'],
392
+                    $fields['ownerFederatedId'],
393
+                    $fields['owner'],
394
+                    $fields['sharedByFederatedId'],
395
+                    $fields['sharedBy'],
396
+                    $fields['token'],
397
+                    $fields['shareType'],
398
+                    'file'
399
+                );
400
+                return $this->federationProviderManager->sendShare($share);
401
+            case 'reshare':
402
+                // ask owner to reshare a file
403
+                $notification = $this->cloudFederationFactory->getCloudFederationNotification();
404
+                $notification->setMessage('REQUEST_RESHARE',
405
+                    'file',
406
+                    $fields['remoteId'],
407
+                    [
408
+                        'sharedSecret' => $fields['token'],
409
+                        'shareWith' => $fields['shareWith'],
410
+                        'senderId' => $fields['localId'],
411
+                        'shareType' => $fields['shareType'],
412
+                        'message' => 'Ask owner to reshare the file'
413
+                    ]
414
+                );
415
+                return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
416
+            case 'unshare':
417
+                //owner unshares the file from the recipient again
418
+                $notification = $this->cloudFederationFactory->getCloudFederationNotification();
419
+                $notification->setMessage('SHARE_UNSHARED',
420
+                    'file',
421
+                    $fields['remoteId'],
422
+                    [
423
+                        'sharedSecret' => $fields['token'],
424
+                        'messgage' => 'file is no longer shared with you'
425
+                    ]
426
+                );
427
+                return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
428
+            case 'reshare_undo':
429
+                // if a reshare was unshared we send the information to the initiator/owner
430
+                $notification = $this->cloudFederationFactory->getCloudFederationNotification();
431
+                $notification->setMessage('RESHARE_UNDO',
432
+                    'file',
433
+                    $fields['remoteId'],
434
+                    [
435
+                        'sharedSecret' => $fields['token'],
436
+                        'message' => 'reshare was revoked'
437
+                    ]
438
+                );
439
+                return $this->federationProviderManager->sendNotification($remoteDomain, $notification);
440
+        }
441
+
442
+        return false;
443
+
444
+    }
445 445
 }
Please login to merge, or discard this patch.