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