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