Passed
Push — master ( 0a9a5f...6b6049 )
by Julius
13:49 queued 12s
created
lib/private/Share20/Manager.php 1 patch
Indentation   +1878 added lines, -1878 removed lines patch added patch discarded remove patch
@@ -81,1903 +81,1903 @@
 block discarded – undo
81 81
  */
82 82
 class Manager implements IManager {
83 83
 
84
-	/** @var IProviderFactory */
85
-	private $factory;
86
-	/** @var ILogger */
87
-	private $logger;
88
-	/** @var IConfig */
89
-	private $config;
90
-	/** @var ISecureRandom */
91
-	private $secureRandom;
92
-	/** @var IHasher */
93
-	private $hasher;
94
-	/** @var IMountManager */
95
-	private $mountManager;
96
-	/** @var IGroupManager */
97
-	private $groupManager;
98
-	/** @var IL10N */
99
-	private $l;
100
-	/** @var IFactory */
101
-	private $l10nFactory;
102
-	/** @var IUserManager */
103
-	private $userManager;
104
-	/** @var IRootFolder */
105
-	private $rootFolder;
106
-	/** @var CappedMemoryCache */
107
-	private $sharingDisabledForUsersCache;
108
-	/** @var EventDispatcherInterface */
109
-	private $legacyDispatcher;
110
-	/** @var LegacyHooks */
111
-	private $legacyHooks;
112
-	/** @var IMailer */
113
-	private $mailer;
114
-	/** @var IURLGenerator */
115
-	private $urlGenerator;
116
-	/** @var \OC_Defaults */
117
-	private $defaults;
118
-	/** @var IEventDispatcher */
119
-	private $dispatcher;
120
-	private $userSession;
121
-
122
-	public function __construct(
123
-		ILogger $logger,
124
-		IConfig $config,
125
-		ISecureRandom $secureRandom,
126
-		IHasher $hasher,
127
-		IMountManager $mountManager,
128
-		IGroupManager $groupManager,
129
-		IL10N $l,
130
-		IFactory $l10nFactory,
131
-		IProviderFactory $factory,
132
-		IUserManager $userManager,
133
-		IRootFolder $rootFolder,
134
-		EventDispatcherInterface $legacyDispatcher,
135
-		IMailer $mailer,
136
-		IURLGenerator $urlGenerator,
137
-		\OC_Defaults $defaults,
138
-		IEventDispatcher $dispatcher,
139
-		IUserSession $userSession
140
-	) {
141
-		$this->logger = $logger;
142
-		$this->config = $config;
143
-		$this->secureRandom = $secureRandom;
144
-		$this->hasher = $hasher;
145
-		$this->mountManager = $mountManager;
146
-		$this->groupManager = $groupManager;
147
-		$this->l = $l;
148
-		$this->l10nFactory = $l10nFactory;
149
-		$this->factory = $factory;
150
-		$this->userManager = $userManager;
151
-		$this->rootFolder = $rootFolder;
152
-		$this->legacyDispatcher = $legacyDispatcher;
153
-		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
154
-		// The constructor of LegacyHooks registers the listeners of share events
155
-		// do not remove if those are not properly migrated
156
-		$this->legacyHooks = new LegacyHooks($this->legacyDispatcher);
157
-		$this->mailer = $mailer;
158
-		$this->urlGenerator = $urlGenerator;
159
-		$this->defaults = $defaults;
160
-		$this->dispatcher = $dispatcher;
161
-		$this->userSession = $userSession;
162
-	}
163
-
164
-	/**
165
-	 * Convert from a full share id to a tuple (providerId, shareId)
166
-	 *
167
-	 * @param string $id
168
-	 * @return string[]
169
-	 */
170
-	private function splitFullId($id) {
171
-		return explode(':', $id, 2);
172
-	}
173
-
174
-	/**
175
-	 * Verify if a password meets all requirements
176
-	 *
177
-	 * @param string $password
178
-	 * @throws \Exception
179
-	 */
180
-	protected function verifyPassword($password) {
181
-		if ($password === null) {
182
-			// No password is set, check if this is allowed.
183
-			if ($this->shareApiLinkEnforcePassword()) {
184
-				throw new \InvalidArgumentException('Passwords are enforced for link and mail shares');
185
-			}
186
-
187
-			return;
188
-		}
189
-
190
-		// Let others verify the password
191
-		try {
192
-			$this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
193
-		} catch (HintException $e) {
194
-			throw new \Exception($e->getHint());
195
-		}
196
-	}
197
-
198
-	/**
199
-	 * Check for generic requirements before creating a share
200
-	 *
201
-	 * @param IShare $share
202
-	 * @throws \InvalidArgumentException
203
-	 * @throws GenericShareException
204
-	 *
205
-	 * @suppress PhanUndeclaredClassMethod
206
-	 */
207
-	protected function generalCreateChecks(IShare $share) {
208
-		if ($share->getShareType() === IShare::TYPE_USER) {
209
-			// We expect a valid user as sharedWith for user shares
210
-			if (!$this->userManager->userExists($share->getSharedWith())) {
211
-				throw new \InvalidArgumentException('SharedWith is not a valid user');
212
-			}
213
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
214
-			// We expect a valid group as sharedWith for group shares
215
-			if (!$this->groupManager->groupExists($share->getSharedWith())) {
216
-				throw new \InvalidArgumentException('SharedWith is not a valid group');
217
-			}
218
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
219
-			// No check for TYPE_EMAIL here as we have a recipient for them
220
-			if ($share->getSharedWith() !== null) {
221
-				throw new \InvalidArgumentException('SharedWith should be empty');
222
-			}
223
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
224
-			if ($share->getSharedWith() === null) {
225
-				throw new \InvalidArgumentException('SharedWith should not be empty');
226
-			}
227
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
228
-			if ($share->getSharedWith() === null) {
229
-				throw new \InvalidArgumentException('SharedWith should not be empty');
230
-			}
231
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
232
-			if ($share->getSharedWith() === null) {
233
-				throw new \InvalidArgumentException('SharedWith should not be empty');
234
-			}
235
-		} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
236
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
237
-			if ($circle === null) {
238
-				throw new \InvalidArgumentException('SharedWith is not a valid circle');
239
-			}
240
-		} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
241
-		} elseif ($share->getShareType() === IShare::TYPE_DECK) {
242
-		} else {
243
-			// We cannot handle other types yet
244
-			throw new \InvalidArgumentException('unknown share type');
245
-		}
246
-
247
-		// Verify the initiator of the share is set
248
-		if ($share->getSharedBy() === null) {
249
-			throw new \InvalidArgumentException('SharedBy should be set');
250
-		}
251
-
252
-		// Cannot share with yourself
253
-		if ($share->getShareType() === IShare::TYPE_USER &&
254
-			$share->getSharedWith() === $share->getSharedBy()) {
255
-			throw new \InvalidArgumentException('Cannot share with yourself');
256
-		}
257
-
258
-		// The path should be set
259
-		if ($share->getNode() === null) {
260
-			throw new \InvalidArgumentException('Path should be set');
261
-		}
262
-
263
-		// And it should be a file or a folder
264
-		if (!($share->getNode() instanceof \OCP\Files\File) &&
265
-			!($share->getNode() instanceof \OCP\Files\Folder)) {
266
-			throw new \InvalidArgumentException('Path should be either a file or a folder');
267
-		}
268
-
269
-		// And you cannot share your rootfolder
270
-		if ($this->userManager->userExists($share->getSharedBy())) {
271
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
272
-		} else {
273
-			$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
274
-		}
275
-		if ($userFolder->getId() === $share->getNode()->getId()) {
276
-			throw new \InvalidArgumentException('You cannot share your root folder');
277
-		}
278
-
279
-		// Check if we actually have share permissions
280
-		if (!$share->getNode()->isShareable()) {
281
-			$message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getName()]);
282
-			throw new GenericShareException($message_t, $message_t, 404);
283
-		}
284
-
285
-		// Permissions should be set
286
-		if ($share->getPermissions() === null) {
287
-			throw new \InvalidArgumentException('A share requires permissions');
288
-		}
289
-
290
-		$isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
291
-		$permissions = 0;
292
-
293
-		if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
294
-			$userMounts = array_filter($userFolder->getById($share->getNode()->getId()), function ($mount) {
295
-				// We need to filter since there might be other mountpoints that contain the file
296
-				// e.g. if the user has access to the same external storage that the file is originating from
297
-				return $mount->getStorage()->instanceOfStorage(ISharedStorage::class);
298
-			});
299
-			$userMount = array_shift($userMounts);
300
-			if ($userMount === null) {
301
-				throw new GenericShareException('Could not get proper share mount for ' . $share->getNode()->getId() . '. Failing since else the next calls are called with null');
302
-			}
303
-			$mount = $userMount->getMountPoint();
304
-			// When it's a reshare use the parent share permissions as maximum
305
-			$userMountPointId = $mount->getStorageRootId();
306
-			$userMountPoints = $userFolder->getById($userMountPointId);
307
-			$userMountPoint = array_shift($userMountPoints);
308
-
309
-			if ($userMountPoint === null) {
310
-				throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
311
-			}
312
-
313
-			/* Check if this is an incoming share */
314
-			$incomingShares = $this->getSharedWith($share->getSharedBy(), IShare::TYPE_USER, $userMountPoint, -1, 0);
315
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_GROUP, $userMountPoint, -1, 0));
316
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_CIRCLE, $userMountPoint, -1, 0));
317
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_ROOM, $userMountPoint, -1, 0));
318
-
319
-			/** @var IShare[] $incomingShares */
320
-			if (!empty($incomingShares)) {
321
-				foreach ($incomingShares as $incomingShare) {
322
-					$permissions |= $incomingShare->getPermissions();
323
-				}
324
-			}
325
-		} else {
326
-			/*
84
+    /** @var IProviderFactory */
85
+    private $factory;
86
+    /** @var ILogger */
87
+    private $logger;
88
+    /** @var IConfig */
89
+    private $config;
90
+    /** @var ISecureRandom */
91
+    private $secureRandom;
92
+    /** @var IHasher */
93
+    private $hasher;
94
+    /** @var IMountManager */
95
+    private $mountManager;
96
+    /** @var IGroupManager */
97
+    private $groupManager;
98
+    /** @var IL10N */
99
+    private $l;
100
+    /** @var IFactory */
101
+    private $l10nFactory;
102
+    /** @var IUserManager */
103
+    private $userManager;
104
+    /** @var IRootFolder */
105
+    private $rootFolder;
106
+    /** @var CappedMemoryCache */
107
+    private $sharingDisabledForUsersCache;
108
+    /** @var EventDispatcherInterface */
109
+    private $legacyDispatcher;
110
+    /** @var LegacyHooks */
111
+    private $legacyHooks;
112
+    /** @var IMailer */
113
+    private $mailer;
114
+    /** @var IURLGenerator */
115
+    private $urlGenerator;
116
+    /** @var \OC_Defaults */
117
+    private $defaults;
118
+    /** @var IEventDispatcher */
119
+    private $dispatcher;
120
+    private $userSession;
121
+
122
+    public function __construct(
123
+        ILogger $logger,
124
+        IConfig $config,
125
+        ISecureRandom $secureRandom,
126
+        IHasher $hasher,
127
+        IMountManager $mountManager,
128
+        IGroupManager $groupManager,
129
+        IL10N $l,
130
+        IFactory $l10nFactory,
131
+        IProviderFactory $factory,
132
+        IUserManager $userManager,
133
+        IRootFolder $rootFolder,
134
+        EventDispatcherInterface $legacyDispatcher,
135
+        IMailer $mailer,
136
+        IURLGenerator $urlGenerator,
137
+        \OC_Defaults $defaults,
138
+        IEventDispatcher $dispatcher,
139
+        IUserSession $userSession
140
+    ) {
141
+        $this->logger = $logger;
142
+        $this->config = $config;
143
+        $this->secureRandom = $secureRandom;
144
+        $this->hasher = $hasher;
145
+        $this->mountManager = $mountManager;
146
+        $this->groupManager = $groupManager;
147
+        $this->l = $l;
148
+        $this->l10nFactory = $l10nFactory;
149
+        $this->factory = $factory;
150
+        $this->userManager = $userManager;
151
+        $this->rootFolder = $rootFolder;
152
+        $this->legacyDispatcher = $legacyDispatcher;
153
+        $this->sharingDisabledForUsersCache = new CappedMemoryCache();
154
+        // The constructor of LegacyHooks registers the listeners of share events
155
+        // do not remove if those are not properly migrated
156
+        $this->legacyHooks = new LegacyHooks($this->legacyDispatcher);
157
+        $this->mailer = $mailer;
158
+        $this->urlGenerator = $urlGenerator;
159
+        $this->defaults = $defaults;
160
+        $this->dispatcher = $dispatcher;
161
+        $this->userSession = $userSession;
162
+    }
163
+
164
+    /**
165
+     * Convert from a full share id to a tuple (providerId, shareId)
166
+     *
167
+     * @param string $id
168
+     * @return string[]
169
+     */
170
+    private function splitFullId($id) {
171
+        return explode(':', $id, 2);
172
+    }
173
+
174
+    /**
175
+     * Verify if a password meets all requirements
176
+     *
177
+     * @param string $password
178
+     * @throws \Exception
179
+     */
180
+    protected function verifyPassword($password) {
181
+        if ($password === null) {
182
+            // No password is set, check if this is allowed.
183
+            if ($this->shareApiLinkEnforcePassword()) {
184
+                throw new \InvalidArgumentException('Passwords are enforced for link and mail shares');
185
+            }
186
+
187
+            return;
188
+        }
189
+
190
+        // Let others verify the password
191
+        try {
192
+            $this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
193
+        } catch (HintException $e) {
194
+            throw new \Exception($e->getHint());
195
+        }
196
+    }
197
+
198
+    /**
199
+     * Check for generic requirements before creating a share
200
+     *
201
+     * @param IShare $share
202
+     * @throws \InvalidArgumentException
203
+     * @throws GenericShareException
204
+     *
205
+     * @suppress PhanUndeclaredClassMethod
206
+     */
207
+    protected function generalCreateChecks(IShare $share) {
208
+        if ($share->getShareType() === IShare::TYPE_USER) {
209
+            // We expect a valid user as sharedWith for user shares
210
+            if (!$this->userManager->userExists($share->getSharedWith())) {
211
+                throw new \InvalidArgumentException('SharedWith is not a valid user');
212
+            }
213
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
214
+            // We expect a valid group as sharedWith for group shares
215
+            if (!$this->groupManager->groupExists($share->getSharedWith())) {
216
+                throw new \InvalidArgumentException('SharedWith is not a valid group');
217
+            }
218
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
219
+            // No check for TYPE_EMAIL here as we have a recipient for them
220
+            if ($share->getSharedWith() !== null) {
221
+                throw new \InvalidArgumentException('SharedWith should be empty');
222
+            }
223
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
224
+            if ($share->getSharedWith() === null) {
225
+                throw new \InvalidArgumentException('SharedWith should not be empty');
226
+            }
227
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
228
+            if ($share->getSharedWith() === null) {
229
+                throw new \InvalidArgumentException('SharedWith should not be empty');
230
+            }
231
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
232
+            if ($share->getSharedWith() === null) {
233
+                throw new \InvalidArgumentException('SharedWith should not be empty');
234
+            }
235
+        } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
236
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
237
+            if ($circle === null) {
238
+                throw new \InvalidArgumentException('SharedWith is not a valid circle');
239
+            }
240
+        } elseif ($share->getShareType() === IShare::TYPE_ROOM) {
241
+        } elseif ($share->getShareType() === IShare::TYPE_DECK) {
242
+        } else {
243
+            // We cannot handle other types yet
244
+            throw new \InvalidArgumentException('unknown share type');
245
+        }
246
+
247
+        // Verify the initiator of the share is set
248
+        if ($share->getSharedBy() === null) {
249
+            throw new \InvalidArgumentException('SharedBy should be set');
250
+        }
251
+
252
+        // Cannot share with yourself
253
+        if ($share->getShareType() === IShare::TYPE_USER &&
254
+            $share->getSharedWith() === $share->getSharedBy()) {
255
+            throw new \InvalidArgumentException('Cannot share with yourself');
256
+        }
257
+
258
+        // The path should be set
259
+        if ($share->getNode() === null) {
260
+            throw new \InvalidArgumentException('Path should be set');
261
+        }
262
+
263
+        // And it should be a file or a folder
264
+        if (!($share->getNode() instanceof \OCP\Files\File) &&
265
+            !($share->getNode() instanceof \OCP\Files\Folder)) {
266
+            throw new \InvalidArgumentException('Path should be either a file or a folder');
267
+        }
268
+
269
+        // And you cannot share your rootfolder
270
+        if ($this->userManager->userExists($share->getSharedBy())) {
271
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
272
+        } else {
273
+            $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
274
+        }
275
+        if ($userFolder->getId() === $share->getNode()->getId()) {
276
+            throw new \InvalidArgumentException('You cannot share your root folder');
277
+        }
278
+
279
+        // Check if we actually have share permissions
280
+        if (!$share->getNode()->isShareable()) {
281
+            $message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getName()]);
282
+            throw new GenericShareException($message_t, $message_t, 404);
283
+        }
284
+
285
+        // Permissions should be set
286
+        if ($share->getPermissions() === null) {
287
+            throw new \InvalidArgumentException('A share requires permissions');
288
+        }
289
+
290
+        $isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
291
+        $permissions = 0;
292
+
293
+        if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
294
+            $userMounts = array_filter($userFolder->getById($share->getNode()->getId()), function ($mount) {
295
+                // We need to filter since there might be other mountpoints that contain the file
296
+                // e.g. if the user has access to the same external storage that the file is originating from
297
+                return $mount->getStorage()->instanceOfStorage(ISharedStorage::class);
298
+            });
299
+            $userMount = array_shift($userMounts);
300
+            if ($userMount === null) {
301
+                throw new GenericShareException('Could not get proper share mount for ' . $share->getNode()->getId() . '. Failing since else the next calls are called with null');
302
+            }
303
+            $mount = $userMount->getMountPoint();
304
+            // When it's a reshare use the parent share permissions as maximum
305
+            $userMountPointId = $mount->getStorageRootId();
306
+            $userMountPoints = $userFolder->getById($userMountPointId);
307
+            $userMountPoint = array_shift($userMountPoints);
308
+
309
+            if ($userMountPoint === null) {
310
+                throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
311
+            }
312
+
313
+            /* Check if this is an incoming share */
314
+            $incomingShares = $this->getSharedWith($share->getSharedBy(), IShare::TYPE_USER, $userMountPoint, -1, 0);
315
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_GROUP, $userMountPoint, -1, 0));
316
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_CIRCLE, $userMountPoint, -1, 0));
317
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_ROOM, $userMountPoint, -1, 0));
318
+
319
+            /** @var IShare[] $incomingShares */
320
+            if (!empty($incomingShares)) {
321
+                foreach ($incomingShares as $incomingShare) {
322
+                    $permissions |= $incomingShare->getPermissions();
323
+                }
324
+            }
325
+        } else {
326
+            /*
327 327
 			 * Quick fix for #23536
328 328
 			 * Non moveable mount points do not have update and delete permissions
329 329
 			 * while we 'most likely' do have that on the storage.
330 330
 			 */
331
-			$permissions = $share->getNode()->getPermissions();
332
-			if (!($share->getNode()->getMountPoint() instanceof MoveableMount)) {
333
-				$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
334
-			}
335
-		}
336
-
337
-		// Check that we do not share with more permissions than we have
338
-		if ($share->getPermissions() & ~$permissions) {
339
-			$path = $userFolder->getRelativePath($share->getNode()->getPath());
340
-			$message_t = $this->l->t('Cannot increase permissions of %s', [$path]);
341
-			throw new GenericShareException($message_t, $message_t, 404);
342
-		}
343
-
344
-
345
-		// Check that read permissions are always set
346
-		// Link shares are allowed to have no read permissions to allow upload to hidden folders
347
-		$noReadPermissionRequired = $share->getShareType() === IShare::TYPE_LINK
348
-			|| $share->getShareType() === IShare::TYPE_EMAIL;
349
-		if (!$noReadPermissionRequired &&
350
-			($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
351
-			throw new \InvalidArgumentException('Shares need at least read permissions');
352
-		}
353
-
354
-		if ($share->getNode() instanceof \OCP\Files\File) {
355
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
356
-				$message_t = $this->l->t('Files cannot be shared with delete permissions');
357
-				throw new GenericShareException($message_t);
358
-			}
359
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
360
-				$message_t = $this->l->t('Files cannot be shared with create permissions');
361
-				throw new GenericShareException($message_t);
362
-			}
363
-		}
364
-	}
365
-
366
-	/**
367
-	 * Validate if the expiration date fits the system settings
368
-	 *
369
-	 * @param IShare $share The share to validate the expiration date of
370
-	 * @return IShare The modified share object
371
-	 * @throws GenericShareException
372
-	 * @throws \InvalidArgumentException
373
-	 * @throws \Exception
374
-	 */
375
-	protected function validateExpirationDateInternal(IShare $share) {
376
-		$isRemote = $share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP;
377
-
378
-		$expirationDate = $share->getExpirationDate();
379
-
380
-		if ($expirationDate !== null) {
381
-			//Make sure the expiration date is a date
382
-			$expirationDate->setTime(0, 0, 0);
383
-
384
-			$date = new \DateTime();
385
-			$date->setTime(0, 0, 0);
386
-			if ($date >= $expirationDate) {
387
-				$message = $this->l->t('Expiration date is in the past');
388
-				throw new GenericShareException($message, $message, 404);
389
-			}
390
-		}
391
-
392
-		// If expiredate is empty set a default one if there is a default
393
-		$fullId = null;
394
-		try {
395
-			$fullId = $share->getFullId();
396
-		} catch (\UnexpectedValueException $e) {
397
-			// This is a new share
398
-		}
399
-
400
-		if ($isRemote) {
401
-			$defaultExpireDate = $this->shareApiRemoteDefaultExpireDate();
402
-			$defaultExpireDays = $this->shareApiRemoteDefaultExpireDays();
403
-			$configProp = 'remote_defaultExpDays';
404
-			$isEnforced = $this->shareApiRemoteDefaultExpireDateEnforced();
405
-		} else {
406
-			$defaultExpireDate = $this->shareApiInternalDefaultExpireDate();
407
-			$defaultExpireDays = $this->shareApiInternalDefaultExpireDays();
408
-			$configProp = 'internal_defaultExpDays';
409
-			$isEnforced = $this->shareApiInternalDefaultExpireDateEnforced();
410
-		}
411
-		if ($fullId === null && $expirationDate === null && $defaultExpireDate) {
412
-			$expirationDate = new \DateTime();
413
-			$expirationDate->setTime(0, 0, 0);
414
-
415
-			$days = (int)$this->config->getAppValue('core', $configProp, (string)$defaultExpireDays);
416
-			if ($days > $defaultExpireDays) {
417
-				$days = $defaultExpireDays;
418
-			}
419
-			$expirationDate->add(new \DateInterval('P' . $days . 'D'));
420
-		}
421
-
422
-		// If we enforce the expiration date check that is does not exceed
423
-		if ($isEnforced) {
424
-			if ($expirationDate === null) {
425
-				throw new \InvalidArgumentException('Expiration date is enforced');
426
-			}
427
-
428
-			$date = new \DateTime();
429
-			$date->setTime(0, 0, 0);
430
-			$date->add(new \DateInterval('P' . $defaultExpireDays . 'D'));
431
-			if ($date < $expirationDate) {
432
-				$message = $this->l->n('Cannot set expiration date more than %n day in the future', 'Cannot set expiration date more than %n days in the future', $defaultExpireDays);
433
-				throw new GenericShareException($message, $message, 404);
434
-			}
435
-		}
436
-
437
-		$accepted = true;
438
-		$message = '';
439
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
440
-			'expirationDate' => &$expirationDate,
441
-			'accepted' => &$accepted,
442
-			'message' => &$message,
443
-			'passwordSet' => $share->getPassword() !== null,
444
-		]);
445
-
446
-		if (!$accepted) {
447
-			throw new \Exception($message);
448
-		}
449
-
450
-		$share->setExpirationDate($expirationDate);
451
-
452
-		return $share;
453
-	}
454
-
455
-	/**
456
-	 * Validate if the expiration date fits the system settings
457
-	 *
458
-	 * @param IShare $share The share to validate the expiration date of
459
-	 * @return IShare The modified share object
460
-	 * @throws GenericShareException
461
-	 * @throws \InvalidArgumentException
462
-	 * @throws \Exception
463
-	 */
464
-	protected function validateExpirationDateLink(IShare $share) {
465
-		$expirationDate = $share->getExpirationDate();
466
-
467
-		if ($expirationDate !== null) {
468
-			//Make sure the expiration date is a date
469
-			$expirationDate->setTime(0, 0, 0);
470
-
471
-			$date = new \DateTime();
472
-			$date->setTime(0, 0, 0);
473
-			if ($date >= $expirationDate) {
474
-				$message = $this->l->t('Expiration date is in the past');
475
-				throw new GenericShareException($message, $message, 404);
476
-			}
477
-		}
478
-
479
-		// If expiredate is empty set a default one if there is a default
480
-		$fullId = null;
481
-		try {
482
-			$fullId = $share->getFullId();
483
-		} catch (\UnexpectedValueException $e) {
484
-			// This is a new share
485
-		}
486
-
487
-		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
488
-			$expirationDate = new \DateTime();
489
-			$expirationDate->setTime(0, 0, 0);
490
-
491
-			$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
492
-			if ($days > $this->shareApiLinkDefaultExpireDays()) {
493
-				$days = $this->shareApiLinkDefaultExpireDays();
494
-			}
495
-			$expirationDate->add(new \DateInterval('P' . $days . 'D'));
496
-		}
497
-
498
-		// If we enforce the expiration date check that is does not exceed
499
-		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
500
-			if ($expirationDate === null) {
501
-				throw new \InvalidArgumentException('Expiration date is enforced');
502
-			}
503
-
504
-			$date = new \DateTime();
505
-			$date->setTime(0, 0, 0);
506
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
507
-			if ($date < $expirationDate) {
508
-				$message = $this->l->n('Cannot set expiration date more than %n day in the future', 'Cannot set expiration date more than %n days in the future', $this->shareApiLinkDefaultExpireDays());
509
-				throw new GenericShareException($message, $message, 404);
510
-			}
511
-		}
512
-
513
-		$accepted = true;
514
-		$message = '';
515
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
516
-			'expirationDate' => &$expirationDate,
517
-			'accepted' => &$accepted,
518
-			'message' => &$message,
519
-			'passwordSet' => $share->getPassword() !== null,
520
-		]);
521
-
522
-		if (!$accepted) {
523
-			throw new \Exception($message);
524
-		}
525
-
526
-		$share->setExpirationDate($expirationDate);
527
-
528
-		return $share;
529
-	}
530
-
531
-	/**
532
-	 * Check for pre share requirements for user shares
533
-	 *
534
-	 * @param IShare $share
535
-	 * @throws \Exception
536
-	 */
537
-	protected function userCreateChecks(IShare $share) {
538
-		// Check if we can share with group members only
539
-		if ($this->shareWithGroupMembersOnly()) {
540
-			$sharedBy = $this->userManager->get($share->getSharedBy());
541
-			$sharedWith = $this->userManager->get($share->getSharedWith());
542
-			// Verify we can share with this user
543
-			$groups = array_intersect(
544
-				$this->groupManager->getUserGroupIds($sharedBy),
545
-				$this->groupManager->getUserGroupIds($sharedWith)
546
-			);
547
-			if (empty($groups)) {
548
-				$message_t = $this->l->t('Sharing is only allowed with group members');
549
-				throw new \Exception($message_t);
550
-			}
551
-		}
552
-
553
-		/*
331
+            $permissions = $share->getNode()->getPermissions();
332
+            if (!($share->getNode()->getMountPoint() instanceof MoveableMount)) {
333
+                $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
334
+            }
335
+        }
336
+
337
+        // Check that we do not share with more permissions than we have
338
+        if ($share->getPermissions() & ~$permissions) {
339
+            $path = $userFolder->getRelativePath($share->getNode()->getPath());
340
+            $message_t = $this->l->t('Cannot increase permissions of %s', [$path]);
341
+            throw new GenericShareException($message_t, $message_t, 404);
342
+        }
343
+
344
+
345
+        // Check that read permissions are always set
346
+        // Link shares are allowed to have no read permissions to allow upload to hidden folders
347
+        $noReadPermissionRequired = $share->getShareType() === IShare::TYPE_LINK
348
+            || $share->getShareType() === IShare::TYPE_EMAIL;
349
+        if (!$noReadPermissionRequired &&
350
+            ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
351
+            throw new \InvalidArgumentException('Shares need at least read permissions');
352
+        }
353
+
354
+        if ($share->getNode() instanceof \OCP\Files\File) {
355
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
356
+                $message_t = $this->l->t('Files cannot be shared with delete permissions');
357
+                throw new GenericShareException($message_t);
358
+            }
359
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
360
+                $message_t = $this->l->t('Files cannot be shared with create permissions');
361
+                throw new GenericShareException($message_t);
362
+            }
363
+        }
364
+    }
365
+
366
+    /**
367
+     * Validate if the expiration date fits the system settings
368
+     *
369
+     * @param IShare $share The share to validate the expiration date of
370
+     * @return IShare The modified share object
371
+     * @throws GenericShareException
372
+     * @throws \InvalidArgumentException
373
+     * @throws \Exception
374
+     */
375
+    protected function validateExpirationDateInternal(IShare $share) {
376
+        $isRemote = $share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP;
377
+
378
+        $expirationDate = $share->getExpirationDate();
379
+
380
+        if ($expirationDate !== null) {
381
+            //Make sure the expiration date is a date
382
+            $expirationDate->setTime(0, 0, 0);
383
+
384
+            $date = new \DateTime();
385
+            $date->setTime(0, 0, 0);
386
+            if ($date >= $expirationDate) {
387
+                $message = $this->l->t('Expiration date is in the past');
388
+                throw new GenericShareException($message, $message, 404);
389
+            }
390
+        }
391
+
392
+        // If expiredate is empty set a default one if there is a default
393
+        $fullId = null;
394
+        try {
395
+            $fullId = $share->getFullId();
396
+        } catch (\UnexpectedValueException $e) {
397
+            // This is a new share
398
+        }
399
+
400
+        if ($isRemote) {
401
+            $defaultExpireDate = $this->shareApiRemoteDefaultExpireDate();
402
+            $defaultExpireDays = $this->shareApiRemoteDefaultExpireDays();
403
+            $configProp = 'remote_defaultExpDays';
404
+            $isEnforced = $this->shareApiRemoteDefaultExpireDateEnforced();
405
+        } else {
406
+            $defaultExpireDate = $this->shareApiInternalDefaultExpireDate();
407
+            $defaultExpireDays = $this->shareApiInternalDefaultExpireDays();
408
+            $configProp = 'internal_defaultExpDays';
409
+            $isEnforced = $this->shareApiInternalDefaultExpireDateEnforced();
410
+        }
411
+        if ($fullId === null && $expirationDate === null && $defaultExpireDate) {
412
+            $expirationDate = new \DateTime();
413
+            $expirationDate->setTime(0, 0, 0);
414
+
415
+            $days = (int)$this->config->getAppValue('core', $configProp, (string)$defaultExpireDays);
416
+            if ($days > $defaultExpireDays) {
417
+                $days = $defaultExpireDays;
418
+            }
419
+            $expirationDate->add(new \DateInterval('P' . $days . 'D'));
420
+        }
421
+
422
+        // If we enforce the expiration date check that is does not exceed
423
+        if ($isEnforced) {
424
+            if ($expirationDate === null) {
425
+                throw new \InvalidArgumentException('Expiration date is enforced');
426
+            }
427
+
428
+            $date = new \DateTime();
429
+            $date->setTime(0, 0, 0);
430
+            $date->add(new \DateInterval('P' . $defaultExpireDays . 'D'));
431
+            if ($date < $expirationDate) {
432
+                $message = $this->l->n('Cannot set expiration date more than %n day in the future', 'Cannot set expiration date more than %n days in the future', $defaultExpireDays);
433
+                throw new GenericShareException($message, $message, 404);
434
+            }
435
+        }
436
+
437
+        $accepted = true;
438
+        $message = '';
439
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
440
+            'expirationDate' => &$expirationDate,
441
+            'accepted' => &$accepted,
442
+            'message' => &$message,
443
+            'passwordSet' => $share->getPassword() !== null,
444
+        ]);
445
+
446
+        if (!$accepted) {
447
+            throw new \Exception($message);
448
+        }
449
+
450
+        $share->setExpirationDate($expirationDate);
451
+
452
+        return $share;
453
+    }
454
+
455
+    /**
456
+     * Validate if the expiration date fits the system settings
457
+     *
458
+     * @param IShare $share The share to validate the expiration date of
459
+     * @return IShare The modified share object
460
+     * @throws GenericShareException
461
+     * @throws \InvalidArgumentException
462
+     * @throws \Exception
463
+     */
464
+    protected function validateExpirationDateLink(IShare $share) {
465
+        $expirationDate = $share->getExpirationDate();
466
+
467
+        if ($expirationDate !== null) {
468
+            //Make sure the expiration date is a date
469
+            $expirationDate->setTime(0, 0, 0);
470
+
471
+            $date = new \DateTime();
472
+            $date->setTime(0, 0, 0);
473
+            if ($date >= $expirationDate) {
474
+                $message = $this->l->t('Expiration date is in the past');
475
+                throw new GenericShareException($message, $message, 404);
476
+            }
477
+        }
478
+
479
+        // If expiredate is empty set a default one if there is a default
480
+        $fullId = null;
481
+        try {
482
+            $fullId = $share->getFullId();
483
+        } catch (\UnexpectedValueException $e) {
484
+            // This is a new share
485
+        }
486
+
487
+        if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
488
+            $expirationDate = new \DateTime();
489
+            $expirationDate->setTime(0, 0, 0);
490
+
491
+            $days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
492
+            if ($days > $this->shareApiLinkDefaultExpireDays()) {
493
+                $days = $this->shareApiLinkDefaultExpireDays();
494
+            }
495
+            $expirationDate->add(new \DateInterval('P' . $days . 'D'));
496
+        }
497
+
498
+        // If we enforce the expiration date check that is does not exceed
499
+        if ($this->shareApiLinkDefaultExpireDateEnforced()) {
500
+            if ($expirationDate === null) {
501
+                throw new \InvalidArgumentException('Expiration date is enforced');
502
+            }
503
+
504
+            $date = new \DateTime();
505
+            $date->setTime(0, 0, 0);
506
+            $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
507
+            if ($date < $expirationDate) {
508
+                $message = $this->l->n('Cannot set expiration date more than %n day in the future', 'Cannot set expiration date more than %n days in the future', $this->shareApiLinkDefaultExpireDays());
509
+                throw new GenericShareException($message, $message, 404);
510
+            }
511
+        }
512
+
513
+        $accepted = true;
514
+        $message = '';
515
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
516
+            'expirationDate' => &$expirationDate,
517
+            'accepted' => &$accepted,
518
+            'message' => &$message,
519
+            'passwordSet' => $share->getPassword() !== null,
520
+        ]);
521
+
522
+        if (!$accepted) {
523
+            throw new \Exception($message);
524
+        }
525
+
526
+        $share->setExpirationDate($expirationDate);
527
+
528
+        return $share;
529
+    }
530
+
531
+    /**
532
+     * Check for pre share requirements for user shares
533
+     *
534
+     * @param IShare $share
535
+     * @throws \Exception
536
+     */
537
+    protected function userCreateChecks(IShare $share) {
538
+        // Check if we can share with group members only
539
+        if ($this->shareWithGroupMembersOnly()) {
540
+            $sharedBy = $this->userManager->get($share->getSharedBy());
541
+            $sharedWith = $this->userManager->get($share->getSharedWith());
542
+            // Verify we can share with this user
543
+            $groups = array_intersect(
544
+                $this->groupManager->getUserGroupIds($sharedBy),
545
+                $this->groupManager->getUserGroupIds($sharedWith)
546
+            );
547
+            if (empty($groups)) {
548
+                $message_t = $this->l->t('Sharing is only allowed with group members');
549
+                throw new \Exception($message_t);
550
+            }
551
+        }
552
+
553
+        /*
554 554
 		 * TODO: Could be costly, fix
555 555
 		 *
556 556
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
557 557
 		 */
558
-		$provider = $this->factory->getProviderForType(IShare::TYPE_USER);
559
-		$existingShares = $provider->getSharesByPath($share->getNode());
560
-		foreach ($existingShares as $existingShare) {
561
-			// Ignore if it is the same share
562
-			try {
563
-				if ($existingShare->getFullId() === $share->getFullId()) {
564
-					continue;
565
-				}
566
-			} catch (\UnexpectedValueException $e) {
567
-				//Shares are not identical
568
-			}
569
-
570
-			// Identical share already exists
571
-			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
572
-				$message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
573
-				throw new AlreadySharedException($message, $existingShare);
574
-			}
575
-
576
-			// The share is already shared with this user via a group share
577
-			if ($existingShare->getShareType() === IShare::TYPE_GROUP) {
578
-				$group = $this->groupManager->get($existingShare->getSharedWith());
579
-				if (!is_null($group)) {
580
-					$user = $this->userManager->get($share->getSharedWith());
581
-
582
-					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
583
-						$message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
584
-						throw new AlreadySharedException($message, $existingShare);
585
-					}
586
-				}
587
-			}
588
-		}
589
-	}
590
-
591
-	/**
592
-	 * Check for pre share requirements for group shares
593
-	 *
594
-	 * @param IShare $share
595
-	 * @throws \Exception
596
-	 */
597
-	protected function groupCreateChecks(IShare $share) {
598
-		// Verify group shares are allowed
599
-		if (!$this->allowGroupSharing()) {
600
-			throw new \Exception('Group sharing is now allowed');
601
-		}
602
-
603
-		// Verify if the user can share with this group
604
-		if ($this->shareWithGroupMembersOnly()) {
605
-			$sharedBy = $this->userManager->get($share->getSharedBy());
606
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
607
-			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
608
-				throw new \Exception('Sharing is only allowed within your own groups');
609
-			}
610
-		}
611
-
612
-		/*
558
+        $provider = $this->factory->getProviderForType(IShare::TYPE_USER);
559
+        $existingShares = $provider->getSharesByPath($share->getNode());
560
+        foreach ($existingShares as $existingShare) {
561
+            // Ignore if it is the same share
562
+            try {
563
+                if ($existingShare->getFullId() === $share->getFullId()) {
564
+                    continue;
565
+                }
566
+            } catch (\UnexpectedValueException $e) {
567
+                //Shares are not identical
568
+            }
569
+
570
+            // Identical share already exists
571
+            if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
572
+                $message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
573
+                throw new AlreadySharedException($message, $existingShare);
574
+            }
575
+
576
+            // The share is already shared with this user via a group share
577
+            if ($existingShare->getShareType() === IShare::TYPE_GROUP) {
578
+                $group = $this->groupManager->get($existingShare->getSharedWith());
579
+                if (!is_null($group)) {
580
+                    $user = $this->userManager->get($share->getSharedWith());
581
+
582
+                    if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
583
+                        $message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
584
+                        throw new AlreadySharedException($message, $existingShare);
585
+                    }
586
+                }
587
+            }
588
+        }
589
+    }
590
+
591
+    /**
592
+     * Check for pre share requirements for group shares
593
+     *
594
+     * @param IShare $share
595
+     * @throws \Exception
596
+     */
597
+    protected function groupCreateChecks(IShare $share) {
598
+        // Verify group shares are allowed
599
+        if (!$this->allowGroupSharing()) {
600
+            throw new \Exception('Group sharing is now allowed');
601
+        }
602
+
603
+        // Verify if the user can share with this group
604
+        if ($this->shareWithGroupMembersOnly()) {
605
+            $sharedBy = $this->userManager->get($share->getSharedBy());
606
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
607
+            if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
608
+                throw new \Exception('Sharing is only allowed within your own groups');
609
+            }
610
+        }
611
+
612
+        /*
613 613
 		 * TODO: Could be costly, fix
614 614
 		 *
615 615
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
616 616
 		 */
617
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
618
-		$existingShares = $provider->getSharesByPath($share->getNode());
619
-		foreach ($existingShares as $existingShare) {
620
-			try {
621
-				if ($existingShare->getFullId() === $share->getFullId()) {
622
-					continue;
623
-				}
624
-			} catch (\UnexpectedValueException $e) {
625
-				//It is a new share so just continue
626
-			}
627
-
628
-			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
629
-				throw new AlreadySharedException('Path is already shared with this group', $existingShare);
630
-			}
631
-		}
632
-	}
633
-
634
-	/**
635
-	 * Check for pre share requirements for link shares
636
-	 *
637
-	 * @param IShare $share
638
-	 * @throws \Exception
639
-	 */
640
-	protected function linkCreateChecks(IShare $share) {
641
-		// Are link shares allowed?
642
-		if (!$this->shareApiAllowLinks()) {
643
-			throw new \Exception('Link sharing is not allowed');
644
-		}
645
-
646
-		// Check if public upload is allowed
647
-		if (!$this->shareApiLinkAllowPublicUpload() &&
648
-			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
649
-			throw new \InvalidArgumentException('Public upload is not allowed');
650
-		}
651
-	}
652
-
653
-	/**
654
-	 * To make sure we don't get invisible link shares we set the parent
655
-	 * of a link if it is a reshare. This is a quick word around
656
-	 * until we can properly display multiple link shares in the UI
657
-	 *
658
-	 * See: https://github.com/owncloud/core/issues/22295
659
-	 *
660
-	 * FIXME: Remove once multiple link shares can be properly displayed
661
-	 *
662
-	 * @param IShare $share
663
-	 */
664
-	protected function setLinkParent(IShare $share) {
665
-
666
-		// No sense in checking if the method is not there.
667
-		if (method_exists($share, 'setParent')) {
668
-			$storage = $share->getNode()->getStorage();
669
-			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
670
-				/** @var \OCA\Files_Sharing\SharedStorage $storage */
671
-				$share->setParent($storage->getShareId());
672
-			}
673
-		}
674
-	}
675
-
676
-	/**
677
-	 * @param File|Folder $path
678
-	 */
679
-	protected function pathCreateChecks($path) {
680
-		// Make sure that we do not share a path that contains a shared mountpoint
681
-		if ($path instanceof \OCP\Files\Folder) {
682
-			$mounts = $this->mountManager->findIn($path->getPath());
683
-			foreach ($mounts as $mount) {
684
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
685
-					throw new \InvalidArgumentException('Path contains files shared with you');
686
-				}
687
-			}
688
-		}
689
-	}
690
-
691
-	/**
692
-	 * Check if the user that is sharing can actually share
693
-	 *
694
-	 * @param IShare $share
695
-	 * @throws \Exception
696
-	 */
697
-	protected function canShare(IShare $share) {
698
-		if (!$this->shareApiEnabled()) {
699
-			throw new \Exception('Sharing is disabled');
700
-		}
701
-
702
-		if ($this->sharingDisabledForUser($share->getSharedBy())) {
703
-			throw new \Exception('Sharing is disabled for you');
704
-		}
705
-	}
706
-
707
-	/**
708
-	 * Share a path
709
-	 *
710
-	 * @param IShare $share
711
-	 * @return IShare The share object
712
-	 * @throws \Exception
713
-	 *
714
-	 * TODO: handle link share permissions or check them
715
-	 */
716
-	public function createShare(IShare $share) {
717
-		$this->canShare($share);
718
-
719
-		$this->generalCreateChecks($share);
720
-
721
-		// Verify if there are any issues with the path
722
-		$this->pathCreateChecks($share->getNode());
723
-
724
-		/*
617
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
618
+        $existingShares = $provider->getSharesByPath($share->getNode());
619
+        foreach ($existingShares as $existingShare) {
620
+            try {
621
+                if ($existingShare->getFullId() === $share->getFullId()) {
622
+                    continue;
623
+                }
624
+            } catch (\UnexpectedValueException $e) {
625
+                //It is a new share so just continue
626
+            }
627
+
628
+            if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
629
+                throw new AlreadySharedException('Path is already shared with this group', $existingShare);
630
+            }
631
+        }
632
+    }
633
+
634
+    /**
635
+     * Check for pre share requirements for link shares
636
+     *
637
+     * @param IShare $share
638
+     * @throws \Exception
639
+     */
640
+    protected function linkCreateChecks(IShare $share) {
641
+        // Are link shares allowed?
642
+        if (!$this->shareApiAllowLinks()) {
643
+            throw new \Exception('Link sharing is not allowed');
644
+        }
645
+
646
+        // Check if public upload is allowed
647
+        if (!$this->shareApiLinkAllowPublicUpload() &&
648
+            ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
649
+            throw new \InvalidArgumentException('Public upload is not allowed');
650
+        }
651
+    }
652
+
653
+    /**
654
+     * To make sure we don't get invisible link shares we set the parent
655
+     * of a link if it is a reshare. This is a quick word around
656
+     * until we can properly display multiple link shares in the UI
657
+     *
658
+     * See: https://github.com/owncloud/core/issues/22295
659
+     *
660
+     * FIXME: Remove once multiple link shares can be properly displayed
661
+     *
662
+     * @param IShare $share
663
+     */
664
+    protected function setLinkParent(IShare $share) {
665
+
666
+        // No sense in checking if the method is not there.
667
+        if (method_exists($share, 'setParent')) {
668
+            $storage = $share->getNode()->getStorage();
669
+            if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
670
+                /** @var \OCA\Files_Sharing\SharedStorage $storage */
671
+                $share->setParent($storage->getShareId());
672
+            }
673
+        }
674
+    }
675
+
676
+    /**
677
+     * @param File|Folder $path
678
+     */
679
+    protected function pathCreateChecks($path) {
680
+        // Make sure that we do not share a path that contains a shared mountpoint
681
+        if ($path instanceof \OCP\Files\Folder) {
682
+            $mounts = $this->mountManager->findIn($path->getPath());
683
+            foreach ($mounts as $mount) {
684
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
685
+                    throw new \InvalidArgumentException('Path contains files shared with you');
686
+                }
687
+            }
688
+        }
689
+    }
690
+
691
+    /**
692
+     * Check if the user that is sharing can actually share
693
+     *
694
+     * @param IShare $share
695
+     * @throws \Exception
696
+     */
697
+    protected function canShare(IShare $share) {
698
+        if (!$this->shareApiEnabled()) {
699
+            throw new \Exception('Sharing is disabled');
700
+        }
701
+
702
+        if ($this->sharingDisabledForUser($share->getSharedBy())) {
703
+            throw new \Exception('Sharing is disabled for you');
704
+        }
705
+    }
706
+
707
+    /**
708
+     * Share a path
709
+     *
710
+     * @param IShare $share
711
+     * @return IShare The share object
712
+     * @throws \Exception
713
+     *
714
+     * TODO: handle link share permissions or check them
715
+     */
716
+    public function createShare(IShare $share) {
717
+        $this->canShare($share);
718
+
719
+        $this->generalCreateChecks($share);
720
+
721
+        // Verify if there are any issues with the path
722
+        $this->pathCreateChecks($share->getNode());
723
+
724
+        /*
725 725
 		 * On creation of a share the owner is always the owner of the path
726 726
 		 * Except for mounted federated shares.
727 727
 		 */
728
-		$storage = $share->getNode()->getStorage();
729
-		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
730
-			$parent = $share->getNode()->getParent();
731
-			while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
732
-				$parent = $parent->getParent();
733
-			}
734
-			$share->setShareOwner($parent->getOwner()->getUID());
735
-		} else {
736
-			if ($share->getNode()->getOwner()) {
737
-				$share->setShareOwner($share->getNode()->getOwner()->getUID());
738
-			} else {
739
-				$share->setShareOwner($share->getSharedBy());
740
-			}
741
-		}
742
-
743
-		try {
744
-			// Verify share type
745
-			if ($share->getShareType() === IShare::TYPE_USER) {
746
-				$this->userCreateChecks($share);
747
-
748
-				// Verify the expiration date
749
-				$share = $this->validateExpirationDateInternal($share);
750
-			} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
751
-				$this->groupCreateChecks($share);
752
-
753
-				// Verify the expiration date
754
-				$share = $this->validateExpirationDateInternal($share);
755
-			} elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
756
-				//Verify the expiration date
757
-				$share = $this->validateExpirationDateInternal($share);
758
-			} elseif ($share->getShareType() === IShare::TYPE_LINK
759
-				|| $share->getShareType() === IShare::TYPE_EMAIL) {
760
-				$this->linkCreateChecks($share);
761
-				$this->setLinkParent($share);
762
-
763
-				// For now ignore a set token.
764
-				$share->setToken(
765
-					$this->secureRandom->generate(
766
-						\OC\Share\Constants::TOKEN_LENGTH,
767
-						\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
768
-					)
769
-				);
770
-
771
-				// Verify the expiration date
772
-				$share = $this->validateExpirationDateLink($share);
773
-
774
-				// Verify the password
775
-				$this->verifyPassword($share->getPassword());
776
-
777
-				// If a password is set. Hash it!
778
-				if ($share->getShareType() === IShare::TYPE_LINK
779
-					&& $share->getPassword() !== null) {
780
-					$share->setPassword($this->hasher->hash($share->getPassword()));
781
-				}
782
-			}
783
-
784
-			// Cannot share with the owner
785
-			if ($share->getShareType() === IShare::TYPE_USER &&
786
-				$share->getSharedWith() === $share->getShareOwner()) {
787
-				throw new \InvalidArgumentException('Cannot share with the share owner');
788
-			}
789
-
790
-			// Generate the target
791
-			$target = $this->config->getSystemValue('share_folder', '/') . '/' . $share->getNode()->getName();
792
-			$target = \OC\Files\Filesystem::normalizePath($target);
793
-			$share->setTarget($target);
794
-
795
-			// Pre share event
796
-			$event = new GenericEvent($share);
797
-			$this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
798
-			if ($event->isPropagationStopped() && $event->hasArgument('error')) {
799
-				throw new \Exception($event->getArgument('error'));
800
-			}
801
-
802
-			$oldShare = $share;
803
-			$provider = $this->factory->getProviderForType($share->getShareType());
804
-			$share = $provider->create($share);
805
-
806
-			// Reuse the node we already have
807
-			$share->setNode($oldShare->getNode());
808
-
809
-			// Reset the target if it is null for the new share
810
-			if ($share->getTarget() === '') {
811
-				$share->setTarget($target);
812
-			}
813
-		} catch (AlreadySharedException $e) {
814
-			// if a share for the same target already exists, dont create a new one, but do trigger the hooks and notifications again
815
-			$share = $e->getExistingShare();
816
-		}
817
-
818
-		// Post share event
819
-		$event = new GenericEvent($share);
820
-		$this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
821
-
822
-		$this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
823
-
824
-		if ($this->config->getSystemValueBool('sharing.enable_share_mail', true)
825
-			&& $share->getShareType() === IShare::TYPE_USER) {
826
-			$mailSend = $share->getMailSend();
827
-			if ($mailSend === true) {
828
-				$user = $this->userManager->get($share->getSharedWith());
829
-				if ($user !== null) {
830
-					$emailAddress = $user->getEMailAddress();
831
-					if ($emailAddress !== null && $emailAddress !== '') {
832
-						$userLang = $this->l10nFactory->getUserLanguage($user);
833
-						$l = $this->l10nFactory->get('lib', $userLang);
834
-						$this->sendMailNotification(
835
-							$l,
836
-							$share->getNode()->getName(),
837
-							$this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]),
838
-							$share->getSharedBy(),
839
-							$emailAddress,
840
-							$share->getExpirationDate()
841
-						);
842
-						$this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
843
-					} else {
844
-						$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
845
-					}
846
-				} else {
847
-					$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
848
-				}
849
-			} else {
850
-				$this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
851
-			}
852
-		}
853
-
854
-		return $share;
855
-	}
856
-
857
-	/**
858
-	 * Send mail notifications
859
-	 *
860
-	 * This method will catch and log mail transmission errors
861
-	 *
862
-	 * @param IL10N $l Language of the recipient
863
-	 * @param string $filename file/folder name
864
-	 * @param string $link link to the file/folder
865
-	 * @param string $initiator user ID of share sender
866
-	 * @param string $shareWith email address of share receiver
867
-	 * @param \DateTime|null $expiration
868
-	 */
869
-	protected function sendMailNotification(IL10N $l,
870
-											$filename,
871
-											$link,
872
-											$initiator,
873
-											$shareWith,
874
-											\DateTime $expiration = null) {
875
-		$initiatorUser = $this->userManager->get($initiator);
876
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
877
-
878
-		$message = $this->mailer->createMessage();
879
-
880
-		$emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
881
-			'filename' => $filename,
882
-			'link' => $link,
883
-			'initiator' => $initiatorDisplayName,
884
-			'expiration' => $expiration,
885
-			'shareWith' => $shareWith,
886
-		]);
887
-
888
-		$emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
889
-		$emailTemplate->addHeader();
890
-		$emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
891
-		$text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
892
-
893
-		$emailTemplate->addBodyText(
894
-			htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
895
-			$text
896
-		);
897
-		$emailTemplate->addBodyButton(
898
-			$l->t('Open »%s«', [$filename]),
899
-			$link
900
-		);
901
-
902
-		$message->setTo([$shareWith]);
903
-
904
-		// The "From" contains the sharers name
905
-		$instanceName = $this->defaults->getName();
906
-		$senderName = $l->t(
907
-			'%1$s via %2$s',
908
-			[
909
-				$initiatorDisplayName,
910
-				$instanceName,
911
-			]
912
-		);
913
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress('noreply') => $senderName]);
914
-
915
-		// The "Reply-To" is set to the sharer if an mail address is configured
916
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
917
-		$initiatorEmail = $initiatorUser->getEMailAddress();
918
-		if ($initiatorEmail !== null) {
919
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
920
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
921
-		} else {
922
-			$emailTemplate->addFooter('', $l->getLanguageCode());
923
-		}
924
-
925
-		$message->useTemplate($emailTemplate);
926
-		try {
927
-			$failedRecipients = $this->mailer->send($message);
928
-			if (!empty($failedRecipients)) {
929
-				$this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
930
-				return;
931
-			}
932
-		} catch (\Exception $e) {
933
-			$this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
934
-		}
935
-	}
936
-
937
-	/**
938
-	 * Update a share
939
-	 *
940
-	 * @param IShare $share
941
-	 * @return IShare The share object
942
-	 * @throws \InvalidArgumentException
943
-	 */
944
-	public function updateShare(IShare $share) {
945
-		$expirationDateUpdated = false;
946
-
947
-		$this->canShare($share);
948
-
949
-		try {
950
-			$originalShare = $this->getShareById($share->getFullId());
951
-		} catch (\UnexpectedValueException $e) {
952
-			throw new \InvalidArgumentException('Share does not have a full id');
953
-		}
954
-
955
-		// We cannot change the share type!
956
-		if ($share->getShareType() !== $originalShare->getShareType()) {
957
-			throw new \InvalidArgumentException('Cannot change share type');
958
-		}
959
-
960
-		// We can only change the recipient on user shares
961
-		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
962
-			$share->getShareType() !== IShare::TYPE_USER) {
963
-			throw new \InvalidArgumentException('Can only update recipient on user shares');
964
-		}
965
-
966
-		// Cannot share with the owner
967
-		if ($share->getShareType() === IShare::TYPE_USER &&
968
-			$share->getSharedWith() === $share->getShareOwner()) {
969
-			throw new \InvalidArgumentException('Cannot share with the share owner');
970
-		}
971
-
972
-		$this->generalCreateChecks($share);
973
-
974
-		if ($share->getShareType() === IShare::TYPE_USER) {
975
-			$this->userCreateChecks($share);
976
-
977
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
978
-				//Verify the expiration date
979
-				$this->validateExpirationDateInternal($share);
980
-				$expirationDateUpdated = true;
981
-			}
982
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
983
-			$this->groupCreateChecks($share);
984
-
985
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
986
-				//Verify the expiration date
987
-				$this->validateExpirationDateInternal($share);
988
-				$expirationDateUpdated = true;
989
-			}
990
-		} elseif ($share->getShareType() === IShare::TYPE_LINK
991
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
992
-			$this->linkCreateChecks($share);
993
-
994
-			// The new password is not set again if it is the same as the old
995
-			// one, unless when switching from sending by Talk to sending by
996
-			// mail.
997
-			$plainTextPassword = $share->getPassword();
998
-			$updatedPassword = $this->updateSharePasswordIfNeeded($share, $originalShare);
999
-
1000
-			/**
1001
-			 * Cannot enable the getSendPasswordByTalk if there is no password set
1002
-			 */
1003
-			if (empty($plainTextPassword) && $share->getSendPasswordByTalk()) {
1004
-				throw new \InvalidArgumentException('Cannot enable sending the password by Talk with an empty password');
1005
-			}
1006
-
1007
-			/**
1008
-			 * If we're in a mail share, we need to force a password change
1009
-			 * as either the user is not aware of the password or is already (received by mail)
1010
-			 * Thus the SendPasswordByTalk feature would not make sense
1011
-			 */
1012
-			if (!$updatedPassword && $share->getShareType() === IShare::TYPE_EMAIL) {
1013
-				if (!$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
1014
-					throw new \InvalidArgumentException('Cannot enable sending the password by Talk without setting a new password');
1015
-				}
1016
-				if ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()) {
1017
-					throw new \InvalidArgumentException('Cannot disable sending the password by Talk without setting a new password');
1018
-				}
1019
-			}
1020
-
1021
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1022
-				// Verify the expiration date
1023
-				$this->validateExpirationDateLink($share);
1024
-				$expirationDateUpdated = true;
1025
-			}
1026
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
1027
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1028
-				//Verify the expiration date
1029
-				$this->validateExpirationDateInternal($share);
1030
-				$expirationDateUpdated = true;
1031
-			}
1032
-		}
1033
-
1034
-		$this->pathCreateChecks($share->getNode());
1035
-
1036
-		// Now update the share!
1037
-		$provider = $this->factory->getProviderForType($share->getShareType());
1038
-		if ($share->getShareType() === IShare::TYPE_EMAIL) {
1039
-			$share = $provider->update($share, $plainTextPassword);
1040
-		} else {
1041
-			$share = $provider->update($share);
1042
-		}
1043
-
1044
-		if ($expirationDateUpdated === true) {
1045
-			\OC_Hook::emit(Share::class, 'post_set_expiration_date', [
1046
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1047
-				'itemSource' => $share->getNode()->getId(),
1048
-				'date' => $share->getExpirationDate(),
1049
-				'uidOwner' => $share->getSharedBy(),
1050
-			]);
1051
-		}
1052
-
1053
-		if ($share->getPassword() !== $originalShare->getPassword()) {
1054
-			\OC_Hook::emit(Share::class, 'post_update_password', [
1055
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1056
-				'itemSource' => $share->getNode()->getId(),
1057
-				'uidOwner' => $share->getSharedBy(),
1058
-				'token' => $share->getToken(),
1059
-				'disabled' => is_null($share->getPassword()),
1060
-			]);
1061
-		}
1062
-
1063
-		if ($share->getPermissions() !== $originalShare->getPermissions()) {
1064
-			if ($this->userManager->userExists($share->getShareOwner())) {
1065
-				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1066
-			} else {
1067
-				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1068
-			}
1069
-			\OC_Hook::emit(Share::class, 'post_update_permissions', [
1070
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1071
-				'itemSource' => $share->getNode()->getId(),
1072
-				'shareType' => $share->getShareType(),
1073
-				'shareWith' => $share->getSharedWith(),
1074
-				'uidOwner' => $share->getSharedBy(),
1075
-				'permissions' => $share->getPermissions(),
1076
-				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1077
-			]);
1078
-		}
1079
-
1080
-		return $share;
1081
-	}
1082
-
1083
-	/**
1084
-	 * Accept a share.
1085
-	 *
1086
-	 * @param IShare $share
1087
-	 * @param string $recipientId
1088
-	 * @return IShare The share object
1089
-	 * @throws \InvalidArgumentException
1090
-	 * @since 9.0.0
1091
-	 */
1092
-	public function acceptShare(IShare $share, string $recipientId): IShare {
1093
-		[$providerId,] = $this->splitFullId($share->getFullId());
1094
-		$provider = $this->factory->getProvider($providerId);
1095
-
1096
-		if (!method_exists($provider, 'acceptShare')) {
1097
-			// TODO FIX ME
1098
-			throw new \InvalidArgumentException('Share provider does not support accepting');
1099
-		}
1100
-		$provider->acceptShare($share, $recipientId);
1101
-		$event = new GenericEvent($share);
1102
-		$this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
1103
-
1104
-		return $share;
1105
-	}
1106
-
1107
-	/**
1108
-	 * Updates the password of the given share if it is not the same as the
1109
-	 * password of the original share.
1110
-	 *
1111
-	 * @param IShare $share the share to update its password.
1112
-	 * @param IShare $originalShare the original share to compare its
1113
-	 *        password with.
1114
-	 * @return boolean whether the password was updated or not.
1115
-	 */
1116
-	private function updateSharePasswordIfNeeded(IShare $share, IShare $originalShare) {
1117
-		$passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) &&
1118
-			(($share->getPassword() !== null && $originalShare->getPassword() === null) ||
1119
-				($share->getPassword() === null && $originalShare->getPassword() !== null) ||
1120
-				($share->getPassword() !== null && $originalShare->getPassword() !== null &&
1121
-					!$this->hasher->verify($share->getPassword(), $originalShare->getPassword())));
1122
-
1123
-		// Password updated.
1124
-		if ($passwordsAreDifferent) {
1125
-			//Verify the password
1126
-			$this->verifyPassword($share->getPassword());
1127
-
1128
-			// If a password is set. Hash it!
1129
-			if (!empty($share->getPassword())) {
1130
-				$share->setPassword($this->hasher->hash($share->getPassword()));
1131
-
1132
-				return true;
1133
-			} else {
1134
-				// Empty string and null are seen as NOT password protected
1135
-				$share->setPassword(null);
1136
-				return true;
1137
-			}
1138
-		} else {
1139
-			// Reset the password to the original one, as it is either the same
1140
-			// as the "new" password or a hashed version of it.
1141
-			$share->setPassword($originalShare->getPassword());
1142
-		}
1143
-
1144
-		return false;
1145
-	}
1146
-
1147
-	/**
1148
-	 * Delete all the children of this share
1149
-	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1150
-	 *
1151
-	 * @param IShare $share
1152
-	 * @return IShare[] List of deleted shares
1153
-	 */
1154
-	protected function deleteChildren(IShare $share) {
1155
-		$deletedShares = [];
1156
-
1157
-		$provider = $this->factory->getProviderForType($share->getShareType());
1158
-
1159
-		foreach ($provider->getChildren($share) as $child) {
1160
-			$deletedChildren = $this->deleteChildren($child);
1161
-			$deletedShares = array_merge($deletedShares, $deletedChildren);
1162
-
1163
-			$provider->delete($child);
1164
-			$this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($child));
1165
-			$deletedShares[] = $child;
1166
-		}
1167
-
1168
-		return $deletedShares;
1169
-	}
1170
-
1171
-	/**
1172
-	 * Delete a share
1173
-	 *
1174
-	 * @param IShare $share
1175
-	 * @throws ShareNotFound
1176
-	 * @throws \InvalidArgumentException
1177
-	 */
1178
-	public function deleteShare(IShare $share) {
1179
-		try {
1180
-			$share->getFullId();
1181
-		} catch (\UnexpectedValueException $e) {
1182
-			throw new \InvalidArgumentException('Share does not have a full id');
1183
-		}
1184
-
1185
-		$event = new GenericEvent($share);
1186
-		$this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
1187
-
1188
-		// Get all children and delete them as well
1189
-		$deletedShares = $this->deleteChildren($share);
1190
-
1191
-		// Do the actual delete
1192
-		$provider = $this->factory->getProviderForType($share->getShareType());
1193
-		$provider->delete($share);
1194
-
1195
-		$this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($share));
1196
-
1197
-		// All the deleted shares caused by this delete
1198
-		$deletedShares[] = $share;
1199
-
1200
-		// Emit post hook
1201
-		$event->setArgument('deletedShares', $deletedShares);
1202
-		$this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1203
-	}
1204
-
1205
-
1206
-	/**
1207
-	 * Unshare a file as the recipient.
1208
-	 * This can be different from a regular delete for example when one of
1209
-	 * the users in a groups deletes that share. But the provider should
1210
-	 * handle this.
1211
-	 *
1212
-	 * @param IShare $share
1213
-	 * @param string $recipientId
1214
-	 */
1215
-	public function deleteFromSelf(IShare $share, $recipientId) {
1216
-		[$providerId,] = $this->splitFullId($share->getFullId());
1217
-		$provider = $this->factory->getProvider($providerId);
1218
-
1219
-		$provider->deleteFromSelf($share, $recipientId);
1220
-		$event = new GenericEvent($share);
1221
-		$this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
1222
-	}
1223
-
1224
-	public function restoreShare(IShare $share, string $recipientId): IShare {
1225
-		[$providerId,] = $this->splitFullId($share->getFullId());
1226
-		$provider = $this->factory->getProvider($providerId);
1227
-
1228
-		return $provider->restore($share, $recipientId);
1229
-	}
1230
-
1231
-	/**
1232
-	 * @inheritdoc
1233
-	 */
1234
-	public function moveShare(IShare $share, $recipientId) {
1235
-		if ($share->getShareType() === IShare::TYPE_LINK
1236
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
1237
-			throw new \InvalidArgumentException('Cannot change target of link share');
1238
-		}
1239
-
1240
-		if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() !== $recipientId) {
1241
-			throw new \InvalidArgumentException('Invalid recipient');
1242
-		}
1243
-
1244
-		if ($share->getShareType() === IShare::TYPE_GROUP) {
1245
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1246
-			if (is_null($sharedWith)) {
1247
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1248
-			}
1249
-			$recipient = $this->userManager->get($recipientId);
1250
-			if (!$sharedWith->inGroup($recipient)) {
1251
-				throw new \InvalidArgumentException('Invalid recipient');
1252
-			}
1253
-		}
1254
-
1255
-		[$providerId,] = $this->splitFullId($share->getFullId());
1256
-		$provider = $this->factory->getProvider($providerId);
1257
-
1258
-		return $provider->move($share, $recipientId);
1259
-	}
1260
-
1261
-	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1262
-		$providers = $this->factory->getAllProviders();
1263
-
1264
-		return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1265
-			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1266
-			foreach ($newShares as $fid => $data) {
1267
-				if (!isset($shares[$fid])) {
1268
-					$shares[$fid] = [];
1269
-				}
1270
-
1271
-				$shares[$fid] = array_merge($shares[$fid], $data);
1272
-			}
1273
-			return $shares;
1274
-		}, []);
1275
-	}
1276
-
1277
-	/**
1278
-	 * @inheritdoc
1279
-	 */
1280
-	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1281
-		if ($path !== null &&
1282
-			!($path instanceof \OCP\Files\File) &&
1283
-			!($path instanceof \OCP\Files\Folder)) {
1284
-			throw new \InvalidArgumentException('invalid path');
1285
-		}
1286
-
1287
-		try {
1288
-			$provider = $this->factory->getProviderForType($shareType);
1289
-		} catch (ProviderException $e) {
1290
-			return [];
1291
-		}
1292
-
1293
-		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1294
-
1295
-		/*
728
+        $storage = $share->getNode()->getStorage();
729
+        if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
730
+            $parent = $share->getNode()->getParent();
731
+            while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
732
+                $parent = $parent->getParent();
733
+            }
734
+            $share->setShareOwner($parent->getOwner()->getUID());
735
+        } else {
736
+            if ($share->getNode()->getOwner()) {
737
+                $share->setShareOwner($share->getNode()->getOwner()->getUID());
738
+            } else {
739
+                $share->setShareOwner($share->getSharedBy());
740
+            }
741
+        }
742
+
743
+        try {
744
+            // Verify share type
745
+            if ($share->getShareType() === IShare::TYPE_USER) {
746
+                $this->userCreateChecks($share);
747
+
748
+                // Verify the expiration date
749
+                $share = $this->validateExpirationDateInternal($share);
750
+            } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
751
+                $this->groupCreateChecks($share);
752
+
753
+                // Verify the expiration date
754
+                $share = $this->validateExpirationDateInternal($share);
755
+            } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
756
+                //Verify the expiration date
757
+                $share = $this->validateExpirationDateInternal($share);
758
+            } elseif ($share->getShareType() === IShare::TYPE_LINK
759
+                || $share->getShareType() === IShare::TYPE_EMAIL) {
760
+                $this->linkCreateChecks($share);
761
+                $this->setLinkParent($share);
762
+
763
+                // For now ignore a set token.
764
+                $share->setToken(
765
+                    $this->secureRandom->generate(
766
+                        \OC\Share\Constants::TOKEN_LENGTH,
767
+                        \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
768
+                    )
769
+                );
770
+
771
+                // Verify the expiration date
772
+                $share = $this->validateExpirationDateLink($share);
773
+
774
+                // Verify the password
775
+                $this->verifyPassword($share->getPassword());
776
+
777
+                // If a password is set. Hash it!
778
+                if ($share->getShareType() === IShare::TYPE_LINK
779
+                    && $share->getPassword() !== null) {
780
+                    $share->setPassword($this->hasher->hash($share->getPassword()));
781
+                }
782
+            }
783
+
784
+            // Cannot share with the owner
785
+            if ($share->getShareType() === IShare::TYPE_USER &&
786
+                $share->getSharedWith() === $share->getShareOwner()) {
787
+                throw new \InvalidArgumentException('Cannot share with the share owner');
788
+            }
789
+
790
+            // Generate the target
791
+            $target = $this->config->getSystemValue('share_folder', '/') . '/' . $share->getNode()->getName();
792
+            $target = \OC\Files\Filesystem::normalizePath($target);
793
+            $share->setTarget($target);
794
+
795
+            // Pre share event
796
+            $event = new GenericEvent($share);
797
+            $this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
798
+            if ($event->isPropagationStopped() && $event->hasArgument('error')) {
799
+                throw new \Exception($event->getArgument('error'));
800
+            }
801
+
802
+            $oldShare = $share;
803
+            $provider = $this->factory->getProviderForType($share->getShareType());
804
+            $share = $provider->create($share);
805
+
806
+            // Reuse the node we already have
807
+            $share->setNode($oldShare->getNode());
808
+
809
+            // Reset the target if it is null for the new share
810
+            if ($share->getTarget() === '') {
811
+                $share->setTarget($target);
812
+            }
813
+        } catch (AlreadySharedException $e) {
814
+            // if a share for the same target already exists, dont create a new one, but do trigger the hooks and notifications again
815
+            $share = $e->getExistingShare();
816
+        }
817
+
818
+        // Post share event
819
+        $event = new GenericEvent($share);
820
+        $this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
821
+
822
+        $this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
823
+
824
+        if ($this->config->getSystemValueBool('sharing.enable_share_mail', true)
825
+            && $share->getShareType() === IShare::TYPE_USER) {
826
+            $mailSend = $share->getMailSend();
827
+            if ($mailSend === true) {
828
+                $user = $this->userManager->get($share->getSharedWith());
829
+                if ($user !== null) {
830
+                    $emailAddress = $user->getEMailAddress();
831
+                    if ($emailAddress !== null && $emailAddress !== '') {
832
+                        $userLang = $this->l10nFactory->getUserLanguage($user);
833
+                        $l = $this->l10nFactory->get('lib', $userLang);
834
+                        $this->sendMailNotification(
835
+                            $l,
836
+                            $share->getNode()->getName(),
837
+                            $this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]),
838
+                            $share->getSharedBy(),
839
+                            $emailAddress,
840
+                            $share->getExpirationDate()
841
+                        );
842
+                        $this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
843
+                    } else {
844
+                        $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
845
+                    }
846
+                } else {
847
+                    $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
848
+                }
849
+            } else {
850
+                $this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
851
+            }
852
+        }
853
+
854
+        return $share;
855
+    }
856
+
857
+    /**
858
+     * Send mail notifications
859
+     *
860
+     * This method will catch and log mail transmission errors
861
+     *
862
+     * @param IL10N $l Language of the recipient
863
+     * @param string $filename file/folder name
864
+     * @param string $link link to the file/folder
865
+     * @param string $initiator user ID of share sender
866
+     * @param string $shareWith email address of share receiver
867
+     * @param \DateTime|null $expiration
868
+     */
869
+    protected function sendMailNotification(IL10N $l,
870
+                                            $filename,
871
+                                            $link,
872
+                                            $initiator,
873
+                                            $shareWith,
874
+                                            \DateTime $expiration = null) {
875
+        $initiatorUser = $this->userManager->get($initiator);
876
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
877
+
878
+        $message = $this->mailer->createMessage();
879
+
880
+        $emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
881
+            'filename' => $filename,
882
+            'link' => $link,
883
+            'initiator' => $initiatorDisplayName,
884
+            'expiration' => $expiration,
885
+            'shareWith' => $shareWith,
886
+        ]);
887
+
888
+        $emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
889
+        $emailTemplate->addHeader();
890
+        $emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
891
+        $text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
892
+
893
+        $emailTemplate->addBodyText(
894
+            htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
895
+            $text
896
+        );
897
+        $emailTemplate->addBodyButton(
898
+            $l->t('Open »%s«', [$filename]),
899
+            $link
900
+        );
901
+
902
+        $message->setTo([$shareWith]);
903
+
904
+        // The "From" contains the sharers name
905
+        $instanceName = $this->defaults->getName();
906
+        $senderName = $l->t(
907
+            '%1$s via %2$s',
908
+            [
909
+                $initiatorDisplayName,
910
+                $instanceName,
911
+            ]
912
+        );
913
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress('noreply') => $senderName]);
914
+
915
+        // The "Reply-To" is set to the sharer if an mail address is configured
916
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
917
+        $initiatorEmail = $initiatorUser->getEMailAddress();
918
+        if ($initiatorEmail !== null) {
919
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
920
+            $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
921
+        } else {
922
+            $emailTemplate->addFooter('', $l->getLanguageCode());
923
+        }
924
+
925
+        $message->useTemplate($emailTemplate);
926
+        try {
927
+            $failedRecipients = $this->mailer->send($message);
928
+            if (!empty($failedRecipients)) {
929
+                $this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
930
+                return;
931
+            }
932
+        } catch (\Exception $e) {
933
+            $this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
934
+        }
935
+    }
936
+
937
+    /**
938
+     * Update a share
939
+     *
940
+     * @param IShare $share
941
+     * @return IShare The share object
942
+     * @throws \InvalidArgumentException
943
+     */
944
+    public function updateShare(IShare $share) {
945
+        $expirationDateUpdated = false;
946
+
947
+        $this->canShare($share);
948
+
949
+        try {
950
+            $originalShare = $this->getShareById($share->getFullId());
951
+        } catch (\UnexpectedValueException $e) {
952
+            throw new \InvalidArgumentException('Share does not have a full id');
953
+        }
954
+
955
+        // We cannot change the share type!
956
+        if ($share->getShareType() !== $originalShare->getShareType()) {
957
+            throw new \InvalidArgumentException('Cannot change share type');
958
+        }
959
+
960
+        // We can only change the recipient on user shares
961
+        if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
962
+            $share->getShareType() !== IShare::TYPE_USER) {
963
+            throw new \InvalidArgumentException('Can only update recipient on user shares');
964
+        }
965
+
966
+        // Cannot share with the owner
967
+        if ($share->getShareType() === IShare::TYPE_USER &&
968
+            $share->getSharedWith() === $share->getShareOwner()) {
969
+            throw new \InvalidArgumentException('Cannot share with the share owner');
970
+        }
971
+
972
+        $this->generalCreateChecks($share);
973
+
974
+        if ($share->getShareType() === IShare::TYPE_USER) {
975
+            $this->userCreateChecks($share);
976
+
977
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
978
+                //Verify the expiration date
979
+                $this->validateExpirationDateInternal($share);
980
+                $expirationDateUpdated = true;
981
+            }
982
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
983
+            $this->groupCreateChecks($share);
984
+
985
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
986
+                //Verify the expiration date
987
+                $this->validateExpirationDateInternal($share);
988
+                $expirationDateUpdated = true;
989
+            }
990
+        } elseif ($share->getShareType() === IShare::TYPE_LINK
991
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
992
+            $this->linkCreateChecks($share);
993
+
994
+            // The new password is not set again if it is the same as the old
995
+            // one, unless when switching from sending by Talk to sending by
996
+            // mail.
997
+            $plainTextPassword = $share->getPassword();
998
+            $updatedPassword = $this->updateSharePasswordIfNeeded($share, $originalShare);
999
+
1000
+            /**
1001
+             * Cannot enable the getSendPasswordByTalk if there is no password set
1002
+             */
1003
+            if (empty($plainTextPassword) && $share->getSendPasswordByTalk()) {
1004
+                throw new \InvalidArgumentException('Cannot enable sending the password by Talk with an empty password');
1005
+            }
1006
+
1007
+            /**
1008
+             * If we're in a mail share, we need to force a password change
1009
+             * as either the user is not aware of the password or is already (received by mail)
1010
+             * Thus the SendPasswordByTalk feature would not make sense
1011
+             */
1012
+            if (!$updatedPassword && $share->getShareType() === IShare::TYPE_EMAIL) {
1013
+                if (!$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
1014
+                    throw new \InvalidArgumentException('Cannot enable sending the password by Talk without setting a new password');
1015
+                }
1016
+                if ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()) {
1017
+                    throw new \InvalidArgumentException('Cannot disable sending the password by Talk without setting a new password');
1018
+                }
1019
+            }
1020
+
1021
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1022
+                // Verify the expiration date
1023
+                $this->validateExpirationDateLink($share);
1024
+                $expirationDateUpdated = true;
1025
+            }
1026
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
1027
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1028
+                //Verify the expiration date
1029
+                $this->validateExpirationDateInternal($share);
1030
+                $expirationDateUpdated = true;
1031
+            }
1032
+        }
1033
+
1034
+        $this->pathCreateChecks($share->getNode());
1035
+
1036
+        // Now update the share!
1037
+        $provider = $this->factory->getProviderForType($share->getShareType());
1038
+        if ($share->getShareType() === IShare::TYPE_EMAIL) {
1039
+            $share = $provider->update($share, $plainTextPassword);
1040
+        } else {
1041
+            $share = $provider->update($share);
1042
+        }
1043
+
1044
+        if ($expirationDateUpdated === true) {
1045
+            \OC_Hook::emit(Share::class, 'post_set_expiration_date', [
1046
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1047
+                'itemSource' => $share->getNode()->getId(),
1048
+                'date' => $share->getExpirationDate(),
1049
+                'uidOwner' => $share->getSharedBy(),
1050
+            ]);
1051
+        }
1052
+
1053
+        if ($share->getPassword() !== $originalShare->getPassword()) {
1054
+            \OC_Hook::emit(Share::class, 'post_update_password', [
1055
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1056
+                'itemSource' => $share->getNode()->getId(),
1057
+                'uidOwner' => $share->getSharedBy(),
1058
+                'token' => $share->getToken(),
1059
+                'disabled' => is_null($share->getPassword()),
1060
+            ]);
1061
+        }
1062
+
1063
+        if ($share->getPermissions() !== $originalShare->getPermissions()) {
1064
+            if ($this->userManager->userExists($share->getShareOwner())) {
1065
+                $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1066
+            } else {
1067
+                $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1068
+            }
1069
+            \OC_Hook::emit(Share::class, 'post_update_permissions', [
1070
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1071
+                'itemSource' => $share->getNode()->getId(),
1072
+                'shareType' => $share->getShareType(),
1073
+                'shareWith' => $share->getSharedWith(),
1074
+                'uidOwner' => $share->getSharedBy(),
1075
+                'permissions' => $share->getPermissions(),
1076
+                'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1077
+            ]);
1078
+        }
1079
+
1080
+        return $share;
1081
+    }
1082
+
1083
+    /**
1084
+     * Accept a share.
1085
+     *
1086
+     * @param IShare $share
1087
+     * @param string $recipientId
1088
+     * @return IShare The share object
1089
+     * @throws \InvalidArgumentException
1090
+     * @since 9.0.0
1091
+     */
1092
+    public function acceptShare(IShare $share, string $recipientId): IShare {
1093
+        [$providerId,] = $this->splitFullId($share->getFullId());
1094
+        $provider = $this->factory->getProvider($providerId);
1095
+
1096
+        if (!method_exists($provider, 'acceptShare')) {
1097
+            // TODO FIX ME
1098
+            throw new \InvalidArgumentException('Share provider does not support accepting');
1099
+        }
1100
+        $provider->acceptShare($share, $recipientId);
1101
+        $event = new GenericEvent($share);
1102
+        $this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
1103
+
1104
+        return $share;
1105
+    }
1106
+
1107
+    /**
1108
+     * Updates the password of the given share if it is not the same as the
1109
+     * password of the original share.
1110
+     *
1111
+     * @param IShare $share the share to update its password.
1112
+     * @param IShare $originalShare the original share to compare its
1113
+     *        password with.
1114
+     * @return boolean whether the password was updated or not.
1115
+     */
1116
+    private function updateSharePasswordIfNeeded(IShare $share, IShare $originalShare) {
1117
+        $passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) &&
1118
+            (($share->getPassword() !== null && $originalShare->getPassword() === null) ||
1119
+                ($share->getPassword() === null && $originalShare->getPassword() !== null) ||
1120
+                ($share->getPassword() !== null && $originalShare->getPassword() !== null &&
1121
+                    !$this->hasher->verify($share->getPassword(), $originalShare->getPassword())));
1122
+
1123
+        // Password updated.
1124
+        if ($passwordsAreDifferent) {
1125
+            //Verify the password
1126
+            $this->verifyPassword($share->getPassword());
1127
+
1128
+            // If a password is set. Hash it!
1129
+            if (!empty($share->getPassword())) {
1130
+                $share->setPassword($this->hasher->hash($share->getPassword()));
1131
+
1132
+                return true;
1133
+            } else {
1134
+                // Empty string and null are seen as NOT password protected
1135
+                $share->setPassword(null);
1136
+                return true;
1137
+            }
1138
+        } else {
1139
+            // Reset the password to the original one, as it is either the same
1140
+            // as the "new" password or a hashed version of it.
1141
+            $share->setPassword($originalShare->getPassword());
1142
+        }
1143
+
1144
+        return false;
1145
+    }
1146
+
1147
+    /**
1148
+     * Delete all the children of this share
1149
+     * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1150
+     *
1151
+     * @param IShare $share
1152
+     * @return IShare[] List of deleted shares
1153
+     */
1154
+    protected function deleteChildren(IShare $share) {
1155
+        $deletedShares = [];
1156
+
1157
+        $provider = $this->factory->getProviderForType($share->getShareType());
1158
+
1159
+        foreach ($provider->getChildren($share) as $child) {
1160
+            $deletedChildren = $this->deleteChildren($child);
1161
+            $deletedShares = array_merge($deletedShares, $deletedChildren);
1162
+
1163
+            $provider->delete($child);
1164
+            $this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($child));
1165
+            $deletedShares[] = $child;
1166
+        }
1167
+
1168
+        return $deletedShares;
1169
+    }
1170
+
1171
+    /**
1172
+     * Delete a share
1173
+     *
1174
+     * @param IShare $share
1175
+     * @throws ShareNotFound
1176
+     * @throws \InvalidArgumentException
1177
+     */
1178
+    public function deleteShare(IShare $share) {
1179
+        try {
1180
+            $share->getFullId();
1181
+        } catch (\UnexpectedValueException $e) {
1182
+            throw new \InvalidArgumentException('Share does not have a full id');
1183
+        }
1184
+
1185
+        $event = new GenericEvent($share);
1186
+        $this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
1187
+
1188
+        // Get all children and delete them as well
1189
+        $deletedShares = $this->deleteChildren($share);
1190
+
1191
+        // Do the actual delete
1192
+        $provider = $this->factory->getProviderForType($share->getShareType());
1193
+        $provider->delete($share);
1194
+
1195
+        $this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($share));
1196
+
1197
+        // All the deleted shares caused by this delete
1198
+        $deletedShares[] = $share;
1199
+
1200
+        // Emit post hook
1201
+        $event->setArgument('deletedShares', $deletedShares);
1202
+        $this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1203
+    }
1204
+
1205
+
1206
+    /**
1207
+     * Unshare a file as the recipient.
1208
+     * This can be different from a regular delete for example when one of
1209
+     * the users in a groups deletes that share. But the provider should
1210
+     * handle this.
1211
+     *
1212
+     * @param IShare $share
1213
+     * @param string $recipientId
1214
+     */
1215
+    public function deleteFromSelf(IShare $share, $recipientId) {
1216
+        [$providerId,] = $this->splitFullId($share->getFullId());
1217
+        $provider = $this->factory->getProvider($providerId);
1218
+
1219
+        $provider->deleteFromSelf($share, $recipientId);
1220
+        $event = new GenericEvent($share);
1221
+        $this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
1222
+    }
1223
+
1224
+    public function restoreShare(IShare $share, string $recipientId): IShare {
1225
+        [$providerId,] = $this->splitFullId($share->getFullId());
1226
+        $provider = $this->factory->getProvider($providerId);
1227
+
1228
+        return $provider->restore($share, $recipientId);
1229
+    }
1230
+
1231
+    /**
1232
+     * @inheritdoc
1233
+     */
1234
+    public function moveShare(IShare $share, $recipientId) {
1235
+        if ($share->getShareType() === IShare::TYPE_LINK
1236
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
1237
+            throw new \InvalidArgumentException('Cannot change target of link share');
1238
+        }
1239
+
1240
+        if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() !== $recipientId) {
1241
+            throw new \InvalidArgumentException('Invalid recipient');
1242
+        }
1243
+
1244
+        if ($share->getShareType() === IShare::TYPE_GROUP) {
1245
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1246
+            if (is_null($sharedWith)) {
1247
+                throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1248
+            }
1249
+            $recipient = $this->userManager->get($recipientId);
1250
+            if (!$sharedWith->inGroup($recipient)) {
1251
+                throw new \InvalidArgumentException('Invalid recipient');
1252
+            }
1253
+        }
1254
+
1255
+        [$providerId,] = $this->splitFullId($share->getFullId());
1256
+        $provider = $this->factory->getProvider($providerId);
1257
+
1258
+        return $provider->move($share, $recipientId);
1259
+    }
1260
+
1261
+    public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1262
+        $providers = $this->factory->getAllProviders();
1263
+
1264
+        return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1265
+            $newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1266
+            foreach ($newShares as $fid => $data) {
1267
+                if (!isset($shares[$fid])) {
1268
+                    $shares[$fid] = [];
1269
+                }
1270
+
1271
+                $shares[$fid] = array_merge($shares[$fid], $data);
1272
+            }
1273
+            return $shares;
1274
+        }, []);
1275
+    }
1276
+
1277
+    /**
1278
+     * @inheritdoc
1279
+     */
1280
+    public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1281
+        if ($path !== null &&
1282
+            !($path instanceof \OCP\Files\File) &&
1283
+            !($path instanceof \OCP\Files\Folder)) {
1284
+            throw new \InvalidArgumentException('invalid path');
1285
+        }
1286
+
1287
+        try {
1288
+            $provider = $this->factory->getProviderForType($shareType);
1289
+        } catch (ProviderException $e) {
1290
+            return [];
1291
+        }
1292
+
1293
+        $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1294
+
1295
+        /*
1296 1296
 		 * Work around so we don't return expired shares but still follow
1297 1297
 		 * proper pagination.
1298 1298
 		 */
1299 1299
 
1300
-		$shares2 = [];
1301
-
1302
-		while (true) {
1303
-			$added = 0;
1304
-			foreach ($shares as $share) {
1305
-				try {
1306
-					$this->checkExpireDate($share);
1307
-				} catch (ShareNotFound $e) {
1308
-					//Ignore since this basically means the share is deleted
1309
-					continue;
1310
-				}
1311
-
1312
-				$added++;
1313
-				$shares2[] = $share;
1314
-
1315
-				if (count($shares2) === $limit) {
1316
-					break;
1317
-				}
1318
-			}
1319
-
1320
-			// If we did not fetch more shares than the limit then there are no more shares
1321
-			if (count($shares) < $limit) {
1322
-				break;
1323
-			}
1324
-
1325
-			if (count($shares2) === $limit) {
1326
-				break;
1327
-			}
1328
-
1329
-			// If there was no limit on the select we are done
1330
-			if ($limit === -1) {
1331
-				break;
1332
-			}
1333
-
1334
-			$offset += $added;
1335
-
1336
-			// Fetch again $limit shares
1337
-			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1338
-
1339
-			// No more shares means we are done
1340
-			if (empty($shares)) {
1341
-				break;
1342
-			}
1343
-		}
1344
-
1345
-		$shares = $shares2;
1346
-
1347
-		return $shares;
1348
-	}
1349
-
1350
-	/**
1351
-	 * @inheritdoc
1352
-	 */
1353
-	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1354
-		try {
1355
-			$provider = $this->factory->getProviderForType($shareType);
1356
-		} catch (ProviderException $e) {
1357
-			return [];
1358
-		}
1359
-
1360
-		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1361
-
1362
-		// remove all shares which are already expired
1363
-		foreach ($shares as $key => $share) {
1364
-			try {
1365
-				$this->checkExpireDate($share);
1366
-			} catch (ShareNotFound $e) {
1367
-				unset($shares[$key]);
1368
-			}
1369
-		}
1370
-
1371
-		return $shares;
1372
-	}
1373
-
1374
-	/**
1375
-	 * @inheritdoc
1376
-	 */
1377
-	public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1378
-		$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1379
-
1380
-		// Only get deleted shares
1381
-		$shares = array_filter($shares, function (IShare $share) {
1382
-			return $share->getPermissions() === 0;
1383
-		});
1384
-
1385
-		// Only get shares where the owner still exists
1386
-		$shares = array_filter($shares, function (IShare $share) {
1387
-			return $this->userManager->userExists($share->getShareOwner());
1388
-		});
1389
-
1390
-		return $shares;
1391
-	}
1392
-
1393
-	/**
1394
-	 * @inheritdoc
1395
-	 */
1396
-	public function getShareById($id, $recipient = null) {
1397
-		if ($id === null) {
1398
-			throw new ShareNotFound();
1399
-		}
1400
-
1401
-		[$providerId, $id] = $this->splitFullId($id);
1402
-
1403
-		try {
1404
-			$provider = $this->factory->getProvider($providerId);
1405
-		} catch (ProviderException $e) {
1406
-			throw new ShareNotFound();
1407
-		}
1408
-
1409
-		$share = $provider->getShareById($id, $recipient);
1410
-
1411
-		$this->checkExpireDate($share);
1412
-
1413
-		return $share;
1414
-	}
1415
-
1416
-	/**
1417
-	 * Get all the shares for a given path
1418
-	 *
1419
-	 * @param \OCP\Files\Node $path
1420
-	 * @param int $page
1421
-	 * @param int $perPage
1422
-	 *
1423
-	 * @return Share[]
1424
-	 */
1425
-	public function getSharesByPath(\OCP\Files\Node $path, $page = 0, $perPage = 50) {
1426
-		return [];
1427
-	}
1428
-
1429
-	/**
1430
-	 * Get the share by token possible with password
1431
-	 *
1432
-	 * @param string $token
1433
-	 * @return IShare
1434
-	 *
1435
-	 * @throws ShareNotFound
1436
-	 */
1437
-	public function getShareByToken($token) {
1438
-		// tokens cannot be valid local user names
1439
-		if ($this->userManager->userExists($token)) {
1440
-			throw new ShareNotFound();
1441
-		}
1442
-		$share = null;
1443
-		try {
1444
-			if ($this->shareApiAllowLinks()) {
1445
-				$provider = $this->factory->getProviderForType(IShare::TYPE_LINK);
1446
-				$share = $provider->getShareByToken($token);
1447
-			}
1448
-		} catch (ProviderException $e) {
1449
-		} catch (ShareNotFound $e) {
1450
-		}
1451
-
1452
-
1453
-		// If it is not a link share try to fetch a federated share by token
1454
-		if ($share === null) {
1455
-			try {
1456
-				$provider = $this->factory->getProviderForType(IShare::TYPE_REMOTE);
1457
-				$share = $provider->getShareByToken($token);
1458
-			} catch (ProviderException $e) {
1459
-			} catch (ShareNotFound $e) {
1460
-			}
1461
-		}
1462
-
1463
-		// If it is not a link share try to fetch a mail share by token
1464
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_EMAIL)) {
1465
-			try {
1466
-				$provider = $this->factory->getProviderForType(IShare::TYPE_EMAIL);
1467
-				$share = $provider->getShareByToken($token);
1468
-			} catch (ProviderException $e) {
1469
-			} catch (ShareNotFound $e) {
1470
-			}
1471
-		}
1472
-
1473
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_CIRCLE)) {
1474
-			try {
1475
-				$provider = $this->factory->getProviderForType(IShare::TYPE_CIRCLE);
1476
-				$share = $provider->getShareByToken($token);
1477
-			} catch (ProviderException $e) {
1478
-			} catch (ShareNotFound $e) {
1479
-			}
1480
-		}
1481
-
1482
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_ROOM)) {
1483
-			try {
1484
-				$provider = $this->factory->getProviderForType(IShare::TYPE_ROOM);
1485
-				$share = $provider->getShareByToken($token);
1486
-			} catch (ProviderException $e) {
1487
-			} catch (ShareNotFound $e) {
1488
-			}
1489
-		}
1490
-
1491
-		if ($share === null) {
1492
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1493
-		}
1494
-
1495
-		$this->checkExpireDate($share);
1496
-
1497
-		/*
1300
+        $shares2 = [];
1301
+
1302
+        while (true) {
1303
+            $added = 0;
1304
+            foreach ($shares as $share) {
1305
+                try {
1306
+                    $this->checkExpireDate($share);
1307
+                } catch (ShareNotFound $e) {
1308
+                    //Ignore since this basically means the share is deleted
1309
+                    continue;
1310
+                }
1311
+
1312
+                $added++;
1313
+                $shares2[] = $share;
1314
+
1315
+                if (count($shares2) === $limit) {
1316
+                    break;
1317
+                }
1318
+            }
1319
+
1320
+            // If we did not fetch more shares than the limit then there are no more shares
1321
+            if (count($shares) < $limit) {
1322
+                break;
1323
+            }
1324
+
1325
+            if (count($shares2) === $limit) {
1326
+                break;
1327
+            }
1328
+
1329
+            // If there was no limit on the select we are done
1330
+            if ($limit === -1) {
1331
+                break;
1332
+            }
1333
+
1334
+            $offset += $added;
1335
+
1336
+            // Fetch again $limit shares
1337
+            $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1338
+
1339
+            // No more shares means we are done
1340
+            if (empty($shares)) {
1341
+                break;
1342
+            }
1343
+        }
1344
+
1345
+        $shares = $shares2;
1346
+
1347
+        return $shares;
1348
+    }
1349
+
1350
+    /**
1351
+     * @inheritdoc
1352
+     */
1353
+    public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1354
+        try {
1355
+            $provider = $this->factory->getProviderForType($shareType);
1356
+        } catch (ProviderException $e) {
1357
+            return [];
1358
+        }
1359
+
1360
+        $shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1361
+
1362
+        // remove all shares which are already expired
1363
+        foreach ($shares as $key => $share) {
1364
+            try {
1365
+                $this->checkExpireDate($share);
1366
+            } catch (ShareNotFound $e) {
1367
+                unset($shares[$key]);
1368
+            }
1369
+        }
1370
+
1371
+        return $shares;
1372
+    }
1373
+
1374
+    /**
1375
+     * @inheritdoc
1376
+     */
1377
+    public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1378
+        $shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1379
+
1380
+        // Only get deleted shares
1381
+        $shares = array_filter($shares, function (IShare $share) {
1382
+            return $share->getPermissions() === 0;
1383
+        });
1384
+
1385
+        // Only get shares where the owner still exists
1386
+        $shares = array_filter($shares, function (IShare $share) {
1387
+            return $this->userManager->userExists($share->getShareOwner());
1388
+        });
1389
+
1390
+        return $shares;
1391
+    }
1392
+
1393
+    /**
1394
+     * @inheritdoc
1395
+     */
1396
+    public function getShareById($id, $recipient = null) {
1397
+        if ($id === null) {
1398
+            throw new ShareNotFound();
1399
+        }
1400
+
1401
+        [$providerId, $id] = $this->splitFullId($id);
1402
+
1403
+        try {
1404
+            $provider = $this->factory->getProvider($providerId);
1405
+        } catch (ProviderException $e) {
1406
+            throw new ShareNotFound();
1407
+        }
1408
+
1409
+        $share = $provider->getShareById($id, $recipient);
1410
+
1411
+        $this->checkExpireDate($share);
1412
+
1413
+        return $share;
1414
+    }
1415
+
1416
+    /**
1417
+     * Get all the shares for a given path
1418
+     *
1419
+     * @param \OCP\Files\Node $path
1420
+     * @param int $page
1421
+     * @param int $perPage
1422
+     *
1423
+     * @return Share[]
1424
+     */
1425
+    public function getSharesByPath(\OCP\Files\Node $path, $page = 0, $perPage = 50) {
1426
+        return [];
1427
+    }
1428
+
1429
+    /**
1430
+     * Get the share by token possible with password
1431
+     *
1432
+     * @param string $token
1433
+     * @return IShare
1434
+     *
1435
+     * @throws ShareNotFound
1436
+     */
1437
+    public function getShareByToken($token) {
1438
+        // tokens cannot be valid local user names
1439
+        if ($this->userManager->userExists($token)) {
1440
+            throw new ShareNotFound();
1441
+        }
1442
+        $share = null;
1443
+        try {
1444
+            if ($this->shareApiAllowLinks()) {
1445
+                $provider = $this->factory->getProviderForType(IShare::TYPE_LINK);
1446
+                $share = $provider->getShareByToken($token);
1447
+            }
1448
+        } catch (ProviderException $e) {
1449
+        } catch (ShareNotFound $e) {
1450
+        }
1451
+
1452
+
1453
+        // If it is not a link share try to fetch a federated share by token
1454
+        if ($share === null) {
1455
+            try {
1456
+                $provider = $this->factory->getProviderForType(IShare::TYPE_REMOTE);
1457
+                $share = $provider->getShareByToken($token);
1458
+            } catch (ProviderException $e) {
1459
+            } catch (ShareNotFound $e) {
1460
+            }
1461
+        }
1462
+
1463
+        // If it is not a link share try to fetch a mail share by token
1464
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_EMAIL)) {
1465
+            try {
1466
+                $provider = $this->factory->getProviderForType(IShare::TYPE_EMAIL);
1467
+                $share = $provider->getShareByToken($token);
1468
+            } catch (ProviderException $e) {
1469
+            } catch (ShareNotFound $e) {
1470
+            }
1471
+        }
1472
+
1473
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_CIRCLE)) {
1474
+            try {
1475
+                $provider = $this->factory->getProviderForType(IShare::TYPE_CIRCLE);
1476
+                $share = $provider->getShareByToken($token);
1477
+            } catch (ProviderException $e) {
1478
+            } catch (ShareNotFound $e) {
1479
+            }
1480
+        }
1481
+
1482
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_ROOM)) {
1483
+            try {
1484
+                $provider = $this->factory->getProviderForType(IShare::TYPE_ROOM);
1485
+                $share = $provider->getShareByToken($token);
1486
+            } catch (ProviderException $e) {
1487
+            } catch (ShareNotFound $e) {
1488
+            }
1489
+        }
1490
+
1491
+        if ($share === null) {
1492
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1493
+        }
1494
+
1495
+        $this->checkExpireDate($share);
1496
+
1497
+        /*
1498 1498
 		 * Reduce the permissions for link or email shares if public upload is not enabled
1499 1499
 		 */
1500
-		if (($share->getShareType() === IShare::TYPE_LINK || $share->getShareType() === IShare::TYPE_EMAIL)
1501
-			&& !$this->shareApiLinkAllowPublicUpload()) {
1502
-			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1503
-		}
1504
-
1505
-		return $share;
1506
-	}
1507
-
1508
-	protected function checkExpireDate($share) {
1509
-		if ($share->isExpired()) {
1510
-			$this->deleteShare($share);
1511
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1512
-		}
1513
-	}
1514
-
1515
-	/**
1516
-	 * Verify the password of a public share
1517
-	 *
1518
-	 * @param IShare $share
1519
-	 * @param string $password
1520
-	 * @return bool
1521
-	 */
1522
-	public function checkPassword(IShare $share, $password) {
1523
-		$passwordProtected = $share->getShareType() !== IShare::TYPE_LINK
1524
-			|| $share->getShareType() !== IShare::TYPE_EMAIL
1525
-			|| $share->getShareType() !== IShare::TYPE_CIRCLE;
1526
-		if (!$passwordProtected) {
1527
-			//TODO maybe exception?
1528
-			return false;
1529
-		}
1530
-
1531
-		if ($password === null || $share->getPassword() === null) {
1532
-			return false;
1533
-		}
1534
-
1535
-		$newHash = '';
1536
-		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1537
-			return false;
1538
-		}
1539
-
1540
-		if (!empty($newHash)) {
1541
-			$share->setPassword($newHash);
1542
-			$provider = $this->factory->getProviderForType($share->getShareType());
1543
-			$provider->update($share);
1544
-		}
1545
-
1546
-		return true;
1547
-	}
1548
-
1549
-	/**
1550
-	 * @inheritdoc
1551
-	 */
1552
-	public function userDeleted($uid) {
1553
-		$types = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK, IShare::TYPE_REMOTE, IShare::TYPE_EMAIL];
1554
-
1555
-		foreach ($types as $type) {
1556
-			try {
1557
-				$provider = $this->factory->getProviderForType($type);
1558
-			} catch (ProviderException $e) {
1559
-				continue;
1560
-			}
1561
-			$provider->userDeleted($uid, $type);
1562
-		}
1563
-	}
1564
-
1565
-	/**
1566
-	 * @inheritdoc
1567
-	 */
1568
-	public function groupDeleted($gid) {
1569
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1570
-		$provider->groupDeleted($gid);
1571
-
1572
-		$excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1573
-		if ($excludedGroups === '') {
1574
-			return;
1575
-		}
1576
-
1577
-		$excludedGroups = json_decode($excludedGroups, true);
1578
-		if (json_last_error() !== JSON_ERROR_NONE) {
1579
-			return;
1580
-		}
1581
-
1582
-		$excludedGroups = array_diff($excludedGroups, [$gid]);
1583
-		$this->config->setAppValue('core', 'shareapi_exclude_groups_list', json_encode($excludedGroups));
1584
-	}
1585
-
1586
-	/**
1587
-	 * @inheritdoc
1588
-	 */
1589
-	public function userDeletedFromGroup($uid, $gid) {
1590
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1591
-		$provider->userDeletedFromGroup($uid, $gid);
1592
-	}
1593
-
1594
-	/**
1595
-	 * Get access list to a path. This means
1596
-	 * all the users that can access a given path.
1597
-	 *
1598
-	 * Consider:
1599
-	 * -root
1600
-	 * |-folder1 (23)
1601
-	 *  |-folder2 (32)
1602
-	 *   |-fileA (42)
1603
-	 *
1604
-	 * fileA is shared with user1 and user1@server1
1605
-	 * folder2 is shared with group2 (user4 is a member of group2)
1606
-	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1607
-	 *
1608
-	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1609
-	 * [
1610
-	 *  users  => [
1611
-	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1612
-	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1613
-	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1614
-	 *  ],
1615
-	 *  remote => [
1616
-	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1617
-	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1618
-	 *  ],
1619
-	 *  public => bool
1620
-	 *  mail => bool
1621
-	 * ]
1622
-	 *
1623
-	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1624
-	 * [
1625
-	 *  users  => ['user1', 'user2', 'user4'],
1626
-	 *  remote => bool,
1627
-	 *  public => bool
1628
-	 *  mail => bool
1629
-	 * ]
1630
-	 *
1631
-	 * This is required for encryption/activity
1632
-	 *
1633
-	 * @param \OCP\Files\Node $path
1634
-	 * @param bool $recursive Should we check all parent folders as well
1635
-	 * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1636
-	 * @return array
1637
-	 */
1638
-	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1639
-		$owner = $path->getOwner();
1640
-
1641
-		if ($owner === null) {
1642
-			return [];
1643
-		}
1644
-
1645
-		$owner = $owner->getUID();
1646
-
1647
-		if ($currentAccess) {
1648
-			$al = ['users' => [], 'remote' => [], 'public' => false];
1649
-		} else {
1650
-			$al = ['users' => [], 'remote' => false, 'public' => false];
1651
-		}
1652
-		if (!$this->userManager->userExists($owner)) {
1653
-			return $al;
1654
-		}
1655
-
1656
-		//Get node for the owner and correct the owner in case of external storage
1657
-		$userFolder = $this->rootFolder->getUserFolder($owner);
1658
-		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1659
-			$nodes = $userFolder->getById($path->getId());
1660
-			$path = array_shift($nodes);
1661
-			if ($path->getOwner() === null) {
1662
-				return [];
1663
-			}
1664
-			$owner = $path->getOwner()->getUID();
1665
-		}
1666
-
1667
-		$providers = $this->factory->getAllProviders();
1668
-
1669
-		/** @var Node[] $nodes */
1670
-		$nodes = [];
1671
-
1672
-
1673
-		if ($currentAccess) {
1674
-			$ownerPath = $path->getPath();
1675
-			$ownerPath = explode('/', $ownerPath, 4);
1676
-			if (count($ownerPath) < 4) {
1677
-				$ownerPath = '';
1678
-			} else {
1679
-				$ownerPath = $ownerPath[3];
1680
-			}
1681
-			$al['users'][$owner] = [
1682
-				'node_id' => $path->getId(),
1683
-				'node_path' => '/' . $ownerPath,
1684
-			];
1685
-		} else {
1686
-			$al['users'][] = $owner;
1687
-		}
1688
-
1689
-		// Collect all the shares
1690
-		while ($path->getPath() !== $userFolder->getPath()) {
1691
-			$nodes[] = $path;
1692
-			if (!$recursive) {
1693
-				break;
1694
-			}
1695
-			$path = $path->getParent();
1696
-		}
1697
-
1698
-		foreach ($providers as $provider) {
1699
-			$tmp = $provider->getAccessList($nodes, $currentAccess);
1700
-
1701
-			foreach ($tmp as $k => $v) {
1702
-				if (isset($al[$k])) {
1703
-					if (is_array($al[$k])) {
1704
-						if ($currentAccess) {
1705
-							$al[$k] += $v;
1706
-						} else {
1707
-							$al[$k] = array_merge($al[$k], $v);
1708
-							$al[$k] = array_unique($al[$k]);
1709
-							$al[$k] = array_values($al[$k]);
1710
-						}
1711
-					} else {
1712
-						$al[$k] = $al[$k] || $v;
1713
-					}
1714
-				} else {
1715
-					$al[$k] = $v;
1716
-				}
1717
-			}
1718
-		}
1719
-
1720
-		return $al;
1721
-	}
1722
-
1723
-	/**
1724
-	 * Create a new share
1725
-	 *
1726
-	 * @return IShare
1727
-	 */
1728
-	public function newShare() {
1729
-		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1730
-	}
1731
-
1732
-	/**
1733
-	 * Is the share API enabled
1734
-	 *
1735
-	 * @return bool
1736
-	 */
1737
-	public function shareApiEnabled() {
1738
-		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1739
-	}
1740
-
1741
-	/**
1742
-	 * Is public link sharing enabled
1743
-	 *
1744
-	 * @return bool
1745
-	 */
1746
-	public function shareApiAllowLinks() {
1747
-		if ($this->config->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
1748
-			return false;
1749
-		}
1750
-
1751
-		$user = $this->userSession->getUser();
1752
-		if ($user) {
1753
-			$excludedGroups = json_decode($this->config->getAppValue('core', 'shareapi_allow_links_exclude_groups', '[]'));
1754
-			if ($excludedGroups) {
1755
-				$userGroups = $this->groupManager->getUserGroupIds($user);
1756
-				return !(bool)array_intersect($excludedGroups, $userGroups);
1757
-			}
1758
-		}
1759
-
1760
-		return true;
1761
-	}
1762
-
1763
-	/**
1764
-	 * Is password on public link requires
1765
-	 *
1766
-	 * @return bool
1767
-	 */
1768
-	public function shareApiLinkEnforcePassword() {
1769
-		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1770
-	}
1771
-
1772
-	/**
1773
-	 * Is default link expire date enabled
1774
-	 *
1775
-	 * @return bool
1776
-	 */
1777
-	public function shareApiLinkDefaultExpireDate() {
1778
-		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1779
-	}
1780
-
1781
-	/**
1782
-	 * Is default link expire date enforced
1783
-	 *`
1784
-	 *
1785
-	 * @return bool
1786
-	 */
1787
-	public function shareApiLinkDefaultExpireDateEnforced() {
1788
-		return $this->shareApiLinkDefaultExpireDate() &&
1789
-			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1790
-	}
1791
-
1792
-
1793
-	/**
1794
-	 * Number of default link expire days
1795
-	 *
1796
-	 * @return int
1797
-	 */
1798
-	public function shareApiLinkDefaultExpireDays() {
1799
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1800
-	}
1801
-
1802
-	/**
1803
-	 * Is default internal expire date enabled
1804
-	 *
1805
-	 * @return bool
1806
-	 */
1807
-	public function shareApiInternalDefaultExpireDate(): bool {
1808
-		return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
1809
-	}
1810
-
1811
-	/**
1812
-	 * Is default remote expire date enabled
1813
-	 *
1814
-	 * @return bool
1815
-	 */
1816
-	public function shareApiRemoteDefaultExpireDate(): bool {
1817
-		return $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no') === 'yes';
1818
-	}
1819
-
1820
-	/**
1821
-	 * Is default expire date enforced
1822
-	 *
1823
-	 * @return bool
1824
-	 */
1825
-	public function shareApiInternalDefaultExpireDateEnforced(): bool {
1826
-		return $this->shareApiInternalDefaultExpireDate() &&
1827
-			$this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
1828
-	}
1829
-
1830
-	/**
1831
-	 * Is default expire date enforced for remote shares
1832
-	 *
1833
-	 * @return bool
1834
-	 */
1835
-	public function shareApiRemoteDefaultExpireDateEnforced(): bool {
1836
-		return $this->shareApiRemoteDefaultExpireDate() &&
1837
-			$this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes';
1838
-	}
1839
-
1840
-	/**
1841
-	 * Number of default expire days
1842
-	 *
1843
-	 * @return int
1844
-	 */
1845
-	public function shareApiInternalDefaultExpireDays(): int {
1846
-		return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1847
-	}
1848
-
1849
-	/**
1850
-	 * Number of default expire days for remote shares
1851
-	 *
1852
-	 * @return int
1853
-	 */
1854
-	public function shareApiRemoteDefaultExpireDays(): int {
1855
-		return (int)$this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
1856
-	}
1857
-
1858
-	/**
1859
-	 * Allow public upload on link shares
1860
-	 *
1861
-	 * @return bool
1862
-	 */
1863
-	public function shareApiLinkAllowPublicUpload() {
1864
-		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1865
-	}
1866
-
1867
-	/**
1868
-	 * check if user can only share with group members
1869
-	 *
1870
-	 * @return bool
1871
-	 */
1872
-	public function shareWithGroupMembersOnly() {
1873
-		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1874
-	}
1875
-
1876
-	/**
1877
-	 * Check if users can share with groups
1878
-	 *
1879
-	 * @return bool
1880
-	 */
1881
-	public function allowGroupSharing() {
1882
-		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1883
-	}
1884
-
1885
-	public function allowEnumeration(): bool {
1886
-		return $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
1887
-	}
1888
-
1889
-	public function limitEnumerationToGroups(): bool {
1890
-		return $this->allowEnumeration() &&
1891
-			$this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
1892
-	}
1893
-
1894
-	public function limitEnumerationToPhone(): bool {
1895
-		return $this->allowEnumeration() &&
1896
-			$this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
1897
-	}
1898
-
1899
-	public function allowEnumerationFullMatch(): bool {
1900
-		return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
1901
-	}
1902
-
1903
-	/**
1904
-	 * Copied from \OC_Util::isSharingDisabledForUser
1905
-	 *
1906
-	 * TODO: Deprecate fuction from OC_Util
1907
-	 *
1908
-	 * @param string $userId
1909
-	 * @return bool
1910
-	 */
1911
-	public function sharingDisabledForUser($userId) {
1912
-		if ($userId === null) {
1913
-			return false;
1914
-		}
1915
-
1916
-		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1917
-			return $this->sharingDisabledForUsersCache[$userId];
1918
-		}
1919
-
1920
-		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1921
-			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1922
-			$excludedGroups = json_decode($groupsList);
1923
-			if (is_null($excludedGroups)) {
1924
-				$excludedGroups = explode(',', $groupsList);
1925
-				$newValue = json_encode($excludedGroups);
1926
-				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1927
-			}
1928
-			$user = $this->userManager->get($userId);
1929
-			$usersGroups = $this->groupManager->getUserGroupIds($user);
1930
-			if (!empty($usersGroups)) {
1931
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1932
-				// if the user is only in groups which are disabled for sharing then
1933
-				// sharing is also disabled for the user
1934
-				if (empty($remainingGroups)) {
1935
-					$this->sharingDisabledForUsersCache[$userId] = true;
1936
-					return true;
1937
-				}
1938
-			}
1939
-		}
1940
-
1941
-		$this->sharingDisabledForUsersCache[$userId] = false;
1942
-		return false;
1943
-	}
1944
-
1945
-	/**
1946
-	 * @inheritdoc
1947
-	 */
1948
-	public function outgoingServer2ServerSharesAllowed() {
1949
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1950
-	}
1951
-
1952
-	/**
1953
-	 * @inheritdoc
1954
-	 */
1955
-	public function outgoingServer2ServerGroupSharesAllowed() {
1956
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1957
-	}
1958
-
1959
-	/**
1960
-	 * @inheritdoc
1961
-	 */
1962
-	public function shareProviderExists($shareType) {
1963
-		try {
1964
-			$this->factory->getProviderForType($shareType);
1965
-		} catch (ProviderException $e) {
1966
-			return false;
1967
-		}
1968
-
1969
-		return true;
1970
-	}
1971
-
1972
-	public function registerShareProvider(string $shareProviderClass): void {
1973
-		$this->factory->registerProvider($shareProviderClass);
1974
-	}
1975
-
1976
-	public function getAllShares(): iterable {
1977
-		$providers = $this->factory->getAllProviders();
1978
-
1979
-		foreach ($providers as $provider) {
1980
-			yield from $provider->getAllShares();
1981
-		}
1982
-	}
1500
+        if (($share->getShareType() === IShare::TYPE_LINK || $share->getShareType() === IShare::TYPE_EMAIL)
1501
+            && !$this->shareApiLinkAllowPublicUpload()) {
1502
+            $share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1503
+        }
1504
+
1505
+        return $share;
1506
+    }
1507
+
1508
+    protected function checkExpireDate($share) {
1509
+        if ($share->isExpired()) {
1510
+            $this->deleteShare($share);
1511
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1512
+        }
1513
+    }
1514
+
1515
+    /**
1516
+     * Verify the password of a public share
1517
+     *
1518
+     * @param IShare $share
1519
+     * @param string $password
1520
+     * @return bool
1521
+     */
1522
+    public function checkPassword(IShare $share, $password) {
1523
+        $passwordProtected = $share->getShareType() !== IShare::TYPE_LINK
1524
+            || $share->getShareType() !== IShare::TYPE_EMAIL
1525
+            || $share->getShareType() !== IShare::TYPE_CIRCLE;
1526
+        if (!$passwordProtected) {
1527
+            //TODO maybe exception?
1528
+            return false;
1529
+        }
1530
+
1531
+        if ($password === null || $share->getPassword() === null) {
1532
+            return false;
1533
+        }
1534
+
1535
+        $newHash = '';
1536
+        if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1537
+            return false;
1538
+        }
1539
+
1540
+        if (!empty($newHash)) {
1541
+            $share->setPassword($newHash);
1542
+            $provider = $this->factory->getProviderForType($share->getShareType());
1543
+            $provider->update($share);
1544
+        }
1545
+
1546
+        return true;
1547
+    }
1548
+
1549
+    /**
1550
+     * @inheritdoc
1551
+     */
1552
+    public function userDeleted($uid) {
1553
+        $types = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK, IShare::TYPE_REMOTE, IShare::TYPE_EMAIL];
1554
+
1555
+        foreach ($types as $type) {
1556
+            try {
1557
+                $provider = $this->factory->getProviderForType($type);
1558
+            } catch (ProviderException $e) {
1559
+                continue;
1560
+            }
1561
+            $provider->userDeleted($uid, $type);
1562
+        }
1563
+    }
1564
+
1565
+    /**
1566
+     * @inheritdoc
1567
+     */
1568
+    public function groupDeleted($gid) {
1569
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1570
+        $provider->groupDeleted($gid);
1571
+
1572
+        $excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1573
+        if ($excludedGroups === '') {
1574
+            return;
1575
+        }
1576
+
1577
+        $excludedGroups = json_decode($excludedGroups, true);
1578
+        if (json_last_error() !== JSON_ERROR_NONE) {
1579
+            return;
1580
+        }
1581
+
1582
+        $excludedGroups = array_diff($excludedGroups, [$gid]);
1583
+        $this->config->setAppValue('core', 'shareapi_exclude_groups_list', json_encode($excludedGroups));
1584
+    }
1585
+
1586
+    /**
1587
+     * @inheritdoc
1588
+     */
1589
+    public function userDeletedFromGroup($uid, $gid) {
1590
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1591
+        $provider->userDeletedFromGroup($uid, $gid);
1592
+    }
1593
+
1594
+    /**
1595
+     * Get access list to a path. This means
1596
+     * all the users that can access a given path.
1597
+     *
1598
+     * Consider:
1599
+     * -root
1600
+     * |-folder1 (23)
1601
+     *  |-folder2 (32)
1602
+     *   |-fileA (42)
1603
+     *
1604
+     * fileA is shared with user1 and user1@server1
1605
+     * folder2 is shared with group2 (user4 is a member of group2)
1606
+     * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1607
+     *
1608
+     * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1609
+     * [
1610
+     *  users  => [
1611
+     *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1612
+     *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1613
+     *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1614
+     *  ],
1615
+     *  remote => [
1616
+     *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1617
+     *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1618
+     *  ],
1619
+     *  public => bool
1620
+     *  mail => bool
1621
+     * ]
1622
+     *
1623
+     * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1624
+     * [
1625
+     *  users  => ['user1', 'user2', 'user4'],
1626
+     *  remote => bool,
1627
+     *  public => bool
1628
+     *  mail => bool
1629
+     * ]
1630
+     *
1631
+     * This is required for encryption/activity
1632
+     *
1633
+     * @param \OCP\Files\Node $path
1634
+     * @param bool $recursive Should we check all parent folders as well
1635
+     * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1636
+     * @return array
1637
+     */
1638
+    public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1639
+        $owner = $path->getOwner();
1640
+
1641
+        if ($owner === null) {
1642
+            return [];
1643
+        }
1644
+
1645
+        $owner = $owner->getUID();
1646
+
1647
+        if ($currentAccess) {
1648
+            $al = ['users' => [], 'remote' => [], 'public' => false];
1649
+        } else {
1650
+            $al = ['users' => [], 'remote' => false, 'public' => false];
1651
+        }
1652
+        if (!$this->userManager->userExists($owner)) {
1653
+            return $al;
1654
+        }
1655
+
1656
+        //Get node for the owner and correct the owner in case of external storage
1657
+        $userFolder = $this->rootFolder->getUserFolder($owner);
1658
+        if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1659
+            $nodes = $userFolder->getById($path->getId());
1660
+            $path = array_shift($nodes);
1661
+            if ($path->getOwner() === null) {
1662
+                return [];
1663
+            }
1664
+            $owner = $path->getOwner()->getUID();
1665
+        }
1666
+
1667
+        $providers = $this->factory->getAllProviders();
1668
+
1669
+        /** @var Node[] $nodes */
1670
+        $nodes = [];
1671
+
1672
+
1673
+        if ($currentAccess) {
1674
+            $ownerPath = $path->getPath();
1675
+            $ownerPath = explode('/', $ownerPath, 4);
1676
+            if (count($ownerPath) < 4) {
1677
+                $ownerPath = '';
1678
+            } else {
1679
+                $ownerPath = $ownerPath[3];
1680
+            }
1681
+            $al['users'][$owner] = [
1682
+                'node_id' => $path->getId(),
1683
+                'node_path' => '/' . $ownerPath,
1684
+            ];
1685
+        } else {
1686
+            $al['users'][] = $owner;
1687
+        }
1688
+
1689
+        // Collect all the shares
1690
+        while ($path->getPath() !== $userFolder->getPath()) {
1691
+            $nodes[] = $path;
1692
+            if (!$recursive) {
1693
+                break;
1694
+            }
1695
+            $path = $path->getParent();
1696
+        }
1697
+
1698
+        foreach ($providers as $provider) {
1699
+            $tmp = $provider->getAccessList($nodes, $currentAccess);
1700
+
1701
+            foreach ($tmp as $k => $v) {
1702
+                if (isset($al[$k])) {
1703
+                    if (is_array($al[$k])) {
1704
+                        if ($currentAccess) {
1705
+                            $al[$k] += $v;
1706
+                        } else {
1707
+                            $al[$k] = array_merge($al[$k], $v);
1708
+                            $al[$k] = array_unique($al[$k]);
1709
+                            $al[$k] = array_values($al[$k]);
1710
+                        }
1711
+                    } else {
1712
+                        $al[$k] = $al[$k] || $v;
1713
+                    }
1714
+                } else {
1715
+                    $al[$k] = $v;
1716
+                }
1717
+            }
1718
+        }
1719
+
1720
+        return $al;
1721
+    }
1722
+
1723
+    /**
1724
+     * Create a new share
1725
+     *
1726
+     * @return IShare
1727
+     */
1728
+    public function newShare() {
1729
+        return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1730
+    }
1731
+
1732
+    /**
1733
+     * Is the share API enabled
1734
+     *
1735
+     * @return bool
1736
+     */
1737
+    public function shareApiEnabled() {
1738
+        return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1739
+    }
1740
+
1741
+    /**
1742
+     * Is public link sharing enabled
1743
+     *
1744
+     * @return bool
1745
+     */
1746
+    public function shareApiAllowLinks() {
1747
+        if ($this->config->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
1748
+            return false;
1749
+        }
1750
+
1751
+        $user = $this->userSession->getUser();
1752
+        if ($user) {
1753
+            $excludedGroups = json_decode($this->config->getAppValue('core', 'shareapi_allow_links_exclude_groups', '[]'));
1754
+            if ($excludedGroups) {
1755
+                $userGroups = $this->groupManager->getUserGroupIds($user);
1756
+                return !(bool)array_intersect($excludedGroups, $userGroups);
1757
+            }
1758
+        }
1759
+
1760
+        return true;
1761
+    }
1762
+
1763
+    /**
1764
+     * Is password on public link requires
1765
+     *
1766
+     * @return bool
1767
+     */
1768
+    public function shareApiLinkEnforcePassword() {
1769
+        return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1770
+    }
1771
+
1772
+    /**
1773
+     * Is default link expire date enabled
1774
+     *
1775
+     * @return bool
1776
+     */
1777
+    public function shareApiLinkDefaultExpireDate() {
1778
+        return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1779
+    }
1780
+
1781
+    /**
1782
+     * Is default link expire date enforced
1783
+     *`
1784
+     *
1785
+     * @return bool
1786
+     */
1787
+    public function shareApiLinkDefaultExpireDateEnforced() {
1788
+        return $this->shareApiLinkDefaultExpireDate() &&
1789
+            $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1790
+    }
1791
+
1792
+
1793
+    /**
1794
+     * Number of default link expire days
1795
+     *
1796
+     * @return int
1797
+     */
1798
+    public function shareApiLinkDefaultExpireDays() {
1799
+        return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1800
+    }
1801
+
1802
+    /**
1803
+     * Is default internal expire date enabled
1804
+     *
1805
+     * @return bool
1806
+     */
1807
+    public function shareApiInternalDefaultExpireDate(): bool {
1808
+        return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
1809
+    }
1810
+
1811
+    /**
1812
+     * Is default remote expire date enabled
1813
+     *
1814
+     * @return bool
1815
+     */
1816
+    public function shareApiRemoteDefaultExpireDate(): bool {
1817
+        return $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no') === 'yes';
1818
+    }
1819
+
1820
+    /**
1821
+     * Is default expire date enforced
1822
+     *
1823
+     * @return bool
1824
+     */
1825
+    public function shareApiInternalDefaultExpireDateEnforced(): bool {
1826
+        return $this->shareApiInternalDefaultExpireDate() &&
1827
+            $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
1828
+    }
1829
+
1830
+    /**
1831
+     * Is default expire date enforced for remote shares
1832
+     *
1833
+     * @return bool
1834
+     */
1835
+    public function shareApiRemoteDefaultExpireDateEnforced(): bool {
1836
+        return $this->shareApiRemoteDefaultExpireDate() &&
1837
+            $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes';
1838
+    }
1839
+
1840
+    /**
1841
+     * Number of default expire days
1842
+     *
1843
+     * @return int
1844
+     */
1845
+    public function shareApiInternalDefaultExpireDays(): int {
1846
+        return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1847
+    }
1848
+
1849
+    /**
1850
+     * Number of default expire days for remote shares
1851
+     *
1852
+     * @return int
1853
+     */
1854
+    public function shareApiRemoteDefaultExpireDays(): int {
1855
+        return (int)$this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
1856
+    }
1857
+
1858
+    /**
1859
+     * Allow public upload on link shares
1860
+     *
1861
+     * @return bool
1862
+     */
1863
+    public function shareApiLinkAllowPublicUpload() {
1864
+        return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1865
+    }
1866
+
1867
+    /**
1868
+     * check if user can only share with group members
1869
+     *
1870
+     * @return bool
1871
+     */
1872
+    public function shareWithGroupMembersOnly() {
1873
+        return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1874
+    }
1875
+
1876
+    /**
1877
+     * Check if users can share with groups
1878
+     *
1879
+     * @return bool
1880
+     */
1881
+    public function allowGroupSharing() {
1882
+        return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1883
+    }
1884
+
1885
+    public function allowEnumeration(): bool {
1886
+        return $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
1887
+    }
1888
+
1889
+    public function limitEnumerationToGroups(): bool {
1890
+        return $this->allowEnumeration() &&
1891
+            $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
1892
+    }
1893
+
1894
+    public function limitEnumerationToPhone(): bool {
1895
+        return $this->allowEnumeration() &&
1896
+            $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
1897
+    }
1898
+
1899
+    public function allowEnumerationFullMatch(): bool {
1900
+        return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
1901
+    }
1902
+
1903
+    /**
1904
+     * Copied from \OC_Util::isSharingDisabledForUser
1905
+     *
1906
+     * TODO: Deprecate fuction from OC_Util
1907
+     *
1908
+     * @param string $userId
1909
+     * @return bool
1910
+     */
1911
+    public function sharingDisabledForUser($userId) {
1912
+        if ($userId === null) {
1913
+            return false;
1914
+        }
1915
+
1916
+        if (isset($this->sharingDisabledForUsersCache[$userId])) {
1917
+            return $this->sharingDisabledForUsersCache[$userId];
1918
+        }
1919
+
1920
+        if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1921
+            $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1922
+            $excludedGroups = json_decode($groupsList);
1923
+            if (is_null($excludedGroups)) {
1924
+                $excludedGroups = explode(',', $groupsList);
1925
+                $newValue = json_encode($excludedGroups);
1926
+                $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1927
+            }
1928
+            $user = $this->userManager->get($userId);
1929
+            $usersGroups = $this->groupManager->getUserGroupIds($user);
1930
+            if (!empty($usersGroups)) {
1931
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
1932
+                // if the user is only in groups which are disabled for sharing then
1933
+                // sharing is also disabled for the user
1934
+                if (empty($remainingGroups)) {
1935
+                    $this->sharingDisabledForUsersCache[$userId] = true;
1936
+                    return true;
1937
+                }
1938
+            }
1939
+        }
1940
+
1941
+        $this->sharingDisabledForUsersCache[$userId] = false;
1942
+        return false;
1943
+    }
1944
+
1945
+    /**
1946
+     * @inheritdoc
1947
+     */
1948
+    public function outgoingServer2ServerSharesAllowed() {
1949
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1950
+    }
1951
+
1952
+    /**
1953
+     * @inheritdoc
1954
+     */
1955
+    public function outgoingServer2ServerGroupSharesAllowed() {
1956
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1957
+    }
1958
+
1959
+    /**
1960
+     * @inheritdoc
1961
+     */
1962
+    public function shareProviderExists($shareType) {
1963
+        try {
1964
+            $this->factory->getProviderForType($shareType);
1965
+        } catch (ProviderException $e) {
1966
+            return false;
1967
+        }
1968
+
1969
+        return true;
1970
+    }
1971
+
1972
+    public function registerShareProvider(string $shareProviderClass): void {
1973
+        $this->factory->registerProvider($shareProviderClass);
1974
+    }
1975
+
1976
+    public function getAllShares(): iterable {
1977
+        $providers = $this->factory->getAllProviders();
1978
+
1979
+        foreach ($providers as $provider) {
1980
+            yield from $provider->getAllShares();
1981
+        }
1982
+    }
1983 1983
 }
Please login to merge, or discard this patch.