Passed
Push — master ( 8ef920...1c35b3 )
by Julius
32:28 queued 12s
created
lib/private/Share20/Manager.php 2 patches
Indentation   +1874 added lines, -1874 removed lines patch added patch discarded remove patch
@@ -78,1899 +78,1899 @@
 block discarded – undo
78 78
  */
79 79
 class Manager implements IManager {
80 80
 
81
-	/** @var IProviderFactory */
82
-	private $factory;
83
-	/** @var ILogger */
84
-	private $logger;
85
-	/** @var IConfig */
86
-	private $config;
87
-	/** @var ISecureRandom */
88
-	private $secureRandom;
89
-	/** @var IHasher */
90
-	private $hasher;
91
-	/** @var IMountManager */
92
-	private $mountManager;
93
-	/** @var IGroupManager */
94
-	private $groupManager;
95
-	/** @var IL10N */
96
-	private $l;
97
-	/** @var IFactory */
98
-	private $l10nFactory;
99
-	/** @var IUserManager */
100
-	private $userManager;
101
-	/** @var IRootFolder */
102
-	private $rootFolder;
103
-	/** @var CappedMemoryCache */
104
-	private $sharingDisabledForUsersCache;
105
-	/** @var EventDispatcherInterface */
106
-	private $legacyDispatcher;
107
-	/** @var LegacyHooks */
108
-	private $legacyHooks;
109
-	/** @var IMailer */
110
-	private $mailer;
111
-	/** @var IURLGenerator */
112
-	private $urlGenerator;
113
-	/** @var \OC_Defaults */
114
-	private $defaults;
115
-	/** @var IEventDispatcher */
116
-	private $dispatcher;
117
-
118
-
119
-	/**
120
-	 * Manager constructor.
121
-	 *
122
-	 * @param ILogger $logger
123
-	 * @param IConfig $config
124
-	 * @param ISecureRandom $secureRandom
125
-	 * @param IHasher $hasher
126
-	 * @param IMountManager $mountManager
127
-	 * @param IGroupManager $groupManager
128
-	 * @param IL10N $l
129
-	 * @param IFactory $l10nFactory
130
-	 * @param IProviderFactory $factory
131
-	 * @param IUserManager $userManager
132
-	 * @param IRootFolder $rootFolder
133
-	 * @param EventDispatcherInterface $eventDispatcher
134
-	 * @param IMailer $mailer
135
-	 * @param IURLGenerator $urlGenerator
136
-	 * @param \OC_Defaults $defaults
137
-	 */
138
-	public function __construct(
139
-			ILogger $logger,
140
-			IConfig $config,
141
-			ISecureRandom $secureRandom,
142
-			IHasher $hasher,
143
-			IMountManager $mountManager,
144
-			IGroupManager $groupManager,
145
-			IL10N $l,
146
-			IFactory $l10nFactory,
147
-			IProviderFactory $factory,
148
-			IUserManager $userManager,
149
-			IRootFolder $rootFolder,
150
-			EventDispatcherInterface $legacyDispatcher,
151
-			IMailer $mailer,
152
-			IURLGenerator $urlGenerator,
153
-			\OC_Defaults $defaults,
154
-			IEventDispatcher $dispatcher
155
-	) {
156
-		$this->logger = $logger;
157
-		$this->config = $config;
158
-		$this->secureRandom = $secureRandom;
159
-		$this->hasher = $hasher;
160
-		$this->mountManager = $mountManager;
161
-		$this->groupManager = $groupManager;
162
-		$this->l = $l;
163
-		$this->l10nFactory = $l10nFactory;
164
-		$this->factory = $factory;
165
-		$this->userManager = $userManager;
166
-		$this->rootFolder = $rootFolder;
167
-		$this->legacyDispatcher = $legacyDispatcher;
168
-		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
169
-		$this->legacyHooks = new LegacyHooks($this->legacyDispatcher);
170
-		$this->mailer = $mailer;
171
-		$this->urlGenerator = $urlGenerator;
172
-		$this->defaults = $defaults;
173
-		$this->dispatcher = $dispatcher;
174
-	}
175
-
176
-	/**
177
-	 * Convert from a full share id to a tuple (providerId, shareId)
178
-	 *
179
-	 * @param string $id
180
-	 * @return string[]
181
-	 */
182
-	private function splitFullId($id) {
183
-		return explode(':', $id, 2);
184
-	}
185
-
186
-	/**
187
-	 * Verify if a password meets all requirements
188
-	 *
189
-	 * @param string $password
190
-	 * @throws \Exception
191
-	 */
192
-	protected function verifyPassword($password) {
193
-		if ($password === null) {
194
-			// No password is set, check if this is allowed.
195
-			if ($this->shareApiLinkEnforcePassword()) {
196
-				throw new \InvalidArgumentException('Passwords are enforced for link and mail shares');
197
-			}
198
-
199
-			return;
200
-		}
201
-
202
-		// Let others verify the password
203
-		try {
204
-			$this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
205
-		} catch (HintException $e) {
206
-			throw new \Exception($e->getHint());
207
-		}
208
-	}
209
-
210
-	/**
211
-	 * Check for generic requirements before creating a share
212
-	 *
213
-	 * @param IShare $share
214
-	 * @throws \InvalidArgumentException
215
-	 * @throws GenericShareException
216
-	 *
217
-	 * @suppress PhanUndeclaredClassMethod
218
-	 */
219
-	protected function generalCreateChecks(IShare $share) {
220
-		if ($share->getShareType() === IShare::TYPE_USER) {
221
-			// We expect a valid user as sharedWith for user shares
222
-			if (!$this->userManager->userExists($share->getSharedWith())) {
223
-				throw new \InvalidArgumentException('SharedWith is not a valid user');
224
-			}
225
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
226
-			// We expect a valid group as sharedWith for group shares
227
-			if (!$this->groupManager->groupExists($share->getSharedWith())) {
228
-				throw new \InvalidArgumentException('SharedWith is not a valid group');
229
-			}
230
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
231
-			// No check for TYPE_EMAIL here as we have a recipient for them
232
-			if ($share->getSharedWith() !== null) {
233
-				throw new \InvalidArgumentException('SharedWith should be empty');
234
-			}
235
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
236
-			if ($share->getSharedWith() === null) {
237
-				throw new \InvalidArgumentException('SharedWith should not be empty');
238
-			}
239
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
240
-			if ($share->getSharedWith() === null) {
241
-				throw new \InvalidArgumentException('SharedWith should not be empty');
242
-			}
243
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
244
-			if ($share->getSharedWith() === null) {
245
-				throw new \InvalidArgumentException('SharedWith should not be empty');
246
-			}
247
-		} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
248
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
249
-			if ($circle === null) {
250
-				throw new \InvalidArgumentException('SharedWith is not a valid circle');
251
-			}
252
-		} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
253
-		} elseif ($share->getShareType() === IShare::TYPE_DECK) {
254
-		} else {
255
-			// We can't handle other types yet
256
-			throw new \InvalidArgumentException('unknown share type');
257
-		}
258
-
259
-		// Verify the initiator of the share is set
260
-		if ($share->getSharedBy() === null) {
261
-			throw new \InvalidArgumentException('SharedBy should be set');
262
-		}
263
-
264
-		// Cannot share with yourself
265
-		if ($share->getShareType() === IShare::TYPE_USER &&
266
-			$share->getSharedWith() === $share->getSharedBy()) {
267
-			throw new \InvalidArgumentException('Can’t share with yourself');
268
-		}
269
-
270
-		// The path should be set
271
-		if ($share->getNode() === null) {
272
-			throw new \InvalidArgumentException('Path should be set');
273
-		}
274
-
275
-		// And it should be a file or a folder
276
-		if (!($share->getNode() instanceof \OCP\Files\File) &&
277
-				!($share->getNode() instanceof \OCP\Files\Folder)) {
278
-			throw new \InvalidArgumentException('Path should be either a file or a folder');
279
-		}
280
-
281
-		// And you can't share your rootfolder
282
-		if ($this->userManager->userExists($share->getSharedBy())) {
283
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
284
-		} else {
285
-			$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
286
-		}
287
-		if ($userFolder->getId() === $share->getNode()->getId()) {
288
-			throw new \InvalidArgumentException('You can’t share your root folder');
289
-		}
290
-
291
-		// Check if we actually have share permissions
292
-		if (!$share->getNode()->isShareable()) {
293
-			$message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getName()]);
294
-			throw new GenericShareException($message_t, $message_t, 404);
295
-		}
296
-
297
-		// Permissions should be set
298
-		if ($share->getPermissions() === null) {
299
-			throw new \InvalidArgumentException('A share requires permissions');
300
-		}
301
-
302
-		$isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
303
-		$permissions = 0;
304
-
305
-		if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
306
-			$userMounts = array_filter($userFolder->getById($share->getNode()->getId()), function ($mount) {
307
-				// We need to filter since there might be other mountpoints that contain the file
308
-				// e.g. if the user has access to the same external storage that the file is originating from
309
-				return $mount->getStorage()->instanceOfStorage(ISharedStorage::class);
310
-			});
311
-			$userMount = array_shift($userMounts);
312
-			if ($userMount === null) {
313
-				throw new GenericShareException('Could not get proper share mount for ' . $share->getNode()->getId() . '. Failing since else the next calls are called with null');
314
-			}
315
-			$mount = $userMount->getMountPoint();
316
-			// When it's a reshare use the parent share permissions as maximum
317
-			$userMountPointId = $mount->getStorageRootId();
318
-			$userMountPoints = $userFolder->getById($userMountPointId);
319
-			$userMountPoint = array_shift($userMountPoints);
320
-
321
-			if ($userMountPoint === null) {
322
-				throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
323
-			}
324
-
325
-			/* Check if this is an incoming share */
326
-			$incomingShares = $this->getSharedWith($share->getSharedBy(), IShare::TYPE_USER, $userMountPoint, -1, 0);
327
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_GROUP, $userMountPoint, -1, 0));
328
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_CIRCLE, $userMountPoint, -1, 0));
329
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_ROOM, $userMountPoint, -1, 0));
330
-
331
-			/** @var IShare[] $incomingShares */
332
-			if (!empty($incomingShares)) {
333
-				foreach ($incomingShares as $incomingShare) {
334
-					$permissions |= $incomingShare->getPermissions();
335
-				}
336
-			}
337
-		} else {
338
-			/*
81
+    /** @var IProviderFactory */
82
+    private $factory;
83
+    /** @var ILogger */
84
+    private $logger;
85
+    /** @var IConfig */
86
+    private $config;
87
+    /** @var ISecureRandom */
88
+    private $secureRandom;
89
+    /** @var IHasher */
90
+    private $hasher;
91
+    /** @var IMountManager */
92
+    private $mountManager;
93
+    /** @var IGroupManager */
94
+    private $groupManager;
95
+    /** @var IL10N */
96
+    private $l;
97
+    /** @var IFactory */
98
+    private $l10nFactory;
99
+    /** @var IUserManager */
100
+    private $userManager;
101
+    /** @var IRootFolder */
102
+    private $rootFolder;
103
+    /** @var CappedMemoryCache */
104
+    private $sharingDisabledForUsersCache;
105
+    /** @var EventDispatcherInterface */
106
+    private $legacyDispatcher;
107
+    /** @var LegacyHooks */
108
+    private $legacyHooks;
109
+    /** @var IMailer */
110
+    private $mailer;
111
+    /** @var IURLGenerator */
112
+    private $urlGenerator;
113
+    /** @var \OC_Defaults */
114
+    private $defaults;
115
+    /** @var IEventDispatcher */
116
+    private $dispatcher;
117
+
118
+
119
+    /**
120
+     * Manager constructor.
121
+     *
122
+     * @param ILogger $logger
123
+     * @param IConfig $config
124
+     * @param ISecureRandom $secureRandom
125
+     * @param IHasher $hasher
126
+     * @param IMountManager $mountManager
127
+     * @param IGroupManager $groupManager
128
+     * @param IL10N $l
129
+     * @param IFactory $l10nFactory
130
+     * @param IProviderFactory $factory
131
+     * @param IUserManager $userManager
132
+     * @param IRootFolder $rootFolder
133
+     * @param EventDispatcherInterface $eventDispatcher
134
+     * @param IMailer $mailer
135
+     * @param IURLGenerator $urlGenerator
136
+     * @param \OC_Defaults $defaults
137
+     */
138
+    public function __construct(
139
+            ILogger $logger,
140
+            IConfig $config,
141
+            ISecureRandom $secureRandom,
142
+            IHasher $hasher,
143
+            IMountManager $mountManager,
144
+            IGroupManager $groupManager,
145
+            IL10N $l,
146
+            IFactory $l10nFactory,
147
+            IProviderFactory $factory,
148
+            IUserManager $userManager,
149
+            IRootFolder $rootFolder,
150
+            EventDispatcherInterface $legacyDispatcher,
151
+            IMailer $mailer,
152
+            IURLGenerator $urlGenerator,
153
+            \OC_Defaults $defaults,
154
+            IEventDispatcher $dispatcher
155
+    ) {
156
+        $this->logger = $logger;
157
+        $this->config = $config;
158
+        $this->secureRandom = $secureRandom;
159
+        $this->hasher = $hasher;
160
+        $this->mountManager = $mountManager;
161
+        $this->groupManager = $groupManager;
162
+        $this->l = $l;
163
+        $this->l10nFactory = $l10nFactory;
164
+        $this->factory = $factory;
165
+        $this->userManager = $userManager;
166
+        $this->rootFolder = $rootFolder;
167
+        $this->legacyDispatcher = $legacyDispatcher;
168
+        $this->sharingDisabledForUsersCache = new CappedMemoryCache();
169
+        $this->legacyHooks = new LegacyHooks($this->legacyDispatcher);
170
+        $this->mailer = $mailer;
171
+        $this->urlGenerator = $urlGenerator;
172
+        $this->defaults = $defaults;
173
+        $this->dispatcher = $dispatcher;
174
+    }
175
+
176
+    /**
177
+     * Convert from a full share id to a tuple (providerId, shareId)
178
+     *
179
+     * @param string $id
180
+     * @return string[]
181
+     */
182
+    private function splitFullId($id) {
183
+        return explode(':', $id, 2);
184
+    }
185
+
186
+    /**
187
+     * Verify if a password meets all requirements
188
+     *
189
+     * @param string $password
190
+     * @throws \Exception
191
+     */
192
+    protected function verifyPassword($password) {
193
+        if ($password === null) {
194
+            // No password is set, check if this is allowed.
195
+            if ($this->shareApiLinkEnforcePassword()) {
196
+                throw new \InvalidArgumentException('Passwords are enforced for link and mail shares');
197
+            }
198
+
199
+            return;
200
+        }
201
+
202
+        // Let others verify the password
203
+        try {
204
+            $this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
205
+        } catch (HintException $e) {
206
+            throw new \Exception($e->getHint());
207
+        }
208
+    }
209
+
210
+    /**
211
+     * Check for generic requirements before creating a share
212
+     *
213
+     * @param IShare $share
214
+     * @throws \InvalidArgumentException
215
+     * @throws GenericShareException
216
+     *
217
+     * @suppress PhanUndeclaredClassMethod
218
+     */
219
+    protected function generalCreateChecks(IShare $share) {
220
+        if ($share->getShareType() === IShare::TYPE_USER) {
221
+            // We expect a valid user as sharedWith for user shares
222
+            if (!$this->userManager->userExists($share->getSharedWith())) {
223
+                throw new \InvalidArgumentException('SharedWith is not a valid user');
224
+            }
225
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
226
+            // We expect a valid group as sharedWith for group shares
227
+            if (!$this->groupManager->groupExists($share->getSharedWith())) {
228
+                throw new \InvalidArgumentException('SharedWith is not a valid group');
229
+            }
230
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
231
+            // No check for TYPE_EMAIL here as we have a recipient for them
232
+            if ($share->getSharedWith() !== null) {
233
+                throw new \InvalidArgumentException('SharedWith should be empty');
234
+            }
235
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
236
+            if ($share->getSharedWith() === null) {
237
+                throw new \InvalidArgumentException('SharedWith should not be empty');
238
+            }
239
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
240
+            if ($share->getSharedWith() === null) {
241
+                throw new \InvalidArgumentException('SharedWith should not be empty');
242
+            }
243
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
244
+            if ($share->getSharedWith() === null) {
245
+                throw new \InvalidArgumentException('SharedWith should not be empty');
246
+            }
247
+        } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
248
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
249
+            if ($circle === null) {
250
+                throw new \InvalidArgumentException('SharedWith is not a valid circle');
251
+            }
252
+        } elseif ($share->getShareType() === IShare::TYPE_ROOM) {
253
+        } elseif ($share->getShareType() === IShare::TYPE_DECK) {
254
+        } else {
255
+            // We can't handle other types yet
256
+            throw new \InvalidArgumentException('unknown share type');
257
+        }
258
+
259
+        // Verify the initiator of the share is set
260
+        if ($share->getSharedBy() === null) {
261
+            throw new \InvalidArgumentException('SharedBy should be set');
262
+        }
263
+
264
+        // Cannot share with yourself
265
+        if ($share->getShareType() === IShare::TYPE_USER &&
266
+            $share->getSharedWith() === $share->getSharedBy()) {
267
+            throw new \InvalidArgumentException('Can’t share with yourself');
268
+        }
269
+
270
+        // The path should be set
271
+        if ($share->getNode() === null) {
272
+            throw new \InvalidArgumentException('Path should be set');
273
+        }
274
+
275
+        // And it should be a file or a folder
276
+        if (!($share->getNode() instanceof \OCP\Files\File) &&
277
+                !($share->getNode() instanceof \OCP\Files\Folder)) {
278
+            throw new \InvalidArgumentException('Path should be either a file or a folder');
279
+        }
280
+
281
+        // And you can't share your rootfolder
282
+        if ($this->userManager->userExists($share->getSharedBy())) {
283
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
284
+        } else {
285
+            $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
286
+        }
287
+        if ($userFolder->getId() === $share->getNode()->getId()) {
288
+            throw new \InvalidArgumentException('You can’t share your root folder');
289
+        }
290
+
291
+        // Check if we actually have share permissions
292
+        if (!$share->getNode()->isShareable()) {
293
+            $message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getName()]);
294
+            throw new GenericShareException($message_t, $message_t, 404);
295
+        }
296
+
297
+        // Permissions should be set
298
+        if ($share->getPermissions() === null) {
299
+            throw new \InvalidArgumentException('A share requires permissions');
300
+        }
301
+
302
+        $isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
303
+        $permissions = 0;
304
+
305
+        if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
306
+            $userMounts = array_filter($userFolder->getById($share->getNode()->getId()), function ($mount) {
307
+                // We need to filter since there might be other mountpoints that contain the file
308
+                // e.g. if the user has access to the same external storage that the file is originating from
309
+                return $mount->getStorage()->instanceOfStorage(ISharedStorage::class);
310
+            });
311
+            $userMount = array_shift($userMounts);
312
+            if ($userMount === null) {
313
+                throw new GenericShareException('Could not get proper share mount for ' . $share->getNode()->getId() . '. Failing since else the next calls are called with null');
314
+            }
315
+            $mount = $userMount->getMountPoint();
316
+            // When it's a reshare use the parent share permissions as maximum
317
+            $userMountPointId = $mount->getStorageRootId();
318
+            $userMountPoints = $userFolder->getById($userMountPointId);
319
+            $userMountPoint = array_shift($userMountPoints);
320
+
321
+            if ($userMountPoint === null) {
322
+                throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
323
+            }
324
+
325
+            /* Check if this is an incoming share */
326
+            $incomingShares = $this->getSharedWith($share->getSharedBy(), IShare::TYPE_USER, $userMountPoint, -1, 0);
327
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_GROUP, $userMountPoint, -1, 0));
328
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_CIRCLE, $userMountPoint, -1, 0));
329
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_ROOM, $userMountPoint, -1, 0));
330
+
331
+            /** @var IShare[] $incomingShares */
332
+            if (!empty($incomingShares)) {
333
+                foreach ($incomingShares as $incomingShare) {
334
+                    $permissions |= $incomingShare->getPermissions();
335
+                }
336
+            }
337
+        } else {
338
+            /*
339 339
 			 * Quick fix for #23536
340 340
 			 * Non moveable mount points do not have update and delete permissions
341 341
 			 * while we 'most likely' do have that on the storage.
342 342
 			 */
343
-			$permissions = $share->getNode()->getPermissions();
344
-			if (!($share->getNode()->getMountPoint() instanceof MoveableMount)) {
345
-				$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
346
-			}
347
-		}
348
-
349
-		// Check that we do not share with more permissions than we have
350
-		if ($share->getPermissions() & ~$permissions) {
351
-			$path = $userFolder->getRelativePath($share->getNode()->getPath());
352
-			$message_t = $this->l->t('Can’t increase permissions of %s', [$path]);
353
-			throw new GenericShareException($message_t, $message_t, 404);
354
-		}
355
-
356
-
357
-		// Check that read permissions are always set
358
-		// Link shares are allowed to have no read permissions to allow upload to hidden folders
359
-		$noReadPermissionRequired = $share->getShareType() === IShare::TYPE_LINK
360
-			|| $share->getShareType() === IShare::TYPE_EMAIL;
361
-		if (!$noReadPermissionRequired &&
362
-			($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
363
-			throw new \InvalidArgumentException('Shares need at least read permissions');
364
-		}
365
-
366
-		if ($share->getNode() instanceof \OCP\Files\File) {
367
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
368
-				$message_t = $this->l->t('Files can’t be shared with delete permissions');
369
-				throw new GenericShareException($message_t);
370
-			}
371
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
372
-				$message_t = $this->l->t('Files can’t be shared with create permissions');
373
-				throw new GenericShareException($message_t);
374
-			}
375
-		}
376
-	}
377
-
378
-	/**
379
-	 * Validate if the expiration date fits the system settings
380
-	 *
381
-	 * @param IShare $share The share to validate the expiration date of
382
-	 * @return IShare The modified share object
383
-	 * @throws GenericShareException
384
-	 * @throws \InvalidArgumentException
385
-	 * @throws \Exception
386
-	 */
387
-	protected function validateExpirationDateInternal(IShare $share) {
388
-		$isRemote = $share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP;
389
-
390
-		$expirationDate = $share->getExpirationDate();
391
-
392
-		if ($expirationDate !== null) {
393
-			//Make sure the expiration date is a date
394
-			$expirationDate->setTime(0, 0, 0);
395
-
396
-			$date = new \DateTime();
397
-			$date->setTime(0, 0, 0);
398
-			if ($date >= $expirationDate) {
399
-				$message = $this->l->t('Expiration date is in the past');
400
-				throw new GenericShareException($message, $message, 404);
401
-			}
402
-		}
403
-
404
-		// If expiredate is empty set a default one if there is a default
405
-		$fullId = null;
406
-		try {
407
-			$fullId = $share->getFullId();
408
-		} catch (\UnexpectedValueException $e) {
409
-			// This is a new share
410
-		}
411
-
412
-		if ($isRemote) {
413
-			$defaultExpireDate = $this->shareApiRemoteDefaultExpireDate();
414
-			$defaultExpireDays = $this->shareApiRemoteDefaultExpireDays();
415
-			$configProp = 'remote_defaultExpDays';
416
-			$isEnforced = $this->shareApiRemoteDefaultExpireDateEnforced();
417
-		} else {
418
-			$defaultExpireDate = $this->shareApiInternalDefaultExpireDate();
419
-			$defaultExpireDays = $this->shareApiInternalDefaultExpireDays();
420
-			$configProp = 'internal_defaultExpDays';
421
-			$isEnforced = $this->shareApiInternalDefaultExpireDateEnforced();
422
-		}
423
-		if ($fullId === null && $expirationDate === null && $defaultExpireDate) {
424
-			$expirationDate = new \DateTime();
425
-			$expirationDate->setTime(0,0,0);
426
-
427
-			$days = (int)$this->config->getAppValue('core', $configProp, (string)$defaultExpireDays);
428
-			if ($days > $defaultExpireDays) {
429
-				$days = $defaultExpireDays;
430
-			}
431
-			$expirationDate->add(new \DateInterval('P'.$days.'D'));
432
-		}
433
-
434
-		// If we enforce the expiration date check that is does not exceed
435
-		if ($isEnforced) {
436
-			if ($expirationDate === null) {
437
-				throw new \InvalidArgumentException('Expiration date is enforced');
438
-			}
439
-
440
-			$date = new \DateTime();
441
-			$date->setTime(0, 0, 0);
442
-			$date->add(new \DateInterval('P' . $defaultExpireDays . 'D'));
443
-			if ($date < $expirationDate) {
444
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$defaultExpireDays]);
445
-				throw new GenericShareException($message, $message, 404);
446
-			}
447
-		}
448
-
449
-		$accepted = true;
450
-		$message = '';
451
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
452
-			'expirationDate' => &$expirationDate,
453
-			'accepted' => &$accepted,
454
-			'message' => &$message,
455
-			'passwordSet' => $share->getPassword() !== null,
456
-		]);
457
-
458
-		if (!$accepted) {
459
-			throw new \Exception($message);
460
-		}
461
-
462
-		$share->setExpirationDate($expirationDate);
463
-
464
-		return $share;
465
-	}
466
-
467
-	/**
468
-	 * Validate if the expiration date fits the system settings
469
-	 *
470
-	 * @param IShare $share The share to validate the expiration date of
471
-	 * @return IShare The modified share object
472
-	 * @throws GenericShareException
473
-	 * @throws \InvalidArgumentException
474
-	 * @throws \Exception
475
-	 */
476
-	protected function validateExpirationDateLink(IShare $share) {
477
-		$expirationDate = $share->getExpirationDate();
478
-
479
-		if ($expirationDate !== null) {
480
-			//Make sure the expiration date is a date
481
-			$expirationDate->setTime(0, 0, 0);
482
-
483
-			$date = new \DateTime();
484
-			$date->setTime(0, 0, 0);
485
-			if ($date >= $expirationDate) {
486
-				$message = $this->l->t('Expiration date is in the past');
487
-				throw new GenericShareException($message, $message, 404);
488
-			}
489
-		}
490
-
491
-		// If expiredate is empty set a default one if there is a default
492
-		$fullId = null;
493
-		try {
494
-			$fullId = $share->getFullId();
495
-		} catch (\UnexpectedValueException $e) {
496
-			// This is a new share
497
-		}
498
-
499
-		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
500
-			$expirationDate = new \DateTime();
501
-			$expirationDate->setTime(0,0,0);
502
-
503
-			$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
504
-			if ($days > $this->shareApiLinkDefaultExpireDays()) {
505
-				$days = $this->shareApiLinkDefaultExpireDays();
506
-			}
507
-			$expirationDate->add(new \DateInterval('P'.$days.'D'));
508
-		}
509
-
510
-		// If we enforce the expiration date check that is does not exceed
511
-		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
512
-			if ($expirationDate === null) {
513
-				throw new \InvalidArgumentException('Expiration date is enforced');
514
-			}
515
-
516
-			$date = new \DateTime();
517
-			$date->setTime(0, 0, 0);
518
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
519
-			if ($date < $expirationDate) {
520
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
521
-				throw new GenericShareException($message, $message, 404);
522
-			}
523
-		}
524
-
525
-		$accepted = true;
526
-		$message = '';
527
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
528
-			'expirationDate' => &$expirationDate,
529
-			'accepted' => &$accepted,
530
-			'message' => &$message,
531
-			'passwordSet' => $share->getPassword() !== null,
532
-		]);
533
-
534
-		if (!$accepted) {
535
-			throw new \Exception($message);
536
-		}
537
-
538
-		$share->setExpirationDate($expirationDate);
539
-
540
-		return $share;
541
-	}
542
-
543
-	/**
544
-	 * Check for pre share requirements for user shares
545
-	 *
546
-	 * @param IShare $share
547
-	 * @throws \Exception
548
-	 */
549
-	protected function userCreateChecks(IShare $share) {
550
-		// Check if we can share with group members only
551
-		if ($this->shareWithGroupMembersOnly()) {
552
-			$sharedBy = $this->userManager->get($share->getSharedBy());
553
-			$sharedWith = $this->userManager->get($share->getSharedWith());
554
-			// Verify we can share with this user
555
-			$groups = array_intersect(
556
-					$this->groupManager->getUserGroupIds($sharedBy),
557
-					$this->groupManager->getUserGroupIds($sharedWith)
558
-			);
559
-			if (empty($groups)) {
560
-				$message_t = $this->l->t('Sharing is only allowed with group members');
561
-				throw new \Exception($message_t);
562
-			}
563
-		}
564
-
565
-		/*
343
+            $permissions = $share->getNode()->getPermissions();
344
+            if (!($share->getNode()->getMountPoint() instanceof MoveableMount)) {
345
+                $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
346
+            }
347
+        }
348
+
349
+        // Check that we do not share with more permissions than we have
350
+        if ($share->getPermissions() & ~$permissions) {
351
+            $path = $userFolder->getRelativePath($share->getNode()->getPath());
352
+            $message_t = $this->l->t('Can’t increase permissions of %s', [$path]);
353
+            throw new GenericShareException($message_t, $message_t, 404);
354
+        }
355
+
356
+
357
+        // Check that read permissions are always set
358
+        // Link shares are allowed to have no read permissions to allow upload to hidden folders
359
+        $noReadPermissionRequired = $share->getShareType() === IShare::TYPE_LINK
360
+            || $share->getShareType() === IShare::TYPE_EMAIL;
361
+        if (!$noReadPermissionRequired &&
362
+            ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
363
+            throw new \InvalidArgumentException('Shares need at least read permissions');
364
+        }
365
+
366
+        if ($share->getNode() instanceof \OCP\Files\File) {
367
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
368
+                $message_t = $this->l->t('Files can’t be shared with delete permissions');
369
+                throw new GenericShareException($message_t);
370
+            }
371
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
372
+                $message_t = $this->l->t('Files can’t be shared with create permissions');
373
+                throw new GenericShareException($message_t);
374
+            }
375
+        }
376
+    }
377
+
378
+    /**
379
+     * Validate if the expiration date fits the system settings
380
+     *
381
+     * @param IShare $share The share to validate the expiration date of
382
+     * @return IShare The modified share object
383
+     * @throws GenericShareException
384
+     * @throws \InvalidArgumentException
385
+     * @throws \Exception
386
+     */
387
+    protected function validateExpirationDateInternal(IShare $share) {
388
+        $isRemote = $share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP;
389
+
390
+        $expirationDate = $share->getExpirationDate();
391
+
392
+        if ($expirationDate !== null) {
393
+            //Make sure the expiration date is a date
394
+            $expirationDate->setTime(0, 0, 0);
395
+
396
+            $date = new \DateTime();
397
+            $date->setTime(0, 0, 0);
398
+            if ($date >= $expirationDate) {
399
+                $message = $this->l->t('Expiration date is in the past');
400
+                throw new GenericShareException($message, $message, 404);
401
+            }
402
+        }
403
+
404
+        // If expiredate is empty set a default one if there is a default
405
+        $fullId = null;
406
+        try {
407
+            $fullId = $share->getFullId();
408
+        } catch (\UnexpectedValueException $e) {
409
+            // This is a new share
410
+        }
411
+
412
+        if ($isRemote) {
413
+            $defaultExpireDate = $this->shareApiRemoteDefaultExpireDate();
414
+            $defaultExpireDays = $this->shareApiRemoteDefaultExpireDays();
415
+            $configProp = 'remote_defaultExpDays';
416
+            $isEnforced = $this->shareApiRemoteDefaultExpireDateEnforced();
417
+        } else {
418
+            $defaultExpireDate = $this->shareApiInternalDefaultExpireDate();
419
+            $defaultExpireDays = $this->shareApiInternalDefaultExpireDays();
420
+            $configProp = 'internal_defaultExpDays';
421
+            $isEnforced = $this->shareApiInternalDefaultExpireDateEnforced();
422
+        }
423
+        if ($fullId === null && $expirationDate === null && $defaultExpireDate) {
424
+            $expirationDate = new \DateTime();
425
+            $expirationDate->setTime(0,0,0);
426
+
427
+            $days = (int)$this->config->getAppValue('core', $configProp, (string)$defaultExpireDays);
428
+            if ($days > $defaultExpireDays) {
429
+                $days = $defaultExpireDays;
430
+            }
431
+            $expirationDate->add(new \DateInterval('P'.$days.'D'));
432
+        }
433
+
434
+        // If we enforce the expiration date check that is does not exceed
435
+        if ($isEnforced) {
436
+            if ($expirationDate === null) {
437
+                throw new \InvalidArgumentException('Expiration date is enforced');
438
+            }
439
+
440
+            $date = new \DateTime();
441
+            $date->setTime(0, 0, 0);
442
+            $date->add(new \DateInterval('P' . $defaultExpireDays . 'D'));
443
+            if ($date < $expirationDate) {
444
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$defaultExpireDays]);
445
+                throw new GenericShareException($message, $message, 404);
446
+            }
447
+        }
448
+
449
+        $accepted = true;
450
+        $message = '';
451
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
452
+            'expirationDate' => &$expirationDate,
453
+            'accepted' => &$accepted,
454
+            'message' => &$message,
455
+            'passwordSet' => $share->getPassword() !== null,
456
+        ]);
457
+
458
+        if (!$accepted) {
459
+            throw new \Exception($message);
460
+        }
461
+
462
+        $share->setExpirationDate($expirationDate);
463
+
464
+        return $share;
465
+    }
466
+
467
+    /**
468
+     * Validate if the expiration date fits the system settings
469
+     *
470
+     * @param IShare $share The share to validate the expiration date of
471
+     * @return IShare The modified share object
472
+     * @throws GenericShareException
473
+     * @throws \InvalidArgumentException
474
+     * @throws \Exception
475
+     */
476
+    protected function validateExpirationDateLink(IShare $share) {
477
+        $expirationDate = $share->getExpirationDate();
478
+
479
+        if ($expirationDate !== null) {
480
+            //Make sure the expiration date is a date
481
+            $expirationDate->setTime(0, 0, 0);
482
+
483
+            $date = new \DateTime();
484
+            $date->setTime(0, 0, 0);
485
+            if ($date >= $expirationDate) {
486
+                $message = $this->l->t('Expiration date is in the past');
487
+                throw new GenericShareException($message, $message, 404);
488
+            }
489
+        }
490
+
491
+        // If expiredate is empty set a default one if there is a default
492
+        $fullId = null;
493
+        try {
494
+            $fullId = $share->getFullId();
495
+        } catch (\UnexpectedValueException $e) {
496
+            // This is a new share
497
+        }
498
+
499
+        if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
500
+            $expirationDate = new \DateTime();
501
+            $expirationDate->setTime(0,0,0);
502
+
503
+            $days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
504
+            if ($days > $this->shareApiLinkDefaultExpireDays()) {
505
+                $days = $this->shareApiLinkDefaultExpireDays();
506
+            }
507
+            $expirationDate->add(new \DateInterval('P'.$days.'D'));
508
+        }
509
+
510
+        // If we enforce the expiration date check that is does not exceed
511
+        if ($this->shareApiLinkDefaultExpireDateEnforced()) {
512
+            if ($expirationDate === null) {
513
+                throw new \InvalidArgumentException('Expiration date is enforced');
514
+            }
515
+
516
+            $date = new \DateTime();
517
+            $date->setTime(0, 0, 0);
518
+            $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
519
+            if ($date < $expirationDate) {
520
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
521
+                throw new GenericShareException($message, $message, 404);
522
+            }
523
+        }
524
+
525
+        $accepted = true;
526
+        $message = '';
527
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
528
+            'expirationDate' => &$expirationDate,
529
+            'accepted' => &$accepted,
530
+            'message' => &$message,
531
+            'passwordSet' => $share->getPassword() !== null,
532
+        ]);
533
+
534
+        if (!$accepted) {
535
+            throw new \Exception($message);
536
+        }
537
+
538
+        $share->setExpirationDate($expirationDate);
539
+
540
+        return $share;
541
+    }
542
+
543
+    /**
544
+     * Check for pre share requirements for user shares
545
+     *
546
+     * @param IShare $share
547
+     * @throws \Exception
548
+     */
549
+    protected function userCreateChecks(IShare $share) {
550
+        // Check if we can share with group members only
551
+        if ($this->shareWithGroupMembersOnly()) {
552
+            $sharedBy = $this->userManager->get($share->getSharedBy());
553
+            $sharedWith = $this->userManager->get($share->getSharedWith());
554
+            // Verify we can share with this user
555
+            $groups = array_intersect(
556
+                    $this->groupManager->getUserGroupIds($sharedBy),
557
+                    $this->groupManager->getUserGroupIds($sharedWith)
558
+            );
559
+            if (empty($groups)) {
560
+                $message_t = $this->l->t('Sharing is only allowed with group members');
561
+                throw new \Exception($message_t);
562
+            }
563
+        }
564
+
565
+        /*
566 566
 		 * TODO: Could be costly, fix
567 567
 		 *
568 568
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
569 569
 		 */
570
-		$provider = $this->factory->getProviderForType(IShare::TYPE_USER);
571
-		$existingShares = $provider->getSharesByPath($share->getNode());
572
-		foreach ($existingShares as $existingShare) {
573
-			// Ignore if it is the same share
574
-			try {
575
-				if ($existingShare->getFullId() === $share->getFullId()) {
576
-					continue;
577
-				}
578
-			} catch (\UnexpectedValueException $e) {
579
-				//Shares are not identical
580
-			}
581
-
582
-			// Identical share already exists
583
-			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
584
-				$message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
585
-				throw new AlreadySharedException($message, $existingShare);
586
-			}
587
-
588
-			// The share is already shared with this user via a group share
589
-			if ($existingShare->getShareType() === IShare::TYPE_GROUP) {
590
-				$group = $this->groupManager->get($existingShare->getSharedWith());
591
-				if (!is_null($group)) {
592
-					$user = $this->userManager->get($share->getSharedWith());
593
-
594
-					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
595
-						$message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
596
-						throw new AlreadySharedException($message, $existingShare);
597
-					}
598
-				}
599
-			}
600
-		}
601
-	}
602
-
603
-	/**
604
-	 * Check for pre share requirements for group shares
605
-	 *
606
-	 * @param IShare $share
607
-	 * @throws \Exception
608
-	 */
609
-	protected function groupCreateChecks(IShare $share) {
610
-		// Verify group shares are allowed
611
-		if (!$this->allowGroupSharing()) {
612
-			throw new \Exception('Group sharing is now allowed');
613
-		}
614
-
615
-		// Verify if the user can share with this group
616
-		if ($this->shareWithGroupMembersOnly()) {
617
-			$sharedBy = $this->userManager->get($share->getSharedBy());
618
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
619
-			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
620
-				throw new \Exception('Sharing is only allowed within your own groups');
621
-			}
622
-		}
623
-
624
-		/*
570
+        $provider = $this->factory->getProviderForType(IShare::TYPE_USER);
571
+        $existingShares = $provider->getSharesByPath($share->getNode());
572
+        foreach ($existingShares as $existingShare) {
573
+            // Ignore if it is the same share
574
+            try {
575
+                if ($existingShare->getFullId() === $share->getFullId()) {
576
+                    continue;
577
+                }
578
+            } catch (\UnexpectedValueException $e) {
579
+                //Shares are not identical
580
+            }
581
+
582
+            // Identical share already exists
583
+            if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
584
+                $message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
585
+                throw new AlreadySharedException($message, $existingShare);
586
+            }
587
+
588
+            // The share is already shared with this user via a group share
589
+            if ($existingShare->getShareType() === IShare::TYPE_GROUP) {
590
+                $group = $this->groupManager->get($existingShare->getSharedWith());
591
+                if (!is_null($group)) {
592
+                    $user = $this->userManager->get($share->getSharedWith());
593
+
594
+                    if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
595
+                        $message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
596
+                        throw new AlreadySharedException($message, $existingShare);
597
+                    }
598
+                }
599
+            }
600
+        }
601
+    }
602
+
603
+    /**
604
+     * Check for pre share requirements for group shares
605
+     *
606
+     * @param IShare $share
607
+     * @throws \Exception
608
+     */
609
+    protected function groupCreateChecks(IShare $share) {
610
+        // Verify group shares are allowed
611
+        if (!$this->allowGroupSharing()) {
612
+            throw new \Exception('Group sharing is now allowed');
613
+        }
614
+
615
+        // Verify if the user can share with this group
616
+        if ($this->shareWithGroupMembersOnly()) {
617
+            $sharedBy = $this->userManager->get($share->getSharedBy());
618
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
619
+            if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
620
+                throw new \Exception('Sharing is only allowed within your own groups');
621
+            }
622
+        }
623
+
624
+        /*
625 625
 		 * TODO: Could be costly, fix
626 626
 		 *
627 627
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
628 628
 		 */
629
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
630
-		$existingShares = $provider->getSharesByPath($share->getNode());
631
-		foreach ($existingShares as $existingShare) {
632
-			try {
633
-				if ($existingShare->getFullId() === $share->getFullId()) {
634
-					continue;
635
-				}
636
-			} catch (\UnexpectedValueException $e) {
637
-				//It is a new share so just continue
638
-			}
639
-
640
-			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
641
-				throw new AlreadySharedException('Path is already shared with this group', $existingShare);
642
-			}
643
-		}
644
-	}
645
-
646
-	/**
647
-	 * Check for pre share requirements for link shares
648
-	 *
649
-	 * @param IShare $share
650
-	 * @throws \Exception
651
-	 */
652
-	protected function linkCreateChecks(IShare $share) {
653
-		// Are link shares allowed?
654
-		if (!$this->shareApiAllowLinks()) {
655
-			throw new \Exception('Link sharing is not allowed');
656
-		}
657
-
658
-		// Check if public upload is allowed
659
-		if (!$this->shareApiLinkAllowPublicUpload() &&
660
-			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
661
-			throw new \InvalidArgumentException('Public upload is not allowed');
662
-		}
663
-	}
664
-
665
-	/**
666
-	 * To make sure we don't get invisible link shares we set the parent
667
-	 * of a link if it is a reshare. This is a quick word around
668
-	 * until we can properly display multiple link shares in the UI
669
-	 *
670
-	 * See: https://github.com/owncloud/core/issues/22295
671
-	 *
672
-	 * FIXME: Remove once multiple link shares can be properly displayed
673
-	 *
674
-	 * @param IShare $share
675
-	 */
676
-	protected function setLinkParent(IShare $share) {
677
-
678
-		// No sense in checking if the method is not there.
679
-		if (method_exists($share, 'setParent')) {
680
-			$storage = $share->getNode()->getStorage();
681
-			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
682
-				/** @var \OCA\Files_Sharing\SharedStorage $storage */
683
-				$share->setParent($storage->getShareId());
684
-			}
685
-		}
686
-	}
687
-
688
-	/**
689
-	 * @param File|Folder $path
690
-	 */
691
-	protected function pathCreateChecks($path) {
692
-		// Make sure that we do not share a path that contains a shared mountpoint
693
-		if ($path instanceof \OCP\Files\Folder) {
694
-			$mounts = $this->mountManager->findIn($path->getPath());
695
-			foreach ($mounts as $mount) {
696
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
697
-					throw new \InvalidArgumentException('Path contains files shared with you');
698
-				}
699
-			}
700
-		}
701
-	}
702
-
703
-	/**
704
-	 * Check if the user that is sharing can actually share
705
-	 *
706
-	 * @param IShare $share
707
-	 * @throws \Exception
708
-	 */
709
-	protected function canShare(IShare $share) {
710
-		if (!$this->shareApiEnabled()) {
711
-			throw new \Exception('Sharing is disabled');
712
-		}
713
-
714
-		if ($this->sharingDisabledForUser($share->getSharedBy())) {
715
-			throw new \Exception('Sharing is disabled for you');
716
-		}
717
-	}
718
-
719
-	/**
720
-	 * Share a path
721
-	 *
722
-	 * @param IShare $share
723
-	 * @return IShare The share object
724
-	 * @throws \Exception
725
-	 *
726
-	 * TODO: handle link share permissions or check them
727
-	 */
728
-	public function createShare(IShare $share) {
729
-		$this->canShare($share);
730
-
731
-		$this->generalCreateChecks($share);
732
-
733
-		// Verify if there are any issues with the path
734
-		$this->pathCreateChecks($share->getNode());
735
-
736
-		/*
629
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
630
+        $existingShares = $provider->getSharesByPath($share->getNode());
631
+        foreach ($existingShares as $existingShare) {
632
+            try {
633
+                if ($existingShare->getFullId() === $share->getFullId()) {
634
+                    continue;
635
+                }
636
+            } catch (\UnexpectedValueException $e) {
637
+                //It is a new share so just continue
638
+            }
639
+
640
+            if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
641
+                throw new AlreadySharedException('Path is already shared with this group', $existingShare);
642
+            }
643
+        }
644
+    }
645
+
646
+    /**
647
+     * Check for pre share requirements for link shares
648
+     *
649
+     * @param IShare $share
650
+     * @throws \Exception
651
+     */
652
+    protected function linkCreateChecks(IShare $share) {
653
+        // Are link shares allowed?
654
+        if (!$this->shareApiAllowLinks()) {
655
+            throw new \Exception('Link sharing is not allowed');
656
+        }
657
+
658
+        // Check if public upload is allowed
659
+        if (!$this->shareApiLinkAllowPublicUpload() &&
660
+            ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
661
+            throw new \InvalidArgumentException('Public upload is not allowed');
662
+        }
663
+    }
664
+
665
+    /**
666
+     * To make sure we don't get invisible link shares we set the parent
667
+     * of a link if it is a reshare. This is a quick word around
668
+     * until we can properly display multiple link shares in the UI
669
+     *
670
+     * See: https://github.com/owncloud/core/issues/22295
671
+     *
672
+     * FIXME: Remove once multiple link shares can be properly displayed
673
+     *
674
+     * @param IShare $share
675
+     */
676
+    protected function setLinkParent(IShare $share) {
677
+
678
+        // No sense in checking if the method is not there.
679
+        if (method_exists($share, 'setParent')) {
680
+            $storage = $share->getNode()->getStorage();
681
+            if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
682
+                /** @var \OCA\Files_Sharing\SharedStorage $storage */
683
+                $share->setParent($storage->getShareId());
684
+            }
685
+        }
686
+    }
687
+
688
+    /**
689
+     * @param File|Folder $path
690
+     */
691
+    protected function pathCreateChecks($path) {
692
+        // Make sure that we do not share a path that contains a shared mountpoint
693
+        if ($path instanceof \OCP\Files\Folder) {
694
+            $mounts = $this->mountManager->findIn($path->getPath());
695
+            foreach ($mounts as $mount) {
696
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
697
+                    throw new \InvalidArgumentException('Path contains files shared with you');
698
+                }
699
+            }
700
+        }
701
+    }
702
+
703
+    /**
704
+     * Check if the user that is sharing can actually share
705
+     *
706
+     * @param IShare $share
707
+     * @throws \Exception
708
+     */
709
+    protected function canShare(IShare $share) {
710
+        if (!$this->shareApiEnabled()) {
711
+            throw new \Exception('Sharing is disabled');
712
+        }
713
+
714
+        if ($this->sharingDisabledForUser($share->getSharedBy())) {
715
+            throw new \Exception('Sharing is disabled for you');
716
+        }
717
+    }
718
+
719
+    /**
720
+     * Share a path
721
+     *
722
+     * @param IShare $share
723
+     * @return IShare The share object
724
+     * @throws \Exception
725
+     *
726
+     * TODO: handle link share permissions or check them
727
+     */
728
+    public function createShare(IShare $share) {
729
+        $this->canShare($share);
730
+
731
+        $this->generalCreateChecks($share);
732
+
733
+        // Verify if there are any issues with the path
734
+        $this->pathCreateChecks($share->getNode());
735
+
736
+        /*
737 737
 		 * On creation of a share the owner is always the owner of the path
738 738
 		 * Except for mounted federated shares.
739 739
 		 */
740
-		$storage = $share->getNode()->getStorage();
741
-		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
742
-			$parent = $share->getNode()->getParent();
743
-			while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
744
-				$parent = $parent->getParent();
745
-			}
746
-			$share->setShareOwner($parent->getOwner()->getUID());
747
-		} else {
748
-			if ($share->getNode()->getOwner()) {
749
-				$share->setShareOwner($share->getNode()->getOwner()->getUID());
750
-			} else {
751
-				$share->setShareOwner($share->getSharedBy());
752
-			}
753
-		}
754
-
755
-		try {
756
-			// Verify share type
757
-			if ($share->getShareType() === IShare::TYPE_USER) {
758
-				$this->userCreateChecks($share);
759
-
760
-				// Verify the expiration date
761
-				$share = $this->validateExpirationDateInternal($share);
762
-			} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
763
-				$this->groupCreateChecks($share);
764
-
765
-				// Verify the expiration date
766
-				$share = $this->validateExpirationDateInternal($share);
767
-			} elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
768
-				//Verify the expiration date
769
-				$share = $this->validateExpirationDateInternal($share);
770
-			} elseif ($share->getShareType() === IShare::TYPE_LINK
771
-				|| $share->getShareType() === IShare::TYPE_EMAIL) {
772
-				$this->linkCreateChecks($share);
773
-				$this->setLinkParent($share);
774
-
775
-				// For now ignore a set token.
776
-				$share->setToken(
777
-					$this->secureRandom->generate(
778
-						\OC\Share\Constants::TOKEN_LENGTH,
779
-						\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
780
-					)
781
-				);
782
-
783
-				// Verify the expiration date
784
-				$share = $this->validateExpirationDateLink($share);
785
-
786
-				// Verify the password
787
-				$this->verifyPassword($share->getPassword());
788
-
789
-				// If a password is set. Hash it!
790
-				if ($share->getShareType() === IShare::TYPE_LINK
791
-					&& $share->getPassword() !== null) {
792
-					$share->setPassword($this->hasher->hash($share->getPassword()));
793
-				}
794
-			}
795
-
796
-			// Cannot share with the owner
797
-			if ($share->getShareType() === IShare::TYPE_USER &&
798
-				$share->getSharedWith() === $share->getShareOwner()) {
799
-				throw new \InvalidArgumentException('Can’t share with the share owner');
800
-			}
801
-
802
-			// Generate the target
803
-			$target = $this->config->getSystemValue('share_folder', '/') . '/' . $share->getNode()->getName();
804
-			$target = \OC\Files\Filesystem::normalizePath($target);
805
-			$share->setTarget($target);
806
-
807
-			// Pre share event
808
-			$event = new GenericEvent($share);
809
-			$this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
810
-			if ($event->isPropagationStopped() && $event->hasArgument('error')) {
811
-				throw new \Exception($event->getArgument('error'));
812
-			}
813
-
814
-			$oldShare = $share;
815
-			$provider = $this->factory->getProviderForType($share->getShareType());
816
-			$share = $provider->create($share);
817
-
818
-			// Reuse the node we already have
819
-			$share->setNode($oldShare->getNode());
820
-
821
-			// Reset the target if it is null for the new share
822
-			if ($share->getTarget() === '') {
823
-				$share->setTarget($target);
824
-			}
825
-		} catch (AlreadySharedException $e) {
826
-			// if a share for the same target already exists, dont create a new one, but do trigger the hooks and notifications again
827
-			$share = $e->getExistingShare();
828
-		}
829
-
830
-		// Post share event
831
-		$event = new GenericEvent($share);
832
-		$this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
833
-
834
-		$this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
835
-
836
-		if ($this->config->getSystemValueBool('sharing.enable_share_mail', true)
837
-			&& $share->getShareType() === IShare::TYPE_USER) {
838
-			$mailSend = $share->getMailSend();
839
-			if ($mailSend === true) {
840
-				$user = $this->userManager->get($share->getSharedWith());
841
-				if ($user !== null) {
842
-					$emailAddress = $user->getEMailAddress();
843
-					if ($emailAddress !== null && $emailAddress !== '') {
844
-						$userLang = $this->l10nFactory->getUserLanguage($user);
845
-						$l = $this->l10nFactory->get('lib', $userLang);
846
-						$this->sendMailNotification(
847
-							$l,
848
-							$share->getNode()->getName(),
849
-							$this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]),
850
-							$share->getSharedBy(),
851
-							$emailAddress,
852
-							$share->getExpirationDate()
853
-						);
854
-						$this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
855
-					} else {
856
-						$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
857
-					}
858
-				} else {
859
-					$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
860
-				}
861
-			} else {
862
-				$this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
863
-			}
864
-		}
865
-
866
-		return $share;
867
-	}
868
-
869
-	/**
870
-	 * Send mail notifications
871
-	 *
872
-	 * This method will catch and log mail transmission errors
873
-	 *
874
-	 * @param IL10N $l Language of the recipient
875
-	 * @param string $filename file/folder name
876
-	 * @param string $link link to the file/folder
877
-	 * @param string $initiator user ID of share sender
878
-	 * @param string $shareWith email address of share receiver
879
-	 * @param \DateTime|null $expiration
880
-	 */
881
-	protected function sendMailNotification(IL10N $l,
882
-											$filename,
883
-											$link,
884
-											$initiator,
885
-											$shareWith,
886
-											\DateTime $expiration = null) {
887
-		$initiatorUser = $this->userManager->get($initiator);
888
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
889
-
890
-		$message = $this->mailer->createMessage();
891
-
892
-		$emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
893
-			'filename' => $filename,
894
-			'link' => $link,
895
-			'initiator' => $initiatorDisplayName,
896
-			'expiration' => $expiration,
897
-			'shareWith' => $shareWith,
898
-		]);
899
-
900
-		$emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
901
-		$emailTemplate->addHeader();
902
-		$emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
903
-		$text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
904
-
905
-		$emailTemplate->addBodyText(
906
-			htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
907
-			$text
908
-		);
909
-		$emailTemplate->addBodyButton(
910
-			$l->t('Open »%s«', [$filename]),
911
-			$link
912
-		);
913
-
914
-		$message->setTo([$shareWith]);
915
-
916
-		// The "From" contains the sharers name
917
-		$instanceName = $this->defaults->getName();
918
-		$senderName = $l->t(
919
-			'%1$s via %2$s',
920
-			[
921
-				$initiatorDisplayName,
922
-				$instanceName
923
-			]
924
-		);
925
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
926
-
927
-		// The "Reply-To" is set to the sharer if an mail address is configured
928
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
929
-		$initiatorEmail = $initiatorUser->getEMailAddress();
930
-		if ($initiatorEmail !== null) {
931
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
932
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
933
-		} else {
934
-			$emailTemplate->addFooter('', $l->getLanguageCode());
935
-		}
936
-
937
-		$message->useTemplate($emailTemplate);
938
-		try {
939
-			$failedRecipients = $this->mailer->send($message);
940
-			if (!empty($failedRecipients)) {
941
-				$this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
942
-				return;
943
-			}
944
-		} catch (\Exception $e) {
945
-			$this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
946
-		}
947
-	}
948
-
949
-	/**
950
-	 * Update a share
951
-	 *
952
-	 * @param IShare $share
953
-	 * @return IShare The share object
954
-	 * @throws \InvalidArgumentException
955
-	 */
956
-	public function updateShare(IShare $share) {
957
-		$expirationDateUpdated = false;
958
-
959
-		$this->canShare($share);
960
-
961
-		try {
962
-			$originalShare = $this->getShareById($share->getFullId());
963
-		} catch (\UnexpectedValueException $e) {
964
-			throw new \InvalidArgumentException('Share does not have a full id');
965
-		}
966
-
967
-		// We can't change the share type!
968
-		if ($share->getShareType() !== $originalShare->getShareType()) {
969
-			throw new \InvalidArgumentException('Can’t change share type');
970
-		}
971
-
972
-		// We can only change the recipient on user shares
973
-		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
974
-			$share->getShareType() !== IShare::TYPE_USER) {
975
-			throw new \InvalidArgumentException('Can only update recipient on user shares');
976
-		}
977
-
978
-		// Cannot share with the owner
979
-		if ($share->getShareType() === IShare::TYPE_USER &&
980
-			$share->getSharedWith() === $share->getShareOwner()) {
981
-			throw new \InvalidArgumentException('Can’t share with the share owner');
982
-		}
983
-
984
-		$this->generalCreateChecks($share);
985
-
986
-		if ($share->getShareType() === IShare::TYPE_USER) {
987
-			$this->userCreateChecks($share);
988
-
989
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
990
-				//Verify the expiration date
991
-				$this->validateExpirationDateInternal($share);
992
-				$expirationDateUpdated = true;
993
-			}
994
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
995
-			$this->groupCreateChecks($share);
996
-
997
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
998
-				//Verify the expiration date
999
-				$this->validateExpirationDateInternal($share);
1000
-				$expirationDateUpdated = true;
1001
-			}
1002
-		} elseif ($share->getShareType() === IShare::TYPE_LINK
1003
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
1004
-			$this->linkCreateChecks($share);
1005
-
1006
-			// The new password is not set again if it is the same as the old
1007
-			// one, unless when switching from sending by Talk to sending by
1008
-			// mail.
1009
-			$plainTextPassword = $share->getPassword();
1010
-			$updatedPassword = $this->updateSharePasswordIfNeeded($share, $originalShare);
1011
-
1012
-			/**
1013
-			 * Cannot enable the getSendPasswordByTalk if there is no password set
1014
-			 */
1015
-			if (empty($plainTextPassword) && $share->getSendPasswordByTalk()) {
1016
-				throw new \InvalidArgumentException('Can’t enable sending the password by Talk with an empty password');
1017
-			}
1018
-
1019
-			/**
1020
-			 * If we're in a mail share, we need to force a password change
1021
-			 * as either the user is not aware of the password or is already (received by mail)
1022
-			 * Thus the SendPasswordByTalk feature would not make sense
1023
-			 */
1024
-			if (!$updatedPassword && $share->getShareType() === IShare::TYPE_EMAIL) {
1025
-				if (!$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
1026
-					throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
1027
-				}
1028
-				if ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()) {
1029
-					throw new \InvalidArgumentException('Can’t disable sending the password by Talk without setting a new password');
1030
-				}
1031
-			}
1032
-
1033
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1034
-				// Verify the expiration date
1035
-				$this->validateExpirationDateLink($share);
1036
-				$expirationDateUpdated = true;
1037
-			}
1038
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
1039
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1040
-				//Verify the expiration date
1041
-				$this->validateExpirationDateInternal($share);
1042
-				$expirationDateUpdated = true;
1043
-			}
1044
-		}
1045
-
1046
-		$this->pathCreateChecks($share->getNode());
1047
-
1048
-		// Now update the share!
1049
-		$provider = $this->factory->getProviderForType($share->getShareType());
1050
-		if ($share->getShareType() === IShare::TYPE_EMAIL) {
1051
-			$share = $provider->update($share, $plainTextPassword);
1052
-		} else {
1053
-			$share = $provider->update($share);
1054
-		}
1055
-
1056
-		if ($expirationDateUpdated === true) {
1057
-			\OC_Hook::emit(Share::class, 'post_set_expiration_date', [
1058
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1059
-				'itemSource' => $share->getNode()->getId(),
1060
-				'date' => $share->getExpirationDate(),
1061
-				'uidOwner' => $share->getSharedBy(),
1062
-			]);
1063
-		}
1064
-
1065
-		if ($share->getPassword() !== $originalShare->getPassword()) {
1066
-			\OC_Hook::emit(Share::class, 'post_update_password', [
1067
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1068
-				'itemSource' => $share->getNode()->getId(),
1069
-				'uidOwner' => $share->getSharedBy(),
1070
-				'token' => $share->getToken(),
1071
-				'disabled' => is_null($share->getPassword()),
1072
-			]);
1073
-		}
1074
-
1075
-		if ($share->getPermissions() !== $originalShare->getPermissions()) {
1076
-			if ($this->userManager->userExists($share->getShareOwner())) {
1077
-				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1078
-			} else {
1079
-				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1080
-			}
1081
-			\OC_Hook::emit(Share::class, 'post_update_permissions', [
1082
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1083
-				'itemSource' => $share->getNode()->getId(),
1084
-				'shareType' => $share->getShareType(),
1085
-				'shareWith' => $share->getSharedWith(),
1086
-				'uidOwner' => $share->getSharedBy(),
1087
-				'permissions' => $share->getPermissions(),
1088
-				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1089
-			]);
1090
-		}
1091
-
1092
-		return $share;
1093
-	}
1094
-
1095
-	/**
1096
-	 * Accept a share.
1097
-	 *
1098
-	 * @param IShare $share
1099
-	 * @param string $recipientId
1100
-	 * @return IShare The share object
1101
-	 * @throws \InvalidArgumentException
1102
-	 * @since 9.0.0
1103
-	 */
1104
-	public function acceptShare(IShare $share, string $recipientId): IShare {
1105
-		[$providerId, ] = $this->splitFullId($share->getFullId());
1106
-		$provider = $this->factory->getProvider($providerId);
1107
-
1108
-		if (!method_exists($provider, 'acceptShare')) {
1109
-			// TODO FIX ME
1110
-			throw new \InvalidArgumentException('Share provider does not support accepting');
1111
-		}
1112
-		$provider->acceptShare($share, $recipientId);
1113
-		$event = new GenericEvent($share);
1114
-		$this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
1115
-
1116
-		return $share;
1117
-	}
1118
-
1119
-	/**
1120
-	 * Updates the password of the given share if it is not the same as the
1121
-	 * password of the original share.
1122
-	 *
1123
-	 * @param IShare $share the share to update its password.
1124
-	 * @param IShare $originalShare the original share to compare its
1125
-	 *        password with.
1126
-	 * @return boolean whether the password was updated or not.
1127
-	 */
1128
-	private function updateSharePasswordIfNeeded(IShare $share, IShare $originalShare) {
1129
-		$passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) &&
1130
-									(($share->getPassword() !== null && $originalShare->getPassword() === null) ||
1131
-									 ($share->getPassword() === null && $originalShare->getPassword() !== null) ||
1132
-									 ($share->getPassword() !== null && $originalShare->getPassword() !== null &&
1133
-										!$this->hasher->verify($share->getPassword(), $originalShare->getPassword())));
1134
-
1135
-		// Password updated.
1136
-		if ($passwordsAreDifferent) {
1137
-			//Verify the password
1138
-			$this->verifyPassword($share->getPassword());
1139
-
1140
-			// If a password is set. Hash it!
1141
-			if (!empty($share->getPassword())) {
1142
-				$share->setPassword($this->hasher->hash($share->getPassword()));
1143
-
1144
-				return true;
1145
-			} else {
1146
-				// Empty string and null are seen as NOT password protected
1147
-				$share->setPassword(null);
1148
-				return true;
1149
-			}
1150
-		} else {
1151
-			// Reset the password to the original one, as it is either the same
1152
-			// as the "new" password or a hashed version of it.
1153
-			$share->setPassword($originalShare->getPassword());
1154
-		}
1155
-
1156
-		return false;
1157
-	}
1158
-
1159
-	/**
1160
-	 * Delete all the children of this share
1161
-	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1162
-	 *
1163
-	 * @param IShare $share
1164
-	 * @return IShare[] List of deleted shares
1165
-	 */
1166
-	protected function deleteChildren(IShare $share) {
1167
-		$deletedShares = [];
1168
-
1169
-		$provider = $this->factory->getProviderForType($share->getShareType());
1170
-
1171
-		foreach ($provider->getChildren($share) as $child) {
1172
-			$deletedChildren = $this->deleteChildren($child);
1173
-			$deletedShares = array_merge($deletedShares, $deletedChildren);
1174
-
1175
-			$provider->delete($child);
1176
-			$this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($child));
1177
-			$deletedShares[] = $child;
1178
-		}
1179
-
1180
-		return $deletedShares;
1181
-	}
1182
-
1183
-	/**
1184
-	 * Delete a share
1185
-	 *
1186
-	 * @param IShare $share
1187
-	 * @throws ShareNotFound
1188
-	 * @throws \InvalidArgumentException
1189
-	 */
1190
-	public function deleteShare(IShare $share) {
1191
-		try {
1192
-			$share->getFullId();
1193
-		} catch (\UnexpectedValueException $e) {
1194
-			throw new \InvalidArgumentException('Share does not have a full id');
1195
-		}
1196
-
1197
-		$event = new GenericEvent($share);
1198
-		$this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
1199
-
1200
-		// Get all children and delete them as well
1201
-		$deletedShares = $this->deleteChildren($share);
1202
-
1203
-		// Do the actual delete
1204
-		$provider = $this->factory->getProviderForType($share->getShareType());
1205
-		$provider->delete($share);
1206
-
1207
-		$this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($share));
1208
-
1209
-		// All the deleted shares caused by this delete
1210
-		$deletedShares[] = $share;
1211
-
1212
-		// Emit post hook
1213
-		$event->setArgument('deletedShares', $deletedShares);
1214
-		$this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1215
-	}
1216
-
1217
-
1218
-	/**
1219
-	 * Unshare a file as the recipient.
1220
-	 * This can be different from a regular delete for example when one of
1221
-	 * the users in a groups deletes that share. But the provider should
1222
-	 * handle this.
1223
-	 *
1224
-	 * @param IShare $share
1225
-	 * @param string $recipientId
1226
-	 */
1227
-	public function deleteFromSelf(IShare $share, $recipientId) {
1228
-		[$providerId, ] = $this->splitFullId($share->getFullId());
1229
-		$provider = $this->factory->getProvider($providerId);
1230
-
1231
-		$provider->deleteFromSelf($share, $recipientId);
1232
-		$event = new GenericEvent($share);
1233
-		$this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
1234
-	}
1235
-
1236
-	public function restoreShare(IShare $share, string $recipientId): IShare {
1237
-		[$providerId, ] = $this->splitFullId($share->getFullId());
1238
-		$provider = $this->factory->getProvider($providerId);
1239
-
1240
-		return $provider->restore($share, $recipientId);
1241
-	}
1242
-
1243
-	/**
1244
-	 * @inheritdoc
1245
-	 */
1246
-	public function moveShare(IShare $share, $recipientId) {
1247
-		if ($share->getShareType() === IShare::TYPE_LINK
1248
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
1249
-			throw new \InvalidArgumentException('Can’t change target of link share');
1250
-		}
1251
-
1252
-		if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() !== $recipientId) {
1253
-			throw new \InvalidArgumentException('Invalid recipient');
1254
-		}
1255
-
1256
-		if ($share->getShareType() === IShare::TYPE_GROUP) {
1257
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1258
-			if (is_null($sharedWith)) {
1259
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1260
-			}
1261
-			$recipient = $this->userManager->get($recipientId);
1262
-			if (!$sharedWith->inGroup($recipient)) {
1263
-				throw new \InvalidArgumentException('Invalid recipient');
1264
-			}
1265
-		}
1266
-
1267
-		[$providerId, ] = $this->splitFullId($share->getFullId());
1268
-		$provider = $this->factory->getProvider($providerId);
1269
-
1270
-		return $provider->move($share, $recipientId);
1271
-	}
1272
-
1273
-	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1274
-		$providers = $this->factory->getAllProviders();
1275
-
1276
-		return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1277
-			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1278
-			foreach ($newShares as $fid => $data) {
1279
-				if (!isset($shares[$fid])) {
1280
-					$shares[$fid] = [];
1281
-				}
1282
-
1283
-				$shares[$fid] = array_merge($shares[$fid], $data);
1284
-			}
1285
-			return $shares;
1286
-		}, []);
1287
-	}
1288
-
1289
-	/**
1290
-	 * @inheritdoc
1291
-	 */
1292
-	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1293
-		if ($path !== null &&
1294
-				!($path instanceof \OCP\Files\File) &&
1295
-				!($path instanceof \OCP\Files\Folder)) {
1296
-			throw new \InvalidArgumentException('invalid path');
1297
-		}
1298
-
1299
-		try {
1300
-			$provider = $this->factory->getProviderForType($shareType);
1301
-		} catch (ProviderException $e) {
1302
-			return [];
1303
-		}
1304
-
1305
-		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1306
-
1307
-		/*
740
+        $storage = $share->getNode()->getStorage();
741
+        if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
742
+            $parent = $share->getNode()->getParent();
743
+            while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
744
+                $parent = $parent->getParent();
745
+            }
746
+            $share->setShareOwner($parent->getOwner()->getUID());
747
+        } else {
748
+            if ($share->getNode()->getOwner()) {
749
+                $share->setShareOwner($share->getNode()->getOwner()->getUID());
750
+            } else {
751
+                $share->setShareOwner($share->getSharedBy());
752
+            }
753
+        }
754
+
755
+        try {
756
+            // Verify share type
757
+            if ($share->getShareType() === IShare::TYPE_USER) {
758
+                $this->userCreateChecks($share);
759
+
760
+                // Verify the expiration date
761
+                $share = $this->validateExpirationDateInternal($share);
762
+            } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
763
+                $this->groupCreateChecks($share);
764
+
765
+                // Verify the expiration date
766
+                $share = $this->validateExpirationDateInternal($share);
767
+            } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
768
+                //Verify the expiration date
769
+                $share = $this->validateExpirationDateInternal($share);
770
+            } elseif ($share->getShareType() === IShare::TYPE_LINK
771
+                || $share->getShareType() === IShare::TYPE_EMAIL) {
772
+                $this->linkCreateChecks($share);
773
+                $this->setLinkParent($share);
774
+
775
+                // For now ignore a set token.
776
+                $share->setToken(
777
+                    $this->secureRandom->generate(
778
+                        \OC\Share\Constants::TOKEN_LENGTH,
779
+                        \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
780
+                    )
781
+                );
782
+
783
+                // Verify the expiration date
784
+                $share = $this->validateExpirationDateLink($share);
785
+
786
+                // Verify the password
787
+                $this->verifyPassword($share->getPassword());
788
+
789
+                // If a password is set. Hash it!
790
+                if ($share->getShareType() === IShare::TYPE_LINK
791
+                    && $share->getPassword() !== null) {
792
+                    $share->setPassword($this->hasher->hash($share->getPassword()));
793
+                }
794
+            }
795
+
796
+            // Cannot share with the owner
797
+            if ($share->getShareType() === IShare::TYPE_USER &&
798
+                $share->getSharedWith() === $share->getShareOwner()) {
799
+                throw new \InvalidArgumentException('Can’t share with the share owner');
800
+            }
801
+
802
+            // Generate the target
803
+            $target = $this->config->getSystemValue('share_folder', '/') . '/' . $share->getNode()->getName();
804
+            $target = \OC\Files\Filesystem::normalizePath($target);
805
+            $share->setTarget($target);
806
+
807
+            // Pre share event
808
+            $event = new GenericEvent($share);
809
+            $this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
810
+            if ($event->isPropagationStopped() && $event->hasArgument('error')) {
811
+                throw new \Exception($event->getArgument('error'));
812
+            }
813
+
814
+            $oldShare = $share;
815
+            $provider = $this->factory->getProviderForType($share->getShareType());
816
+            $share = $provider->create($share);
817
+
818
+            // Reuse the node we already have
819
+            $share->setNode($oldShare->getNode());
820
+
821
+            // Reset the target if it is null for the new share
822
+            if ($share->getTarget() === '') {
823
+                $share->setTarget($target);
824
+            }
825
+        } catch (AlreadySharedException $e) {
826
+            // if a share for the same target already exists, dont create a new one, but do trigger the hooks and notifications again
827
+            $share = $e->getExistingShare();
828
+        }
829
+
830
+        // Post share event
831
+        $event = new GenericEvent($share);
832
+        $this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
833
+
834
+        $this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
835
+
836
+        if ($this->config->getSystemValueBool('sharing.enable_share_mail', true)
837
+            && $share->getShareType() === IShare::TYPE_USER) {
838
+            $mailSend = $share->getMailSend();
839
+            if ($mailSend === true) {
840
+                $user = $this->userManager->get($share->getSharedWith());
841
+                if ($user !== null) {
842
+                    $emailAddress = $user->getEMailAddress();
843
+                    if ($emailAddress !== null && $emailAddress !== '') {
844
+                        $userLang = $this->l10nFactory->getUserLanguage($user);
845
+                        $l = $this->l10nFactory->get('lib', $userLang);
846
+                        $this->sendMailNotification(
847
+                            $l,
848
+                            $share->getNode()->getName(),
849
+                            $this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]),
850
+                            $share->getSharedBy(),
851
+                            $emailAddress,
852
+                            $share->getExpirationDate()
853
+                        );
854
+                        $this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
855
+                    } else {
856
+                        $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
857
+                    }
858
+                } else {
859
+                    $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
860
+                }
861
+            } else {
862
+                $this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
863
+            }
864
+        }
865
+
866
+        return $share;
867
+    }
868
+
869
+    /**
870
+     * Send mail notifications
871
+     *
872
+     * This method will catch and log mail transmission errors
873
+     *
874
+     * @param IL10N $l Language of the recipient
875
+     * @param string $filename file/folder name
876
+     * @param string $link link to the file/folder
877
+     * @param string $initiator user ID of share sender
878
+     * @param string $shareWith email address of share receiver
879
+     * @param \DateTime|null $expiration
880
+     */
881
+    protected function sendMailNotification(IL10N $l,
882
+                                            $filename,
883
+                                            $link,
884
+                                            $initiator,
885
+                                            $shareWith,
886
+                                            \DateTime $expiration = null) {
887
+        $initiatorUser = $this->userManager->get($initiator);
888
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
889
+
890
+        $message = $this->mailer->createMessage();
891
+
892
+        $emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
893
+            'filename' => $filename,
894
+            'link' => $link,
895
+            'initiator' => $initiatorDisplayName,
896
+            'expiration' => $expiration,
897
+            'shareWith' => $shareWith,
898
+        ]);
899
+
900
+        $emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
901
+        $emailTemplate->addHeader();
902
+        $emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
903
+        $text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
904
+
905
+        $emailTemplate->addBodyText(
906
+            htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
907
+            $text
908
+        );
909
+        $emailTemplate->addBodyButton(
910
+            $l->t('Open »%s«', [$filename]),
911
+            $link
912
+        );
913
+
914
+        $message->setTo([$shareWith]);
915
+
916
+        // The "From" contains the sharers name
917
+        $instanceName = $this->defaults->getName();
918
+        $senderName = $l->t(
919
+            '%1$s via %2$s',
920
+            [
921
+                $initiatorDisplayName,
922
+                $instanceName
923
+            ]
924
+        );
925
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
926
+
927
+        // The "Reply-To" is set to the sharer if an mail address is configured
928
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
929
+        $initiatorEmail = $initiatorUser->getEMailAddress();
930
+        if ($initiatorEmail !== null) {
931
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
932
+            $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
933
+        } else {
934
+            $emailTemplate->addFooter('', $l->getLanguageCode());
935
+        }
936
+
937
+        $message->useTemplate($emailTemplate);
938
+        try {
939
+            $failedRecipients = $this->mailer->send($message);
940
+            if (!empty($failedRecipients)) {
941
+                $this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
942
+                return;
943
+            }
944
+        } catch (\Exception $e) {
945
+            $this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
946
+        }
947
+    }
948
+
949
+    /**
950
+     * Update a share
951
+     *
952
+     * @param IShare $share
953
+     * @return IShare The share object
954
+     * @throws \InvalidArgumentException
955
+     */
956
+    public function updateShare(IShare $share) {
957
+        $expirationDateUpdated = false;
958
+
959
+        $this->canShare($share);
960
+
961
+        try {
962
+            $originalShare = $this->getShareById($share->getFullId());
963
+        } catch (\UnexpectedValueException $e) {
964
+            throw new \InvalidArgumentException('Share does not have a full id');
965
+        }
966
+
967
+        // We can't change the share type!
968
+        if ($share->getShareType() !== $originalShare->getShareType()) {
969
+            throw new \InvalidArgumentException('Can’t change share type');
970
+        }
971
+
972
+        // We can only change the recipient on user shares
973
+        if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
974
+            $share->getShareType() !== IShare::TYPE_USER) {
975
+            throw new \InvalidArgumentException('Can only update recipient on user shares');
976
+        }
977
+
978
+        // Cannot share with the owner
979
+        if ($share->getShareType() === IShare::TYPE_USER &&
980
+            $share->getSharedWith() === $share->getShareOwner()) {
981
+            throw new \InvalidArgumentException('Can’t share with the share owner');
982
+        }
983
+
984
+        $this->generalCreateChecks($share);
985
+
986
+        if ($share->getShareType() === IShare::TYPE_USER) {
987
+            $this->userCreateChecks($share);
988
+
989
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
990
+                //Verify the expiration date
991
+                $this->validateExpirationDateInternal($share);
992
+                $expirationDateUpdated = true;
993
+            }
994
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
995
+            $this->groupCreateChecks($share);
996
+
997
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
998
+                //Verify the expiration date
999
+                $this->validateExpirationDateInternal($share);
1000
+                $expirationDateUpdated = true;
1001
+            }
1002
+        } elseif ($share->getShareType() === IShare::TYPE_LINK
1003
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
1004
+            $this->linkCreateChecks($share);
1005
+
1006
+            // The new password is not set again if it is the same as the old
1007
+            // one, unless when switching from sending by Talk to sending by
1008
+            // mail.
1009
+            $plainTextPassword = $share->getPassword();
1010
+            $updatedPassword = $this->updateSharePasswordIfNeeded($share, $originalShare);
1011
+
1012
+            /**
1013
+             * Cannot enable the getSendPasswordByTalk if there is no password set
1014
+             */
1015
+            if (empty($plainTextPassword) && $share->getSendPasswordByTalk()) {
1016
+                throw new \InvalidArgumentException('Can’t enable sending the password by Talk with an empty password');
1017
+            }
1018
+
1019
+            /**
1020
+             * If we're in a mail share, we need to force a password change
1021
+             * as either the user is not aware of the password or is already (received by mail)
1022
+             * Thus the SendPasswordByTalk feature would not make sense
1023
+             */
1024
+            if (!$updatedPassword && $share->getShareType() === IShare::TYPE_EMAIL) {
1025
+                if (!$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
1026
+                    throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
1027
+                }
1028
+                if ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()) {
1029
+                    throw new \InvalidArgumentException('Can’t disable sending the password by Talk without setting a new password');
1030
+                }
1031
+            }
1032
+
1033
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1034
+                // Verify the expiration date
1035
+                $this->validateExpirationDateLink($share);
1036
+                $expirationDateUpdated = true;
1037
+            }
1038
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
1039
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1040
+                //Verify the expiration date
1041
+                $this->validateExpirationDateInternal($share);
1042
+                $expirationDateUpdated = true;
1043
+            }
1044
+        }
1045
+
1046
+        $this->pathCreateChecks($share->getNode());
1047
+
1048
+        // Now update the share!
1049
+        $provider = $this->factory->getProviderForType($share->getShareType());
1050
+        if ($share->getShareType() === IShare::TYPE_EMAIL) {
1051
+            $share = $provider->update($share, $plainTextPassword);
1052
+        } else {
1053
+            $share = $provider->update($share);
1054
+        }
1055
+
1056
+        if ($expirationDateUpdated === true) {
1057
+            \OC_Hook::emit(Share::class, 'post_set_expiration_date', [
1058
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1059
+                'itemSource' => $share->getNode()->getId(),
1060
+                'date' => $share->getExpirationDate(),
1061
+                'uidOwner' => $share->getSharedBy(),
1062
+            ]);
1063
+        }
1064
+
1065
+        if ($share->getPassword() !== $originalShare->getPassword()) {
1066
+            \OC_Hook::emit(Share::class, 'post_update_password', [
1067
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1068
+                'itemSource' => $share->getNode()->getId(),
1069
+                'uidOwner' => $share->getSharedBy(),
1070
+                'token' => $share->getToken(),
1071
+                'disabled' => is_null($share->getPassword()),
1072
+            ]);
1073
+        }
1074
+
1075
+        if ($share->getPermissions() !== $originalShare->getPermissions()) {
1076
+            if ($this->userManager->userExists($share->getShareOwner())) {
1077
+                $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1078
+            } else {
1079
+                $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1080
+            }
1081
+            \OC_Hook::emit(Share::class, 'post_update_permissions', [
1082
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1083
+                'itemSource' => $share->getNode()->getId(),
1084
+                'shareType' => $share->getShareType(),
1085
+                'shareWith' => $share->getSharedWith(),
1086
+                'uidOwner' => $share->getSharedBy(),
1087
+                'permissions' => $share->getPermissions(),
1088
+                'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1089
+            ]);
1090
+        }
1091
+
1092
+        return $share;
1093
+    }
1094
+
1095
+    /**
1096
+     * Accept a share.
1097
+     *
1098
+     * @param IShare $share
1099
+     * @param string $recipientId
1100
+     * @return IShare The share object
1101
+     * @throws \InvalidArgumentException
1102
+     * @since 9.0.0
1103
+     */
1104
+    public function acceptShare(IShare $share, string $recipientId): IShare {
1105
+        [$providerId, ] = $this->splitFullId($share->getFullId());
1106
+        $provider = $this->factory->getProvider($providerId);
1107
+
1108
+        if (!method_exists($provider, 'acceptShare')) {
1109
+            // TODO FIX ME
1110
+            throw new \InvalidArgumentException('Share provider does not support accepting');
1111
+        }
1112
+        $provider->acceptShare($share, $recipientId);
1113
+        $event = new GenericEvent($share);
1114
+        $this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
1115
+
1116
+        return $share;
1117
+    }
1118
+
1119
+    /**
1120
+     * Updates the password of the given share if it is not the same as the
1121
+     * password of the original share.
1122
+     *
1123
+     * @param IShare $share the share to update its password.
1124
+     * @param IShare $originalShare the original share to compare its
1125
+     *        password with.
1126
+     * @return boolean whether the password was updated or not.
1127
+     */
1128
+    private function updateSharePasswordIfNeeded(IShare $share, IShare $originalShare) {
1129
+        $passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) &&
1130
+                                    (($share->getPassword() !== null && $originalShare->getPassword() === null) ||
1131
+                                     ($share->getPassword() === null && $originalShare->getPassword() !== null) ||
1132
+                                     ($share->getPassword() !== null && $originalShare->getPassword() !== null &&
1133
+                                        !$this->hasher->verify($share->getPassword(), $originalShare->getPassword())));
1134
+
1135
+        // Password updated.
1136
+        if ($passwordsAreDifferent) {
1137
+            //Verify the password
1138
+            $this->verifyPassword($share->getPassword());
1139
+
1140
+            // If a password is set. Hash it!
1141
+            if (!empty($share->getPassword())) {
1142
+                $share->setPassword($this->hasher->hash($share->getPassword()));
1143
+
1144
+                return true;
1145
+            } else {
1146
+                // Empty string and null are seen as NOT password protected
1147
+                $share->setPassword(null);
1148
+                return true;
1149
+            }
1150
+        } else {
1151
+            // Reset the password to the original one, as it is either the same
1152
+            // as the "new" password or a hashed version of it.
1153
+            $share->setPassword($originalShare->getPassword());
1154
+        }
1155
+
1156
+        return false;
1157
+    }
1158
+
1159
+    /**
1160
+     * Delete all the children of this share
1161
+     * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1162
+     *
1163
+     * @param IShare $share
1164
+     * @return IShare[] List of deleted shares
1165
+     */
1166
+    protected function deleteChildren(IShare $share) {
1167
+        $deletedShares = [];
1168
+
1169
+        $provider = $this->factory->getProviderForType($share->getShareType());
1170
+
1171
+        foreach ($provider->getChildren($share) as $child) {
1172
+            $deletedChildren = $this->deleteChildren($child);
1173
+            $deletedShares = array_merge($deletedShares, $deletedChildren);
1174
+
1175
+            $provider->delete($child);
1176
+            $this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($child));
1177
+            $deletedShares[] = $child;
1178
+        }
1179
+
1180
+        return $deletedShares;
1181
+    }
1182
+
1183
+    /**
1184
+     * Delete a share
1185
+     *
1186
+     * @param IShare $share
1187
+     * @throws ShareNotFound
1188
+     * @throws \InvalidArgumentException
1189
+     */
1190
+    public function deleteShare(IShare $share) {
1191
+        try {
1192
+            $share->getFullId();
1193
+        } catch (\UnexpectedValueException $e) {
1194
+            throw new \InvalidArgumentException('Share does not have a full id');
1195
+        }
1196
+
1197
+        $event = new GenericEvent($share);
1198
+        $this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
1199
+
1200
+        // Get all children and delete them as well
1201
+        $deletedShares = $this->deleteChildren($share);
1202
+
1203
+        // Do the actual delete
1204
+        $provider = $this->factory->getProviderForType($share->getShareType());
1205
+        $provider->delete($share);
1206
+
1207
+        $this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($share));
1208
+
1209
+        // All the deleted shares caused by this delete
1210
+        $deletedShares[] = $share;
1211
+
1212
+        // Emit post hook
1213
+        $event->setArgument('deletedShares', $deletedShares);
1214
+        $this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1215
+    }
1216
+
1217
+
1218
+    /**
1219
+     * Unshare a file as the recipient.
1220
+     * This can be different from a regular delete for example when one of
1221
+     * the users in a groups deletes that share. But the provider should
1222
+     * handle this.
1223
+     *
1224
+     * @param IShare $share
1225
+     * @param string $recipientId
1226
+     */
1227
+    public function deleteFromSelf(IShare $share, $recipientId) {
1228
+        [$providerId, ] = $this->splitFullId($share->getFullId());
1229
+        $provider = $this->factory->getProvider($providerId);
1230
+
1231
+        $provider->deleteFromSelf($share, $recipientId);
1232
+        $event = new GenericEvent($share);
1233
+        $this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
1234
+    }
1235
+
1236
+    public function restoreShare(IShare $share, string $recipientId): IShare {
1237
+        [$providerId, ] = $this->splitFullId($share->getFullId());
1238
+        $provider = $this->factory->getProvider($providerId);
1239
+
1240
+        return $provider->restore($share, $recipientId);
1241
+    }
1242
+
1243
+    /**
1244
+     * @inheritdoc
1245
+     */
1246
+    public function moveShare(IShare $share, $recipientId) {
1247
+        if ($share->getShareType() === IShare::TYPE_LINK
1248
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
1249
+            throw new \InvalidArgumentException('Can’t change target of link share');
1250
+        }
1251
+
1252
+        if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() !== $recipientId) {
1253
+            throw new \InvalidArgumentException('Invalid recipient');
1254
+        }
1255
+
1256
+        if ($share->getShareType() === IShare::TYPE_GROUP) {
1257
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1258
+            if (is_null($sharedWith)) {
1259
+                throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1260
+            }
1261
+            $recipient = $this->userManager->get($recipientId);
1262
+            if (!$sharedWith->inGroup($recipient)) {
1263
+                throw new \InvalidArgumentException('Invalid recipient');
1264
+            }
1265
+        }
1266
+
1267
+        [$providerId, ] = $this->splitFullId($share->getFullId());
1268
+        $provider = $this->factory->getProvider($providerId);
1269
+
1270
+        return $provider->move($share, $recipientId);
1271
+    }
1272
+
1273
+    public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1274
+        $providers = $this->factory->getAllProviders();
1275
+
1276
+        return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1277
+            $newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1278
+            foreach ($newShares as $fid => $data) {
1279
+                if (!isset($shares[$fid])) {
1280
+                    $shares[$fid] = [];
1281
+                }
1282
+
1283
+                $shares[$fid] = array_merge($shares[$fid], $data);
1284
+            }
1285
+            return $shares;
1286
+        }, []);
1287
+    }
1288
+
1289
+    /**
1290
+     * @inheritdoc
1291
+     */
1292
+    public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1293
+        if ($path !== null &&
1294
+                !($path instanceof \OCP\Files\File) &&
1295
+                !($path instanceof \OCP\Files\Folder)) {
1296
+            throw new \InvalidArgumentException('invalid path');
1297
+        }
1298
+
1299
+        try {
1300
+            $provider = $this->factory->getProviderForType($shareType);
1301
+        } catch (ProviderException $e) {
1302
+            return [];
1303
+        }
1304
+
1305
+        $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1306
+
1307
+        /*
1308 1308
 		 * Work around so we don't return expired shares but still follow
1309 1309
 		 * proper pagination.
1310 1310
 		 */
1311 1311
 
1312
-		$shares2 = [];
1313
-
1314
-		while (true) {
1315
-			$added = 0;
1316
-			foreach ($shares as $share) {
1317
-				try {
1318
-					$this->checkExpireDate($share);
1319
-				} catch (ShareNotFound $e) {
1320
-					//Ignore since this basically means the share is deleted
1321
-					continue;
1322
-				}
1323
-
1324
-				$added++;
1325
-				$shares2[] = $share;
1326
-
1327
-				if (count($shares2) === $limit) {
1328
-					break;
1329
-				}
1330
-			}
1331
-
1332
-			// If we did not fetch more shares than the limit then there are no more shares
1333
-			if (count($shares) < $limit) {
1334
-				break;
1335
-			}
1336
-
1337
-			if (count($shares2) === $limit) {
1338
-				break;
1339
-			}
1340
-
1341
-			// If there was no limit on the select we are done
1342
-			if ($limit === -1) {
1343
-				break;
1344
-			}
1345
-
1346
-			$offset += $added;
1347
-
1348
-			// Fetch again $limit shares
1349
-			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1350
-
1351
-			// No more shares means we are done
1352
-			if (empty($shares)) {
1353
-				break;
1354
-			}
1355
-		}
1356
-
1357
-		$shares = $shares2;
1358
-
1359
-		return $shares;
1360
-	}
1361
-
1362
-	/**
1363
-	 * @inheritdoc
1364
-	 */
1365
-	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1366
-		try {
1367
-			$provider = $this->factory->getProviderForType($shareType);
1368
-		} catch (ProviderException $e) {
1369
-			return [];
1370
-		}
1371
-
1372
-		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1373
-
1374
-		// remove all shares which are already expired
1375
-		foreach ($shares as $key => $share) {
1376
-			try {
1377
-				$this->checkExpireDate($share);
1378
-			} catch (ShareNotFound $e) {
1379
-				unset($shares[$key]);
1380
-			}
1381
-		}
1382
-
1383
-		return $shares;
1384
-	}
1385
-
1386
-	/**
1387
-	 * @inheritdoc
1388
-	 */
1389
-	public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1390
-		$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1391
-
1392
-		// Only get deleted shares
1393
-		$shares = array_filter($shares, function (IShare $share) {
1394
-			return $share->getPermissions() === 0;
1395
-		});
1396
-
1397
-		// Only get shares where the owner still exists
1398
-		$shares = array_filter($shares, function (IShare $share) {
1399
-			return $this->userManager->userExists($share->getShareOwner());
1400
-		});
1401
-
1402
-		return $shares;
1403
-	}
1404
-
1405
-	/**
1406
-	 * @inheritdoc
1407
-	 */
1408
-	public function getShareById($id, $recipient = null) {
1409
-		if ($id === null) {
1410
-			throw new ShareNotFound();
1411
-		}
1412
-
1413
-		[$providerId, $id] = $this->splitFullId($id);
1414
-
1415
-		try {
1416
-			$provider = $this->factory->getProvider($providerId);
1417
-		} catch (ProviderException $e) {
1418
-			throw new ShareNotFound();
1419
-		}
1420
-
1421
-		$share = $provider->getShareById($id, $recipient);
1422
-
1423
-		$this->checkExpireDate($share);
1424
-
1425
-		return $share;
1426
-	}
1427
-
1428
-	/**
1429
-	 * Get all the shares for a given path
1430
-	 *
1431
-	 * @param \OCP\Files\Node $path
1432
-	 * @param int $page
1433
-	 * @param int $perPage
1434
-	 *
1435
-	 * @return Share[]
1436
-	 */
1437
-	public function getSharesByPath(\OCP\Files\Node $path, $page = 0, $perPage = 50) {
1438
-		return [];
1439
-	}
1440
-
1441
-	/**
1442
-	 * Get the share by token possible with password
1443
-	 *
1444
-	 * @param string $token
1445
-	 * @return IShare
1446
-	 *
1447
-	 * @throws ShareNotFound
1448
-	 */
1449
-	public function getShareByToken($token) {
1450
-		// tokens can't be valid local user names
1451
-		if ($this->userManager->userExists($token)) {
1452
-			throw new ShareNotFound();
1453
-		}
1454
-		$share = null;
1455
-		try {
1456
-			if ($this->shareApiAllowLinks()) {
1457
-				$provider = $this->factory->getProviderForType(IShare::TYPE_LINK);
1458
-				$share = $provider->getShareByToken($token);
1459
-			}
1460
-		} catch (ProviderException $e) {
1461
-		} catch (ShareNotFound $e) {
1462
-		}
1463
-
1464
-
1465
-		// If it is not a link share try to fetch a federated share by token
1466
-		if ($share === null) {
1467
-			try {
1468
-				$provider = $this->factory->getProviderForType(IShare::TYPE_REMOTE);
1469
-				$share = $provider->getShareByToken($token);
1470
-			} catch (ProviderException $e) {
1471
-			} catch (ShareNotFound $e) {
1472
-			}
1473
-		}
1474
-
1475
-		// If it is not a link share try to fetch a mail share by token
1476
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_EMAIL)) {
1477
-			try {
1478
-				$provider = $this->factory->getProviderForType(IShare::TYPE_EMAIL);
1479
-				$share = $provider->getShareByToken($token);
1480
-			} catch (ProviderException $e) {
1481
-			} catch (ShareNotFound $e) {
1482
-			}
1483
-		}
1484
-
1485
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_CIRCLE)) {
1486
-			try {
1487
-				$provider = $this->factory->getProviderForType(IShare::TYPE_CIRCLE);
1488
-				$share = $provider->getShareByToken($token);
1489
-			} catch (ProviderException $e) {
1490
-			} catch (ShareNotFound $e) {
1491
-			}
1492
-		}
1493
-
1494
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_ROOM)) {
1495
-			try {
1496
-				$provider = $this->factory->getProviderForType(IShare::TYPE_ROOM);
1497
-				$share = $provider->getShareByToken($token);
1498
-			} catch (ProviderException $e) {
1499
-			} catch (ShareNotFound $e) {
1500
-			}
1501
-		}
1502
-
1503
-		if ($share === null) {
1504
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1505
-		}
1506
-
1507
-		$this->checkExpireDate($share);
1508
-
1509
-		/*
1312
+        $shares2 = [];
1313
+
1314
+        while (true) {
1315
+            $added = 0;
1316
+            foreach ($shares as $share) {
1317
+                try {
1318
+                    $this->checkExpireDate($share);
1319
+                } catch (ShareNotFound $e) {
1320
+                    //Ignore since this basically means the share is deleted
1321
+                    continue;
1322
+                }
1323
+
1324
+                $added++;
1325
+                $shares2[] = $share;
1326
+
1327
+                if (count($shares2) === $limit) {
1328
+                    break;
1329
+                }
1330
+            }
1331
+
1332
+            // If we did not fetch more shares than the limit then there are no more shares
1333
+            if (count($shares) < $limit) {
1334
+                break;
1335
+            }
1336
+
1337
+            if (count($shares2) === $limit) {
1338
+                break;
1339
+            }
1340
+
1341
+            // If there was no limit on the select we are done
1342
+            if ($limit === -1) {
1343
+                break;
1344
+            }
1345
+
1346
+            $offset += $added;
1347
+
1348
+            // Fetch again $limit shares
1349
+            $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1350
+
1351
+            // No more shares means we are done
1352
+            if (empty($shares)) {
1353
+                break;
1354
+            }
1355
+        }
1356
+
1357
+        $shares = $shares2;
1358
+
1359
+        return $shares;
1360
+    }
1361
+
1362
+    /**
1363
+     * @inheritdoc
1364
+     */
1365
+    public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1366
+        try {
1367
+            $provider = $this->factory->getProviderForType($shareType);
1368
+        } catch (ProviderException $e) {
1369
+            return [];
1370
+        }
1371
+
1372
+        $shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1373
+
1374
+        // remove all shares which are already expired
1375
+        foreach ($shares as $key => $share) {
1376
+            try {
1377
+                $this->checkExpireDate($share);
1378
+            } catch (ShareNotFound $e) {
1379
+                unset($shares[$key]);
1380
+            }
1381
+        }
1382
+
1383
+        return $shares;
1384
+    }
1385
+
1386
+    /**
1387
+     * @inheritdoc
1388
+     */
1389
+    public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1390
+        $shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1391
+
1392
+        // Only get deleted shares
1393
+        $shares = array_filter($shares, function (IShare $share) {
1394
+            return $share->getPermissions() === 0;
1395
+        });
1396
+
1397
+        // Only get shares where the owner still exists
1398
+        $shares = array_filter($shares, function (IShare $share) {
1399
+            return $this->userManager->userExists($share->getShareOwner());
1400
+        });
1401
+
1402
+        return $shares;
1403
+    }
1404
+
1405
+    /**
1406
+     * @inheritdoc
1407
+     */
1408
+    public function getShareById($id, $recipient = null) {
1409
+        if ($id === null) {
1410
+            throw new ShareNotFound();
1411
+        }
1412
+
1413
+        [$providerId, $id] = $this->splitFullId($id);
1414
+
1415
+        try {
1416
+            $provider = $this->factory->getProvider($providerId);
1417
+        } catch (ProviderException $e) {
1418
+            throw new ShareNotFound();
1419
+        }
1420
+
1421
+        $share = $provider->getShareById($id, $recipient);
1422
+
1423
+        $this->checkExpireDate($share);
1424
+
1425
+        return $share;
1426
+    }
1427
+
1428
+    /**
1429
+     * Get all the shares for a given path
1430
+     *
1431
+     * @param \OCP\Files\Node $path
1432
+     * @param int $page
1433
+     * @param int $perPage
1434
+     *
1435
+     * @return Share[]
1436
+     */
1437
+    public function getSharesByPath(\OCP\Files\Node $path, $page = 0, $perPage = 50) {
1438
+        return [];
1439
+    }
1440
+
1441
+    /**
1442
+     * Get the share by token possible with password
1443
+     *
1444
+     * @param string $token
1445
+     * @return IShare
1446
+     *
1447
+     * @throws ShareNotFound
1448
+     */
1449
+    public function getShareByToken($token) {
1450
+        // tokens can't be valid local user names
1451
+        if ($this->userManager->userExists($token)) {
1452
+            throw new ShareNotFound();
1453
+        }
1454
+        $share = null;
1455
+        try {
1456
+            if ($this->shareApiAllowLinks()) {
1457
+                $provider = $this->factory->getProviderForType(IShare::TYPE_LINK);
1458
+                $share = $provider->getShareByToken($token);
1459
+            }
1460
+        } catch (ProviderException $e) {
1461
+        } catch (ShareNotFound $e) {
1462
+        }
1463
+
1464
+
1465
+        // If it is not a link share try to fetch a federated share by token
1466
+        if ($share === null) {
1467
+            try {
1468
+                $provider = $this->factory->getProviderForType(IShare::TYPE_REMOTE);
1469
+                $share = $provider->getShareByToken($token);
1470
+            } catch (ProviderException $e) {
1471
+            } catch (ShareNotFound $e) {
1472
+            }
1473
+        }
1474
+
1475
+        // If it is not a link share try to fetch a mail share by token
1476
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_EMAIL)) {
1477
+            try {
1478
+                $provider = $this->factory->getProviderForType(IShare::TYPE_EMAIL);
1479
+                $share = $provider->getShareByToken($token);
1480
+            } catch (ProviderException $e) {
1481
+            } catch (ShareNotFound $e) {
1482
+            }
1483
+        }
1484
+
1485
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_CIRCLE)) {
1486
+            try {
1487
+                $provider = $this->factory->getProviderForType(IShare::TYPE_CIRCLE);
1488
+                $share = $provider->getShareByToken($token);
1489
+            } catch (ProviderException $e) {
1490
+            } catch (ShareNotFound $e) {
1491
+            }
1492
+        }
1493
+
1494
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_ROOM)) {
1495
+            try {
1496
+                $provider = $this->factory->getProviderForType(IShare::TYPE_ROOM);
1497
+                $share = $provider->getShareByToken($token);
1498
+            } catch (ProviderException $e) {
1499
+            } catch (ShareNotFound $e) {
1500
+            }
1501
+        }
1502
+
1503
+        if ($share === null) {
1504
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1505
+        }
1506
+
1507
+        $this->checkExpireDate($share);
1508
+
1509
+        /*
1510 1510
 		 * Reduce the permissions for link or email shares if public upload is not enabled
1511 1511
 		 */
1512
-		if (($share->getShareType() === IShare::TYPE_LINK || $share->getShareType() === IShare::TYPE_EMAIL)
1513
-			&& !$this->shareApiLinkAllowPublicUpload()) {
1514
-			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1515
-		}
1516
-
1517
-		return $share;
1518
-	}
1519
-
1520
-	protected function checkExpireDate($share) {
1521
-		if ($share->isExpired()) {
1522
-			$this->deleteShare($share);
1523
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1524
-		}
1525
-	}
1526
-
1527
-	/**
1528
-	 * Verify the password of a public share
1529
-	 *
1530
-	 * @param IShare $share
1531
-	 * @param string $password
1532
-	 * @return bool
1533
-	 */
1534
-	public function checkPassword(IShare $share, $password) {
1535
-		$passwordProtected = $share->getShareType() !== IShare::TYPE_LINK
1536
-							 || $share->getShareType() !== IShare::TYPE_EMAIL
1537
-							 || $share->getShareType() !== IShare::TYPE_CIRCLE;
1538
-		if (!$passwordProtected) {
1539
-			//TODO maybe exception?
1540
-			return false;
1541
-		}
1542
-
1543
-		if ($password === null || $share->getPassword() === null) {
1544
-			return false;
1545
-		}
1546
-
1547
-		$newHash = '';
1548
-		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1549
-			return false;
1550
-		}
1551
-
1552
-		if (!empty($newHash)) {
1553
-			$share->setPassword($newHash);
1554
-			$provider = $this->factory->getProviderForType($share->getShareType());
1555
-			$provider->update($share);
1556
-		}
1557
-
1558
-		return true;
1559
-	}
1560
-
1561
-	/**
1562
-	 * @inheritdoc
1563
-	 */
1564
-	public function userDeleted($uid) {
1565
-		$types = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK, IShare::TYPE_REMOTE, IShare::TYPE_EMAIL];
1566
-
1567
-		foreach ($types as $type) {
1568
-			try {
1569
-				$provider = $this->factory->getProviderForType($type);
1570
-			} catch (ProviderException $e) {
1571
-				continue;
1572
-			}
1573
-			$provider->userDeleted($uid, $type);
1574
-		}
1575
-	}
1576
-
1577
-	/**
1578
-	 * @inheritdoc
1579
-	 */
1580
-	public function groupDeleted($gid) {
1581
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1582
-		$provider->groupDeleted($gid);
1583
-
1584
-		$excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1585
-		if ($excludedGroups === '') {
1586
-			return;
1587
-		}
1588
-
1589
-		$excludedGroups = json_decode($excludedGroups, true);
1590
-		if (json_last_error() !== JSON_ERROR_NONE) {
1591
-			return;
1592
-		}
1593
-
1594
-		$excludedGroups = array_diff($excludedGroups, [$gid]);
1595
-		$this->config->setAppValue('core', 'shareapi_exclude_groups_list', json_encode($excludedGroups));
1596
-	}
1597
-
1598
-	/**
1599
-	 * @inheritdoc
1600
-	 */
1601
-	public function userDeletedFromGroup($uid, $gid) {
1602
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1603
-		$provider->userDeletedFromGroup($uid, $gid);
1604
-	}
1605
-
1606
-	/**
1607
-	 * Get access list to a path. This means
1608
-	 * all the users that can access a given path.
1609
-	 *
1610
-	 * Consider:
1611
-	 * -root
1612
-	 * |-folder1 (23)
1613
-	 *  |-folder2 (32)
1614
-	 *   |-fileA (42)
1615
-	 *
1616
-	 * fileA is shared with user1 and user1@server1
1617
-	 * folder2 is shared with group2 (user4 is a member of group2)
1618
-	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1619
-	 *
1620
-	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1621
-	 * [
1622
-	 *  users  => [
1623
-	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1624
-	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1625
-	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1626
-	 *  ],
1627
-	 *  remote => [
1628
-	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1629
-	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1630
-	 *  ],
1631
-	 *  public => bool
1632
-	 *  mail => bool
1633
-	 * ]
1634
-	 *
1635
-	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1636
-	 * [
1637
-	 *  users  => ['user1', 'user2', 'user4'],
1638
-	 *  remote => bool,
1639
-	 *  public => bool
1640
-	 *  mail => bool
1641
-	 * ]
1642
-	 *
1643
-	 * This is required for encryption/activity
1644
-	 *
1645
-	 * @param \OCP\Files\Node $path
1646
-	 * @param bool $recursive Should we check all parent folders as well
1647
-	 * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1648
-	 * @return array
1649
-	 */
1650
-	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1651
-		$owner = $path->getOwner();
1652
-
1653
-		if ($owner === null) {
1654
-			return [];
1655
-		}
1656
-
1657
-		$owner = $owner->getUID();
1658
-
1659
-		if ($currentAccess) {
1660
-			$al = ['users' => [], 'remote' => [], 'public' => false];
1661
-		} else {
1662
-			$al = ['users' => [], 'remote' => false, 'public' => false];
1663
-		}
1664
-		if (!$this->userManager->userExists($owner)) {
1665
-			return $al;
1666
-		}
1667
-
1668
-		//Get node for the owner and correct the owner in case of external storages
1669
-		$userFolder = $this->rootFolder->getUserFolder($owner);
1670
-		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1671
-			$nodes = $userFolder->getById($path->getId());
1672
-			$path = array_shift($nodes);
1673
-			if ($path->getOwner() === null) {
1674
-				return [];
1675
-			}
1676
-			$owner = $path->getOwner()->getUID();
1677
-		}
1678
-
1679
-		$providers = $this->factory->getAllProviders();
1680
-
1681
-		/** @var Node[] $nodes */
1682
-		$nodes = [];
1683
-
1684
-
1685
-		if ($currentAccess) {
1686
-			$ownerPath = $path->getPath();
1687
-			$ownerPath = explode('/', $ownerPath, 4);
1688
-			if (count($ownerPath) < 4) {
1689
-				$ownerPath = '';
1690
-			} else {
1691
-				$ownerPath = $ownerPath[3];
1692
-			}
1693
-			$al['users'][$owner] = [
1694
-				'node_id' => $path->getId(),
1695
-				'node_path' => '/' . $ownerPath,
1696
-			];
1697
-		} else {
1698
-			$al['users'][] = $owner;
1699
-		}
1700
-
1701
-		// Collect all the shares
1702
-		while ($path->getPath() !== $userFolder->getPath()) {
1703
-			$nodes[] = $path;
1704
-			if (!$recursive) {
1705
-				break;
1706
-			}
1707
-			$path = $path->getParent();
1708
-		}
1709
-
1710
-		foreach ($providers as $provider) {
1711
-			$tmp = $provider->getAccessList($nodes, $currentAccess);
1712
-
1713
-			foreach ($tmp as $k => $v) {
1714
-				if (isset($al[$k])) {
1715
-					if (is_array($al[$k])) {
1716
-						if ($currentAccess) {
1717
-							$al[$k] += $v;
1718
-						} else {
1719
-							$al[$k] = array_merge($al[$k], $v);
1720
-							$al[$k] = array_unique($al[$k]);
1721
-							$al[$k] = array_values($al[$k]);
1722
-						}
1723
-					} else {
1724
-						$al[$k] = $al[$k] || $v;
1725
-					}
1726
-				} else {
1727
-					$al[$k] = $v;
1728
-				}
1729
-			}
1730
-		}
1731
-
1732
-		return $al;
1733
-	}
1734
-
1735
-	/**
1736
-	 * Create a new share
1737
-	 *
1738
-	 * @return IShare
1739
-	 */
1740
-	public function newShare() {
1741
-		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1742
-	}
1743
-
1744
-	/**
1745
-	 * Is the share API enabled
1746
-	 *
1747
-	 * @return bool
1748
-	 */
1749
-	public function shareApiEnabled() {
1750
-		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1751
-	}
1752
-
1753
-	/**
1754
-	 * Is public link sharing enabled
1755
-	 *
1756
-	 * @return bool
1757
-	 */
1758
-	public function shareApiAllowLinks() {
1759
-		return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1760
-	}
1761
-
1762
-	/**
1763
-	 * Is password on public link requires
1764
-	 *
1765
-	 * @return bool
1766
-	 */
1767
-	public function shareApiLinkEnforcePassword() {
1768
-		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1769
-	}
1770
-
1771
-	/**
1772
-	 * Is default link expire date enabled
1773
-	 *
1774
-	 * @return bool
1775
-	 */
1776
-	public function shareApiLinkDefaultExpireDate() {
1777
-		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1778
-	}
1779
-
1780
-	/**
1781
-	 * Is default link expire date enforced
1782
-	 *`
1783
-	 * @return bool
1784
-	 */
1785
-	public function shareApiLinkDefaultExpireDateEnforced() {
1786
-		return $this->shareApiLinkDefaultExpireDate() &&
1787
-			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1788
-	}
1789
-
1790
-
1791
-	/**
1792
-	 * Number of default link expire days
1793
-	 * @return int
1794
-	 */
1795
-	public function shareApiLinkDefaultExpireDays() {
1796
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1797
-	}
1798
-
1799
-	/**
1800
-	 * Is default internal expire date enabled
1801
-	 *
1802
-	 * @return bool
1803
-	 */
1804
-	public function shareApiInternalDefaultExpireDate(): bool {
1805
-		return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
1806
-	}
1807
-
1808
-	/**
1809
-	 * Is default remote expire date enabled
1810
-	 *
1811
-	 * @return bool
1812
-	 */
1813
-	public function shareApiRemoteDefaultExpireDate(): bool {
1814
-		return $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no') === 'yes';
1815
-	}
1816
-
1817
-	/**
1818
-	 * Is default expire date enforced
1819
-	 *
1820
-	 * @return bool
1821
-	 */
1822
-	public function shareApiInternalDefaultExpireDateEnforced(): bool {
1823
-		return $this->shareApiInternalDefaultExpireDate() &&
1824
-			$this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
1825
-	}
1826
-
1827
-	/**
1828
-	 * Is default expire date enforced for remote shares
1829
-	 *
1830
-	 * @return bool
1831
-	 */
1832
-	public function shareApiRemoteDefaultExpireDateEnforced(): bool {
1833
-		return $this->shareApiRemoteDefaultExpireDate() &&
1834
-			$this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes';
1835
-	}
1836
-
1837
-	/**
1838
-	 * Number of default expire days
1839
-	 * @return int
1840
-	 */
1841
-	public function shareApiInternalDefaultExpireDays(): int {
1842
-		return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1843
-	}
1844
-
1845
-	/**
1846
-	 * Number of default expire days for remote shares
1847
-	 * @return int
1848
-	 */
1849
-	public function shareApiRemoteDefaultExpireDays(): int {
1850
-		return (int)$this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
1851
-	}
1852
-
1853
-	/**
1854
-	 * Allow public upload on link shares
1855
-	 *
1856
-	 * @return bool
1857
-	 */
1858
-	public function shareApiLinkAllowPublicUpload() {
1859
-		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1860
-	}
1861
-
1862
-	/**
1863
-	 * check if user can only share with group members
1864
-	 * @return bool
1865
-	 */
1866
-	public function shareWithGroupMembersOnly() {
1867
-		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1868
-	}
1869
-
1870
-	/**
1871
-	 * Check if users can share with groups
1872
-	 * @return bool
1873
-	 */
1874
-	public function allowGroupSharing() {
1875
-		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1876
-	}
1877
-
1878
-	public function allowEnumeration(): bool {
1879
-		return $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
1880
-	}
1881
-
1882
-	public function limitEnumerationToGroups(): bool {
1883
-		return $this->allowEnumeration() &&
1884
-			$this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
1885
-	}
1886
-
1887
-	public function limitEnumerationToPhone(): bool {
1888
-		return $this->allowEnumeration() &&
1889
-			$this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
1890
-	}
1891
-
1892
-	public function allowEnumerationFullMatch(): bool {
1893
-		return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
1894
-	}
1895
-
1896
-	/**
1897
-	 * Copied from \OC_Util::isSharingDisabledForUser
1898
-	 *
1899
-	 * TODO: Deprecate fuction from OC_Util
1900
-	 *
1901
-	 * @param string $userId
1902
-	 * @return bool
1903
-	 */
1904
-	public function sharingDisabledForUser($userId) {
1905
-		if ($userId === null) {
1906
-			return false;
1907
-		}
1908
-
1909
-		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1910
-			return $this->sharingDisabledForUsersCache[$userId];
1911
-		}
1912
-
1913
-		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1914
-			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1915
-			$excludedGroups = json_decode($groupsList);
1916
-			if (is_null($excludedGroups)) {
1917
-				$excludedGroups = explode(',', $groupsList);
1918
-				$newValue = json_encode($excludedGroups);
1919
-				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1920
-			}
1921
-			$user = $this->userManager->get($userId);
1922
-			$usersGroups = $this->groupManager->getUserGroupIds($user);
1923
-			if (!empty($usersGroups)) {
1924
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1925
-				// if the user is only in groups which are disabled for sharing then
1926
-				// sharing is also disabled for the user
1927
-				if (empty($remainingGroups)) {
1928
-					$this->sharingDisabledForUsersCache[$userId] = true;
1929
-					return true;
1930
-				}
1931
-			}
1932
-		}
1933
-
1934
-		$this->sharingDisabledForUsersCache[$userId] = false;
1935
-		return false;
1936
-	}
1937
-
1938
-	/**
1939
-	 * @inheritdoc
1940
-	 */
1941
-	public function outgoingServer2ServerSharesAllowed() {
1942
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1943
-	}
1944
-
1945
-	/**
1946
-	 * @inheritdoc
1947
-	 */
1948
-	public function outgoingServer2ServerGroupSharesAllowed() {
1949
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1950
-	}
1951
-
1952
-	/**
1953
-	 * @inheritdoc
1954
-	 */
1955
-	public function shareProviderExists($shareType) {
1956
-		try {
1957
-			$this->factory->getProviderForType($shareType);
1958
-		} catch (ProviderException $e) {
1959
-			return false;
1960
-		}
1961
-
1962
-		return true;
1963
-	}
1964
-
1965
-	public function registerShareProvider(string $shareProviderClass): void {
1966
-		$this->factory->registerProvider($shareProviderClass);
1967
-	}
1968
-
1969
-	public function getAllShares(): iterable {
1970
-		$providers = $this->factory->getAllProviders();
1971
-
1972
-		foreach ($providers as $provider) {
1973
-			yield from $provider->getAllShares();
1974
-		}
1975
-	}
1512
+        if (($share->getShareType() === IShare::TYPE_LINK || $share->getShareType() === IShare::TYPE_EMAIL)
1513
+            && !$this->shareApiLinkAllowPublicUpload()) {
1514
+            $share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1515
+        }
1516
+
1517
+        return $share;
1518
+    }
1519
+
1520
+    protected function checkExpireDate($share) {
1521
+        if ($share->isExpired()) {
1522
+            $this->deleteShare($share);
1523
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1524
+        }
1525
+    }
1526
+
1527
+    /**
1528
+     * Verify the password of a public share
1529
+     *
1530
+     * @param IShare $share
1531
+     * @param string $password
1532
+     * @return bool
1533
+     */
1534
+    public function checkPassword(IShare $share, $password) {
1535
+        $passwordProtected = $share->getShareType() !== IShare::TYPE_LINK
1536
+                             || $share->getShareType() !== IShare::TYPE_EMAIL
1537
+                             || $share->getShareType() !== IShare::TYPE_CIRCLE;
1538
+        if (!$passwordProtected) {
1539
+            //TODO maybe exception?
1540
+            return false;
1541
+        }
1542
+
1543
+        if ($password === null || $share->getPassword() === null) {
1544
+            return false;
1545
+        }
1546
+
1547
+        $newHash = '';
1548
+        if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1549
+            return false;
1550
+        }
1551
+
1552
+        if (!empty($newHash)) {
1553
+            $share->setPassword($newHash);
1554
+            $provider = $this->factory->getProviderForType($share->getShareType());
1555
+            $provider->update($share);
1556
+        }
1557
+
1558
+        return true;
1559
+    }
1560
+
1561
+    /**
1562
+     * @inheritdoc
1563
+     */
1564
+    public function userDeleted($uid) {
1565
+        $types = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK, IShare::TYPE_REMOTE, IShare::TYPE_EMAIL];
1566
+
1567
+        foreach ($types as $type) {
1568
+            try {
1569
+                $provider = $this->factory->getProviderForType($type);
1570
+            } catch (ProviderException $e) {
1571
+                continue;
1572
+            }
1573
+            $provider->userDeleted($uid, $type);
1574
+        }
1575
+    }
1576
+
1577
+    /**
1578
+     * @inheritdoc
1579
+     */
1580
+    public function groupDeleted($gid) {
1581
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1582
+        $provider->groupDeleted($gid);
1583
+
1584
+        $excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1585
+        if ($excludedGroups === '') {
1586
+            return;
1587
+        }
1588
+
1589
+        $excludedGroups = json_decode($excludedGroups, true);
1590
+        if (json_last_error() !== JSON_ERROR_NONE) {
1591
+            return;
1592
+        }
1593
+
1594
+        $excludedGroups = array_diff($excludedGroups, [$gid]);
1595
+        $this->config->setAppValue('core', 'shareapi_exclude_groups_list', json_encode($excludedGroups));
1596
+    }
1597
+
1598
+    /**
1599
+     * @inheritdoc
1600
+     */
1601
+    public function userDeletedFromGroup($uid, $gid) {
1602
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1603
+        $provider->userDeletedFromGroup($uid, $gid);
1604
+    }
1605
+
1606
+    /**
1607
+     * Get access list to a path. This means
1608
+     * all the users that can access a given path.
1609
+     *
1610
+     * Consider:
1611
+     * -root
1612
+     * |-folder1 (23)
1613
+     *  |-folder2 (32)
1614
+     *   |-fileA (42)
1615
+     *
1616
+     * fileA is shared with user1 and user1@server1
1617
+     * folder2 is shared with group2 (user4 is a member of group2)
1618
+     * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1619
+     *
1620
+     * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1621
+     * [
1622
+     *  users  => [
1623
+     *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1624
+     *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1625
+     *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1626
+     *  ],
1627
+     *  remote => [
1628
+     *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1629
+     *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1630
+     *  ],
1631
+     *  public => bool
1632
+     *  mail => bool
1633
+     * ]
1634
+     *
1635
+     * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1636
+     * [
1637
+     *  users  => ['user1', 'user2', 'user4'],
1638
+     *  remote => bool,
1639
+     *  public => bool
1640
+     *  mail => bool
1641
+     * ]
1642
+     *
1643
+     * This is required for encryption/activity
1644
+     *
1645
+     * @param \OCP\Files\Node $path
1646
+     * @param bool $recursive Should we check all parent folders as well
1647
+     * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1648
+     * @return array
1649
+     */
1650
+    public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1651
+        $owner = $path->getOwner();
1652
+
1653
+        if ($owner === null) {
1654
+            return [];
1655
+        }
1656
+
1657
+        $owner = $owner->getUID();
1658
+
1659
+        if ($currentAccess) {
1660
+            $al = ['users' => [], 'remote' => [], 'public' => false];
1661
+        } else {
1662
+            $al = ['users' => [], 'remote' => false, 'public' => false];
1663
+        }
1664
+        if (!$this->userManager->userExists($owner)) {
1665
+            return $al;
1666
+        }
1667
+
1668
+        //Get node for the owner and correct the owner in case of external storages
1669
+        $userFolder = $this->rootFolder->getUserFolder($owner);
1670
+        if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1671
+            $nodes = $userFolder->getById($path->getId());
1672
+            $path = array_shift($nodes);
1673
+            if ($path->getOwner() === null) {
1674
+                return [];
1675
+            }
1676
+            $owner = $path->getOwner()->getUID();
1677
+        }
1678
+
1679
+        $providers = $this->factory->getAllProviders();
1680
+
1681
+        /** @var Node[] $nodes */
1682
+        $nodes = [];
1683
+
1684
+
1685
+        if ($currentAccess) {
1686
+            $ownerPath = $path->getPath();
1687
+            $ownerPath = explode('/', $ownerPath, 4);
1688
+            if (count($ownerPath) < 4) {
1689
+                $ownerPath = '';
1690
+            } else {
1691
+                $ownerPath = $ownerPath[3];
1692
+            }
1693
+            $al['users'][$owner] = [
1694
+                'node_id' => $path->getId(),
1695
+                'node_path' => '/' . $ownerPath,
1696
+            ];
1697
+        } else {
1698
+            $al['users'][] = $owner;
1699
+        }
1700
+
1701
+        // Collect all the shares
1702
+        while ($path->getPath() !== $userFolder->getPath()) {
1703
+            $nodes[] = $path;
1704
+            if (!$recursive) {
1705
+                break;
1706
+            }
1707
+            $path = $path->getParent();
1708
+        }
1709
+
1710
+        foreach ($providers as $provider) {
1711
+            $tmp = $provider->getAccessList($nodes, $currentAccess);
1712
+
1713
+            foreach ($tmp as $k => $v) {
1714
+                if (isset($al[$k])) {
1715
+                    if (is_array($al[$k])) {
1716
+                        if ($currentAccess) {
1717
+                            $al[$k] += $v;
1718
+                        } else {
1719
+                            $al[$k] = array_merge($al[$k], $v);
1720
+                            $al[$k] = array_unique($al[$k]);
1721
+                            $al[$k] = array_values($al[$k]);
1722
+                        }
1723
+                    } else {
1724
+                        $al[$k] = $al[$k] || $v;
1725
+                    }
1726
+                } else {
1727
+                    $al[$k] = $v;
1728
+                }
1729
+            }
1730
+        }
1731
+
1732
+        return $al;
1733
+    }
1734
+
1735
+    /**
1736
+     * Create a new share
1737
+     *
1738
+     * @return IShare
1739
+     */
1740
+    public function newShare() {
1741
+        return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1742
+    }
1743
+
1744
+    /**
1745
+     * Is the share API enabled
1746
+     *
1747
+     * @return bool
1748
+     */
1749
+    public function shareApiEnabled() {
1750
+        return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1751
+    }
1752
+
1753
+    /**
1754
+     * Is public link sharing enabled
1755
+     *
1756
+     * @return bool
1757
+     */
1758
+    public function shareApiAllowLinks() {
1759
+        return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1760
+    }
1761
+
1762
+    /**
1763
+     * Is password on public link requires
1764
+     *
1765
+     * @return bool
1766
+     */
1767
+    public function shareApiLinkEnforcePassword() {
1768
+        return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1769
+    }
1770
+
1771
+    /**
1772
+     * Is default link expire date enabled
1773
+     *
1774
+     * @return bool
1775
+     */
1776
+    public function shareApiLinkDefaultExpireDate() {
1777
+        return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1778
+    }
1779
+
1780
+    /**
1781
+     * Is default link expire date enforced
1782
+     *`
1783
+     * @return bool
1784
+     */
1785
+    public function shareApiLinkDefaultExpireDateEnforced() {
1786
+        return $this->shareApiLinkDefaultExpireDate() &&
1787
+            $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1788
+    }
1789
+
1790
+
1791
+    /**
1792
+     * Number of default link expire days
1793
+     * @return int
1794
+     */
1795
+    public function shareApiLinkDefaultExpireDays() {
1796
+        return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1797
+    }
1798
+
1799
+    /**
1800
+     * Is default internal expire date enabled
1801
+     *
1802
+     * @return bool
1803
+     */
1804
+    public function shareApiInternalDefaultExpireDate(): bool {
1805
+        return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
1806
+    }
1807
+
1808
+    /**
1809
+     * Is default remote expire date enabled
1810
+     *
1811
+     * @return bool
1812
+     */
1813
+    public function shareApiRemoteDefaultExpireDate(): bool {
1814
+        return $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no') === 'yes';
1815
+    }
1816
+
1817
+    /**
1818
+     * Is default expire date enforced
1819
+     *
1820
+     * @return bool
1821
+     */
1822
+    public function shareApiInternalDefaultExpireDateEnforced(): bool {
1823
+        return $this->shareApiInternalDefaultExpireDate() &&
1824
+            $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
1825
+    }
1826
+
1827
+    /**
1828
+     * Is default expire date enforced for remote shares
1829
+     *
1830
+     * @return bool
1831
+     */
1832
+    public function shareApiRemoteDefaultExpireDateEnforced(): bool {
1833
+        return $this->shareApiRemoteDefaultExpireDate() &&
1834
+            $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes';
1835
+    }
1836
+
1837
+    /**
1838
+     * Number of default expire days
1839
+     * @return int
1840
+     */
1841
+    public function shareApiInternalDefaultExpireDays(): int {
1842
+        return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1843
+    }
1844
+
1845
+    /**
1846
+     * Number of default expire days for remote shares
1847
+     * @return int
1848
+     */
1849
+    public function shareApiRemoteDefaultExpireDays(): int {
1850
+        return (int)$this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
1851
+    }
1852
+
1853
+    /**
1854
+     * Allow public upload on link shares
1855
+     *
1856
+     * @return bool
1857
+     */
1858
+    public function shareApiLinkAllowPublicUpload() {
1859
+        return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1860
+    }
1861
+
1862
+    /**
1863
+     * check if user can only share with group members
1864
+     * @return bool
1865
+     */
1866
+    public function shareWithGroupMembersOnly() {
1867
+        return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1868
+    }
1869
+
1870
+    /**
1871
+     * Check if users can share with groups
1872
+     * @return bool
1873
+     */
1874
+    public function allowGroupSharing() {
1875
+        return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1876
+    }
1877
+
1878
+    public function allowEnumeration(): bool {
1879
+        return $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
1880
+    }
1881
+
1882
+    public function limitEnumerationToGroups(): bool {
1883
+        return $this->allowEnumeration() &&
1884
+            $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
1885
+    }
1886
+
1887
+    public function limitEnumerationToPhone(): bool {
1888
+        return $this->allowEnumeration() &&
1889
+            $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
1890
+    }
1891
+
1892
+    public function allowEnumerationFullMatch(): bool {
1893
+        return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
1894
+    }
1895
+
1896
+    /**
1897
+     * Copied from \OC_Util::isSharingDisabledForUser
1898
+     *
1899
+     * TODO: Deprecate fuction from OC_Util
1900
+     *
1901
+     * @param string $userId
1902
+     * @return bool
1903
+     */
1904
+    public function sharingDisabledForUser($userId) {
1905
+        if ($userId === null) {
1906
+            return false;
1907
+        }
1908
+
1909
+        if (isset($this->sharingDisabledForUsersCache[$userId])) {
1910
+            return $this->sharingDisabledForUsersCache[$userId];
1911
+        }
1912
+
1913
+        if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1914
+            $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1915
+            $excludedGroups = json_decode($groupsList);
1916
+            if (is_null($excludedGroups)) {
1917
+                $excludedGroups = explode(',', $groupsList);
1918
+                $newValue = json_encode($excludedGroups);
1919
+                $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1920
+            }
1921
+            $user = $this->userManager->get($userId);
1922
+            $usersGroups = $this->groupManager->getUserGroupIds($user);
1923
+            if (!empty($usersGroups)) {
1924
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
1925
+                // if the user is only in groups which are disabled for sharing then
1926
+                // sharing is also disabled for the user
1927
+                if (empty($remainingGroups)) {
1928
+                    $this->sharingDisabledForUsersCache[$userId] = true;
1929
+                    return true;
1930
+                }
1931
+            }
1932
+        }
1933
+
1934
+        $this->sharingDisabledForUsersCache[$userId] = false;
1935
+        return false;
1936
+    }
1937
+
1938
+    /**
1939
+     * @inheritdoc
1940
+     */
1941
+    public function outgoingServer2ServerSharesAllowed() {
1942
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1943
+    }
1944
+
1945
+    /**
1946
+     * @inheritdoc
1947
+     */
1948
+    public function outgoingServer2ServerGroupSharesAllowed() {
1949
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1950
+    }
1951
+
1952
+    /**
1953
+     * @inheritdoc
1954
+     */
1955
+    public function shareProviderExists($shareType) {
1956
+        try {
1957
+            $this->factory->getProviderForType($shareType);
1958
+        } catch (ProviderException $e) {
1959
+            return false;
1960
+        }
1961
+
1962
+        return true;
1963
+    }
1964
+
1965
+    public function registerShareProvider(string $shareProviderClass): void {
1966
+        $this->factory->registerProvider($shareProviderClass);
1967
+    }
1968
+
1969
+    public function getAllShares(): iterable {
1970
+        $providers = $this->factory->getAllProviders();
1971
+
1972
+        foreach ($providers as $provider) {
1973
+            yield from $provider->getAllShares();
1974
+        }
1975
+    }
1976 1976
 }
Please login to merge, or discard this patch.
Spacing   +24 added lines, -24 removed lines patch added patch discarded remove patch
@@ -303,14 +303,14 @@  discard block
 block discarded – undo
303 303
 		$permissions = 0;
304 304
 
305 305
 		if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
306
-			$userMounts = array_filter($userFolder->getById($share->getNode()->getId()), function ($mount) {
306
+			$userMounts = array_filter($userFolder->getById($share->getNode()->getId()), function($mount) {
307 307
 				// We need to filter since there might be other mountpoints that contain the file
308 308
 				// e.g. if the user has access to the same external storage that the file is originating from
309 309
 				return $mount->getStorage()->instanceOfStorage(ISharedStorage::class);
310 310
 			});
311 311
 			$userMount = array_shift($userMounts);
312 312
 			if ($userMount === null) {
313
-				throw new GenericShareException('Could not get proper share mount for ' . $share->getNode()->getId() . '. Failing since else the next calls are called with null');
313
+				throw new GenericShareException('Could not get proper share mount for '.$share->getNode()->getId().'. Failing since else the next calls are called with null');
314 314
 			}
315 315
 			$mount = $userMount->getMountPoint();
316 316
 			// When it's a reshare use the parent share permissions as maximum
@@ -319,7 +319,7 @@  discard block
 block discarded – undo
319 319
 			$userMountPoint = array_shift($userMountPoints);
320 320
 
321 321
 			if ($userMountPoint === null) {
322
-				throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
322
+				throw new GenericShareException('Could not get proper user mount for '.$userMountPointId.'. Failing since else the next calls are called with null');
323 323
 			}
324 324
 
325 325
 			/* Check if this is an incoming share */
@@ -422,9 +422,9 @@  discard block
 block discarded – undo
422 422
 		}
423 423
 		if ($fullId === null && $expirationDate === null && $defaultExpireDate) {
424 424
 			$expirationDate = new \DateTime();
425
-			$expirationDate->setTime(0,0,0);
425
+			$expirationDate->setTime(0, 0, 0);
426 426
 
427
-			$days = (int)$this->config->getAppValue('core', $configProp, (string)$defaultExpireDays);
427
+			$days = (int) $this->config->getAppValue('core', $configProp, (string) $defaultExpireDays);
428 428
 			if ($days > $defaultExpireDays) {
429 429
 				$days = $defaultExpireDays;
430 430
 			}
@@ -439,7 +439,7 @@  discard block
 block discarded – undo
439 439
 
440 440
 			$date = new \DateTime();
441 441
 			$date->setTime(0, 0, 0);
442
-			$date->add(new \DateInterval('P' . $defaultExpireDays . 'D'));
442
+			$date->add(new \DateInterval('P'.$defaultExpireDays.'D'));
443 443
 			if ($date < $expirationDate) {
444 444
 				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$defaultExpireDays]);
445 445
 				throw new GenericShareException($message, $message, 404);
@@ -498,9 +498,9 @@  discard block
 block discarded – undo
498 498
 
499 499
 		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
500 500
 			$expirationDate = new \DateTime();
501
-			$expirationDate->setTime(0,0,0);
501
+			$expirationDate->setTime(0, 0, 0);
502 502
 
503
-			$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
503
+			$days = (int) $this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
504 504
 			if ($days > $this->shareApiLinkDefaultExpireDays()) {
505 505
 				$days = $this->shareApiLinkDefaultExpireDays();
506 506
 			}
@@ -515,7 +515,7 @@  discard block
 block discarded – undo
515 515
 
516 516
 			$date = new \DateTime();
517 517
 			$date->setTime(0, 0, 0);
518
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
518
+			$date->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
519 519
 			if ($date < $expirationDate) {
520 520
 				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
521 521
 				throw new GenericShareException($message, $message, 404);
@@ -800,7 +800,7 @@  discard block
 block discarded – undo
800 800
 			}
801 801
 
802 802
 			// Generate the target
803
-			$target = $this->config->getSystemValue('share_folder', '/') . '/' . $share->getNode()->getName();
803
+			$target = $this->config->getSystemValue('share_folder', '/').'/'.$share->getNode()->getName();
804 804
 			$target = \OC\Files\Filesystem::normalizePath($target);
805 805
 			$share->setTarget($target);
806 806
 
@@ -851,12 +851,12 @@  discard block
 block discarded – undo
851 851
 							$emailAddress,
852 852
 							$share->getExpirationDate()
853 853
 						);
854
-						$this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
854
+						$this->logger->debug('Sent share notification to '.$emailAddress.' for share with ID '.$share->getId(), ['app' => 'share']);
855 855
 					} else {
856
-						$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
856
+						$this->logger->debug('Share notification not sent to '.$share->getSharedWith().' because email address is not set.', ['app' => 'share']);
857 857
 					}
858 858
 				} else {
859
-					$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
859
+					$this->logger->debug('Share notification not sent to '.$share->getSharedWith().' because user could not be found.', ['app' => 'share']);
860 860
 				}
861 861
 			} else {
862 862
 				$this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
@@ -903,7 +903,7 @@  discard block
 block discarded – undo
903 903
 		$text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
904 904
 
905 905
 		$emailTemplate->addBodyText(
906
-			htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
906
+			htmlspecialchars($text.' '.$l->t('Click the button below to open it.')),
907 907
 			$text
908 908
 		);
909 909
 		$emailTemplate->addBodyButton(
@@ -929,7 +929,7 @@  discard block
 block discarded – undo
929 929
 		$initiatorEmail = $initiatorUser->getEMailAddress();
930 930
 		if ($initiatorEmail !== null) {
931 931
 			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
932
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
932
+			$emailTemplate->addFooter($instanceName.($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - '.$this->defaults->getSlogan($l->getLanguageCode()) : ''));
933 933
 		} else {
934 934
 			$emailTemplate->addFooter('', $l->getLanguageCode());
935 935
 		}
@@ -938,7 +938,7 @@  discard block
 block discarded – undo
938 938
 		try {
939 939
 			$failedRecipients = $this->mailer->send($message);
940 940
 			if (!empty($failedRecipients)) {
941
-				$this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
941
+				$this->logger->error('Share notification mail could not be sent to: '.implode(', ', $failedRecipients));
942 942
 				return;
943 943
 			}
944 944
 		} catch (\Exception $e) {
@@ -1256,7 +1256,7 @@  discard block
 block discarded – undo
1256 1256
 		if ($share->getShareType() === IShare::TYPE_GROUP) {
1257 1257
 			$sharedWith = $this->groupManager->get($share->getSharedWith());
1258 1258
 			if (is_null($sharedWith)) {
1259
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1259
+				throw new \InvalidArgumentException('Group "'.$share->getSharedWith().'" does not exist');
1260 1260
 			}
1261 1261
 			$recipient = $this->userManager->get($recipientId);
1262 1262
 			if (!$sharedWith->inGroup($recipient)) {
@@ -1273,7 +1273,7 @@  discard block
 block discarded – undo
1273 1273
 	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1274 1274
 		$providers = $this->factory->getAllProviders();
1275 1275
 
1276
-		return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1276
+		return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1277 1277
 			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1278 1278
 			foreach ($newShares as $fid => $data) {
1279 1279
 				if (!isset($shares[$fid])) {
@@ -1390,12 +1390,12 @@  discard block
 block discarded – undo
1390 1390
 		$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1391 1391
 
1392 1392
 		// Only get deleted shares
1393
-		$shares = array_filter($shares, function (IShare $share) {
1393
+		$shares = array_filter($shares, function(IShare $share) {
1394 1394
 			return $share->getPermissions() === 0;
1395 1395
 		});
1396 1396
 
1397 1397
 		// Only get shares where the owner still exists
1398
-		$shares = array_filter($shares, function (IShare $share) {
1398
+		$shares = array_filter($shares, function(IShare $share) {
1399 1399
 			return $this->userManager->userExists($share->getShareOwner());
1400 1400
 		});
1401 1401
 
@@ -1692,7 +1692,7 @@  discard block
 block discarded – undo
1692 1692
 			}
1693 1693
 			$al['users'][$owner] = [
1694 1694
 				'node_id' => $path->getId(),
1695
-				'node_path' => '/' . $ownerPath,
1695
+				'node_path' => '/'.$ownerPath,
1696 1696
 			];
1697 1697
 		} else {
1698 1698
 			$al['users'][] = $owner;
@@ -1793,7 +1793,7 @@  discard block
 block discarded – undo
1793 1793
 	 * @return int
1794 1794
 	 */
1795 1795
 	public function shareApiLinkDefaultExpireDays() {
1796
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1796
+		return (int) $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1797 1797
 	}
1798 1798
 
1799 1799
 	/**
@@ -1839,7 +1839,7 @@  discard block
 block discarded – undo
1839 1839
 	 * @return int
1840 1840
 	 */
1841 1841
 	public function shareApiInternalDefaultExpireDays(): int {
1842
-		return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1842
+		return (int) $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1843 1843
 	}
1844 1844
 
1845 1845
 	/**
@@ -1847,7 +1847,7 @@  discard block
 block discarded – undo
1847 1847
 	 * @return int
1848 1848
 	 */
1849 1849
 	public function shareApiRemoteDefaultExpireDays(): int {
1850
-		return (int)$this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
1850
+		return (int) $this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
1851 1851
 	}
1852 1852
 
1853 1853
 	/**
Please login to merge, or discard this patch.
lib/private/Template/JSConfigHelper.php 2 patches
Indentation   +283 added lines, -283 removed lines patch added patch discarded remove patch
@@ -47,287 +47,287 @@
 block discarded – undo
47 47
 
48 48
 class JSConfigHelper {
49 49
 
50
-	/** @var IL10N */
51
-	private $l;
52
-
53
-	/** @var Defaults */
54
-	private $defaults;
55
-
56
-	/** @var IAppManager */
57
-	private $appManager;
58
-
59
-	/** @var ISession */
60
-	private $session;
61
-
62
-	/** @var IUser|null */
63
-	private $currentUser;
64
-
65
-	/** @var IConfig */
66
-	private $config;
67
-
68
-	/** @var IGroupManager */
69
-	private $groupManager;
70
-
71
-	/** @var IniGetWrapper */
72
-	private $iniWrapper;
73
-
74
-	/** @var IURLGenerator */
75
-	private $urlGenerator;
76
-
77
-	/** @var CapabilitiesManager */
78
-	private $capabilitiesManager;
79
-
80
-	/** @var IInitialStateService */
81
-	private $initialStateService;
82
-
83
-	/** @var array user back-ends excluded from password verification */
84
-	private $excludedUserBackEnds = ['user_saml' => true, 'user_globalsiteselector' => true];
85
-
86
-	/**
87
-	 * @param IL10N $l
88
-	 * @param Defaults $defaults
89
-	 * @param IAppManager $appManager
90
-	 * @param ISession $session
91
-	 * @param IUser|null $currentUser
92
-	 * @param IConfig $config
93
-	 * @param IGroupManager $groupManager
94
-	 * @param IniGetWrapper $iniWrapper
95
-	 * @param IURLGenerator $urlGenerator
96
-	 * @param CapabilitiesManager $capabilitiesManager
97
-	 */
98
-	public function __construct(IL10N $l,
99
-								Defaults $defaults,
100
-								IAppManager $appManager,
101
-								ISession $session,
102
-								$currentUser,
103
-								IConfig $config,
104
-								IGroupManager $groupManager,
105
-								IniGetWrapper $iniWrapper,
106
-								IURLGenerator $urlGenerator,
107
-								CapabilitiesManager $capabilitiesManager,
108
-								IInitialStateService $initialStateService) {
109
-		$this->l = $l;
110
-		$this->defaults = $defaults;
111
-		$this->appManager = $appManager;
112
-		$this->session = $session;
113
-		$this->currentUser = $currentUser;
114
-		$this->config = $config;
115
-		$this->groupManager = $groupManager;
116
-		$this->iniWrapper = $iniWrapper;
117
-		$this->urlGenerator = $urlGenerator;
118
-		$this->capabilitiesManager = $capabilitiesManager;
119
-		$this->initialStateService = $initialStateService;
120
-	}
121
-
122
-	public function getConfig() {
123
-		$userBackendAllowsPasswordConfirmation = true;
124
-		if ($this->currentUser !== null) {
125
-			$uid = $this->currentUser->getUID();
126
-
127
-			$backend = $this->currentUser->getBackend();
128
-			if ($backend instanceof IPasswordConfirmationBackend) {
129
-				$userBackendAllowsPasswordConfirmation = $backend->canConfirmPassword($uid);
130
-			} elseif (isset($this->excludedUserBackEnds[$this->currentUser->getBackendClassName()])) {
131
-				$userBackendAllowsPasswordConfirmation = false;
132
-			}
133
-		} else {
134
-			$uid = null;
135
-		}
136
-
137
-		// Get the config
138
-		$apps_paths = [];
139
-
140
-		if ($this->currentUser === null) {
141
-			$apps = $this->appManager->getInstalledApps();
142
-		} else {
143
-			$apps = $this->appManager->getEnabledAppsForUser($this->currentUser);
144
-		}
145
-
146
-		foreach ($apps as $app) {
147
-			$apps_paths[$app] = \OC_App::getAppWebPath($app);
148
-		}
149
-
150
-
151
-		$enableLinkPasswordByDefault = $this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no');
152
-		$enableLinkPasswordByDefault = $enableLinkPasswordByDefault === 'yes';
153
-		$defaultExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
154
-		$defaultExpireDate = $enforceDefaultExpireDate = null;
155
-		if ($defaultExpireDateEnabled) {
156
-			$defaultExpireDate = (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
157
-			$enforceDefaultExpireDate = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
158
-		}
159
-		$outgoingServer2serverShareEnabled = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
160
-
161
-		$defaultInternalExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
162
-		$defaultInternalExpireDate = $defaultInternalExpireDateEnforced = null;
163
-		if ($defaultInternalExpireDateEnabled) {
164
-			$defaultInternalExpireDate = (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
165
-			$defaultInternalExpireDateEnforced = $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
166
-		}
167
-
168
-		$defaultRemoteExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no') === 'yes';
169
-		$defaultRemoteExpireDate = $defaultRemoteExpireDateEnforced = null;
170
-		if ($defaultRemoteExpireDateEnabled) {
171
-			$defaultRemoteExpireDate = (int)$this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
172
-			$defaultRemoteExpireDateEnforced = $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes';
173
-		}
174
-
175
-		$countOfDataLocation = 0;
176
-		$dataLocation = str_replace(\OC::$SERVERROOT . '/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation);
177
-		if ($countOfDataLocation !== 1 || $uid === null || !$this->groupManager->isAdmin($uid)) {
178
-			$dataLocation = false;
179
-		}
180
-
181
-		if ($this->currentUser instanceof IUser) {
182
-			$lastConfirmTimestamp = $this->session->get('last-password-confirm');
183
-			if (!is_int($lastConfirmTimestamp)) {
184
-				$lastConfirmTimestamp = 0;
185
-			}
186
-		} else {
187
-			$lastConfirmTimestamp = 0;
188
-		}
189
-
190
-		$capabilities = $this->capabilitiesManager->getCapabilities();
191
-
192
-		$config = [
193
-			'session_lifetime' => min($this->config->getSystemValue('session_lifetime', $this->iniWrapper->getNumeric('session.gc_maxlifetime')), $this->iniWrapper->getNumeric('session.gc_maxlifetime')),
194
-			'session_keepalive' => $this->config->getSystemValue('session_keepalive', true),
195
-			'auto_logout' => $this->config->getSystemValue('auto_logout', false),
196
-			'version' => implode('.', \OCP\Util::getVersion()),
197
-			'versionstring' => \OC_Util::getVersionString(),
198
-			'enable_avatars' => true, // here for legacy reasons - to not crash existing code that relies on this value
199
-			'lost_password_link' => $this->config->getSystemValue('lost_password_link', null),
200
-			'modRewriteWorking' => $this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true',
201
-			'sharing.maxAutocompleteResults' => max(0, $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT)),
202
-			'sharing.minSearchStringLength' => $this->config->getSystemValueInt('sharing.minSearchStringLength', 0),
203
-			'blacklist_files_regex' => \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX,
204
-		];
205
-
206
-		$array = [
207
-			"_oc_debug" => $this->config->getSystemValue('debug', false) ? 'true' : 'false',
208
-			"_oc_isadmin" => $uid !== null && $this->groupManager->isAdmin($uid) ? 'true' : 'false',
209
-			"backendAllowsPasswordConfirmation" => $userBackendAllowsPasswordConfirmation ? 'true' : 'false',
210
-			"oc_dataURL" => is_string($dataLocation) ? "\"" . $dataLocation . "\"" : 'false',
211
-			"_oc_webroot" => "\"" . \OC::$WEBROOT . "\"",
212
-			"_oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution
213
-			"datepickerFormatDate" => json_encode($this->l->l('jsdate', null)),
214
-			'nc_lastLogin' => $lastConfirmTimestamp,
215
-			'nc_pageLoad' => time(),
216
-			"dayNames" => json_encode([
217
-				$this->l->t('Sunday'),
218
-				$this->l->t('Monday'),
219
-				$this->l->t('Tuesday'),
220
-				$this->l->t('Wednesday'),
221
-				$this->l->t('Thursday'),
222
-				$this->l->t('Friday'),
223
-				$this->l->t('Saturday')
224
-			]),
225
-			"dayNamesShort" => json_encode([
226
-				$this->l->t('Sun.'),
227
-				$this->l->t('Mon.'),
228
-				$this->l->t('Tue.'),
229
-				$this->l->t('Wed.'),
230
-				$this->l->t('Thu.'),
231
-				$this->l->t('Fri.'),
232
-				$this->l->t('Sat.')
233
-			]),
234
-			"dayNamesMin" => json_encode([
235
-				$this->l->t('Su'),
236
-				$this->l->t('Mo'),
237
-				$this->l->t('Tu'),
238
-				$this->l->t('We'),
239
-				$this->l->t('Th'),
240
-				$this->l->t('Fr'),
241
-				$this->l->t('Sa')
242
-			]),
243
-			"monthNames" => json_encode([
244
-				$this->l->t('January'),
245
-				$this->l->t('February'),
246
-				$this->l->t('March'),
247
-				$this->l->t('April'),
248
-				$this->l->t('May'),
249
-				$this->l->t('June'),
250
-				$this->l->t('July'),
251
-				$this->l->t('August'),
252
-				$this->l->t('September'),
253
-				$this->l->t('October'),
254
-				$this->l->t('November'),
255
-				$this->l->t('December')
256
-			]),
257
-			"monthNamesShort" => json_encode([
258
-				$this->l->t('Jan.'),
259
-				$this->l->t('Feb.'),
260
-				$this->l->t('Mar.'),
261
-				$this->l->t('Apr.'),
262
-				$this->l->t('May.'),
263
-				$this->l->t('Jun.'),
264
-				$this->l->t('Jul.'),
265
-				$this->l->t('Aug.'),
266
-				$this->l->t('Sep.'),
267
-				$this->l->t('Oct.'),
268
-				$this->l->t('Nov.'),
269
-				$this->l->t('Dec.')
270
-			]),
271
-			"firstDay" => json_encode($this->l->l('firstday', null)),
272
-			"_oc_config" => json_encode($config),
273
-			"oc_appconfig" => json_encode([
274
-				'core' => [
275
-					'defaultExpireDateEnabled' => $defaultExpireDateEnabled,
276
-					'defaultExpireDate' => $defaultExpireDate,
277
-					'defaultExpireDateEnforced' => $enforceDefaultExpireDate,
278
-					'enforcePasswordForPublicLink' => \OCP\Util::isPublicLinkPasswordRequired(),
279
-					'enableLinkPasswordByDefault' => $enableLinkPasswordByDefault,
280
-					'sharingDisabledForUser' => \OCP\Util::isSharingDisabledForUser(),
281
-					'resharingAllowed' => \OC\Share\Share::isResharingAllowed(),
282
-					'remoteShareAllowed' => $outgoingServer2serverShareEnabled,
283
-					'federatedCloudShareDoc' => $this->urlGenerator->linkToDocs('user-sharing-federated'),
284
-					'allowGroupSharing' => \OC::$server->getShareManager()->allowGroupSharing(),
285
-					'defaultInternalExpireDateEnabled' => $defaultInternalExpireDateEnabled,
286
-					'defaultInternalExpireDate' => $defaultInternalExpireDate,
287
-					'defaultInternalExpireDateEnforced' => $defaultInternalExpireDateEnforced,
288
-					'defaultRemoteExpireDateEnabled' => $defaultRemoteExpireDateEnabled,
289
-					'defaultRemoteExpireDate' => $defaultRemoteExpireDate,
290
-					'defaultRemoteExpireDateEnforced' => $defaultRemoteExpireDateEnforced,
291
-				]
292
-			]),
293
-			"_theme" => json_encode([
294
-				'entity' => $this->defaults->getEntity(),
295
-				'name' => $this->defaults->getName(),
296
-				'title' => $this->defaults->getTitle(),
297
-				'baseUrl' => $this->defaults->getBaseUrl(),
298
-				'syncClientUrl' => $this->defaults->getSyncClientUrl(),
299
-				'docBaseUrl' => $this->defaults->getDocBaseUrl(),
300
-				'docPlaceholderUrl' => $this->defaults->buildDocLinkToKey('PLACEHOLDER'),
301
-				'slogan' => $this->defaults->getSlogan(),
302
-				'logoClaim' => '',
303
-				'shortFooter' => $this->defaults->getShortFooter(),
304
-				'longFooter' => $this->defaults->getLongFooter(),
305
-				'folder' => \OC_Util::getTheme(),
306
-			]),
307
-		];
308
-
309
-		if ($this->currentUser !== null) {
310
-			$array['oc_userconfig'] = json_encode([
311
-				'avatar' => [
312
-					'version' => (int)$this->config->getUserValue($uid, 'avatar', 'version', 0),
313
-					'generated' => $this->config->getUserValue($uid, 'avatar', 'generated', 'true') === 'true',
314
-				]
315
-			]);
316
-		}
317
-
318
-		$this->initialStateService->provideInitialState('core', 'config', $config);
319
-		$this->initialStateService->provideInitialState('core', 'capabilities', $capabilities);
320
-
321
-		// Allow hooks to modify the output values
322
-		\OC_Hook::emit('\OCP\Config', 'js', ['array' => &$array]);
323
-
324
-		$result = '';
325
-
326
-		// Echo it
327
-		foreach ($array as  $setting => $value) {
328
-			$result .= 'var '. $setting . '='. $value . ';' . PHP_EOL;
329
-		}
330
-
331
-		return $result;
332
-	}
50
+    /** @var IL10N */
51
+    private $l;
52
+
53
+    /** @var Defaults */
54
+    private $defaults;
55
+
56
+    /** @var IAppManager */
57
+    private $appManager;
58
+
59
+    /** @var ISession */
60
+    private $session;
61
+
62
+    /** @var IUser|null */
63
+    private $currentUser;
64
+
65
+    /** @var IConfig */
66
+    private $config;
67
+
68
+    /** @var IGroupManager */
69
+    private $groupManager;
70
+
71
+    /** @var IniGetWrapper */
72
+    private $iniWrapper;
73
+
74
+    /** @var IURLGenerator */
75
+    private $urlGenerator;
76
+
77
+    /** @var CapabilitiesManager */
78
+    private $capabilitiesManager;
79
+
80
+    /** @var IInitialStateService */
81
+    private $initialStateService;
82
+
83
+    /** @var array user back-ends excluded from password verification */
84
+    private $excludedUserBackEnds = ['user_saml' => true, 'user_globalsiteselector' => true];
85
+
86
+    /**
87
+     * @param IL10N $l
88
+     * @param Defaults $defaults
89
+     * @param IAppManager $appManager
90
+     * @param ISession $session
91
+     * @param IUser|null $currentUser
92
+     * @param IConfig $config
93
+     * @param IGroupManager $groupManager
94
+     * @param IniGetWrapper $iniWrapper
95
+     * @param IURLGenerator $urlGenerator
96
+     * @param CapabilitiesManager $capabilitiesManager
97
+     */
98
+    public function __construct(IL10N $l,
99
+                                Defaults $defaults,
100
+                                IAppManager $appManager,
101
+                                ISession $session,
102
+                                $currentUser,
103
+                                IConfig $config,
104
+                                IGroupManager $groupManager,
105
+                                IniGetWrapper $iniWrapper,
106
+                                IURLGenerator $urlGenerator,
107
+                                CapabilitiesManager $capabilitiesManager,
108
+                                IInitialStateService $initialStateService) {
109
+        $this->l = $l;
110
+        $this->defaults = $defaults;
111
+        $this->appManager = $appManager;
112
+        $this->session = $session;
113
+        $this->currentUser = $currentUser;
114
+        $this->config = $config;
115
+        $this->groupManager = $groupManager;
116
+        $this->iniWrapper = $iniWrapper;
117
+        $this->urlGenerator = $urlGenerator;
118
+        $this->capabilitiesManager = $capabilitiesManager;
119
+        $this->initialStateService = $initialStateService;
120
+    }
121
+
122
+    public function getConfig() {
123
+        $userBackendAllowsPasswordConfirmation = true;
124
+        if ($this->currentUser !== null) {
125
+            $uid = $this->currentUser->getUID();
126
+
127
+            $backend = $this->currentUser->getBackend();
128
+            if ($backend instanceof IPasswordConfirmationBackend) {
129
+                $userBackendAllowsPasswordConfirmation = $backend->canConfirmPassword($uid);
130
+            } elseif (isset($this->excludedUserBackEnds[$this->currentUser->getBackendClassName()])) {
131
+                $userBackendAllowsPasswordConfirmation = false;
132
+            }
133
+        } else {
134
+            $uid = null;
135
+        }
136
+
137
+        // Get the config
138
+        $apps_paths = [];
139
+
140
+        if ($this->currentUser === null) {
141
+            $apps = $this->appManager->getInstalledApps();
142
+        } else {
143
+            $apps = $this->appManager->getEnabledAppsForUser($this->currentUser);
144
+        }
145
+
146
+        foreach ($apps as $app) {
147
+            $apps_paths[$app] = \OC_App::getAppWebPath($app);
148
+        }
149
+
150
+
151
+        $enableLinkPasswordByDefault = $this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no');
152
+        $enableLinkPasswordByDefault = $enableLinkPasswordByDefault === 'yes';
153
+        $defaultExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
154
+        $defaultExpireDate = $enforceDefaultExpireDate = null;
155
+        if ($defaultExpireDateEnabled) {
156
+            $defaultExpireDate = (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
157
+            $enforceDefaultExpireDate = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
158
+        }
159
+        $outgoingServer2serverShareEnabled = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
160
+
161
+        $defaultInternalExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
162
+        $defaultInternalExpireDate = $defaultInternalExpireDateEnforced = null;
163
+        if ($defaultInternalExpireDateEnabled) {
164
+            $defaultInternalExpireDate = (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
165
+            $defaultInternalExpireDateEnforced = $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
166
+        }
167
+
168
+        $defaultRemoteExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no') === 'yes';
169
+        $defaultRemoteExpireDate = $defaultRemoteExpireDateEnforced = null;
170
+        if ($defaultRemoteExpireDateEnabled) {
171
+            $defaultRemoteExpireDate = (int)$this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
172
+            $defaultRemoteExpireDateEnforced = $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes';
173
+        }
174
+
175
+        $countOfDataLocation = 0;
176
+        $dataLocation = str_replace(\OC::$SERVERROOT . '/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation);
177
+        if ($countOfDataLocation !== 1 || $uid === null || !$this->groupManager->isAdmin($uid)) {
178
+            $dataLocation = false;
179
+        }
180
+
181
+        if ($this->currentUser instanceof IUser) {
182
+            $lastConfirmTimestamp = $this->session->get('last-password-confirm');
183
+            if (!is_int($lastConfirmTimestamp)) {
184
+                $lastConfirmTimestamp = 0;
185
+            }
186
+        } else {
187
+            $lastConfirmTimestamp = 0;
188
+        }
189
+
190
+        $capabilities = $this->capabilitiesManager->getCapabilities();
191
+
192
+        $config = [
193
+            'session_lifetime' => min($this->config->getSystemValue('session_lifetime', $this->iniWrapper->getNumeric('session.gc_maxlifetime')), $this->iniWrapper->getNumeric('session.gc_maxlifetime')),
194
+            'session_keepalive' => $this->config->getSystemValue('session_keepalive', true),
195
+            'auto_logout' => $this->config->getSystemValue('auto_logout', false),
196
+            'version' => implode('.', \OCP\Util::getVersion()),
197
+            'versionstring' => \OC_Util::getVersionString(),
198
+            'enable_avatars' => true, // here for legacy reasons - to not crash existing code that relies on this value
199
+            'lost_password_link' => $this->config->getSystemValue('lost_password_link', null),
200
+            'modRewriteWorking' => $this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true',
201
+            'sharing.maxAutocompleteResults' => max(0, $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT)),
202
+            'sharing.minSearchStringLength' => $this->config->getSystemValueInt('sharing.minSearchStringLength', 0),
203
+            'blacklist_files_regex' => \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX,
204
+        ];
205
+
206
+        $array = [
207
+            "_oc_debug" => $this->config->getSystemValue('debug', false) ? 'true' : 'false',
208
+            "_oc_isadmin" => $uid !== null && $this->groupManager->isAdmin($uid) ? 'true' : 'false',
209
+            "backendAllowsPasswordConfirmation" => $userBackendAllowsPasswordConfirmation ? 'true' : 'false',
210
+            "oc_dataURL" => is_string($dataLocation) ? "\"" . $dataLocation . "\"" : 'false',
211
+            "_oc_webroot" => "\"" . \OC::$WEBROOT . "\"",
212
+            "_oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution
213
+            "datepickerFormatDate" => json_encode($this->l->l('jsdate', null)),
214
+            'nc_lastLogin' => $lastConfirmTimestamp,
215
+            'nc_pageLoad' => time(),
216
+            "dayNames" => json_encode([
217
+                $this->l->t('Sunday'),
218
+                $this->l->t('Monday'),
219
+                $this->l->t('Tuesday'),
220
+                $this->l->t('Wednesday'),
221
+                $this->l->t('Thursday'),
222
+                $this->l->t('Friday'),
223
+                $this->l->t('Saturday')
224
+            ]),
225
+            "dayNamesShort" => json_encode([
226
+                $this->l->t('Sun.'),
227
+                $this->l->t('Mon.'),
228
+                $this->l->t('Tue.'),
229
+                $this->l->t('Wed.'),
230
+                $this->l->t('Thu.'),
231
+                $this->l->t('Fri.'),
232
+                $this->l->t('Sat.')
233
+            ]),
234
+            "dayNamesMin" => json_encode([
235
+                $this->l->t('Su'),
236
+                $this->l->t('Mo'),
237
+                $this->l->t('Tu'),
238
+                $this->l->t('We'),
239
+                $this->l->t('Th'),
240
+                $this->l->t('Fr'),
241
+                $this->l->t('Sa')
242
+            ]),
243
+            "monthNames" => json_encode([
244
+                $this->l->t('January'),
245
+                $this->l->t('February'),
246
+                $this->l->t('March'),
247
+                $this->l->t('April'),
248
+                $this->l->t('May'),
249
+                $this->l->t('June'),
250
+                $this->l->t('July'),
251
+                $this->l->t('August'),
252
+                $this->l->t('September'),
253
+                $this->l->t('October'),
254
+                $this->l->t('November'),
255
+                $this->l->t('December')
256
+            ]),
257
+            "monthNamesShort" => json_encode([
258
+                $this->l->t('Jan.'),
259
+                $this->l->t('Feb.'),
260
+                $this->l->t('Mar.'),
261
+                $this->l->t('Apr.'),
262
+                $this->l->t('May.'),
263
+                $this->l->t('Jun.'),
264
+                $this->l->t('Jul.'),
265
+                $this->l->t('Aug.'),
266
+                $this->l->t('Sep.'),
267
+                $this->l->t('Oct.'),
268
+                $this->l->t('Nov.'),
269
+                $this->l->t('Dec.')
270
+            ]),
271
+            "firstDay" => json_encode($this->l->l('firstday', null)),
272
+            "_oc_config" => json_encode($config),
273
+            "oc_appconfig" => json_encode([
274
+                'core' => [
275
+                    'defaultExpireDateEnabled' => $defaultExpireDateEnabled,
276
+                    'defaultExpireDate' => $defaultExpireDate,
277
+                    'defaultExpireDateEnforced' => $enforceDefaultExpireDate,
278
+                    'enforcePasswordForPublicLink' => \OCP\Util::isPublicLinkPasswordRequired(),
279
+                    'enableLinkPasswordByDefault' => $enableLinkPasswordByDefault,
280
+                    'sharingDisabledForUser' => \OCP\Util::isSharingDisabledForUser(),
281
+                    'resharingAllowed' => \OC\Share\Share::isResharingAllowed(),
282
+                    'remoteShareAllowed' => $outgoingServer2serverShareEnabled,
283
+                    'federatedCloudShareDoc' => $this->urlGenerator->linkToDocs('user-sharing-federated'),
284
+                    'allowGroupSharing' => \OC::$server->getShareManager()->allowGroupSharing(),
285
+                    'defaultInternalExpireDateEnabled' => $defaultInternalExpireDateEnabled,
286
+                    'defaultInternalExpireDate' => $defaultInternalExpireDate,
287
+                    'defaultInternalExpireDateEnforced' => $defaultInternalExpireDateEnforced,
288
+                    'defaultRemoteExpireDateEnabled' => $defaultRemoteExpireDateEnabled,
289
+                    'defaultRemoteExpireDate' => $defaultRemoteExpireDate,
290
+                    'defaultRemoteExpireDateEnforced' => $defaultRemoteExpireDateEnforced,
291
+                ]
292
+            ]),
293
+            "_theme" => json_encode([
294
+                'entity' => $this->defaults->getEntity(),
295
+                'name' => $this->defaults->getName(),
296
+                'title' => $this->defaults->getTitle(),
297
+                'baseUrl' => $this->defaults->getBaseUrl(),
298
+                'syncClientUrl' => $this->defaults->getSyncClientUrl(),
299
+                'docBaseUrl' => $this->defaults->getDocBaseUrl(),
300
+                'docPlaceholderUrl' => $this->defaults->buildDocLinkToKey('PLACEHOLDER'),
301
+                'slogan' => $this->defaults->getSlogan(),
302
+                'logoClaim' => '',
303
+                'shortFooter' => $this->defaults->getShortFooter(),
304
+                'longFooter' => $this->defaults->getLongFooter(),
305
+                'folder' => \OC_Util::getTheme(),
306
+            ]),
307
+        ];
308
+
309
+        if ($this->currentUser !== null) {
310
+            $array['oc_userconfig'] = json_encode([
311
+                'avatar' => [
312
+                    'version' => (int)$this->config->getUserValue($uid, 'avatar', 'version', 0),
313
+                    'generated' => $this->config->getUserValue($uid, 'avatar', 'generated', 'true') === 'true',
314
+                ]
315
+            ]);
316
+        }
317
+
318
+        $this->initialStateService->provideInitialState('core', 'config', $config);
319
+        $this->initialStateService->provideInitialState('core', 'capabilities', $capabilities);
320
+
321
+        // Allow hooks to modify the output values
322
+        \OC_Hook::emit('\OCP\Config', 'js', ['array' => &$array]);
323
+
324
+        $result = '';
325
+
326
+        // Echo it
327
+        foreach ($array as  $setting => $value) {
328
+            $result .= 'var '. $setting . '='. $value . ';' . PHP_EOL;
329
+        }
330
+
331
+        return $result;
332
+    }
333 333
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -153,7 +153,7 @@  discard block
 block discarded – undo
153 153
 		$defaultExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
154 154
 		$defaultExpireDate = $enforceDefaultExpireDate = null;
155 155
 		if ($defaultExpireDateEnabled) {
156
-			$defaultExpireDate = (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
156
+			$defaultExpireDate = (int) $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
157 157
 			$enforceDefaultExpireDate = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
158 158
 		}
159 159
 		$outgoingServer2serverShareEnabled = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
@@ -161,19 +161,19 @@  discard block
 block discarded – undo
161 161
 		$defaultInternalExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
162 162
 		$defaultInternalExpireDate = $defaultInternalExpireDateEnforced = null;
163 163
 		if ($defaultInternalExpireDateEnabled) {
164
-			$defaultInternalExpireDate = (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
164
+			$defaultInternalExpireDate = (int) $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
165 165
 			$defaultInternalExpireDateEnforced = $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
166 166
 		}
167 167
 
168 168
 		$defaultRemoteExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no') === 'yes';
169 169
 		$defaultRemoteExpireDate = $defaultRemoteExpireDateEnforced = null;
170 170
 		if ($defaultRemoteExpireDateEnabled) {
171
-			$defaultRemoteExpireDate = (int)$this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
171
+			$defaultRemoteExpireDate = (int) $this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
172 172
 			$defaultRemoteExpireDateEnforced = $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes';
173 173
 		}
174 174
 
175 175
 		$countOfDataLocation = 0;
176
-		$dataLocation = str_replace(\OC::$SERVERROOT . '/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation);
176
+		$dataLocation = str_replace(\OC::$SERVERROOT.'/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation);
177 177
 		if ($countOfDataLocation !== 1 || $uid === null || !$this->groupManager->isAdmin($uid)) {
178 178
 			$dataLocation = false;
179 179
 		}
@@ -207,8 +207,8 @@  discard block
 block discarded – undo
207 207
 			"_oc_debug" => $this->config->getSystemValue('debug', false) ? 'true' : 'false',
208 208
 			"_oc_isadmin" => $uid !== null && $this->groupManager->isAdmin($uid) ? 'true' : 'false',
209 209
 			"backendAllowsPasswordConfirmation" => $userBackendAllowsPasswordConfirmation ? 'true' : 'false',
210
-			"oc_dataURL" => is_string($dataLocation) ? "\"" . $dataLocation . "\"" : 'false',
211
-			"_oc_webroot" => "\"" . \OC::$WEBROOT . "\"",
210
+			"oc_dataURL" => is_string($dataLocation) ? "\"".$dataLocation."\"" : 'false',
211
+			"_oc_webroot" => "\"".\OC::$WEBROOT."\"",
212 212
 			"_oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution
213 213
 			"datepickerFormatDate" => json_encode($this->l->l('jsdate', null)),
214 214
 			'nc_lastLogin' => $lastConfirmTimestamp,
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
 		if ($this->currentUser !== null) {
310 310
 			$array['oc_userconfig'] = json_encode([
311 311
 				'avatar' => [
312
-					'version' => (int)$this->config->getUserValue($uid, 'avatar', 'version', 0),
312
+					'version' => (int) $this->config->getUserValue($uid, 'avatar', 'version', 0),
313 313
 					'generated' => $this->config->getUserValue($uid, 'avatar', 'generated', 'true') === 'true',
314 314
 				]
315 315
 			]);
@@ -325,7 +325,7 @@  discard block
 block discarded – undo
325 325
 
326 326
 		// Echo it
327 327
 		foreach ($array as  $setting => $value) {
328
-			$result .= 'var '. $setting . '='. $value . ';' . PHP_EOL;
328
+			$result .= 'var '.$setting.'='.$value.';'.PHP_EOL;
329 329
 		}
330 330
 
331 331
 		return $result;
Please login to merge, or discard this patch.
apps/settings/templates/settings/admin/sharing.php 2 patches
Indentation   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -35,22 +35,22 @@  discard block
 block discarded – undo
35 35
 	<p id="enable">
36 36
 		<input type="checkbox" name="shareapi_enabled" id="shareAPIEnabled" class="checkbox"
37 37
 			   value="1" <?php if ($_['shareAPIEnabled'] === 'yes') {
38
-	print_unescaped('checked="checked"');
38
+    print_unescaped('checked="checked"');
39 39
 } ?> />
40 40
 		<label for="shareAPIEnabled"><?php p($l->t('Allow apps to use the Share API'));?></label><br/>
41 41
 	</p>
42 42
 
43 43
 	<p id="internalShareSettings" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
44
-	p('hidden');
44
+    p('hidden');
45 45
 } ?>">
46 46
 		<input type="checkbox" name="shareapi_default_internal_expire_date" id="shareapiDefaultInternalExpireDate" class="checkbox"
47 47
 			   value="1" <?php if ($_['shareDefaultInternalExpireDateSet'] === 'yes') {
48
-	print_unescaped('checked="checked"');
48
+    print_unescaped('checked="checked"');
49 49
 } ?> />
50 50
 		<label for="shareapiDefaultInternalExpireDate"><?php p($l->t('Set default expiration date for shares'));?></label><br/>
51 51
 	</p>
52 52
 	<p id="setDefaultInternalExpireDate" class="double-indent <?php if ($_['shareDefaultInternalExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
53
-	p('hidden');
53
+    p('hidden');
54 54
 }?>">
55 55
 		<?php p($l->t('Expire after ')); ?>
56 56
 		<input type="text" name='shareapi_internal_expire_after_n_days' id="shareapiInternalExpireAfterNDays" placeholder="<?php p('7')?>"
@@ -58,22 +58,22 @@  discard block
 block discarded – undo
58 58
 		<?php p($l->t('days')); ?>
59 59
 		<input type="checkbox" name="shareapi_enforce_internal_expire_date" id="shareapiInternalEnforceExpireDate" class="checkbox"
60 60
 			   value="1" <?php if ($_['shareInternalEnforceExpireDate'] === 'yes') {
61
-	print_unescaped('checked="checked"');
61
+    print_unescaped('checked="checked"');
62 62
 } ?> />
63 63
 		<label for="shareapiInternalEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
64 64
 	</p>
65 65
 
66 66
 	<p id="remoteShareSettings" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
67
-	p('hidden');
67
+    p('hidden');
68 68
 } ?>">
69 69
 		<input type="checkbox" name="shareapi_default_remote_expire_date" id="shareapiDefaultRemoteExpireDate" class="checkbox"
70 70
 			   value="1" <?php if ($_['shareDefaultRemoteExpireDateSet'] === 'yes') {
71
-	print_unescaped('checked="checked"');
71
+    print_unescaped('checked="checked"');
72 72
 } ?> />
73 73
 		<label for="shareapiDefaultRemoteExpireDate"><?php p($l->t('Set default expiration date for shares to other servers'));?></label><br/>
74 74
 	</p>
75 75
 	<p id="setDefaultRemoteExpireDate" class="double-indent <?php if ($_['shareDefaultRemoteExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
76
-	p('hidden');
76
+    p('hidden');
77 77
 }?>">
78 78
 		<?php p($l->t('Expire after ')); ?>
79 79
 		<input type="text" name='shareapi_remote_expire_after_n_days' id="shareapiRemoteExpireAfterNDays" placeholder="<?php p('7')?>"
@@ -81,49 +81,49 @@  discard block
 block discarded – undo
81 81
 		<?php p($l->t('days')); ?>
82 82
 		<input type="checkbox" name="shareapi_enforce_remote_expire_date" id="shareapiRemoteEnforceExpireDate" class="checkbox"
83 83
 			   value="1" <?php if ($_['shareRemoteEnforceExpireDate'] === 'yes') {
84
-	print_unescaped('checked="checked"');
84
+    print_unescaped('checked="checked"');
85 85
 } ?> />
86 86
 		<label for="shareapiRemoteEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
87 87
 	</p>
88 88
 
89 89
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
90
-	p('hidden');
90
+    p('hidden');
91 91
 }?>">
92 92
 		<input type="checkbox" name="shareapi_allow_links" id="allowLinks" class="checkbox"
93 93
 			   value="1" <?php if ($_['allowLinks'] === 'yes') {
94
-	print_unescaped('checked="checked"');
94
+    print_unescaped('checked="checked"');
95 95
 } ?> />
96 96
 		<label for="allowLinks"><?php p($l->t('Allow users to share via link and emails'));?></label><br/>
97 97
 	</p>
98 98
 
99 99
 	<p id="publicLinkSettings" class="indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareAPIEnabled'] === 'no') {
100
-	p('hidden');
100
+    p('hidden');
101 101
 } ?>">
102 102
 		<input type="checkbox" name="shareapi_allow_public_upload" id="allowPublicUpload" class="checkbox"
103 103
 			   value="1" <?php if ($_['allowPublicUpload'] == 'yes') {
104
-	print_unescaped('checked="checked"');
104
+    print_unescaped('checked="checked"');
105 105
 } ?> />
106 106
 		<label for="allowPublicUpload"><?php p($l->t('Allow public uploads'));?></label><br/>
107 107
 		<input type="checkbox" name="shareapi_enable_link_password_by_default" id="enableLinkPasswordByDefault" class="checkbox"
108 108
 			   value="1" <?php if ($_['enableLinkPasswordByDefault'] === 'yes') {
109
-	print_unescaped('checked="checked"');
109
+    print_unescaped('checked="checked"');
110 110
 } ?> />
111 111
 		<label for="enableLinkPasswordByDefault"><?php p($l->t('Always ask for a password'));?></label><br/>
112 112
 		<input type="checkbox" name="shareapi_enforce_links_password" id="enforceLinkPassword" class="checkbox"
113 113
 			   value="1" <?php if ($_['enforceLinkPassword']) {
114
-	print_unescaped('checked="checked"');
114
+    print_unescaped('checked="checked"');
115 115
 } ?> />
116 116
 		<label for="enforceLinkPassword"><?php p($l->t('Enforce password protection'));?></label><br/>
117 117
 
118 118
 		<input type="checkbox" name="shareapi_default_expire_date" id="shareapiDefaultExpireDate" class="checkbox"
119 119
 			   value="1" <?php if ($_['shareDefaultExpireDateSet'] === 'yes') {
120
-	print_unescaped('checked="checked"');
120
+    print_unescaped('checked="checked"');
121 121
 } ?> />
122 122
 		<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date'));?></label><br/>
123 123
 
124 124
 	</p>
125 125
 	<p id="setDefaultExpireDate" class="double-indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareDefaultExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
126
-	p('hidden');
126
+    p('hidden');
127 127
 }?>">
128 128
 		<?php p($l->t('Expire after ')); ?>
129 129
 		<input type="text" name='shareapi_expire_after_n_days' id="shareapiExpireAfterNDays" placeholder="<?php p('7')?>"
@@ -131,48 +131,48 @@  discard block
 block discarded – undo
131 131
 		<?php p($l->t('days')); ?>
132 132
 		<input type="checkbox" name="shareapi_enforce_expire_date" id="shareapiEnforceExpireDate" class="checkbox"
133 133
 			   value="1" <?php if ($_['shareEnforceExpireDate'] === 'yes') {
134
-	print_unescaped('checked="checked"');
134
+    print_unescaped('checked="checked"');
135 135
 } ?> />
136 136
 		<label for="shareapiEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
137 137
 	</p>
138 138
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
139
-	p('hidden');
139
+    p('hidden');
140 140
 }?>">
141 141
 		<input type="checkbox" name="shareapi_allow_resharing" id="allowResharing" class="checkbox"
142 142
 			   value="1" <?php if ($_['allowResharing'] === 'yes') {
143
-	print_unescaped('checked="checked"');
143
+    print_unescaped('checked="checked"');
144 144
 } ?> />
145 145
 		<label for="allowResharing"><?php p($l->t('Allow resharing'));?></label><br/>
146 146
 	</p>
147 147
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
148
-	p('hidden');
148
+    p('hidden');
149 149
 }?>">
150 150
 		<input type="checkbox" name="shareapi_allow_group_sharing" id="allowGroupSharing" class="checkbox"
151 151
 			   value="1" <?php if ($_['allowGroupSharing'] === 'yes') {
152
-	print_unescaped('checked="checked"');
152
+    print_unescaped('checked="checked"');
153 153
 } ?> />
154 154
 		<label for="allowGroupSharing"><?php p($l->t('Allow sharing with groups'));?></label><br />
155 155
 	</p>
156 156
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
157
-	p('hidden');
157
+    p('hidden');
158 158
 }?>">
159 159
 		<input type="checkbox" name="shareapi_only_share_with_group_members" id="onlyShareWithGroupMembers" class="checkbox"
160 160
 			   value="1" <?php if ($_['onlyShareWithGroupMembers']) {
161
-	print_unescaped('checked="checked"');
161
+    print_unescaped('checked="checked"');
162 162
 } ?> />
163 163
 		<label for="onlyShareWithGroupMembers"><?php p($l->t('Restrict users to only share with users in their groups'));?></label><br/>
164 164
 	</p>
165 165
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
166
-	p('hidden');
166
+    p('hidden');
167 167
 }?>">
168 168
 		<input type="checkbox" name="shareapi_exclude_groups" id="shareapiExcludeGroups" class="checkbox"
169 169
 			   value="1" <?php if ($_['shareExcludeGroups']) {
170
-	print_unescaped('checked="checked"');
170
+    print_unescaped('checked="checked"');
171 171
 } ?> />
172 172
 		<label for="shareapiExcludeGroups"><?php p($l->t('Exclude groups from sharing'));?></label><br/>
173 173
 	</p>
174 174
 	<p id="selectExcludedGroups" class="indent <?php if (!$_['shareExcludeGroups'] || $_['shareAPIEnabled'] === 'no') {
175
-	p('hidden');
175
+    p('hidden');
176 176
 } ?>">
177 177
 		<input name="shareapi_exclude_groups_list" type="hidden" id="excludedGroups" value="<?php p($_['shareExcludedGroupsList']) ?>" style="width: 400px" class="noJSAutoUpdate"/>
178 178
 		<br />
@@ -180,45 +180,45 @@  discard block
 block discarded – undo
180 180
 	</p>
181 181
 
182 182
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
183
-	p('hidden');
183
+    p('hidden');
184 184
 }?>">
185 185
 		<input type="checkbox" name="shareapi_allow_share_dialog_user_enumeration" value="1" id="shareapi_allow_share_dialog_user_enumeration" class="checkbox"
186 186
 			<?php if ($_['allowShareDialogUserEnumeration'] === 'yes') {
187
-	print_unescaped('checked="checked"');
187
+    print_unescaped('checked="checked"');
188 188
 } ?> />
189 189
 		<label for="shareapi_allow_share_dialog_user_enumeration"><?php p($l->t('Allow username autocompletion in share dialog'));?></label><br />
190 190
 	</p>
191 191
 
192 192
 	<p id="shareapi_restrict_user_enumeration_to_group_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
193
-	p('hidden');
193
+    p('hidden');
194 194
 }?>">
195 195
 		<input type="checkbox" name="shareapi_restrict_user_enumeration_to_group" value="1" id="shareapi_restrict_user_enumeration_to_group" class="checkbox"
196 196
 			<?php if ($_['restrictUserEnumerationToGroup'] === 'yes') {
197
-	print_unescaped('checked="checked"');
197
+    print_unescaped('checked="checked"');
198 198
 } ?> />
199 199
 		<label for="shareapi_restrict_user_enumeration_to_group"><?php p($l->t('Allow username autocompletion to users within the same groups'));?></label><br />
200 200
 	</p>
201 201
 
202 202
 	<p id="shareapi_restrict_user_enumeration_to_phone_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
203
-	p('hidden');
203
+    p('hidden');
204 204
 }?>">
205 205
 		<input type="checkbox" name="shareapi_restrict_user_enumeration_to_phone" value="1" id="shareapi_restrict_user_enumeration_to_phone" class="checkbox"
206 206
 			<?php if ($_['restrictUserEnumerationToPhone'] === 'yes') {
207
-	print_unescaped('checked="checked"');
207
+    print_unescaped('checked="checked"');
208 208
 } ?> />
209 209
 		<label for="shareapi_restrict_user_enumeration_to_phone"><?php p($l->t('Allow username autocompletion to users based on phone number integration'));?></label><br />
210 210
 	</p>
211 211
 	<p id="shareapi_restrict_user_enumeration_combinewarning_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
212
-	p('hidden');
212
+    p('hidden');
213 213
 }?>">
214 214
 		<em><?php p($l->t('If autocompletion "same group" and "phone number integration" are enabled a match in either is enough to show the user.'));?></em><br />
215 215
 	</p>
216 216
 	<p id="shareapi_restrict_user_enumeration_full_match_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
217
-	p('hidden');
217
+    p('hidden');
218 218
 }?>">
219 219
 		<input type="checkbox" name="shareapi_restrict_user_enumeration_full_match" value="1" id="shareapi_restrict_user_enumeration_full_match" class="checkbox"
220 220
 				<?php if ($_['restrictUserEnumerationFullMatch'] === 'yes') {
221
-	print_unescaped('checked="checked"');
221
+    print_unescaped('checked="checked"');
222 222
 } ?> />
223 223
 		<label for="shareapi_restrict_user_enumeration_full_match"><?php p($l->t('Allow username autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)'));?></label><br />
224 224
 	</p>
@@ -226,13 +226,13 @@  discard block
 block discarded – undo
226 226
 	<p>
227 227
 		<input type="checkbox" id="publicShareDisclaimer" class="checkbox noJSAutoUpdate"
228 228
 			<?php if ($_['publicShareDisclaimerText'] !== null) {
229
-	print_unescaped('checked="checked"');
229
+    print_unescaped('checked="checked"');
230 230
 } ?> />
231 231
 		<label for="publicShareDisclaimer"><?php p($l->t('Show disclaimer text on the public link upload page (only shown when the file list is hidden)'));?></label>
232 232
 		<span id="publicShareDisclaimerStatus" class="msg" style="display:none"></span>
233 233
 		<br/>
234 234
 		<textarea placeholder="<?php p($l->t('This text will be shown on the public link upload page when the file list is hidden.')) ?>" id="publicShareDisclaimerText" <?php if ($_['publicShareDisclaimerText'] === null) {
235
-	print_unescaped('class="hidden"');
235
+    print_unescaped('class="hidden"');
236 236
 } ?>><?php p($_['publicShareDisclaimerText']) ?></textarea>
237 237
 	</p>
238 238
 
@@ -240,12 +240,12 @@  discard block
 block discarded – undo
240 240
 	<input type="hidden" name="shareapi_default_permissions" id="shareApiDefaultPermissions" class="checkbox"
241 241
 		   value="<?php p($_['shareApiDefaultPermissions']) ?>" />
242 242
 	<p id="shareApiDefaultPermissionsSection" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
243
-	p('hidden');
243
+    p('hidden');
244 244
 } ?>">
245 245
 		<?php foreach ($_['shareApiDefaultPermissionsCheckboxes'] as $perm): ?>
246 246
 			<input type="checkbox" name="shareapi_default_permission_<?php p($perm['id']) ?>" id="shareapi_default_permission_<?php p($perm['id']) ?>"
247 247
 				   class="noautosave checkbox" value="<?php p($perm['value']) ?>" <?php if (($_['shareApiDefaultPermissions'] & $perm['value']) !== 0) {
248
-	print_unescaped('checked="checked"');
248
+    print_unescaped('checked="checked"');
249 249
 } ?> />
250 250
 			<label for="shareapi_default_permission_<?php p($perm['id']) ?>"><?php p($perm['label']);?></label>
251 251
 		<?php endforeach ?>
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -27,17 +27,17 @@  discard block
 block discarded – undo
27 27
 ?>
28 28
 
29 29
 <div class="section" id="shareAPI">
30
-	<h2><?php p($l->t('Sharing'));?></h2>
30
+	<h2><?php p($l->t('Sharing')); ?></h2>
31 31
 	<a target="_blank" rel="noreferrer noopener" class="icon-info"
32
-	   title="<?php p($l->t('Open documentation'));?>"
32
+	   title="<?php p($l->t('Open documentation')); ?>"
33 33
 	   href="<?php p(link_to_docs('admin-sharing')); ?>"></a>
34
-        <p class="settings-hint"><?php p($l->t('As admin you can fine-tune the sharing behavior. Please see the documentation for more information.'));?></p>
34
+        <p class="settings-hint"><?php p($l->t('As admin you can fine-tune the sharing behavior. Please see the documentation for more information.')); ?></p>
35 35
 	<p id="enable">
36 36
 		<input type="checkbox" name="shareapi_enabled" id="shareAPIEnabled" class="checkbox"
37 37
 			   value="1" <?php if ($_['shareAPIEnabled'] === 'yes') {
38 38
 	print_unescaped('checked="checked"');
39 39
 } ?> />
40
-		<label for="shareAPIEnabled"><?php p($l->t('Allow apps to use the Share API'));?></label><br/>
40
+		<label for="shareAPIEnabled"><?php p($l->t('Allow apps to use the Share API')); ?></label><br/>
41 41
 	</p>
42 42
 
43 43
 	<p id="internalShareSettings" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
@@ -47,7 +47,7 @@  discard block
 block discarded – undo
47 47
 			   value="1" <?php if ($_['shareDefaultInternalExpireDateSet'] === 'yes') {
48 48
 	print_unescaped('checked="checked"');
49 49
 } ?> />
50
-		<label for="shareapiDefaultInternalExpireDate"><?php p($l->t('Set default expiration date for shares'));?></label><br/>
50
+		<label for="shareapiDefaultInternalExpireDate"><?php p($l->t('Set default expiration date for shares')); ?></label><br/>
51 51
 	</p>
52 52
 	<p id="setDefaultInternalExpireDate" class="double-indent <?php if ($_['shareDefaultInternalExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
53 53
 	p('hidden');
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
 			   value="1" <?php if ($_['shareInternalEnforceExpireDate'] === 'yes') {
61 61
 	print_unescaped('checked="checked"');
62 62
 } ?> />
63
-		<label for="shareapiInternalEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
63
+		<label for="shareapiInternalEnforceExpireDate"><?php p($l->t('Enforce expiration date')); ?></label><br/>
64 64
 	</p>
65 65
 
66 66
 	<p id="remoteShareSettings" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
@@ -70,7 +70,7 @@  discard block
 block discarded – undo
70 70
 			   value="1" <?php if ($_['shareDefaultRemoteExpireDateSet'] === 'yes') {
71 71
 	print_unescaped('checked="checked"');
72 72
 } ?> />
73
-		<label for="shareapiDefaultRemoteExpireDate"><?php p($l->t('Set default expiration date for shares to other servers'));?></label><br/>
73
+		<label for="shareapiDefaultRemoteExpireDate"><?php p($l->t('Set default expiration date for shares to other servers')); ?></label><br/>
74 74
 	</p>
75 75
 	<p id="setDefaultRemoteExpireDate" class="double-indent <?php if ($_['shareDefaultRemoteExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
76 76
 	p('hidden');
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
 			   value="1" <?php if ($_['shareRemoteEnforceExpireDate'] === 'yes') {
84 84
 	print_unescaped('checked="checked"');
85 85
 } ?> />
86
-		<label for="shareapiRemoteEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
86
+		<label for="shareapiRemoteEnforceExpireDate"><?php p($l->t('Enforce expiration date')); ?></label><br/>
87 87
 	</p>
88 88
 
89 89
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
 			   value="1" <?php if ($_['allowLinks'] === 'yes') {
94 94
 	print_unescaped('checked="checked"');
95 95
 } ?> />
96
-		<label for="allowLinks"><?php p($l->t('Allow users to share via link and emails'));?></label><br/>
96
+		<label for="allowLinks"><?php p($l->t('Allow users to share via link and emails')); ?></label><br/>
97 97
 	</p>
98 98
 
99 99
 	<p id="publicLinkSettings" class="indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareAPIEnabled'] === 'no') {
@@ -103,23 +103,23 @@  discard block
 block discarded – undo
103 103
 			   value="1" <?php if ($_['allowPublicUpload'] == 'yes') {
104 104
 	print_unescaped('checked="checked"');
105 105
 } ?> />
106
-		<label for="allowPublicUpload"><?php p($l->t('Allow public uploads'));?></label><br/>
106
+		<label for="allowPublicUpload"><?php p($l->t('Allow public uploads')); ?></label><br/>
107 107
 		<input type="checkbox" name="shareapi_enable_link_password_by_default" id="enableLinkPasswordByDefault" class="checkbox"
108 108
 			   value="1" <?php if ($_['enableLinkPasswordByDefault'] === 'yes') {
109 109
 	print_unescaped('checked="checked"');
110 110
 } ?> />
111
-		<label for="enableLinkPasswordByDefault"><?php p($l->t('Always ask for a password'));?></label><br/>
111
+		<label for="enableLinkPasswordByDefault"><?php p($l->t('Always ask for a password')); ?></label><br/>
112 112
 		<input type="checkbox" name="shareapi_enforce_links_password" id="enforceLinkPassword" class="checkbox"
113 113
 			   value="1" <?php if ($_['enforceLinkPassword']) {
114 114
 	print_unescaped('checked="checked"');
115 115
 } ?> />
116
-		<label for="enforceLinkPassword"><?php p($l->t('Enforce password protection'));?></label><br/>
116
+		<label for="enforceLinkPassword"><?php p($l->t('Enforce password protection')); ?></label><br/>
117 117
 
118 118
 		<input type="checkbox" name="shareapi_default_expire_date" id="shareapiDefaultExpireDate" class="checkbox"
119 119
 			   value="1" <?php if ($_['shareDefaultExpireDateSet'] === 'yes') {
120 120
 	print_unescaped('checked="checked"');
121 121
 } ?> />
122
-		<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date'));?></label><br/>
122
+		<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date')); ?></label><br/>
123 123
 
124 124
 	</p>
125 125
 	<p id="setDefaultExpireDate" class="double-indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareDefaultExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
@@ -133,7 +133,7 @@  discard block
 block discarded – undo
133 133
 			   value="1" <?php if ($_['shareEnforceExpireDate'] === 'yes') {
134 134
 	print_unescaped('checked="checked"');
135 135
 } ?> />
136
-		<label for="shareapiEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
136
+		<label for="shareapiEnforceExpireDate"><?php p($l->t('Enforce expiration date')); ?></label><br/>
137 137
 	</p>
138 138
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
139 139
 	p('hidden');
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
 			   value="1" <?php if ($_['allowResharing'] === 'yes') {
143 143
 	print_unescaped('checked="checked"');
144 144
 } ?> />
145
-		<label for="allowResharing"><?php p($l->t('Allow resharing'));?></label><br/>
145
+		<label for="allowResharing"><?php p($l->t('Allow resharing')); ?></label><br/>
146 146
 	</p>
147 147
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
148 148
 	p('hidden');
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
 			   value="1" <?php if ($_['allowGroupSharing'] === 'yes') {
152 152
 	print_unescaped('checked="checked"');
153 153
 } ?> />
154
-		<label for="allowGroupSharing"><?php p($l->t('Allow sharing with groups'));?></label><br />
154
+		<label for="allowGroupSharing"><?php p($l->t('Allow sharing with groups')); ?></label><br />
155 155
 	</p>
156 156
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
157 157
 	p('hidden');
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 			   value="1" <?php if ($_['onlyShareWithGroupMembers']) {
161 161
 	print_unescaped('checked="checked"');
162 162
 } ?> />
163
-		<label for="onlyShareWithGroupMembers"><?php p($l->t('Restrict users to only share with users in their groups'));?></label><br/>
163
+		<label for="onlyShareWithGroupMembers"><?php p($l->t('Restrict users to only share with users in their groups')); ?></label><br/>
164 164
 	</p>
165 165
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
166 166
 	p('hidden');
@@ -169,7 +169,7 @@  discard block
 block discarded – undo
169 169
 			   value="1" <?php if ($_['shareExcludeGroups']) {
170 170
 	print_unescaped('checked="checked"');
171 171
 } ?> />
172
-		<label for="shareapiExcludeGroups"><?php p($l->t('Exclude groups from sharing'));?></label><br/>
172
+		<label for="shareapiExcludeGroups"><?php p($l->t('Exclude groups from sharing')); ?></label><br/>
173 173
 	</p>
174 174
 	<p id="selectExcludedGroups" class="indent <?php if (!$_['shareExcludeGroups'] || $_['shareAPIEnabled'] === 'no') {
175 175
 	p('hidden');
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
 			<?php if ($_['allowShareDialogUserEnumeration'] === 'yes') {
187 187
 	print_unescaped('checked="checked"');
188 188
 } ?> />
189
-		<label for="shareapi_allow_share_dialog_user_enumeration"><?php p($l->t('Allow username autocompletion in share dialog'));?></label><br />
189
+		<label for="shareapi_allow_share_dialog_user_enumeration"><?php p($l->t('Allow username autocompletion in share dialog')); ?></label><br />
190 190
 	</p>
191 191
 
192 192
 	<p id="shareapi_restrict_user_enumeration_to_group_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
 			<?php if ($_['restrictUserEnumerationToGroup'] === 'yes') {
197 197
 	print_unescaped('checked="checked"');
198 198
 } ?> />
199
-		<label for="shareapi_restrict_user_enumeration_to_group"><?php p($l->t('Allow username autocompletion to users within the same groups'));?></label><br />
199
+		<label for="shareapi_restrict_user_enumeration_to_group"><?php p($l->t('Allow username autocompletion to users within the same groups')); ?></label><br />
200 200
 	</p>
201 201
 
202 202
 	<p id="shareapi_restrict_user_enumeration_to_phone_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
@@ -206,12 +206,12 @@  discard block
 block discarded – undo
206 206
 			<?php if ($_['restrictUserEnumerationToPhone'] === 'yes') {
207 207
 	print_unescaped('checked="checked"');
208 208
 } ?> />
209
-		<label for="shareapi_restrict_user_enumeration_to_phone"><?php p($l->t('Allow username autocompletion to users based on phone number integration'));?></label><br />
209
+		<label for="shareapi_restrict_user_enumeration_to_phone"><?php p($l->t('Allow username autocompletion to users based on phone number integration')); ?></label><br />
210 210
 	</p>
211 211
 	<p id="shareapi_restrict_user_enumeration_combinewarning_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
212 212
 	p('hidden');
213 213
 }?>">
214
-		<em><?php p($l->t('If autocompletion "same group" and "phone number integration" are enabled a match in either is enough to show the user.'));?></em><br />
214
+		<em><?php p($l->t('If autocompletion "same group" and "phone number integration" are enabled a match in either is enough to show the user.')); ?></em><br />
215 215
 	</p>
216 216
 	<p id="shareapi_restrict_user_enumeration_full_match_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
217 217
 	p('hidden');
@@ -220,7 +220,7 @@  discard block
 block discarded – undo
220 220
 				<?php if ($_['restrictUserEnumerationFullMatch'] === 'yes') {
221 221
 	print_unescaped('checked="checked"');
222 222
 } ?> />
223
-		<label for="shareapi_restrict_user_enumeration_full_match"><?php p($l->t('Allow username autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)'));?></label><br />
223
+		<label for="shareapi_restrict_user_enumeration_full_match"><?php p($l->t('Allow username autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)')); ?></label><br />
224 224
 	</p>
225 225
 
226 226
 	<p>
@@ -228,7 +228,7 @@  discard block
 block discarded – undo
228 228
 			<?php if ($_['publicShareDisclaimerText'] !== null) {
229 229
 	print_unescaped('checked="checked"');
230 230
 } ?> />
231
-		<label for="publicShareDisclaimer"><?php p($l->t('Show disclaimer text on the public link upload page (only shown when the file list is hidden)'));?></label>
231
+		<label for="publicShareDisclaimer"><?php p($l->t('Show disclaimer text on the public link upload page (only shown when the file list is hidden)')); ?></label>
232 232
 		<span id="publicShareDisclaimerStatus" class="msg" style="display:none"></span>
233 233
 		<br/>
234 234
 		<textarea placeholder="<?php p($l->t('This text will be shown on the public link upload page when the file list is hidden.')) ?>" id="publicShareDisclaimerText" <?php if ($_['publicShareDisclaimerText'] === null) {
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
 } ?>><?php p($_['publicShareDisclaimerText']) ?></textarea>
237 237
 	</p>
238 238
 
239
-	<h3><?php p($l->t('Default share permissions'));?></h3>
239
+	<h3><?php p($l->t('Default share permissions')); ?></h3>
240 240
 	<input type="hidden" name="shareapi_default_permissions" id="shareApiDefaultPermissions" class="checkbox"
241 241
 		   value="<?php p($_['shareApiDefaultPermissions']) ?>" />
242 242
 	<p id="shareApiDefaultPermissionsSection" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
@@ -247,7 +247,7 @@  discard block
 block discarded – undo
247 247
 				   class="noautosave checkbox" value="<?php p($perm['value']) ?>" <?php if (($_['shareApiDefaultPermissions'] & $perm['value']) !== 0) {
248 248
 	print_unescaped('checked="checked"');
249 249
 } ?> />
250
-			<label for="shareapi_default_permission_<?php p($perm['id']) ?>"><?php p($perm['label']);?></label>
250
+			<label for="shareapi_default_permission_<?php p($perm['id']) ?>"><?php p($perm['label']); ?></label>
251 251
 		<?php endforeach ?>
252 252
 	</p>
253 253
 </div>
Please login to merge, or discard this patch.
apps/settings/lib/Settings/Admin/Sharing.php 1 patch
Indentation   +97 added lines, -97 removed lines patch added patch discarded remove patch
@@ -39,110 +39,110 @@
 block discarded – undo
39 39
 use OCP\Util;
40 40
 
41 41
 class Sharing implements ISettings {
42
-	/** @var IConfig */
43
-	private $config;
42
+    /** @var IConfig */
43
+    private $config;
44 44
 
45
-	/** @var IL10N */
46
-	private $l;
45
+    /** @var IL10N */
46
+    private $l;
47 47
 
48
-	/** @var IManager */
49
-	private $shareManager;
48
+    /** @var IManager */
49
+    private $shareManager;
50 50
 
51
-	/**
52
-	 * @param IConfig $config
53
-	 */
54
-	public function __construct(IConfig $config, IL10N $l, IManager $shareManager) {
55
-		$this->config = $config;
56
-		$this->l = $l;
57
-		$this->shareManager = $shareManager;
58
-	}
51
+    /**
52
+     * @param IConfig $config
53
+     */
54
+    public function __construct(IConfig $config, IL10N $l, IManager $shareManager) {
55
+        $this->config = $config;
56
+        $this->l = $l;
57
+        $this->shareManager = $shareManager;
58
+    }
59 59
 
60
-	/**
61
-	 * @return TemplateResponse
62
-	 */
63
-	public function getForm() {
64
-		$excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
65
-		$excludeGroupsList = !is_null(json_decode($excludedGroups))
66
-			? implode('|', json_decode($excludedGroups, true)) : '';
60
+    /**
61
+     * @return TemplateResponse
62
+     */
63
+    public function getForm() {
64
+        $excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
65
+        $excludeGroupsList = !is_null(json_decode($excludedGroups))
66
+            ? implode('|', json_decode($excludedGroups, true)) : '';
67 67
 
68
-		$parameters = [
69
-			// Built-In Sharing
70
-			'allowGroupSharing' => $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes'),
71
-			'allowLinks' => $this->config->getAppValue('core', 'shareapi_allow_links', 'yes'),
72
-			'allowPublicUpload' => $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes'),
73
-			'allowResharing' => $this->config->getAppValue('core', 'shareapi_allow_resharing', 'yes'),
74
-			'allowShareDialogUserEnumeration' => $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes'),
75
-			'restrictUserEnumerationToGroup' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no'),
76
-			'restrictUserEnumerationToPhone' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no'),
77
-			'restrictUserEnumerationFullMatch' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes'),
78
-			'enforceLinkPassword' => Util::isPublicLinkPasswordRequired(),
79
-			'onlyShareWithGroupMembers' => $this->shareManager->shareWithGroupMembersOnly(),
80
-			'shareAPIEnabled' => $this->config->getAppValue('core', 'shareapi_enabled', 'yes'),
81
-			'shareDefaultExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no'),
82
-			'shareExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7'),
83
-			'shareEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no'),
84
-			'shareExcludeGroups' => $this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes',
85
-			'shareExcludedGroupsList' => $excludeGroupsList,
86
-			'publicShareDisclaimerText' => $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null),
87
-			'enableLinkPasswordByDefault' => $this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no'),
88
-			'shareApiDefaultPermissions' => $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL),
89
-			'shareApiDefaultPermissionsCheckboxes' => $this->getSharePermissionList(),
90
-			'shareDefaultInternalExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no'),
91
-			'shareInternalExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7'),
92
-			'shareInternalEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no'),
93
-			'shareDefaultRemoteExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no'),
94
-			'shareRemoteExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7'),
95
-			'shareRemoteEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no'),
96
-		];
68
+        $parameters = [
69
+            // Built-In Sharing
70
+            'allowGroupSharing' => $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes'),
71
+            'allowLinks' => $this->config->getAppValue('core', 'shareapi_allow_links', 'yes'),
72
+            'allowPublicUpload' => $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes'),
73
+            'allowResharing' => $this->config->getAppValue('core', 'shareapi_allow_resharing', 'yes'),
74
+            'allowShareDialogUserEnumeration' => $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes'),
75
+            'restrictUserEnumerationToGroup' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no'),
76
+            'restrictUserEnumerationToPhone' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no'),
77
+            'restrictUserEnumerationFullMatch' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes'),
78
+            'enforceLinkPassword' => Util::isPublicLinkPasswordRequired(),
79
+            'onlyShareWithGroupMembers' => $this->shareManager->shareWithGroupMembersOnly(),
80
+            'shareAPIEnabled' => $this->config->getAppValue('core', 'shareapi_enabled', 'yes'),
81
+            'shareDefaultExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no'),
82
+            'shareExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7'),
83
+            'shareEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no'),
84
+            'shareExcludeGroups' => $this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes',
85
+            'shareExcludedGroupsList' => $excludeGroupsList,
86
+            'publicShareDisclaimerText' => $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null),
87
+            'enableLinkPasswordByDefault' => $this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no'),
88
+            'shareApiDefaultPermissions' => $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL),
89
+            'shareApiDefaultPermissionsCheckboxes' => $this->getSharePermissionList(),
90
+            'shareDefaultInternalExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no'),
91
+            'shareInternalExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7'),
92
+            'shareInternalEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no'),
93
+            'shareDefaultRemoteExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no'),
94
+            'shareRemoteExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7'),
95
+            'shareRemoteEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no'),
96
+        ];
97 97
 
98
-		return new TemplateResponse('settings', 'settings/admin/sharing', $parameters, '');
99
-	}
98
+        return new TemplateResponse('settings', 'settings/admin/sharing', $parameters, '');
99
+    }
100 100
 
101
-	/**
102
-	 * get share permission list for template
103
-	 *
104
-	 * @return array
105
-	 */
106
-	private function getSharePermissionList() {
107
-		return [
108
-			[
109
-				'id' => 'cancreate',
110
-				'label' => $this->l->t('Create'),
111
-				'value' => Constants::PERMISSION_CREATE
112
-			],
113
-			[
114
-				'id' => 'canupdate',
115
-				'label' => $this->l->t('Change'),
116
-				'value' => Constants::PERMISSION_UPDATE
117
-			],
118
-			[
119
-				'id' => 'candelete',
120
-				'label' => $this->l->t('Delete'),
121
-				'value' => Constants::PERMISSION_DELETE
122
-			],
123
-			[
124
-				'id' => 'canshare',
125
-				'label' => $this->l->t('Reshare'),
126
-				'value' => Constants::PERMISSION_SHARE
127
-			],
128
-		];
129
-	}
101
+    /**
102
+     * get share permission list for template
103
+     *
104
+     * @return array
105
+     */
106
+    private function getSharePermissionList() {
107
+        return [
108
+            [
109
+                'id' => 'cancreate',
110
+                'label' => $this->l->t('Create'),
111
+                'value' => Constants::PERMISSION_CREATE
112
+            ],
113
+            [
114
+                'id' => 'canupdate',
115
+                'label' => $this->l->t('Change'),
116
+                'value' => Constants::PERMISSION_UPDATE
117
+            ],
118
+            [
119
+                'id' => 'candelete',
120
+                'label' => $this->l->t('Delete'),
121
+                'value' => Constants::PERMISSION_DELETE
122
+            ],
123
+            [
124
+                'id' => 'canshare',
125
+                'label' => $this->l->t('Reshare'),
126
+                'value' => Constants::PERMISSION_SHARE
127
+            ],
128
+        ];
129
+    }
130 130
 
131
-	/**
132
-	 * @return string the section ID, e.g. 'sharing'
133
-	 */
134
-	public function getSection() {
135
-		return 'sharing';
136
-	}
131
+    /**
132
+     * @return string the section ID, e.g. 'sharing'
133
+     */
134
+    public function getSection() {
135
+        return 'sharing';
136
+    }
137 137
 
138
-	/**
139
-	 * @return int whether the form should be rather on the top or bottom of
140
-	 * the admin section. The forms are arranged in ascending order of the
141
-	 * priority values. It is required to return a value between 0 and 100.
142
-	 *
143
-	 * E.g.: 70
144
-	 */
145
-	public function getPriority() {
146
-		return 0;
147
-	}
138
+    /**
139
+     * @return int whether the form should be rather on the top or bottom of
140
+     * the admin section. The forms are arranged in ascending order of the
141
+     * priority values. It is required to return a value between 0 and 100.
142
+     *
143
+     * E.g.: 70
144
+     */
145
+    public function getPriority() {
146
+        return 0;
147
+    }
148 148
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareAPIController.php 1 patch
Indentation   +1716 added lines, -1716 removed lines patch added patch discarded remove patch
@@ -84,1723 +84,1723 @@
 block discarded – undo
84 84
  */
85 85
 class ShareAPIController extends OCSController {
86 86
 
87
-	/** @var IManager */
88
-	private $shareManager;
89
-	/** @var IGroupManager */
90
-	private $groupManager;
91
-	/** @var IUserManager */
92
-	private $userManager;
93
-	/** @var IRootFolder */
94
-	private $rootFolder;
95
-	/** @var IURLGenerator */
96
-	private $urlGenerator;
97
-	/** @var string */
98
-	private $currentUser;
99
-	/** @var IL10N */
100
-	private $l;
101
-	/** @var \OCP\Files\Node */
102
-	private $lockedNode;
103
-	/** @var IConfig */
104
-	private $config;
105
-	/** @var IAppManager */
106
-	private $appManager;
107
-	/** @var IServerContainer */
108
-	private $serverContainer;
109
-	/** @var IUserStatusManager */
110
-	private $userStatusManager;
111
-	/** @var IPreview */
112
-	private $previewManager;
113
-
114
-	/**
115
-	 * Share20OCS constructor.
116
-	 *
117
-	 * @param string $appName
118
-	 * @param IRequest $request
119
-	 * @param IManager $shareManager
120
-	 * @param IGroupManager $groupManager
121
-	 * @param IUserManager $userManager
122
-	 * @param IRootFolder $rootFolder
123
-	 * @param IURLGenerator $urlGenerator
124
-	 * @param string $userId
125
-	 * @param IL10N $l10n
126
-	 * @param IConfig $config
127
-	 * @param IAppManager $appManager
128
-	 * @param IServerContainer $serverContainer
129
-	 * @param IUserStatusManager $userStatusManager
130
-	 */
131
-	public function __construct(
132
-		string $appName,
133
-		IRequest $request,
134
-		IManager $shareManager,
135
-		IGroupManager $groupManager,
136
-		IUserManager $userManager,
137
-		IRootFolder $rootFolder,
138
-		IURLGenerator $urlGenerator,
139
-		string $userId = null,
140
-		IL10N $l10n,
141
-		IConfig $config,
142
-		IAppManager $appManager,
143
-		IServerContainer $serverContainer,
144
-		IUserStatusManager $userStatusManager,
145
-		IPreview $previewManager
146
-	) {
147
-		parent::__construct($appName, $request);
148
-
149
-		$this->shareManager = $shareManager;
150
-		$this->userManager = $userManager;
151
-		$this->groupManager = $groupManager;
152
-		$this->request = $request;
153
-		$this->rootFolder = $rootFolder;
154
-		$this->urlGenerator = $urlGenerator;
155
-		$this->currentUser = $userId;
156
-		$this->l = $l10n;
157
-		$this->config = $config;
158
-		$this->appManager = $appManager;
159
-		$this->serverContainer = $serverContainer;
160
-		$this->userStatusManager = $userStatusManager;
161
-		$this->previewManager = $previewManager;
162
-	}
163
-
164
-	/**
165
-	 * Convert an IShare to an array for OCS output
166
-	 *
167
-	 * @param \OCP\Share\IShare $share
168
-	 * @param Node|null $recipientNode
169
-	 * @return array
170
-	 * @throws NotFoundException In case the node can't be resolved.
171
-	 *
172
-	 * @suppress PhanUndeclaredClassMethod
173
-	 */
174
-	protected function formatShare(IShare $share, Node $recipientNode = null): array {
175
-		$sharedBy = $this->userManager->get($share->getSharedBy());
176
-		$shareOwner = $this->userManager->get($share->getShareOwner());
177
-
178
-		$result = [
179
-			'id' => $share->getId(),
180
-			'share_type' => $share->getShareType(),
181
-			'uid_owner' => $share->getSharedBy(),
182
-			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
183
-			// recipient permissions
184
-			'permissions' => $share->getPermissions(),
185
-			// current user permissions on this share
186
-			'can_edit' => $this->canEditShare($share),
187
-			'can_delete' => $this->canDeleteShare($share),
188
-			'stime' => $share->getShareTime()->getTimestamp(),
189
-			'parent' => null,
190
-			'expiration' => null,
191
-			'token' => null,
192
-			'uid_file_owner' => $share->getShareOwner(),
193
-			'note' => $share->getNote(),
194
-			'label' => $share->getLabel(),
195
-			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
196
-		];
197
-
198
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
199
-		if ($recipientNode) {
200
-			$node = $recipientNode;
201
-		} else {
202
-			$nodes = $userFolder->getById($share->getNodeId());
203
-			if (empty($nodes)) {
204
-				// fallback to guessing the path
205
-				$node = $userFolder->get($share->getTarget());
206
-				if ($node === null || $share->getTarget() === '') {
207
-					throw new NotFoundException();
208
-				}
209
-			} else {
210
-				$node = reset($nodes);
211
-			}
212
-		}
213
-
214
-		$result['path'] = $userFolder->getRelativePath($node->getPath());
215
-		if ($node instanceof Folder) {
216
-			$result['item_type'] = 'folder';
217
-		} else {
218
-			$result['item_type'] = 'file';
219
-		}
220
-
221
-		$result['mimetype'] = $node->getMimetype();
222
-		$result['has_preview'] = $this->previewManager->isAvailable($node);
223
-		$result['storage_id'] = $node->getStorage()->getId();
224
-		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
225
-		$result['item_source'] = $node->getId();
226
-		$result['file_source'] = $node->getId();
227
-		$result['file_parent'] = $node->getParent()->getId();
228
-		$result['file_target'] = $share->getTarget();
229
-
230
-		$expiration = $share->getExpirationDate();
231
-		if ($expiration !== null) {
232
-			$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
233
-		}
234
-
235
-		if ($share->getShareType() === IShare::TYPE_USER) {
236
-			$sharedWith = $this->userManager->get($share->getSharedWith());
237
-			$result['share_with'] = $share->getSharedWith();
238
-			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
239
-			$result['share_with_displayname_unique'] = $sharedWith !== null ? (
240
-				 $sharedWith->getEMailAddress() !== '' ? $sharedWith->getEMailAddress() : $sharedWith->getUID()
241
-			) : $share->getSharedWith();
242
-			$result['status'] = [];
243
-
244
-			$userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
245
-			$userStatus = array_shift($userStatuses);
246
-			if ($userStatus) {
247
-				$result['status'] = [
248
-					'status' => $userStatus->getStatus(),
249
-					'message' => $userStatus->getMessage(),
250
-					'icon' => $userStatus->getIcon(),
251
-					'clearAt' => $userStatus->getClearAt()
252
-						? (int)$userStatus->getClearAt()->format('U')
253
-						: null,
254
-				];
255
-			}
256
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
257
-			$group = $this->groupManager->get($share->getSharedWith());
258
-			$result['share_with'] = $share->getSharedWith();
259
-			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
260
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
261
-
262
-			// "share_with" and "share_with_displayname" for passwords of link
263
-			// shares was deprecated in Nextcloud 15, use "password" instead.
264
-			$result['share_with'] = $share->getPassword();
265
-			$result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
266
-
267
-			$result['password'] = $share->getPassword();
268
-
269
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
270
-
271
-			$result['token'] = $share->getToken();
272
-			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
273
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
274
-			$result['share_with'] = $share->getSharedWith();
275
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
276
-			$result['token'] = $share->getToken();
277
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
278
-			$result['share_with'] = $share->getSharedWith();
279
-			$result['password'] = $share->getPassword();
280
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
281
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
282
-			$result['token'] = $share->getToken();
283
-		} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
284
-			// getSharedWith() returns either "name (type, owner)" or
285
-			// "name (type, owner) [id]", depending on the Circles app version.
286
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
287
-
288
-			$result['share_with_displayname'] = $share->getSharedWithDisplayName();
289
-			if (empty($result['share_with_displayname'])) {
290
-				$displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
291
-				$result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
292
-			}
293
-
294
-			$result['share_with_avatar'] = $share->getSharedWithAvatar();
295
-
296
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
297
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
298
-			if (is_bool($shareWithLength)) {
299
-				$shareWithLength = -1;
300
-			}
301
-			$result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
302
-		} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
303
-			$result['share_with'] = $share->getSharedWith();
304
-			$result['share_with_displayname'] = '';
305
-
306
-			try {
307
-				$result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
308
-			} catch (QueryException $e) {
309
-			}
310
-		} elseif ($share->getShareType() === IShare::TYPE_DECK) {
311
-			$result['share_with'] = $share->getSharedWith();
312
-			$result['share_with_displayname'] = '';
313
-
314
-			try {
315
-				$result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
316
-			} catch (QueryException $e) {
317
-			}
318
-		}
319
-
320
-
321
-		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
322
-		$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
323
-
324
-		return $result;
325
-	}
326
-
327
-	/**
328
-	 * Check if one of the users address books knows the exact property, if
329
-	 * yes we return the full name.
330
-	 *
331
-	 * @param string $query
332
-	 * @param string $property
333
-	 * @return string
334
-	 */
335
-	private function getDisplayNameFromAddressBook(string $query, string $property): string {
336
-		// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
337
-		$result = \OC::$server->getContactsManager()->search($query, [$property]);
338
-		foreach ($result as $r) {
339
-			foreach ($r[$property] as $value) {
340
-				if ($value === $query && $r['FN']) {
341
-					return $r['FN'];
342
-				}
343
-			}
344
-		}
345
-
346
-		return $query;
347
-	}
348
-
349
-	/**
350
-	 * Get a specific share by id
351
-	 *
352
-	 * @NoAdminRequired
353
-	 *
354
-	 * @param string $id
355
-	 * @return DataResponse
356
-	 * @throws OCSNotFoundException
357
-	 */
358
-	public function getShare(string $id): DataResponse {
359
-		try {
360
-			$share = $this->getShareById($id);
361
-		} catch (ShareNotFound $e) {
362
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
363
-		}
364
-
365
-		try {
366
-			if ($this->canAccessShare($share)) {
367
-				$share = $this->formatShare($share);
368
-				return new DataResponse([$share]);
369
-			}
370
-		} catch (NotFoundException $e) {
371
-			// Fall trough
372
-		}
373
-
374
-		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
375
-	}
376
-
377
-	/**
378
-	 * Delete a share
379
-	 *
380
-	 * @NoAdminRequired
381
-	 *
382
-	 * @param string $id
383
-	 * @return DataResponse
384
-	 * @throws OCSNotFoundException
385
-	 */
386
-	public function deleteShare(string $id): DataResponse {
387
-		try {
388
-			$share = $this->getShareById($id);
389
-		} catch (ShareNotFound $e) {
390
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
391
-		}
392
-
393
-		try {
394
-			$this->lock($share->getNode());
395
-		} catch (LockedException $e) {
396
-			throw new OCSNotFoundException($this->l->t('Could not delete share'));
397
-		}
398
-
399
-		if (!$this->canAccessShare($share)) {
400
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
401
-		}
402
-
403
-		// if it's a group share or a room share
404
-		// we don't delete the share, but only the
405
-		// mount point. Allowing it to be restored
406
-		// from the deleted shares
407
-		if ($this->canDeleteShareFromSelf($share)) {
408
-			$this->shareManager->deleteFromSelf($share, $this->currentUser);
409
-		} else {
410
-			if (!$this->canDeleteShare($share)) {
411
-				throw new OCSForbiddenException($this->l->t('Could not delete share'));
412
-			}
413
-
414
-			$this->shareManager->deleteShare($share);
415
-		}
416
-
417
-		return new DataResponse();
418
-	}
419
-
420
-	/**
421
-	 * @NoAdminRequired
422
-	 *
423
-	 * @param string $path
424
-	 * @param int $permissions
425
-	 * @param int $shareType
426
-	 * @param string $shareWith
427
-	 * @param string $publicUpload
428
-	 * @param string $password
429
-	 * @param string $sendPasswordByTalk
430
-	 * @param string $expireDate
431
-	 * @param string $label
432
-	 *
433
-	 * @return DataResponse
434
-	 * @throws NotFoundException
435
-	 * @throws OCSBadRequestException
436
-	 * @throws OCSException
437
-	 * @throws OCSForbiddenException
438
-	 * @throws OCSNotFoundException
439
-	 * @throws InvalidPathException
440
-	 * @suppress PhanUndeclaredClassMethod
441
-	 */
442
-	public function createShare(
443
-		string $path = null,
444
-		int $permissions = null,
445
-		int $shareType = -1,
446
-		string $shareWith = null,
447
-		string $publicUpload = 'false',
448
-		string $password = '',
449
-		string $sendPasswordByTalk = null,
450
-		string $expireDate = '',
451
-		string $label = ''
452
-	): DataResponse {
453
-		$share = $this->shareManager->newShare();
454
-
455
-		if ($permissions === null) {
456
-			$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
457
-		}
458
-
459
-		// Verify path
460
-		if ($path === null) {
461
-			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
462
-		}
463
-
464
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
465
-		try {
466
-			$path = $userFolder->get($path);
467
-		} catch (NotFoundException $e) {
468
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
469
-		}
470
-
471
-		$share->setNode($path);
472
-
473
-		try {
474
-			$this->lock($share->getNode());
475
-		} catch (LockedException $e) {
476
-			throw new OCSNotFoundException($this->l->t('Could not create share'));
477
-		}
478
-
479
-		if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
480
-			throw new OCSNotFoundException($this->l->t('invalid permissions'));
481
-		}
482
-
483
-		// Shares always require read permissions
484
-		$permissions |= Constants::PERMISSION_READ;
485
-
486
-		if ($path instanceof \OCP\Files\File) {
487
-			// Single file shares should never have delete or create permissions
488
-			$permissions &= ~Constants::PERMISSION_DELETE;
489
-			$permissions &= ~Constants::PERMISSION_CREATE;
490
-		}
491
-
492
-		/**
493
-		 * Hack for https://github.com/owncloud/core/issues/22587
494
-		 * We check the permissions via webdav. But the permissions of the mount point
495
-		 * do not equal the share permissions. Here we fix that for federated mounts.
496
-		 */
497
-		if ($path->getStorage()->instanceOfStorage(Storage::class)) {
498
-			$permissions &= ~($permissions & ~$path->getPermissions());
499
-		}
500
-
501
-		if ($shareType === IShare::TYPE_USER) {
502
-			// Valid user is required to share
503
-			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
504
-				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
505
-			}
506
-			$share->setSharedWith($shareWith);
507
-			$share->setPermissions($permissions);
508
-		} elseif ($shareType === IShare::TYPE_GROUP) {
509
-			if (!$this->shareManager->allowGroupSharing()) {
510
-				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
511
-			}
512
-
513
-			// Valid group is required to share
514
-			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
515
-				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
516
-			}
517
-			$share->setSharedWith($shareWith);
518
-			$share->setPermissions($permissions);
519
-		} elseif ($shareType === IShare::TYPE_LINK
520
-			|| $shareType === IShare::TYPE_EMAIL) {
521
-
522
-			// Can we even share links?
523
-			if (!$this->shareManager->shareApiAllowLinks()) {
524
-				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
525
-			}
526
-
527
-			if ($publicUpload === 'true') {
528
-				// Check if public upload is allowed
529
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
530
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
531
-				}
532
-
533
-				// Public upload can only be set for folders
534
-				if ($path instanceof \OCP\Files\File) {
535
-					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
536
-				}
537
-
538
-				$permissions = Constants::PERMISSION_READ |
539
-					Constants::PERMISSION_CREATE |
540
-					Constants::PERMISSION_UPDATE |
541
-					Constants::PERMISSION_DELETE;
542
-			} else {
543
-				$permissions = Constants::PERMISSION_READ;
544
-			}
545
-
546
-			// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
547
-			if (($permissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
548
-				$permissions |= Constants::PERMISSION_SHARE;
549
-			}
550
-
551
-			$share->setPermissions($permissions);
552
-
553
-			// Set password
554
-			if ($password !== '') {
555
-				$share->setPassword($password);
556
-			}
557
-
558
-			// Only share by mail have a recipient
559
-			if (is_string($shareWith) && $shareType === IShare::TYPE_EMAIL) {
560
-				$share->setSharedWith($shareWith);
561
-			}
562
-
563
-			// If we have a label, use it
564
-			if (!empty($label)) {
565
-				$share->setLabel($label);
566
-			}
567
-
568
-			if ($sendPasswordByTalk === 'true') {
569
-				if (!$this->appManager->isEnabledForUser('spreed')) {
570
-					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
571
-				}
572
-
573
-				$share->setSendPasswordByTalk(true);
574
-			}
575
-
576
-			//Expire date
577
-			if ($expireDate !== '') {
578
-				try {
579
-					$expireDate = $this->parseDate($expireDate);
580
-					$share->setExpirationDate($expireDate);
581
-				} catch (\Exception $e) {
582
-					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
583
-				}
584
-			}
585
-		} elseif ($shareType === IShare::TYPE_REMOTE) {
586
-			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
587
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
588
-			}
589
-
590
-			if ($shareWith === null) {
591
-				throw new OCSNotFoundException($this->l->t('Please specify a valid federated user id'));
592
-			}
593
-
594
-			$share->setSharedWith($shareWith);
595
-			$share->setPermissions($permissions);
596
-			if ($expireDate !== '') {
597
-				try {
598
-					$expireDate = $this->parseDate($expireDate);
599
-					$share->setExpirationDate($expireDate);
600
-				} catch (\Exception $e) {
601
-					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
602
-				}
603
-			}
604
-		} elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
605
-			if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
606
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
607
-			}
608
-
609
-			if ($shareWith === null) {
610
-				throw new OCSNotFoundException($this->l->t('Please specify a valid federated group id'));
611
-			}
612
-
613
-			$share->setSharedWith($shareWith);
614
-			$share->setPermissions($permissions);
615
-			if ($expireDate !== '') {
616
-				try {
617
-					$expireDate = $this->parseDate($expireDate);
618
-					$share->setExpirationDate($expireDate);
619
-				} catch (\Exception $e) {
620
-					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
621
-				}
622
-			}
623
-		} elseif ($shareType === IShare::TYPE_CIRCLE) {
624
-			if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
625
-				throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
626
-			}
627
-
628
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
629
-
630
-			// Valid circle is required to share
631
-			if ($circle === null) {
632
-				throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
633
-			}
634
-			$share->setSharedWith($shareWith);
635
-			$share->setPermissions($permissions);
636
-		} elseif ($shareType === IShare::TYPE_ROOM) {
637
-			try {
638
-				$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
639
-			} catch (QueryException $e) {
640
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
641
-			}
642
-		} elseif ($shareType === IShare::TYPE_DECK) {
643
-			try {
644
-				$this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
645
-			} catch (QueryException $e) {
646
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
647
-			}
648
-		} else {
649
-			throw new OCSBadRequestException($this->l->t('Unknown share type'));
650
-		}
651
-
652
-		$share->setShareType($shareType);
653
-		$share->setSharedBy($this->currentUser);
654
-
655
-		try {
656
-			$share = $this->shareManager->createShare($share);
657
-		} catch (GenericShareException $e) {
658
-			\OC::$server->getLogger()->logException($e);
659
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
660
-			throw new OCSException($e->getHint(), $code);
661
-		} catch (\Exception $e) {
662
-			\OC::$server->getLogger()->logException($e);
663
-			throw new OCSForbiddenException($e->getMessage(), $e);
664
-		}
665
-
666
-		$output = $this->formatShare($share);
667
-
668
-		return new DataResponse($output);
669
-	}
670
-
671
-	/**
672
-	 * @param null|Node $node
673
-	 * @param boolean $includeTags
674
-	 *
675
-	 * @return array
676
-	 */
677
-	private function getSharedWithMe($node, bool $includeTags): array {
678
-		$userShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_USER, $node, -1, 0);
679
-		$groupShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_GROUP, $node, -1, 0);
680
-		$circleShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_CIRCLE, $node, -1, 0);
681
-		$roomShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_ROOM, $node, -1, 0);
682
-		$deckShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_DECK, $node, -1, 0);
683
-
684
-		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares);
685
-
686
-		$filteredShares = array_filter($shares, function (IShare $share) {
687
-			return $share->getShareOwner() !== $this->currentUser;
688
-		});
689
-
690
-		$formatted = [];
691
-		foreach ($filteredShares as $share) {
692
-			if ($this->canAccessShare($share)) {
693
-				try {
694
-					$formatted[] = $this->formatShare($share);
695
-				} catch (NotFoundException $e) {
696
-					// Ignore this share
697
-				}
698
-			}
699
-		}
700
-
701
-		if ($includeTags) {
702
-			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
703
-		}
704
-
705
-		return $formatted;
706
-	}
707
-
708
-	/**
709
-	 * @param \OCP\Files\Node $folder
710
-	 *
711
-	 * @return array
712
-	 * @throws OCSBadRequestException
713
-	 * @throws NotFoundException
714
-	 */
715
-	private function getSharesInDir(Node $folder): array {
716
-		if (!($folder instanceof \OCP\Files\Folder)) {
717
-			throw new OCSBadRequestException($this->l->t('Not a directory'));
718
-		}
719
-
720
-		$nodes = $folder->getDirectoryListing();
721
-
722
-		/** @var \OCP\Share\IShare[] $shares */
723
-		$shares = array_reduce($nodes, function ($carry, $node) {
724
-			$carry = array_merge($carry, $this->getAllShares($node, true));
725
-			return $carry;
726
-		}, []);
727
-
728
-		// filter out duplicate shares
729
-		$known = [];
730
-
731
-
732
-		$formatted = $miniFormatted = [];
733
-		$resharingRight = false;
734
-		$known = [];
735
-		foreach ($shares as $share) {
736
-			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
737
-				continue;
738
-			}
739
-
740
-			try {
741
-				$format = $this->formatShare($share);
742
-
743
-				$known[] = $share->getId();
744
-				$formatted[] = $format;
745
-				if ($share->getSharedBy() === $this->currentUser) {
746
-					$miniFormatted[] = $format;
747
-				}
748
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
749
-					$resharingRight = true;
750
-				}
751
-			} catch (\Exception $e) {
752
-				//Ignore this share
753
-			}
754
-		}
755
-
756
-		if (!$resharingRight) {
757
-			$formatted = $miniFormatted;
758
-		}
759
-
760
-		return $formatted;
761
-	}
762
-
763
-	/**
764
-	 * The getShares function.
765
-	 *
766
-	 * @NoAdminRequired
767
-	 *
768
-	 * @param string $shared_with_me
769
-	 * @param string $reshares
770
-	 * @param string $subfiles
771
-	 * @param string $path
772
-	 *
773
-	 * - Get shares by the current user
774
-	 * - Get shares by the current user and reshares (?reshares=true)
775
-	 * - Get shares with the current user (?shared_with_me=true)
776
-	 * - Get shares for a specific path (?path=...)
777
-	 * - Get all shares in a folder (?subfiles=true&path=..)
778
-	 *
779
-	 * @param string $include_tags
780
-	 *
781
-	 * @return DataResponse
782
-	 * @throws NotFoundException
783
-	 * @throws OCSBadRequestException
784
-	 * @throws OCSNotFoundException
785
-	 */
786
-	public function getShares(
787
-		string $shared_with_me = 'false',
788
-		string $reshares = 'false',
789
-		string $subfiles = 'false',
790
-		string $path = '',
791
-		string $include_tags = 'false'
792
-	): DataResponse {
793
-		$node = null;
794
-		if ($path !== '') {
795
-			$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
796
-			try {
797
-				$node = $userFolder->get($path);
798
-				$this->lock($node);
799
-			} catch (NotFoundException $e) {
800
-				throw new OCSNotFoundException(
801
-					$this->l->t('Wrong path, file/folder doesn\'t exist')
802
-				);
803
-			} catch (LockedException $e) {
804
-				throw new OCSNotFoundException($this->l->t('Could not lock node'));
805
-			}
806
-		}
807
-
808
-		$shares = $this->getFormattedShares(
809
-			$this->currentUser,
810
-			$node,
811
-			($shared_with_me === 'true'),
812
-			($reshares === 'true'),
813
-			($subfiles === 'true'),
814
-			($include_tags === 'true')
815
-		);
816
-
817
-		return new DataResponse($shares);
818
-	}
819
-
820
-
821
-	/**
822
-	 * @param string $viewer
823
-	 * @param Node $node
824
-	 * @param bool $sharedWithMe
825
-	 * @param bool $reShares
826
-	 * @param bool $subFiles
827
-	 * @param bool $includeTags
828
-	 *
829
-	 * @return array
830
-	 * @throws NotFoundException
831
-	 * @throws OCSBadRequestException
832
-	 */
833
-	private function getFormattedShares(
834
-		string $viewer,
835
-		$node = null,
836
-		bool $sharedWithMe = false,
837
-		bool $reShares = false,
838
-		bool $subFiles = false,
839
-		bool $includeTags = false
840
-	): array {
841
-		if ($sharedWithMe) {
842
-			return $this->getSharedWithMe($node, $includeTags);
843
-		}
844
-
845
-		if ($subFiles) {
846
-			return $this->getSharesInDir($node);
847
-		}
848
-
849
-		$shares = $this->getSharesFromNode($viewer, $node, $reShares);
850
-
851
-		$known = $formatted = $miniFormatted = [];
852
-		$resharingRight = false;
853
-		foreach ($shares as $share) {
854
-			try {
855
-				$share->getNode();
856
-			} catch (NotFoundException $e) {
857
-				/*
87
+    /** @var IManager */
88
+    private $shareManager;
89
+    /** @var IGroupManager */
90
+    private $groupManager;
91
+    /** @var IUserManager */
92
+    private $userManager;
93
+    /** @var IRootFolder */
94
+    private $rootFolder;
95
+    /** @var IURLGenerator */
96
+    private $urlGenerator;
97
+    /** @var string */
98
+    private $currentUser;
99
+    /** @var IL10N */
100
+    private $l;
101
+    /** @var \OCP\Files\Node */
102
+    private $lockedNode;
103
+    /** @var IConfig */
104
+    private $config;
105
+    /** @var IAppManager */
106
+    private $appManager;
107
+    /** @var IServerContainer */
108
+    private $serverContainer;
109
+    /** @var IUserStatusManager */
110
+    private $userStatusManager;
111
+    /** @var IPreview */
112
+    private $previewManager;
113
+
114
+    /**
115
+     * Share20OCS constructor.
116
+     *
117
+     * @param string $appName
118
+     * @param IRequest $request
119
+     * @param IManager $shareManager
120
+     * @param IGroupManager $groupManager
121
+     * @param IUserManager $userManager
122
+     * @param IRootFolder $rootFolder
123
+     * @param IURLGenerator $urlGenerator
124
+     * @param string $userId
125
+     * @param IL10N $l10n
126
+     * @param IConfig $config
127
+     * @param IAppManager $appManager
128
+     * @param IServerContainer $serverContainer
129
+     * @param IUserStatusManager $userStatusManager
130
+     */
131
+    public function __construct(
132
+        string $appName,
133
+        IRequest $request,
134
+        IManager $shareManager,
135
+        IGroupManager $groupManager,
136
+        IUserManager $userManager,
137
+        IRootFolder $rootFolder,
138
+        IURLGenerator $urlGenerator,
139
+        string $userId = null,
140
+        IL10N $l10n,
141
+        IConfig $config,
142
+        IAppManager $appManager,
143
+        IServerContainer $serverContainer,
144
+        IUserStatusManager $userStatusManager,
145
+        IPreview $previewManager
146
+    ) {
147
+        parent::__construct($appName, $request);
148
+
149
+        $this->shareManager = $shareManager;
150
+        $this->userManager = $userManager;
151
+        $this->groupManager = $groupManager;
152
+        $this->request = $request;
153
+        $this->rootFolder = $rootFolder;
154
+        $this->urlGenerator = $urlGenerator;
155
+        $this->currentUser = $userId;
156
+        $this->l = $l10n;
157
+        $this->config = $config;
158
+        $this->appManager = $appManager;
159
+        $this->serverContainer = $serverContainer;
160
+        $this->userStatusManager = $userStatusManager;
161
+        $this->previewManager = $previewManager;
162
+    }
163
+
164
+    /**
165
+     * Convert an IShare to an array for OCS output
166
+     *
167
+     * @param \OCP\Share\IShare $share
168
+     * @param Node|null $recipientNode
169
+     * @return array
170
+     * @throws NotFoundException In case the node can't be resolved.
171
+     *
172
+     * @suppress PhanUndeclaredClassMethod
173
+     */
174
+    protected function formatShare(IShare $share, Node $recipientNode = null): array {
175
+        $sharedBy = $this->userManager->get($share->getSharedBy());
176
+        $shareOwner = $this->userManager->get($share->getShareOwner());
177
+
178
+        $result = [
179
+            'id' => $share->getId(),
180
+            'share_type' => $share->getShareType(),
181
+            'uid_owner' => $share->getSharedBy(),
182
+            'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
183
+            // recipient permissions
184
+            'permissions' => $share->getPermissions(),
185
+            // current user permissions on this share
186
+            'can_edit' => $this->canEditShare($share),
187
+            'can_delete' => $this->canDeleteShare($share),
188
+            'stime' => $share->getShareTime()->getTimestamp(),
189
+            'parent' => null,
190
+            'expiration' => null,
191
+            'token' => null,
192
+            'uid_file_owner' => $share->getShareOwner(),
193
+            'note' => $share->getNote(),
194
+            'label' => $share->getLabel(),
195
+            'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
196
+        ];
197
+
198
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
199
+        if ($recipientNode) {
200
+            $node = $recipientNode;
201
+        } else {
202
+            $nodes = $userFolder->getById($share->getNodeId());
203
+            if (empty($nodes)) {
204
+                // fallback to guessing the path
205
+                $node = $userFolder->get($share->getTarget());
206
+                if ($node === null || $share->getTarget() === '') {
207
+                    throw new NotFoundException();
208
+                }
209
+            } else {
210
+                $node = reset($nodes);
211
+            }
212
+        }
213
+
214
+        $result['path'] = $userFolder->getRelativePath($node->getPath());
215
+        if ($node instanceof Folder) {
216
+            $result['item_type'] = 'folder';
217
+        } else {
218
+            $result['item_type'] = 'file';
219
+        }
220
+
221
+        $result['mimetype'] = $node->getMimetype();
222
+        $result['has_preview'] = $this->previewManager->isAvailable($node);
223
+        $result['storage_id'] = $node->getStorage()->getId();
224
+        $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
225
+        $result['item_source'] = $node->getId();
226
+        $result['file_source'] = $node->getId();
227
+        $result['file_parent'] = $node->getParent()->getId();
228
+        $result['file_target'] = $share->getTarget();
229
+
230
+        $expiration = $share->getExpirationDate();
231
+        if ($expiration !== null) {
232
+            $result['expiration'] = $expiration->format('Y-m-d 00:00:00');
233
+        }
234
+
235
+        if ($share->getShareType() === IShare::TYPE_USER) {
236
+            $sharedWith = $this->userManager->get($share->getSharedWith());
237
+            $result['share_with'] = $share->getSharedWith();
238
+            $result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
239
+            $result['share_with_displayname_unique'] = $sharedWith !== null ? (
240
+                    $sharedWith->getEMailAddress() !== '' ? $sharedWith->getEMailAddress() : $sharedWith->getUID()
241
+            ) : $share->getSharedWith();
242
+            $result['status'] = [];
243
+
244
+            $userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
245
+            $userStatus = array_shift($userStatuses);
246
+            if ($userStatus) {
247
+                $result['status'] = [
248
+                    'status' => $userStatus->getStatus(),
249
+                    'message' => $userStatus->getMessage(),
250
+                    'icon' => $userStatus->getIcon(),
251
+                    'clearAt' => $userStatus->getClearAt()
252
+                        ? (int)$userStatus->getClearAt()->format('U')
253
+                        : null,
254
+                ];
255
+            }
256
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
257
+            $group = $this->groupManager->get($share->getSharedWith());
258
+            $result['share_with'] = $share->getSharedWith();
259
+            $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
260
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
261
+
262
+            // "share_with" and "share_with_displayname" for passwords of link
263
+            // shares was deprecated in Nextcloud 15, use "password" instead.
264
+            $result['share_with'] = $share->getPassword();
265
+            $result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
266
+
267
+            $result['password'] = $share->getPassword();
268
+
269
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
270
+
271
+            $result['token'] = $share->getToken();
272
+            $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
273
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
274
+            $result['share_with'] = $share->getSharedWith();
275
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
276
+            $result['token'] = $share->getToken();
277
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
278
+            $result['share_with'] = $share->getSharedWith();
279
+            $result['password'] = $share->getPassword();
280
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
281
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
282
+            $result['token'] = $share->getToken();
283
+        } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
284
+            // getSharedWith() returns either "name (type, owner)" or
285
+            // "name (type, owner) [id]", depending on the Circles app version.
286
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
287
+
288
+            $result['share_with_displayname'] = $share->getSharedWithDisplayName();
289
+            if (empty($result['share_with_displayname'])) {
290
+                $displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
291
+                $result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
292
+            }
293
+
294
+            $result['share_with_avatar'] = $share->getSharedWithAvatar();
295
+
296
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
297
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
298
+            if (is_bool($shareWithLength)) {
299
+                $shareWithLength = -1;
300
+            }
301
+            $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
302
+        } elseif ($share->getShareType() === IShare::TYPE_ROOM) {
303
+            $result['share_with'] = $share->getSharedWith();
304
+            $result['share_with_displayname'] = '';
305
+
306
+            try {
307
+                $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
308
+            } catch (QueryException $e) {
309
+            }
310
+        } elseif ($share->getShareType() === IShare::TYPE_DECK) {
311
+            $result['share_with'] = $share->getSharedWith();
312
+            $result['share_with_displayname'] = '';
313
+
314
+            try {
315
+                $result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
316
+            } catch (QueryException $e) {
317
+            }
318
+        }
319
+
320
+
321
+        $result['mail_send'] = $share->getMailSend() ? 1 : 0;
322
+        $result['hide_download'] = $share->getHideDownload() ? 1 : 0;
323
+
324
+        return $result;
325
+    }
326
+
327
+    /**
328
+     * Check if one of the users address books knows the exact property, if
329
+     * yes we return the full name.
330
+     *
331
+     * @param string $query
332
+     * @param string $property
333
+     * @return string
334
+     */
335
+    private function getDisplayNameFromAddressBook(string $query, string $property): string {
336
+        // FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
337
+        $result = \OC::$server->getContactsManager()->search($query, [$property]);
338
+        foreach ($result as $r) {
339
+            foreach ($r[$property] as $value) {
340
+                if ($value === $query && $r['FN']) {
341
+                    return $r['FN'];
342
+                }
343
+            }
344
+        }
345
+
346
+        return $query;
347
+    }
348
+
349
+    /**
350
+     * Get a specific share by id
351
+     *
352
+     * @NoAdminRequired
353
+     *
354
+     * @param string $id
355
+     * @return DataResponse
356
+     * @throws OCSNotFoundException
357
+     */
358
+    public function getShare(string $id): DataResponse {
359
+        try {
360
+            $share = $this->getShareById($id);
361
+        } catch (ShareNotFound $e) {
362
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
363
+        }
364
+
365
+        try {
366
+            if ($this->canAccessShare($share)) {
367
+                $share = $this->formatShare($share);
368
+                return new DataResponse([$share]);
369
+            }
370
+        } catch (NotFoundException $e) {
371
+            // Fall trough
372
+        }
373
+
374
+        throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
375
+    }
376
+
377
+    /**
378
+     * Delete a share
379
+     *
380
+     * @NoAdminRequired
381
+     *
382
+     * @param string $id
383
+     * @return DataResponse
384
+     * @throws OCSNotFoundException
385
+     */
386
+    public function deleteShare(string $id): DataResponse {
387
+        try {
388
+            $share = $this->getShareById($id);
389
+        } catch (ShareNotFound $e) {
390
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
391
+        }
392
+
393
+        try {
394
+            $this->lock($share->getNode());
395
+        } catch (LockedException $e) {
396
+            throw new OCSNotFoundException($this->l->t('Could not delete share'));
397
+        }
398
+
399
+        if (!$this->canAccessShare($share)) {
400
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
401
+        }
402
+
403
+        // if it's a group share or a room share
404
+        // we don't delete the share, but only the
405
+        // mount point. Allowing it to be restored
406
+        // from the deleted shares
407
+        if ($this->canDeleteShareFromSelf($share)) {
408
+            $this->shareManager->deleteFromSelf($share, $this->currentUser);
409
+        } else {
410
+            if (!$this->canDeleteShare($share)) {
411
+                throw new OCSForbiddenException($this->l->t('Could not delete share'));
412
+            }
413
+
414
+            $this->shareManager->deleteShare($share);
415
+        }
416
+
417
+        return new DataResponse();
418
+    }
419
+
420
+    /**
421
+     * @NoAdminRequired
422
+     *
423
+     * @param string $path
424
+     * @param int $permissions
425
+     * @param int $shareType
426
+     * @param string $shareWith
427
+     * @param string $publicUpload
428
+     * @param string $password
429
+     * @param string $sendPasswordByTalk
430
+     * @param string $expireDate
431
+     * @param string $label
432
+     *
433
+     * @return DataResponse
434
+     * @throws NotFoundException
435
+     * @throws OCSBadRequestException
436
+     * @throws OCSException
437
+     * @throws OCSForbiddenException
438
+     * @throws OCSNotFoundException
439
+     * @throws InvalidPathException
440
+     * @suppress PhanUndeclaredClassMethod
441
+     */
442
+    public function createShare(
443
+        string $path = null,
444
+        int $permissions = null,
445
+        int $shareType = -1,
446
+        string $shareWith = null,
447
+        string $publicUpload = 'false',
448
+        string $password = '',
449
+        string $sendPasswordByTalk = null,
450
+        string $expireDate = '',
451
+        string $label = ''
452
+    ): DataResponse {
453
+        $share = $this->shareManager->newShare();
454
+
455
+        if ($permissions === null) {
456
+            $permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
457
+        }
458
+
459
+        // Verify path
460
+        if ($path === null) {
461
+            throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
462
+        }
463
+
464
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
465
+        try {
466
+            $path = $userFolder->get($path);
467
+        } catch (NotFoundException $e) {
468
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
469
+        }
470
+
471
+        $share->setNode($path);
472
+
473
+        try {
474
+            $this->lock($share->getNode());
475
+        } catch (LockedException $e) {
476
+            throw new OCSNotFoundException($this->l->t('Could not create share'));
477
+        }
478
+
479
+        if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
480
+            throw new OCSNotFoundException($this->l->t('invalid permissions'));
481
+        }
482
+
483
+        // Shares always require read permissions
484
+        $permissions |= Constants::PERMISSION_READ;
485
+
486
+        if ($path instanceof \OCP\Files\File) {
487
+            // Single file shares should never have delete or create permissions
488
+            $permissions &= ~Constants::PERMISSION_DELETE;
489
+            $permissions &= ~Constants::PERMISSION_CREATE;
490
+        }
491
+
492
+        /**
493
+         * Hack for https://github.com/owncloud/core/issues/22587
494
+         * We check the permissions via webdav. But the permissions of the mount point
495
+         * do not equal the share permissions. Here we fix that for federated mounts.
496
+         */
497
+        if ($path->getStorage()->instanceOfStorage(Storage::class)) {
498
+            $permissions &= ~($permissions & ~$path->getPermissions());
499
+        }
500
+
501
+        if ($shareType === IShare::TYPE_USER) {
502
+            // Valid user is required to share
503
+            if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
504
+                throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
505
+            }
506
+            $share->setSharedWith($shareWith);
507
+            $share->setPermissions($permissions);
508
+        } elseif ($shareType === IShare::TYPE_GROUP) {
509
+            if (!$this->shareManager->allowGroupSharing()) {
510
+                throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
511
+            }
512
+
513
+            // Valid group is required to share
514
+            if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
515
+                throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
516
+            }
517
+            $share->setSharedWith($shareWith);
518
+            $share->setPermissions($permissions);
519
+        } elseif ($shareType === IShare::TYPE_LINK
520
+            || $shareType === IShare::TYPE_EMAIL) {
521
+
522
+            // Can we even share links?
523
+            if (!$this->shareManager->shareApiAllowLinks()) {
524
+                throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
525
+            }
526
+
527
+            if ($publicUpload === 'true') {
528
+                // Check if public upload is allowed
529
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
530
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
531
+                }
532
+
533
+                // Public upload can only be set for folders
534
+                if ($path instanceof \OCP\Files\File) {
535
+                    throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
536
+                }
537
+
538
+                $permissions = Constants::PERMISSION_READ |
539
+                    Constants::PERMISSION_CREATE |
540
+                    Constants::PERMISSION_UPDATE |
541
+                    Constants::PERMISSION_DELETE;
542
+            } else {
543
+                $permissions = Constants::PERMISSION_READ;
544
+            }
545
+
546
+            // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
547
+            if (($permissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
548
+                $permissions |= Constants::PERMISSION_SHARE;
549
+            }
550
+
551
+            $share->setPermissions($permissions);
552
+
553
+            // Set password
554
+            if ($password !== '') {
555
+                $share->setPassword($password);
556
+            }
557
+
558
+            // Only share by mail have a recipient
559
+            if (is_string($shareWith) && $shareType === IShare::TYPE_EMAIL) {
560
+                $share->setSharedWith($shareWith);
561
+            }
562
+
563
+            // If we have a label, use it
564
+            if (!empty($label)) {
565
+                $share->setLabel($label);
566
+            }
567
+
568
+            if ($sendPasswordByTalk === 'true') {
569
+                if (!$this->appManager->isEnabledForUser('spreed')) {
570
+                    throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
571
+                }
572
+
573
+                $share->setSendPasswordByTalk(true);
574
+            }
575
+
576
+            //Expire date
577
+            if ($expireDate !== '') {
578
+                try {
579
+                    $expireDate = $this->parseDate($expireDate);
580
+                    $share->setExpirationDate($expireDate);
581
+                } catch (\Exception $e) {
582
+                    throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
583
+                }
584
+            }
585
+        } elseif ($shareType === IShare::TYPE_REMOTE) {
586
+            if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
587
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
588
+            }
589
+
590
+            if ($shareWith === null) {
591
+                throw new OCSNotFoundException($this->l->t('Please specify a valid federated user id'));
592
+            }
593
+
594
+            $share->setSharedWith($shareWith);
595
+            $share->setPermissions($permissions);
596
+            if ($expireDate !== '') {
597
+                try {
598
+                    $expireDate = $this->parseDate($expireDate);
599
+                    $share->setExpirationDate($expireDate);
600
+                } catch (\Exception $e) {
601
+                    throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
602
+                }
603
+            }
604
+        } elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
605
+            if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
606
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
607
+            }
608
+
609
+            if ($shareWith === null) {
610
+                throw new OCSNotFoundException($this->l->t('Please specify a valid federated group id'));
611
+            }
612
+
613
+            $share->setSharedWith($shareWith);
614
+            $share->setPermissions($permissions);
615
+            if ($expireDate !== '') {
616
+                try {
617
+                    $expireDate = $this->parseDate($expireDate);
618
+                    $share->setExpirationDate($expireDate);
619
+                } catch (\Exception $e) {
620
+                    throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
621
+                }
622
+            }
623
+        } elseif ($shareType === IShare::TYPE_CIRCLE) {
624
+            if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
625
+                throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
626
+            }
627
+
628
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
629
+
630
+            // Valid circle is required to share
631
+            if ($circle === null) {
632
+                throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
633
+            }
634
+            $share->setSharedWith($shareWith);
635
+            $share->setPermissions($permissions);
636
+        } elseif ($shareType === IShare::TYPE_ROOM) {
637
+            try {
638
+                $this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
639
+            } catch (QueryException $e) {
640
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
641
+            }
642
+        } elseif ($shareType === IShare::TYPE_DECK) {
643
+            try {
644
+                $this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
645
+            } catch (QueryException $e) {
646
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
647
+            }
648
+        } else {
649
+            throw new OCSBadRequestException($this->l->t('Unknown share type'));
650
+        }
651
+
652
+        $share->setShareType($shareType);
653
+        $share->setSharedBy($this->currentUser);
654
+
655
+        try {
656
+            $share = $this->shareManager->createShare($share);
657
+        } catch (GenericShareException $e) {
658
+            \OC::$server->getLogger()->logException($e);
659
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
660
+            throw new OCSException($e->getHint(), $code);
661
+        } catch (\Exception $e) {
662
+            \OC::$server->getLogger()->logException($e);
663
+            throw new OCSForbiddenException($e->getMessage(), $e);
664
+        }
665
+
666
+        $output = $this->formatShare($share);
667
+
668
+        return new DataResponse($output);
669
+    }
670
+
671
+    /**
672
+     * @param null|Node $node
673
+     * @param boolean $includeTags
674
+     *
675
+     * @return array
676
+     */
677
+    private function getSharedWithMe($node, bool $includeTags): array {
678
+        $userShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_USER, $node, -1, 0);
679
+        $groupShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_GROUP, $node, -1, 0);
680
+        $circleShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_CIRCLE, $node, -1, 0);
681
+        $roomShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_ROOM, $node, -1, 0);
682
+        $deckShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_DECK, $node, -1, 0);
683
+
684
+        $shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares);
685
+
686
+        $filteredShares = array_filter($shares, function (IShare $share) {
687
+            return $share->getShareOwner() !== $this->currentUser;
688
+        });
689
+
690
+        $formatted = [];
691
+        foreach ($filteredShares as $share) {
692
+            if ($this->canAccessShare($share)) {
693
+                try {
694
+                    $formatted[] = $this->formatShare($share);
695
+                } catch (NotFoundException $e) {
696
+                    // Ignore this share
697
+                }
698
+            }
699
+        }
700
+
701
+        if ($includeTags) {
702
+            $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
703
+        }
704
+
705
+        return $formatted;
706
+    }
707
+
708
+    /**
709
+     * @param \OCP\Files\Node $folder
710
+     *
711
+     * @return array
712
+     * @throws OCSBadRequestException
713
+     * @throws NotFoundException
714
+     */
715
+    private function getSharesInDir(Node $folder): array {
716
+        if (!($folder instanceof \OCP\Files\Folder)) {
717
+            throw new OCSBadRequestException($this->l->t('Not a directory'));
718
+        }
719
+
720
+        $nodes = $folder->getDirectoryListing();
721
+
722
+        /** @var \OCP\Share\IShare[] $shares */
723
+        $shares = array_reduce($nodes, function ($carry, $node) {
724
+            $carry = array_merge($carry, $this->getAllShares($node, true));
725
+            return $carry;
726
+        }, []);
727
+
728
+        // filter out duplicate shares
729
+        $known = [];
730
+
731
+
732
+        $formatted = $miniFormatted = [];
733
+        $resharingRight = false;
734
+        $known = [];
735
+        foreach ($shares as $share) {
736
+            if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
737
+                continue;
738
+            }
739
+
740
+            try {
741
+                $format = $this->formatShare($share);
742
+
743
+                $known[] = $share->getId();
744
+                $formatted[] = $format;
745
+                if ($share->getSharedBy() === $this->currentUser) {
746
+                    $miniFormatted[] = $format;
747
+                }
748
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
749
+                    $resharingRight = true;
750
+                }
751
+            } catch (\Exception $e) {
752
+                //Ignore this share
753
+            }
754
+        }
755
+
756
+        if (!$resharingRight) {
757
+            $formatted = $miniFormatted;
758
+        }
759
+
760
+        return $formatted;
761
+    }
762
+
763
+    /**
764
+     * The getShares function.
765
+     *
766
+     * @NoAdminRequired
767
+     *
768
+     * @param string $shared_with_me
769
+     * @param string $reshares
770
+     * @param string $subfiles
771
+     * @param string $path
772
+     *
773
+     * - Get shares by the current user
774
+     * - Get shares by the current user and reshares (?reshares=true)
775
+     * - Get shares with the current user (?shared_with_me=true)
776
+     * - Get shares for a specific path (?path=...)
777
+     * - Get all shares in a folder (?subfiles=true&path=..)
778
+     *
779
+     * @param string $include_tags
780
+     *
781
+     * @return DataResponse
782
+     * @throws NotFoundException
783
+     * @throws OCSBadRequestException
784
+     * @throws OCSNotFoundException
785
+     */
786
+    public function getShares(
787
+        string $shared_with_me = 'false',
788
+        string $reshares = 'false',
789
+        string $subfiles = 'false',
790
+        string $path = '',
791
+        string $include_tags = 'false'
792
+    ): DataResponse {
793
+        $node = null;
794
+        if ($path !== '') {
795
+            $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
796
+            try {
797
+                $node = $userFolder->get($path);
798
+                $this->lock($node);
799
+            } catch (NotFoundException $e) {
800
+                throw new OCSNotFoundException(
801
+                    $this->l->t('Wrong path, file/folder doesn\'t exist')
802
+                );
803
+            } catch (LockedException $e) {
804
+                throw new OCSNotFoundException($this->l->t('Could not lock node'));
805
+            }
806
+        }
807
+
808
+        $shares = $this->getFormattedShares(
809
+            $this->currentUser,
810
+            $node,
811
+            ($shared_with_me === 'true'),
812
+            ($reshares === 'true'),
813
+            ($subfiles === 'true'),
814
+            ($include_tags === 'true')
815
+        );
816
+
817
+        return new DataResponse($shares);
818
+    }
819
+
820
+
821
+    /**
822
+     * @param string $viewer
823
+     * @param Node $node
824
+     * @param bool $sharedWithMe
825
+     * @param bool $reShares
826
+     * @param bool $subFiles
827
+     * @param bool $includeTags
828
+     *
829
+     * @return array
830
+     * @throws NotFoundException
831
+     * @throws OCSBadRequestException
832
+     */
833
+    private function getFormattedShares(
834
+        string $viewer,
835
+        $node = null,
836
+        bool $sharedWithMe = false,
837
+        bool $reShares = false,
838
+        bool $subFiles = false,
839
+        bool $includeTags = false
840
+    ): array {
841
+        if ($sharedWithMe) {
842
+            return $this->getSharedWithMe($node, $includeTags);
843
+        }
844
+
845
+        if ($subFiles) {
846
+            return $this->getSharesInDir($node);
847
+        }
848
+
849
+        $shares = $this->getSharesFromNode($viewer, $node, $reShares);
850
+
851
+        $known = $formatted = $miniFormatted = [];
852
+        $resharingRight = false;
853
+        foreach ($shares as $share) {
854
+            try {
855
+                $share->getNode();
856
+            } catch (NotFoundException $e) {
857
+                /*
858 858
 				 * Ignore shares where we can't get the node
859 859
 				 * For example deleted shares
860 860
 				 */
861
-				continue;
862
-			}
863
-
864
-			if (in_array($share->getId(), $known)
865
-				|| ($share->getSharedWith() === $this->currentUser && $share->getShareType() === IShare::TYPE_USER)) {
866
-				continue;
867
-			}
868
-
869
-			$known[] = $share->getId();
870
-			try {
871
-				/** @var IShare $share */
872
-				$format = $this->formatShare($share, $node);
873
-				$formatted[] = $format;
874
-
875
-				// let's also build a list of shares created
876
-				// by the current user only, in case
877
-				// there is no resharing rights
878
-				if ($share->getSharedBy() === $this->currentUser) {
879
-					$miniFormatted[] = $format;
880
-				}
881
-
882
-				// check if one of those share is shared with me
883
-				// and if I have resharing rights on it
884
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
885
-					$resharingRight = true;
886
-				}
887
-			} catch (InvalidPathException | NotFoundException $e) {
888
-			}
889
-		}
890
-
891
-		if (!$resharingRight) {
892
-			$formatted = $miniFormatted;
893
-		}
894
-
895
-		if ($includeTags) {
896
-			$formatted =
897
-				Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
898
-		}
899
-
900
-		return $formatted;
901
-	}
902
-
903
-
904
-	/**
905
-	 * The getInheritedShares function.
906
-	 * returns all shares relative to a file, including parent folders shares rights.
907
-	 *
908
-	 * @NoAdminRequired
909
-	 *
910
-	 * @param string $path
911
-	 *
912
-	 * - Get shares by the current user
913
-	 * - Get shares by the current user and reshares (?reshares=true)
914
-	 * - Get shares with the current user (?shared_with_me=true)
915
-	 * - Get shares for a specific path (?path=...)
916
-	 * - Get all shares in a folder (?subfiles=true&path=..)
917
-	 *
918
-	 * @return DataResponse
919
-	 * @throws InvalidPathException
920
-	 * @throws NotFoundException
921
-	 * @throws OCSNotFoundException
922
-	 * @throws OCSBadRequestException
923
-	 * @throws SharingRightsException
924
-	 */
925
-	public function getInheritedShares(string $path): DataResponse {
926
-
927
-		// get Node from (string) path.
928
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
929
-		try {
930
-			$node = $userFolder->get($path);
931
-			$this->lock($node);
932
-		} catch (\OCP\Files\NotFoundException $e) {
933
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
934
-		} catch (LockedException $e) {
935
-			throw new OCSNotFoundException($this->l->t('Could not lock path'));
936
-		}
937
-
938
-		if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
939
-			throw new SharingRightsException('no sharing rights on this item');
940
-		}
941
-
942
-		// The current top parent we have access to
943
-		$parent = $node;
944
-
945
-		// initiate real owner.
946
-		$owner = $node->getOwner()
947
-					  ->getUID();
948
-		if (!$this->userManager->userExists($owner)) {
949
-			return new DataResponse([]);
950
-		}
951
-
952
-		// get node based on the owner, fix owner in case of external storage
953
-		$userFolder = $this->rootFolder->getUserFolder($owner);
954
-		if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
955
-			$owner = $node->getOwner()
956
-						  ->getUID();
957
-			$userFolder = $this->rootFolder->getUserFolder($owner);
958
-			$nodes = $userFolder->getById($node->getId());
959
-			$node = array_shift($nodes);
960
-		}
961
-		$basePath = $userFolder->getPath();
962
-
963
-		// generate node list for each parent folders
964
-		/** @var Node[] $nodes */
965
-		$nodes = [];
966
-		while ($node->getPath() !== $basePath) {
967
-			$node = $node->getParent();
968
-			$nodes[] = $node;
969
-		}
970
-
971
-		// The user that is requesting this list
972
-		$currentUserFolder = $this->rootFolder->getUserFolder($this->currentUser);
973
-
974
-		// for each nodes, retrieve shares.
975
-		$shares = [];
976
-
977
-		foreach ($nodes as $node) {
978
-			$getShares = $this->getFormattedShares($owner, $node, false, true);
979
-
980
-			$currentUserNodes = $currentUserFolder->getById($node->getId());
981
-			if (!empty($currentUserNodes)) {
982
-				$parent = array_pop($currentUserNodes);
983
-			}
984
-
985
-			$subPath = $currentUserFolder->getRelativePath($parent->getPath());
986
-			foreach ($getShares as &$share) {
987
-				$share['via_fileid'] = $parent->getId();
988
-				$share['via_path'] = $subPath;
989
-			}
990
-			$this->mergeFormattedShares($shares, $getShares);
991
-		}
992
-
993
-		return new DataResponse(array_values($shares));
994
-	}
995
-
996
-
997
-	/**
998
-	 * @NoAdminRequired
999
-	 *
1000
-	 * @param string $id
1001
-	 * @param int $permissions
1002
-	 * @param string $password
1003
-	 * @param string $sendPasswordByTalk
1004
-	 * @param string $publicUpload
1005
-	 * @param string $expireDate
1006
-	 * @param string $note
1007
-	 * @param string $label
1008
-	 * @param string $hideDownload
1009
-	 * @return DataResponse
1010
-	 * @throws LockedException
1011
-	 * @throws NotFoundException
1012
-	 * @throws OCSBadRequestException
1013
-	 * @throws OCSForbiddenException
1014
-	 * @throws OCSNotFoundException
1015
-	 */
1016
-	public function updateShare(
1017
-		string $id,
1018
-		int $permissions = null,
1019
-		string $password = null,
1020
-		string $sendPasswordByTalk = null,
1021
-		string $publicUpload = null,
1022
-		string $expireDate = null,
1023
-		string $note = null,
1024
-		string $label = null,
1025
-		string $hideDownload = null
1026
-	): DataResponse {
1027
-		try {
1028
-			$share = $this->getShareById($id);
1029
-		} catch (ShareNotFound $e) {
1030
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1031
-		}
1032
-
1033
-		$this->lock($share->getNode());
1034
-
1035
-		if (!$this->canAccessShare($share, false)) {
1036
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1037
-		}
1038
-
1039
-		if (!$this->canEditShare($share)) {
1040
-			throw new OCSForbiddenException('You are not allowed to edit incoming shares');
1041
-		}
1042
-
1043
-		if (
1044
-			$permissions === null &&
1045
-			$password === null &&
1046
-			$sendPasswordByTalk === null &&
1047
-			$publicUpload === null &&
1048
-			$expireDate === null &&
1049
-			$note === null &&
1050
-			$label === null &&
1051
-			$hideDownload === null
1052
-		) {
1053
-			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1054
-		}
1055
-
1056
-		if ($note !== null) {
1057
-			$share->setNote($note);
1058
-		}
1059
-
1060
-		/**
1061
-		 * expirationdate, password and publicUpload only make sense for link shares
1062
-		 */
1063
-		if ($share->getShareType() === IShare::TYPE_LINK
1064
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
1065
-
1066
-			/**
1067
-			 * We do not allow editing link shares that the current user
1068
-			 * doesn't own. This is confusing and lead to errors when
1069
-			 * someone else edit a password or expiration date without
1070
-			 * the share owner knowing about it.
1071
-			 * We only allow deletion
1072
-			 */
1073
-
1074
-			if ($share->getSharedBy() !== $this->currentUser) {
1075
-				throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
1076
-			}
1077
-
1078
-			// Update hide download state
1079
-			if ($hideDownload === 'true') {
1080
-				$share->setHideDownload(true);
1081
-			} elseif ($hideDownload === 'false') {
1082
-				$share->setHideDownload(false);
1083
-			}
1084
-
1085
-			$newPermissions = null;
1086
-			if ($publicUpload === 'true') {
1087
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1088
-			} elseif ($publicUpload === 'false') {
1089
-				$newPermissions = Constants::PERMISSION_READ;
1090
-			}
1091
-
1092
-			if ($permissions !== null) {
1093
-				$newPermissions = $permissions;
1094
-				$newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
1095
-			}
1096
-
1097
-			if ($newPermissions !== null &&
1098
-				!in_array($newPermissions, [
1099
-					Constants::PERMISSION_READ,
1100
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
1101
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
1102
-					Constants::PERMISSION_CREATE, // hidden file list
1103
-					Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1104
-				], true)
1105
-			) {
1106
-				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1107
-			}
1108
-
1109
-			if (
1110
-				// legacy
1111
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1112
-				// correct
1113
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1114
-			) {
1115
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1116
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1117
-				}
1118
-
1119
-				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1120
-					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1121
-				}
1122
-
1123
-				// normalize to correct public upload permissions
1124
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1125
-			}
1126
-
1127
-			if ($newPermissions !== null) {
1128
-				// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
1129
-				if (($newPermissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
1130
-					$newPermissions |= Constants::PERMISSION_SHARE;
1131
-				}
1132
-
1133
-				$share->setPermissions($newPermissions);
1134
-				$permissions = $newPermissions;
1135
-			}
1136
-
1137
-			if ($expireDate === '') {
1138
-				$share->setExpirationDate(null);
1139
-			} elseif ($expireDate !== null) {
1140
-				try {
1141
-					$expireDate = $this->parseDate($expireDate);
1142
-				} catch (\Exception $e) {
1143
-					throw new OCSBadRequestException($e->getMessage(), $e);
1144
-				}
1145
-				$share->setExpirationDate($expireDate);
1146
-			}
1147
-
1148
-			if ($password === '') {
1149
-				$share->setPassword(null);
1150
-			} elseif ($password !== null) {
1151
-				$share->setPassword($password);
1152
-			}
1153
-
1154
-			if ($label !== null) {
1155
-				if (strlen($label) > 255) {
1156
-					throw new OCSBadRequestException("Maxmimum label length is 255");
1157
-				}
1158
-				$share->setLabel($label);
1159
-			}
1160
-
1161
-			if ($sendPasswordByTalk === 'true') {
1162
-				if (!$this->appManager->isEnabledForUser('spreed')) {
1163
-					throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1164
-				}
1165
-
1166
-				$share->setSendPasswordByTalk(true);
1167
-			} elseif ($sendPasswordByTalk !== null) {
1168
-				$share->setSendPasswordByTalk(false);
1169
-			}
1170
-		}
1171
-
1172
-		// NOT A LINK SHARE
1173
-		else {
1174
-			if ($permissions !== null) {
1175
-				$share->setPermissions($permissions);
1176
-			}
1177
-
1178
-			if ($expireDate === '') {
1179
-				$share->setExpirationDate(null);
1180
-			} elseif ($expireDate !== null) {
1181
-				try {
1182
-					$expireDate = $this->parseDate($expireDate);
1183
-				} catch (\Exception $e) {
1184
-					throw new OCSBadRequestException($e->getMessage(), $e);
1185
-				}
1186
-				$share->setExpirationDate($expireDate);
1187
-			}
1188
-		}
1189
-
1190
-		try {
1191
-			$share = $this->shareManager->updateShare($share);
1192
-		} catch (GenericShareException $e) {
1193
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1194
-			throw new OCSException($e->getHint(), $code);
1195
-		} catch (\Exception $e) {
1196
-			throw new OCSBadRequestException($e->getMessage(), $e);
1197
-		}
1198
-
1199
-		return new DataResponse($this->formatShare($share));
1200
-	}
1201
-
1202
-	/**
1203
-	 * @NoAdminRequired
1204
-	 */
1205
-	public function pendingShares(): DataResponse {
1206
-		$pendingShares = [];
1207
-
1208
-		$shareTypes = [
1209
-			IShare::TYPE_USER,
1210
-			IShare::TYPE_GROUP
1211
-		];
1212
-
1213
-		foreach ($shareTypes as $shareType) {
1214
-			$shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1215
-
1216
-			foreach ($shares as $share) {
1217
-				if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1218
-					$pendingShares[] = $share;
1219
-				}
1220
-			}
1221
-		}
1222
-
1223
-		$result = array_filter(array_map(function (IShare $share) {
1224
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1225
-			$nodes = $userFolder->getById($share->getNodeId());
1226
-			if (empty($nodes)) {
1227
-				// fallback to guessing the path
1228
-				$node = $userFolder->get($share->getTarget());
1229
-				if ($node === null || $share->getTarget() === '') {
1230
-					return null;
1231
-				}
1232
-			} else {
1233
-				$node = $nodes[0];
1234
-			}
1235
-
1236
-			try {
1237
-				$formattedShare = $this->formatShare($share, $node);
1238
-				$formattedShare['status'] = $share->getStatus();
1239
-				$formattedShare['path'] = $share->getNode()->getName();
1240
-				$formattedShare['permissions'] = 0;
1241
-				return $formattedShare;
1242
-			} catch (NotFoundException $e) {
1243
-				return null;
1244
-			}
1245
-		}, $pendingShares), function ($entry) {
1246
-			return $entry !== null;
1247
-		});
1248
-
1249
-		return new DataResponse($result);
1250
-	}
1251
-
1252
-	/**
1253
-	 * @NoAdminRequired
1254
-	 *
1255
-	 * @param string $id
1256
-	 * @return DataResponse
1257
-	 * @throws OCSNotFoundException
1258
-	 * @throws OCSException
1259
-	 * @throws OCSBadRequestException
1260
-	 */
1261
-	public function acceptShare(string $id): DataResponse {
1262
-		try {
1263
-			$share = $this->getShareById($id);
1264
-		} catch (ShareNotFound $e) {
1265
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1266
-		}
1267
-
1268
-		if (!$this->canAccessShare($share)) {
1269
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1270
-		}
1271
-
1272
-		try {
1273
-			$this->shareManager->acceptShare($share, $this->currentUser);
1274
-		} catch (GenericShareException $e) {
1275
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1276
-			throw new OCSException($e->getHint(), $code);
1277
-		} catch (\Exception $e) {
1278
-			throw new OCSBadRequestException($e->getMessage(), $e);
1279
-		}
1280
-
1281
-		return new DataResponse();
1282
-	}
1283
-
1284
-	/**
1285
-	 * Does the user have read permission on the share
1286
-	 *
1287
-	 * @param \OCP\Share\IShare $share the share to check
1288
-	 * @param boolean $checkGroups check groups as well?
1289
-	 * @return boolean
1290
-	 * @throws NotFoundException
1291
-	 *
1292
-	 * @suppress PhanUndeclaredClassMethod
1293
-	 */
1294
-	protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1295
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1296
-		if ($share->getPermissions() === 0) {
1297
-			return false;
1298
-		}
1299
-
1300
-		// Owner of the file and the sharer of the file can always get share
1301
-		if ($share->getShareOwner() === $this->currentUser
1302
-			|| $share->getSharedBy() === $this->currentUser) {
1303
-			return true;
1304
-		}
1305
-
1306
-		// If the share is shared with you, you can access it!
1307
-		if ($share->getShareType() === IShare::TYPE_USER
1308
-			&& $share->getSharedWith() === $this->currentUser) {
1309
-			return true;
1310
-		}
1311
-
1312
-		// Have reshare rights on the shared file/folder ?
1313
-		// Does the currentUser have access to the shared file?
1314
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1315
-		$files = $userFolder->getById($share->getNodeId());
1316
-		if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1317
-			return true;
1318
-		}
1319
-
1320
-		// If in the recipient group, you can see the share
1321
-		if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1322
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1323
-			$user = $this->userManager->get($this->currentUser);
1324
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1325
-				return true;
1326
-			}
1327
-		}
1328
-
1329
-		if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1330
-			// TODO: have a sanity check like above?
1331
-			return true;
1332
-		}
1333
-
1334
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1335
-			try {
1336
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1337
-			} catch (QueryException $e) {
1338
-				return false;
1339
-			}
1340
-		}
1341
-
1342
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1343
-			try {
1344
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1345
-			} catch (QueryException $e) {
1346
-				return false;
1347
-			}
1348
-		}
1349
-
1350
-		return false;
1351
-	}
1352
-
1353
-	/**
1354
-	 * Does the user have edit permission on the share
1355
-	 *
1356
-	 * @param \OCP\Share\IShare $share the share to check
1357
-	 * @return boolean
1358
-	 */
1359
-	protected function canEditShare(\OCP\Share\IShare $share): bool {
1360
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1361
-		if ($share->getPermissions() === 0) {
1362
-			return false;
1363
-		}
1364
-
1365
-		// The owner of the file and the creator of the share
1366
-		// can always edit the share
1367
-		if ($share->getShareOwner() === $this->currentUser ||
1368
-			$share->getSharedBy() === $this->currentUser
1369
-		) {
1370
-			return true;
1371
-		}
1372
-
1373
-		//! we do NOT support some kind of `admin` in groups.
1374
-		//! You cannot edit shares shared to a group you're
1375
-		//! a member of if you're not the share owner or the file owner!
1376
-
1377
-		return false;
1378
-	}
1379
-
1380
-	/**
1381
-	 * Does the user have delete permission on the share
1382
-	 *
1383
-	 * @param \OCP\Share\IShare $share the share to check
1384
-	 * @return boolean
1385
-	 */
1386
-	protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1387
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1388
-		if ($share->getPermissions() === 0) {
1389
-			return false;
1390
-		}
1391
-
1392
-		// if the user is the recipient, i can unshare
1393
-		// the share with self
1394
-		if ($share->getShareType() === IShare::TYPE_USER &&
1395
-			$share->getSharedWith() === $this->currentUser
1396
-		) {
1397
-			return true;
1398
-		}
1399
-
1400
-		// The owner of the file and the creator of the share
1401
-		// can always delete the share
1402
-		if ($share->getShareOwner() === $this->currentUser ||
1403
-			$share->getSharedBy() === $this->currentUser
1404
-		) {
1405
-			return true;
1406
-		}
1407
-
1408
-		return false;
1409
-	}
1410
-
1411
-	/**
1412
-	 * Does the user have delete permission on the share
1413
-	 * This differs from the canDeleteShare function as it only
1414
-	 * remove the share for the current user. It does NOT
1415
-	 * completely delete the share but only the mount point.
1416
-	 * It can then be restored from the deleted shares section.
1417
-	 *
1418
-	 * @param \OCP\Share\IShare $share the share to check
1419
-	 * @return boolean
1420
-	 *
1421
-	 * @suppress PhanUndeclaredClassMethod
1422
-	 */
1423
-	protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1424
-		if ($share->getShareType() !== IShare::TYPE_GROUP &&
1425
-			$share->getShareType() !== IShare::TYPE_ROOM &&
1426
-			$share->getShareType() !== IShare::TYPE_DECK
1427
-		) {
1428
-			return false;
1429
-		}
1430
-
1431
-		if ($share->getShareOwner() === $this->currentUser ||
1432
-			$share->getSharedBy() === $this->currentUser
1433
-		) {
1434
-			// Delete the whole share, not just for self
1435
-			return false;
1436
-		}
1437
-
1438
-		// If in the recipient group, you can delete the share from self
1439
-		if ($share->getShareType() === IShare::TYPE_GROUP) {
1440
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1441
-			$user = $this->userManager->get($this->currentUser);
1442
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1443
-				return true;
1444
-			}
1445
-		}
1446
-
1447
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1448
-			try {
1449
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1450
-			} catch (QueryException $e) {
1451
-				return false;
1452
-			}
1453
-		}
1454
-
1455
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1456
-			try {
1457
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1458
-			} catch (QueryException $e) {
1459
-				return false;
1460
-			}
1461
-		}
1462
-
1463
-		return false;
1464
-	}
1465
-
1466
-	/**
1467
-	 * Make sure that the passed date is valid ISO 8601
1468
-	 * So YYYY-MM-DD
1469
-	 * If not throw an exception
1470
-	 *
1471
-	 * @param string $expireDate
1472
-	 *
1473
-	 * @throws \Exception
1474
-	 * @return \DateTime
1475
-	 */
1476
-	private function parseDate(string $expireDate): \DateTime {
1477
-		try {
1478
-			$date = new \DateTime($expireDate);
1479
-		} catch (\Exception $e) {
1480
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1481
-		}
1482
-
1483
-		$date->setTime(0, 0, 0);
1484
-
1485
-		return $date;
1486
-	}
1487
-
1488
-	/**
1489
-	 * Since we have multiple providers but the OCS Share API v1 does
1490
-	 * not support this we need to check all backends.
1491
-	 *
1492
-	 * @param string $id
1493
-	 * @return \OCP\Share\IShare
1494
-	 * @throws ShareNotFound
1495
-	 */
1496
-	private function getShareById(string $id): IShare {
1497
-		$share = null;
1498
-
1499
-		// First check if it is an internal share.
1500
-		try {
1501
-			$share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1502
-			return $share;
1503
-		} catch (ShareNotFound $e) {
1504
-			// Do nothing, just try the other share type
1505
-		}
1506
-
1507
-
1508
-		try {
1509
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_CIRCLE)) {
1510
-				$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1511
-				return $share;
1512
-			}
1513
-		} catch (ShareNotFound $e) {
1514
-			// Do nothing, just try the other share type
1515
-		}
1516
-
1517
-		try {
1518
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
1519
-				$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1520
-				return $share;
1521
-			}
1522
-		} catch (ShareNotFound $e) {
1523
-			// Do nothing, just try the other share type
1524
-		}
1525
-
1526
-		try {
1527
-			$share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1528
-			return $share;
1529
-		} catch (ShareNotFound $e) {
1530
-			// Do nothing, just try the other share type
1531
-		}
1532
-
1533
-		try {
1534
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
1535
-				$share = $this->shareManager->getShareById('deck:' . $id, $this->currentUser);
1536
-				return $share;
1537
-			}
1538
-		} catch (ShareNotFound $e) {
1539
-			// Do nothing, just try the other share type
1540
-		}
1541
-
1542
-		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1543
-			throw new ShareNotFound();
1544
-		}
1545
-		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1546
-
1547
-		return $share;
1548
-	}
1549
-
1550
-	/**
1551
-	 * Lock a Node
1552
-	 *
1553
-	 * @param \OCP\Files\Node $node
1554
-	 * @throws LockedException
1555
-	 */
1556
-	private function lock(\OCP\Files\Node $node) {
1557
-		$node->lock(ILockingProvider::LOCK_SHARED);
1558
-		$this->lockedNode = $node;
1559
-	}
1560
-
1561
-	/**
1562
-	 * Cleanup the remaining locks
1563
-	 * @throws LockedException
1564
-	 */
1565
-	public function cleanup() {
1566
-		if ($this->lockedNode !== null) {
1567
-			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1568
-		}
1569
-	}
1570
-
1571
-	/**
1572
-	 * Returns the helper of ShareAPIController for room shares.
1573
-	 *
1574
-	 * If the Talk application is not enabled or the helper is not available
1575
-	 * a QueryException is thrown instead.
1576
-	 *
1577
-	 * @return \OCA\Talk\Share\Helper\ShareAPIController
1578
-	 * @throws QueryException
1579
-	 */
1580
-	private function getRoomShareHelper() {
1581
-		if (!$this->appManager->isEnabledForUser('spreed')) {
1582
-			throw new QueryException();
1583
-		}
1584
-
1585
-		return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1586
-	}
1587
-
1588
-	/**
1589
-	 * Returns the helper of ShareAPIHelper for deck shares.
1590
-	 *
1591
-	 * If the Deck application is not enabled or the helper is not available
1592
-	 * a QueryException is thrown instead.
1593
-	 *
1594
-	 * @return \OCA\Deck\Sharing\ShareAPIHelper
1595
-	 * @throws QueryException
1596
-	 */
1597
-	private function getDeckShareHelper() {
1598
-		if (!$this->appManager->isEnabledForUser('deck')) {
1599
-			throw new QueryException();
1600
-		}
1601
-
1602
-		return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1603
-	}
1604
-
1605
-	/**
1606
-	 * @param string $viewer
1607
-	 * @param Node $node
1608
-	 * @param bool $reShares
1609
-	 *
1610
-	 * @return IShare[]
1611
-	 */
1612
-	private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1613
-		$providers = [
1614
-			IShare::TYPE_USER,
1615
-			IShare::TYPE_GROUP,
1616
-			IShare::TYPE_LINK,
1617
-			IShare::TYPE_EMAIL,
1618
-			IShare::TYPE_CIRCLE,
1619
-			IShare::TYPE_ROOM,
1620
-			IShare::TYPE_DECK
1621
-		];
1622
-
1623
-		// Should we assume that the (currentUser) viewer is the owner of the node !?
1624
-		$shares = [];
1625
-		foreach ($providers as $provider) {
1626
-			if (!$this->shareManager->shareProviderExists($provider)) {
1627
-				continue;
1628
-			}
1629
-
1630
-			$providerShares =
1631
-				$this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1632
-			$shares = array_merge($shares, $providerShares);
1633
-		}
1634
-
1635
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1636
-			$federatedShares = $this->shareManager->getSharesBy(
1637
-				$this->currentUser, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1638
-			);
1639
-			$shares = array_merge($shares, $federatedShares);
1640
-		}
1641
-
1642
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1643
-			$federatedShares = $this->shareManager->getSharesBy(
1644
-				$this->currentUser, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1645
-			);
1646
-			$shares = array_merge($shares, $federatedShares);
1647
-		}
1648
-
1649
-		return $shares;
1650
-	}
1651
-
1652
-
1653
-	/**
1654
-	 * @param Node $node
1655
-	 *
1656
-	 * @throws SharingRightsException
1657
-	 */
1658
-	private function confirmSharingRights(Node $node): void {
1659
-		if (!$this->hasResharingRights($this->currentUser, $node)) {
1660
-			throw new SharingRightsException('no sharing rights on this item');
1661
-		}
1662
-	}
1663
-
1664
-
1665
-	/**
1666
-	 * @param string $viewer
1667
-	 * @param Node $node
1668
-	 *
1669
-	 * @return bool
1670
-	 */
1671
-	private function hasResharingRights($viewer, $node): bool {
1672
-		if ($viewer === $node->getOwner()->getUID()) {
1673
-			return true;
1674
-		}
1675
-
1676
-		foreach ([$node, $node->getParent()] as $node) {
1677
-			$shares = $this->getSharesFromNode($viewer, $node, true);
1678
-			foreach ($shares as $share) {
1679
-				try {
1680
-					if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1681
-						return true;
1682
-					}
1683
-				} catch (InvalidPathException | NotFoundException $e) {
1684
-				}
1685
-			}
1686
-		}
1687
-
1688
-		return false;
1689
-	}
1690
-
1691
-
1692
-	/**
1693
-	 * Returns if we can find resharing rights in an IShare object for a specific user.
1694
-	 *
1695
-	 * @suppress PhanUndeclaredClassMethod
1696
-	 *
1697
-	 * @param string $userId
1698
-	 * @param IShare $share
1699
-	 * @param Node $node
1700
-	 *
1701
-	 * @return bool
1702
-	 * @throws NotFoundException
1703
-	 * @throws InvalidPathException
1704
-	 */
1705
-	private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1706
-		if ($share->getShareOwner() === $userId) {
1707
-			return true;
1708
-		}
1709
-
1710
-		// we check that current user have parent resharing rights on the current file
1711
-		if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1712
-			return true;
1713
-		}
1714
-
1715
-		if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1716
-			return false;
1717
-		}
1718
-
1719
-		if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1720
-			return true;
1721
-		}
1722
-
1723
-		if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1724
-			return true;
1725
-		}
1726
-
1727
-		if ($share->getShareType() === IShare::TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1728
-			&& class_exists('\OCA\Circles\Api\v1\Circles')) {
1729
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1730
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1731
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1732
-			if ($shareWithLength === false) {
1733
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart);
1734
-			} else {
1735
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1736
-			}
1737
-			try {
1738
-				$member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1739
-				if ($member->getLevel() >= 4) {
1740
-					return true;
1741
-				}
1742
-				return false;
1743
-			} catch (QueryException $e) {
1744
-				return false;
1745
-			}
1746
-		}
1747
-
1748
-		return false;
1749
-	}
1750
-
1751
-	/**
1752
-	 * Get all the shares for the current user
1753
-	 *
1754
-	 * @param Node|null $path
1755
-	 * @param boolean $reshares
1756
-	 * @return IShare[]
1757
-	 */
1758
-	private function getAllShares(?Node $path = null, bool $reshares = false) {
1759
-		// Get all shares
1760
-		$userShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_USER, $path, $reshares, -1, 0);
1761
-		$groupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
1762
-		$linkShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_LINK, $path, $reshares, -1, 0);
1763
-
1764
-		// EMAIL SHARES
1765
-		$mailShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
1766
-
1767
-		// CIRCLE SHARES
1768
-		$circleShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
1769
-
1770
-		// TALK SHARES
1771
-		$roomShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
1772
-
1773
-		$deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0);
1774
-
1775
-		// FEDERATION
1776
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1777
-			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
1778
-		} else {
1779
-			$federatedShares = [];
1780
-		}
1781
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1782
-			$federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1783
-		} else {
1784
-			$federatedGroupShares = [];
1785
-		}
1786
-
1787
-		return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares);
1788
-	}
1789
-
1790
-
1791
-	/**
1792
-	 * merging already formatted shares.
1793
-	 * We'll make an associative array to easily detect duplicate Ids.
1794
-	 * Keys _needs_ to be removed after all shares are retrieved and merged.
1795
-	 *
1796
-	 * @param array $shares
1797
-	 * @param array $newShares
1798
-	 */
1799
-	private function mergeFormattedShares(array &$shares, array $newShares) {
1800
-		foreach ($newShares as $newShare) {
1801
-			if (!array_key_exists($newShare['id'], $shares)) {
1802
-				$shares[$newShare['id']] = $newShare;
1803
-			}
1804
-		}
1805
-	}
861
+                continue;
862
+            }
863
+
864
+            if (in_array($share->getId(), $known)
865
+                || ($share->getSharedWith() === $this->currentUser && $share->getShareType() === IShare::TYPE_USER)) {
866
+                continue;
867
+            }
868
+
869
+            $known[] = $share->getId();
870
+            try {
871
+                /** @var IShare $share */
872
+                $format = $this->formatShare($share, $node);
873
+                $formatted[] = $format;
874
+
875
+                // let's also build a list of shares created
876
+                // by the current user only, in case
877
+                // there is no resharing rights
878
+                if ($share->getSharedBy() === $this->currentUser) {
879
+                    $miniFormatted[] = $format;
880
+                }
881
+
882
+                // check if one of those share is shared with me
883
+                // and if I have resharing rights on it
884
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
885
+                    $resharingRight = true;
886
+                }
887
+            } catch (InvalidPathException | NotFoundException $e) {
888
+            }
889
+        }
890
+
891
+        if (!$resharingRight) {
892
+            $formatted = $miniFormatted;
893
+        }
894
+
895
+        if ($includeTags) {
896
+            $formatted =
897
+                Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
898
+        }
899
+
900
+        return $formatted;
901
+    }
902
+
903
+
904
+    /**
905
+     * The getInheritedShares function.
906
+     * returns all shares relative to a file, including parent folders shares rights.
907
+     *
908
+     * @NoAdminRequired
909
+     *
910
+     * @param string $path
911
+     *
912
+     * - Get shares by the current user
913
+     * - Get shares by the current user and reshares (?reshares=true)
914
+     * - Get shares with the current user (?shared_with_me=true)
915
+     * - Get shares for a specific path (?path=...)
916
+     * - Get all shares in a folder (?subfiles=true&path=..)
917
+     *
918
+     * @return DataResponse
919
+     * @throws InvalidPathException
920
+     * @throws NotFoundException
921
+     * @throws OCSNotFoundException
922
+     * @throws OCSBadRequestException
923
+     * @throws SharingRightsException
924
+     */
925
+    public function getInheritedShares(string $path): DataResponse {
926
+
927
+        // get Node from (string) path.
928
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
929
+        try {
930
+            $node = $userFolder->get($path);
931
+            $this->lock($node);
932
+        } catch (\OCP\Files\NotFoundException $e) {
933
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
934
+        } catch (LockedException $e) {
935
+            throw new OCSNotFoundException($this->l->t('Could not lock path'));
936
+        }
937
+
938
+        if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
939
+            throw new SharingRightsException('no sharing rights on this item');
940
+        }
941
+
942
+        // The current top parent we have access to
943
+        $parent = $node;
944
+
945
+        // initiate real owner.
946
+        $owner = $node->getOwner()
947
+                        ->getUID();
948
+        if (!$this->userManager->userExists($owner)) {
949
+            return new DataResponse([]);
950
+        }
951
+
952
+        // get node based on the owner, fix owner in case of external storage
953
+        $userFolder = $this->rootFolder->getUserFolder($owner);
954
+        if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
955
+            $owner = $node->getOwner()
956
+                            ->getUID();
957
+            $userFolder = $this->rootFolder->getUserFolder($owner);
958
+            $nodes = $userFolder->getById($node->getId());
959
+            $node = array_shift($nodes);
960
+        }
961
+        $basePath = $userFolder->getPath();
962
+
963
+        // generate node list for each parent folders
964
+        /** @var Node[] $nodes */
965
+        $nodes = [];
966
+        while ($node->getPath() !== $basePath) {
967
+            $node = $node->getParent();
968
+            $nodes[] = $node;
969
+        }
970
+
971
+        // The user that is requesting this list
972
+        $currentUserFolder = $this->rootFolder->getUserFolder($this->currentUser);
973
+
974
+        // for each nodes, retrieve shares.
975
+        $shares = [];
976
+
977
+        foreach ($nodes as $node) {
978
+            $getShares = $this->getFormattedShares($owner, $node, false, true);
979
+
980
+            $currentUserNodes = $currentUserFolder->getById($node->getId());
981
+            if (!empty($currentUserNodes)) {
982
+                $parent = array_pop($currentUserNodes);
983
+            }
984
+
985
+            $subPath = $currentUserFolder->getRelativePath($parent->getPath());
986
+            foreach ($getShares as &$share) {
987
+                $share['via_fileid'] = $parent->getId();
988
+                $share['via_path'] = $subPath;
989
+            }
990
+            $this->mergeFormattedShares($shares, $getShares);
991
+        }
992
+
993
+        return new DataResponse(array_values($shares));
994
+    }
995
+
996
+
997
+    /**
998
+     * @NoAdminRequired
999
+     *
1000
+     * @param string $id
1001
+     * @param int $permissions
1002
+     * @param string $password
1003
+     * @param string $sendPasswordByTalk
1004
+     * @param string $publicUpload
1005
+     * @param string $expireDate
1006
+     * @param string $note
1007
+     * @param string $label
1008
+     * @param string $hideDownload
1009
+     * @return DataResponse
1010
+     * @throws LockedException
1011
+     * @throws NotFoundException
1012
+     * @throws OCSBadRequestException
1013
+     * @throws OCSForbiddenException
1014
+     * @throws OCSNotFoundException
1015
+     */
1016
+    public function updateShare(
1017
+        string $id,
1018
+        int $permissions = null,
1019
+        string $password = null,
1020
+        string $sendPasswordByTalk = null,
1021
+        string $publicUpload = null,
1022
+        string $expireDate = null,
1023
+        string $note = null,
1024
+        string $label = null,
1025
+        string $hideDownload = null
1026
+    ): DataResponse {
1027
+        try {
1028
+            $share = $this->getShareById($id);
1029
+        } catch (ShareNotFound $e) {
1030
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1031
+        }
1032
+
1033
+        $this->lock($share->getNode());
1034
+
1035
+        if (!$this->canAccessShare($share, false)) {
1036
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1037
+        }
1038
+
1039
+        if (!$this->canEditShare($share)) {
1040
+            throw new OCSForbiddenException('You are not allowed to edit incoming shares');
1041
+        }
1042
+
1043
+        if (
1044
+            $permissions === null &&
1045
+            $password === null &&
1046
+            $sendPasswordByTalk === null &&
1047
+            $publicUpload === null &&
1048
+            $expireDate === null &&
1049
+            $note === null &&
1050
+            $label === null &&
1051
+            $hideDownload === null
1052
+        ) {
1053
+            throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1054
+        }
1055
+
1056
+        if ($note !== null) {
1057
+            $share->setNote($note);
1058
+        }
1059
+
1060
+        /**
1061
+         * expirationdate, password and publicUpload only make sense for link shares
1062
+         */
1063
+        if ($share->getShareType() === IShare::TYPE_LINK
1064
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
1065
+
1066
+            /**
1067
+             * We do not allow editing link shares that the current user
1068
+             * doesn't own. This is confusing and lead to errors when
1069
+             * someone else edit a password or expiration date without
1070
+             * the share owner knowing about it.
1071
+             * We only allow deletion
1072
+             */
1073
+
1074
+            if ($share->getSharedBy() !== $this->currentUser) {
1075
+                throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
1076
+            }
1077
+
1078
+            // Update hide download state
1079
+            if ($hideDownload === 'true') {
1080
+                $share->setHideDownload(true);
1081
+            } elseif ($hideDownload === 'false') {
1082
+                $share->setHideDownload(false);
1083
+            }
1084
+
1085
+            $newPermissions = null;
1086
+            if ($publicUpload === 'true') {
1087
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1088
+            } elseif ($publicUpload === 'false') {
1089
+                $newPermissions = Constants::PERMISSION_READ;
1090
+            }
1091
+
1092
+            if ($permissions !== null) {
1093
+                $newPermissions = $permissions;
1094
+                $newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
1095
+            }
1096
+
1097
+            if ($newPermissions !== null &&
1098
+                !in_array($newPermissions, [
1099
+                    Constants::PERMISSION_READ,
1100
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
1101
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
1102
+                    Constants::PERMISSION_CREATE, // hidden file list
1103
+                    Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1104
+                ], true)
1105
+            ) {
1106
+                throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1107
+            }
1108
+
1109
+            if (
1110
+                // legacy
1111
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1112
+                // correct
1113
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1114
+            ) {
1115
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1116
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1117
+                }
1118
+
1119
+                if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1120
+                    throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1121
+                }
1122
+
1123
+                // normalize to correct public upload permissions
1124
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1125
+            }
1126
+
1127
+            if ($newPermissions !== null) {
1128
+                // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
1129
+                if (($newPermissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
1130
+                    $newPermissions |= Constants::PERMISSION_SHARE;
1131
+                }
1132
+
1133
+                $share->setPermissions($newPermissions);
1134
+                $permissions = $newPermissions;
1135
+            }
1136
+
1137
+            if ($expireDate === '') {
1138
+                $share->setExpirationDate(null);
1139
+            } elseif ($expireDate !== null) {
1140
+                try {
1141
+                    $expireDate = $this->parseDate($expireDate);
1142
+                } catch (\Exception $e) {
1143
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1144
+                }
1145
+                $share->setExpirationDate($expireDate);
1146
+            }
1147
+
1148
+            if ($password === '') {
1149
+                $share->setPassword(null);
1150
+            } elseif ($password !== null) {
1151
+                $share->setPassword($password);
1152
+            }
1153
+
1154
+            if ($label !== null) {
1155
+                if (strlen($label) > 255) {
1156
+                    throw new OCSBadRequestException("Maxmimum label length is 255");
1157
+                }
1158
+                $share->setLabel($label);
1159
+            }
1160
+
1161
+            if ($sendPasswordByTalk === 'true') {
1162
+                if (!$this->appManager->isEnabledForUser('spreed')) {
1163
+                    throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1164
+                }
1165
+
1166
+                $share->setSendPasswordByTalk(true);
1167
+            } elseif ($sendPasswordByTalk !== null) {
1168
+                $share->setSendPasswordByTalk(false);
1169
+            }
1170
+        }
1171
+
1172
+        // NOT A LINK SHARE
1173
+        else {
1174
+            if ($permissions !== null) {
1175
+                $share->setPermissions($permissions);
1176
+            }
1177
+
1178
+            if ($expireDate === '') {
1179
+                $share->setExpirationDate(null);
1180
+            } elseif ($expireDate !== null) {
1181
+                try {
1182
+                    $expireDate = $this->parseDate($expireDate);
1183
+                } catch (\Exception $e) {
1184
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1185
+                }
1186
+                $share->setExpirationDate($expireDate);
1187
+            }
1188
+        }
1189
+
1190
+        try {
1191
+            $share = $this->shareManager->updateShare($share);
1192
+        } catch (GenericShareException $e) {
1193
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1194
+            throw new OCSException($e->getHint(), $code);
1195
+        } catch (\Exception $e) {
1196
+            throw new OCSBadRequestException($e->getMessage(), $e);
1197
+        }
1198
+
1199
+        return new DataResponse($this->formatShare($share));
1200
+    }
1201
+
1202
+    /**
1203
+     * @NoAdminRequired
1204
+     */
1205
+    public function pendingShares(): DataResponse {
1206
+        $pendingShares = [];
1207
+
1208
+        $shareTypes = [
1209
+            IShare::TYPE_USER,
1210
+            IShare::TYPE_GROUP
1211
+        ];
1212
+
1213
+        foreach ($shareTypes as $shareType) {
1214
+            $shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1215
+
1216
+            foreach ($shares as $share) {
1217
+                if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1218
+                    $pendingShares[] = $share;
1219
+                }
1220
+            }
1221
+        }
1222
+
1223
+        $result = array_filter(array_map(function (IShare $share) {
1224
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1225
+            $nodes = $userFolder->getById($share->getNodeId());
1226
+            if (empty($nodes)) {
1227
+                // fallback to guessing the path
1228
+                $node = $userFolder->get($share->getTarget());
1229
+                if ($node === null || $share->getTarget() === '') {
1230
+                    return null;
1231
+                }
1232
+            } else {
1233
+                $node = $nodes[0];
1234
+            }
1235
+
1236
+            try {
1237
+                $formattedShare = $this->formatShare($share, $node);
1238
+                $formattedShare['status'] = $share->getStatus();
1239
+                $formattedShare['path'] = $share->getNode()->getName();
1240
+                $formattedShare['permissions'] = 0;
1241
+                return $formattedShare;
1242
+            } catch (NotFoundException $e) {
1243
+                return null;
1244
+            }
1245
+        }, $pendingShares), function ($entry) {
1246
+            return $entry !== null;
1247
+        });
1248
+
1249
+        return new DataResponse($result);
1250
+    }
1251
+
1252
+    /**
1253
+     * @NoAdminRequired
1254
+     *
1255
+     * @param string $id
1256
+     * @return DataResponse
1257
+     * @throws OCSNotFoundException
1258
+     * @throws OCSException
1259
+     * @throws OCSBadRequestException
1260
+     */
1261
+    public function acceptShare(string $id): DataResponse {
1262
+        try {
1263
+            $share = $this->getShareById($id);
1264
+        } catch (ShareNotFound $e) {
1265
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1266
+        }
1267
+
1268
+        if (!$this->canAccessShare($share)) {
1269
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1270
+        }
1271
+
1272
+        try {
1273
+            $this->shareManager->acceptShare($share, $this->currentUser);
1274
+        } catch (GenericShareException $e) {
1275
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1276
+            throw new OCSException($e->getHint(), $code);
1277
+        } catch (\Exception $e) {
1278
+            throw new OCSBadRequestException($e->getMessage(), $e);
1279
+        }
1280
+
1281
+        return new DataResponse();
1282
+    }
1283
+
1284
+    /**
1285
+     * Does the user have read permission on the share
1286
+     *
1287
+     * @param \OCP\Share\IShare $share the share to check
1288
+     * @param boolean $checkGroups check groups as well?
1289
+     * @return boolean
1290
+     * @throws NotFoundException
1291
+     *
1292
+     * @suppress PhanUndeclaredClassMethod
1293
+     */
1294
+    protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1295
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1296
+        if ($share->getPermissions() === 0) {
1297
+            return false;
1298
+        }
1299
+
1300
+        // Owner of the file and the sharer of the file can always get share
1301
+        if ($share->getShareOwner() === $this->currentUser
1302
+            || $share->getSharedBy() === $this->currentUser) {
1303
+            return true;
1304
+        }
1305
+
1306
+        // If the share is shared with you, you can access it!
1307
+        if ($share->getShareType() === IShare::TYPE_USER
1308
+            && $share->getSharedWith() === $this->currentUser) {
1309
+            return true;
1310
+        }
1311
+
1312
+        // Have reshare rights on the shared file/folder ?
1313
+        // Does the currentUser have access to the shared file?
1314
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1315
+        $files = $userFolder->getById($share->getNodeId());
1316
+        if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1317
+            return true;
1318
+        }
1319
+
1320
+        // If in the recipient group, you can see the share
1321
+        if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1322
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1323
+            $user = $this->userManager->get($this->currentUser);
1324
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1325
+                return true;
1326
+            }
1327
+        }
1328
+
1329
+        if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1330
+            // TODO: have a sanity check like above?
1331
+            return true;
1332
+        }
1333
+
1334
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1335
+            try {
1336
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1337
+            } catch (QueryException $e) {
1338
+                return false;
1339
+            }
1340
+        }
1341
+
1342
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1343
+            try {
1344
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1345
+            } catch (QueryException $e) {
1346
+                return false;
1347
+            }
1348
+        }
1349
+
1350
+        return false;
1351
+    }
1352
+
1353
+    /**
1354
+     * Does the user have edit permission on the share
1355
+     *
1356
+     * @param \OCP\Share\IShare $share the share to check
1357
+     * @return boolean
1358
+     */
1359
+    protected function canEditShare(\OCP\Share\IShare $share): bool {
1360
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1361
+        if ($share->getPermissions() === 0) {
1362
+            return false;
1363
+        }
1364
+
1365
+        // The owner of the file and the creator of the share
1366
+        // can always edit the share
1367
+        if ($share->getShareOwner() === $this->currentUser ||
1368
+            $share->getSharedBy() === $this->currentUser
1369
+        ) {
1370
+            return true;
1371
+        }
1372
+
1373
+        //! we do NOT support some kind of `admin` in groups.
1374
+        //! You cannot edit shares shared to a group you're
1375
+        //! a member of if you're not the share owner or the file owner!
1376
+
1377
+        return false;
1378
+    }
1379
+
1380
+    /**
1381
+     * Does the user have delete permission on the share
1382
+     *
1383
+     * @param \OCP\Share\IShare $share the share to check
1384
+     * @return boolean
1385
+     */
1386
+    protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1387
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1388
+        if ($share->getPermissions() === 0) {
1389
+            return false;
1390
+        }
1391
+
1392
+        // if the user is the recipient, i can unshare
1393
+        // the share with self
1394
+        if ($share->getShareType() === IShare::TYPE_USER &&
1395
+            $share->getSharedWith() === $this->currentUser
1396
+        ) {
1397
+            return true;
1398
+        }
1399
+
1400
+        // The owner of the file and the creator of the share
1401
+        // can always delete the share
1402
+        if ($share->getShareOwner() === $this->currentUser ||
1403
+            $share->getSharedBy() === $this->currentUser
1404
+        ) {
1405
+            return true;
1406
+        }
1407
+
1408
+        return false;
1409
+    }
1410
+
1411
+    /**
1412
+     * Does the user have delete permission on the share
1413
+     * This differs from the canDeleteShare function as it only
1414
+     * remove the share for the current user. It does NOT
1415
+     * completely delete the share but only the mount point.
1416
+     * It can then be restored from the deleted shares section.
1417
+     *
1418
+     * @param \OCP\Share\IShare $share the share to check
1419
+     * @return boolean
1420
+     *
1421
+     * @suppress PhanUndeclaredClassMethod
1422
+     */
1423
+    protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1424
+        if ($share->getShareType() !== IShare::TYPE_GROUP &&
1425
+            $share->getShareType() !== IShare::TYPE_ROOM &&
1426
+            $share->getShareType() !== IShare::TYPE_DECK
1427
+        ) {
1428
+            return false;
1429
+        }
1430
+
1431
+        if ($share->getShareOwner() === $this->currentUser ||
1432
+            $share->getSharedBy() === $this->currentUser
1433
+        ) {
1434
+            // Delete the whole share, not just for self
1435
+            return false;
1436
+        }
1437
+
1438
+        // If in the recipient group, you can delete the share from self
1439
+        if ($share->getShareType() === IShare::TYPE_GROUP) {
1440
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1441
+            $user = $this->userManager->get($this->currentUser);
1442
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1443
+                return true;
1444
+            }
1445
+        }
1446
+
1447
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1448
+            try {
1449
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1450
+            } catch (QueryException $e) {
1451
+                return false;
1452
+            }
1453
+        }
1454
+
1455
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1456
+            try {
1457
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1458
+            } catch (QueryException $e) {
1459
+                return false;
1460
+            }
1461
+        }
1462
+
1463
+        return false;
1464
+    }
1465
+
1466
+    /**
1467
+     * Make sure that the passed date is valid ISO 8601
1468
+     * So YYYY-MM-DD
1469
+     * If not throw an exception
1470
+     *
1471
+     * @param string $expireDate
1472
+     *
1473
+     * @throws \Exception
1474
+     * @return \DateTime
1475
+     */
1476
+    private function parseDate(string $expireDate): \DateTime {
1477
+        try {
1478
+            $date = new \DateTime($expireDate);
1479
+        } catch (\Exception $e) {
1480
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1481
+        }
1482
+
1483
+        $date->setTime(0, 0, 0);
1484
+
1485
+        return $date;
1486
+    }
1487
+
1488
+    /**
1489
+     * Since we have multiple providers but the OCS Share API v1 does
1490
+     * not support this we need to check all backends.
1491
+     *
1492
+     * @param string $id
1493
+     * @return \OCP\Share\IShare
1494
+     * @throws ShareNotFound
1495
+     */
1496
+    private function getShareById(string $id): IShare {
1497
+        $share = null;
1498
+
1499
+        // First check if it is an internal share.
1500
+        try {
1501
+            $share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1502
+            return $share;
1503
+        } catch (ShareNotFound $e) {
1504
+            // Do nothing, just try the other share type
1505
+        }
1506
+
1507
+
1508
+        try {
1509
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_CIRCLE)) {
1510
+                $share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1511
+                return $share;
1512
+            }
1513
+        } catch (ShareNotFound $e) {
1514
+            // Do nothing, just try the other share type
1515
+        }
1516
+
1517
+        try {
1518
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
1519
+                $share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1520
+                return $share;
1521
+            }
1522
+        } catch (ShareNotFound $e) {
1523
+            // Do nothing, just try the other share type
1524
+        }
1525
+
1526
+        try {
1527
+            $share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1528
+            return $share;
1529
+        } catch (ShareNotFound $e) {
1530
+            // Do nothing, just try the other share type
1531
+        }
1532
+
1533
+        try {
1534
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
1535
+                $share = $this->shareManager->getShareById('deck:' . $id, $this->currentUser);
1536
+                return $share;
1537
+            }
1538
+        } catch (ShareNotFound $e) {
1539
+            // Do nothing, just try the other share type
1540
+        }
1541
+
1542
+        if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1543
+            throw new ShareNotFound();
1544
+        }
1545
+        $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1546
+
1547
+        return $share;
1548
+    }
1549
+
1550
+    /**
1551
+     * Lock a Node
1552
+     *
1553
+     * @param \OCP\Files\Node $node
1554
+     * @throws LockedException
1555
+     */
1556
+    private function lock(\OCP\Files\Node $node) {
1557
+        $node->lock(ILockingProvider::LOCK_SHARED);
1558
+        $this->lockedNode = $node;
1559
+    }
1560
+
1561
+    /**
1562
+     * Cleanup the remaining locks
1563
+     * @throws LockedException
1564
+     */
1565
+    public function cleanup() {
1566
+        if ($this->lockedNode !== null) {
1567
+            $this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1568
+        }
1569
+    }
1570
+
1571
+    /**
1572
+     * Returns the helper of ShareAPIController for room shares.
1573
+     *
1574
+     * If the Talk application is not enabled or the helper is not available
1575
+     * a QueryException is thrown instead.
1576
+     *
1577
+     * @return \OCA\Talk\Share\Helper\ShareAPIController
1578
+     * @throws QueryException
1579
+     */
1580
+    private function getRoomShareHelper() {
1581
+        if (!$this->appManager->isEnabledForUser('spreed')) {
1582
+            throw new QueryException();
1583
+        }
1584
+
1585
+        return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1586
+    }
1587
+
1588
+    /**
1589
+     * Returns the helper of ShareAPIHelper for deck shares.
1590
+     *
1591
+     * If the Deck application is not enabled or the helper is not available
1592
+     * a QueryException is thrown instead.
1593
+     *
1594
+     * @return \OCA\Deck\Sharing\ShareAPIHelper
1595
+     * @throws QueryException
1596
+     */
1597
+    private function getDeckShareHelper() {
1598
+        if (!$this->appManager->isEnabledForUser('deck')) {
1599
+            throw new QueryException();
1600
+        }
1601
+
1602
+        return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1603
+    }
1604
+
1605
+    /**
1606
+     * @param string $viewer
1607
+     * @param Node $node
1608
+     * @param bool $reShares
1609
+     *
1610
+     * @return IShare[]
1611
+     */
1612
+    private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1613
+        $providers = [
1614
+            IShare::TYPE_USER,
1615
+            IShare::TYPE_GROUP,
1616
+            IShare::TYPE_LINK,
1617
+            IShare::TYPE_EMAIL,
1618
+            IShare::TYPE_CIRCLE,
1619
+            IShare::TYPE_ROOM,
1620
+            IShare::TYPE_DECK
1621
+        ];
1622
+
1623
+        // Should we assume that the (currentUser) viewer is the owner of the node !?
1624
+        $shares = [];
1625
+        foreach ($providers as $provider) {
1626
+            if (!$this->shareManager->shareProviderExists($provider)) {
1627
+                continue;
1628
+            }
1629
+
1630
+            $providerShares =
1631
+                $this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1632
+            $shares = array_merge($shares, $providerShares);
1633
+        }
1634
+
1635
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1636
+            $federatedShares = $this->shareManager->getSharesBy(
1637
+                $this->currentUser, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1638
+            );
1639
+            $shares = array_merge($shares, $federatedShares);
1640
+        }
1641
+
1642
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1643
+            $federatedShares = $this->shareManager->getSharesBy(
1644
+                $this->currentUser, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1645
+            );
1646
+            $shares = array_merge($shares, $federatedShares);
1647
+        }
1648
+
1649
+        return $shares;
1650
+    }
1651
+
1652
+
1653
+    /**
1654
+     * @param Node $node
1655
+     *
1656
+     * @throws SharingRightsException
1657
+     */
1658
+    private function confirmSharingRights(Node $node): void {
1659
+        if (!$this->hasResharingRights($this->currentUser, $node)) {
1660
+            throw new SharingRightsException('no sharing rights on this item');
1661
+        }
1662
+    }
1663
+
1664
+
1665
+    /**
1666
+     * @param string $viewer
1667
+     * @param Node $node
1668
+     *
1669
+     * @return bool
1670
+     */
1671
+    private function hasResharingRights($viewer, $node): bool {
1672
+        if ($viewer === $node->getOwner()->getUID()) {
1673
+            return true;
1674
+        }
1675
+
1676
+        foreach ([$node, $node->getParent()] as $node) {
1677
+            $shares = $this->getSharesFromNode($viewer, $node, true);
1678
+            foreach ($shares as $share) {
1679
+                try {
1680
+                    if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1681
+                        return true;
1682
+                    }
1683
+                } catch (InvalidPathException | NotFoundException $e) {
1684
+                }
1685
+            }
1686
+        }
1687
+
1688
+        return false;
1689
+    }
1690
+
1691
+
1692
+    /**
1693
+     * Returns if we can find resharing rights in an IShare object for a specific user.
1694
+     *
1695
+     * @suppress PhanUndeclaredClassMethod
1696
+     *
1697
+     * @param string $userId
1698
+     * @param IShare $share
1699
+     * @param Node $node
1700
+     *
1701
+     * @return bool
1702
+     * @throws NotFoundException
1703
+     * @throws InvalidPathException
1704
+     */
1705
+    private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1706
+        if ($share->getShareOwner() === $userId) {
1707
+            return true;
1708
+        }
1709
+
1710
+        // we check that current user have parent resharing rights on the current file
1711
+        if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1712
+            return true;
1713
+        }
1714
+
1715
+        if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1716
+            return false;
1717
+        }
1718
+
1719
+        if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1720
+            return true;
1721
+        }
1722
+
1723
+        if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1724
+            return true;
1725
+        }
1726
+
1727
+        if ($share->getShareType() === IShare::TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1728
+            && class_exists('\OCA\Circles\Api\v1\Circles')) {
1729
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1730
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1731
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1732
+            if ($shareWithLength === false) {
1733
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart);
1734
+            } else {
1735
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1736
+            }
1737
+            try {
1738
+                $member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1739
+                if ($member->getLevel() >= 4) {
1740
+                    return true;
1741
+                }
1742
+                return false;
1743
+            } catch (QueryException $e) {
1744
+                return false;
1745
+            }
1746
+        }
1747
+
1748
+        return false;
1749
+    }
1750
+
1751
+    /**
1752
+     * Get all the shares for the current user
1753
+     *
1754
+     * @param Node|null $path
1755
+     * @param boolean $reshares
1756
+     * @return IShare[]
1757
+     */
1758
+    private function getAllShares(?Node $path = null, bool $reshares = false) {
1759
+        // Get all shares
1760
+        $userShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_USER, $path, $reshares, -1, 0);
1761
+        $groupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
1762
+        $linkShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_LINK, $path, $reshares, -1, 0);
1763
+
1764
+        // EMAIL SHARES
1765
+        $mailShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
1766
+
1767
+        // CIRCLE SHARES
1768
+        $circleShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
1769
+
1770
+        // TALK SHARES
1771
+        $roomShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
1772
+
1773
+        $deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0);
1774
+
1775
+        // FEDERATION
1776
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1777
+            $federatedShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
1778
+        } else {
1779
+            $federatedShares = [];
1780
+        }
1781
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1782
+            $federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1783
+        } else {
1784
+            $federatedGroupShares = [];
1785
+        }
1786
+
1787
+        return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares);
1788
+    }
1789
+
1790
+
1791
+    /**
1792
+     * merging already formatted shares.
1793
+     * We'll make an associative array to easily detect duplicate Ids.
1794
+     * Keys _needs_ to be removed after all shares are retrieved and merged.
1795
+     *
1796
+     * @param array $shares
1797
+     * @param array $newShares
1798
+     */
1799
+    private function mergeFormattedShares(array &$shares, array $newShares) {
1800
+        foreach ($newShares as $newShare) {
1801
+            if (!array_key_exists($newShare['id'], $shares)) {
1802
+                $shares[$newShare['id']] = $newShare;
1803
+            }
1804
+        }
1805
+    }
1806 1806
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/Capabilities.php 1 patch
Indentation   +98 added lines, -98 removed lines patch added patch discarded remove patch
@@ -36,102 +36,102 @@
 block discarded – undo
36 36
  */
37 37
 class Capabilities implements ICapability {
38 38
 
39
-	/** @var IConfig */
40
-	private $config;
41
-
42
-	public function __construct(IConfig $config) {
43
-		$this->config = $config;
44
-	}
45
-
46
-	/**
47
-	 * Return this classes capabilities
48
-	 *
49
-	 * @return array
50
-	 */
51
-	public function getCapabilities() {
52
-		$res = [];
53
-
54
-		if ($this->config->getAppValue('core', 'shareapi_enabled', 'yes') !== 'yes') {
55
-			$res['api_enabled'] = false;
56
-			$res['public'] = ['enabled' => false];
57
-			$res['user'] = ['send_mail' => false];
58
-			$res['resharing'] = false;
59
-		} else {
60
-			$res['api_enabled'] = true;
61
-
62
-			$public = [];
63
-			$public['enabled'] = $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
64
-			if ($public['enabled']) {
65
-				$public['password'] = [];
66
-				$public['password']['enforced'] = ($this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes');
67
-
68
-				if ($public['password']['enforced']) {
69
-					$public['password']['askForOptionalPassword'] = false;
70
-				} else {
71
-					$public['password']['askForOptionalPassword'] = ($this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no') === 'yes');
72
-				}
73
-
74
-				$public['expire_date'] = [];
75
-				$public['multiple_links'] = true;
76
-				$public['expire_date']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
77
-				if ($public['expire_date']['enabled']) {
78
-					$public['expire_date']['days'] = $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
79
-					$public['expire_date']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
80
-				}
81
-
82
-				$public['expire_date_internal'] = [];
83
-				$public['expire_date_internal']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
84
-				if ($public['expire_date_internal']['enabled']) {
85
-					$public['expire_date_internal']['days'] = $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
86
-					$public['expire_date_internal']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
87
-				}
88
-
89
-				$public['expire_date_remote'] = [];
90
-				$public['expire_date_remote']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no') === 'yes';
91
-				if ($public['expire_date_remote']['enabled']) {
92
-					$public['expire_date_remote']['days'] = $this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
93
-					$public['expire_date_remote']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes';
94
-				}
95
-
96
-				$public['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'no') === 'yes';
97
-				$public['upload'] = $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
98
-				$public['upload_files_drop'] = $public['upload'];
99
-			}
100
-			$res['public'] = $public;
101
-
102
-			$res['resharing'] = $this->config->getAppValue('core', 'shareapi_allow_resharing', 'yes') === 'yes';
103
-
104
-			$res['user']['send_mail'] = false;
105
-			$res['user']['expire_date']['enabled'] = true;
106
-
107
-			// deprecated in favour of 'group', but we need to keep it for now
108
-			// in order to stay compatible with older clients
109
-			$res['group_sharing'] = $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
110
-
111
-			$res['group'] = [];
112
-			$res['group']['enabled'] = $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
113
-			$res['group']['expire_date']['enabled'] = true;
114
-			$res['default_permissions'] = (int)$this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
115
-		}
116
-
117
-		//Federated sharing
118
-		$res['federation'] = [
119
-			'outgoing' => $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes',
120
-			'incoming' => $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'yes',
121
-			// old bogus one, expire_date was not working before, keeping for compatibility
122
-			'expire_date' => ['enabled' => true],
123
-			// the real deal, signifies that expiration date can be set on federated shares
124
-			'expire_date_supported' => ['enabled' => true],
125
-		];
126
-
127
-		// Sharee searches
128
-		$res['sharee'] = [
129
-			'query_lookup_default' => $this->config->getSystemValueBool('gs.enabled', false),
130
-			'always_show_unique' => $this->config->getAppValue('files_sharing', 'always_show_unique', 'yes') === 'yes',
131
-		];
132
-
133
-		return [
134
-			'files_sharing' => $res,
135
-		];
136
-	}
39
+    /** @var IConfig */
40
+    private $config;
41
+
42
+    public function __construct(IConfig $config) {
43
+        $this->config = $config;
44
+    }
45
+
46
+    /**
47
+     * Return this classes capabilities
48
+     *
49
+     * @return array
50
+     */
51
+    public function getCapabilities() {
52
+        $res = [];
53
+
54
+        if ($this->config->getAppValue('core', 'shareapi_enabled', 'yes') !== 'yes') {
55
+            $res['api_enabled'] = false;
56
+            $res['public'] = ['enabled' => false];
57
+            $res['user'] = ['send_mail' => false];
58
+            $res['resharing'] = false;
59
+        } else {
60
+            $res['api_enabled'] = true;
61
+
62
+            $public = [];
63
+            $public['enabled'] = $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
64
+            if ($public['enabled']) {
65
+                $public['password'] = [];
66
+                $public['password']['enforced'] = ($this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes');
67
+
68
+                if ($public['password']['enforced']) {
69
+                    $public['password']['askForOptionalPassword'] = false;
70
+                } else {
71
+                    $public['password']['askForOptionalPassword'] = ($this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no') === 'yes');
72
+                }
73
+
74
+                $public['expire_date'] = [];
75
+                $public['multiple_links'] = true;
76
+                $public['expire_date']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
77
+                if ($public['expire_date']['enabled']) {
78
+                    $public['expire_date']['days'] = $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
79
+                    $public['expire_date']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
80
+                }
81
+
82
+                $public['expire_date_internal'] = [];
83
+                $public['expire_date_internal']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
84
+                if ($public['expire_date_internal']['enabled']) {
85
+                    $public['expire_date_internal']['days'] = $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
86
+                    $public['expire_date_internal']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
87
+                }
88
+
89
+                $public['expire_date_remote'] = [];
90
+                $public['expire_date_remote']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_remote_expire_date', 'no') === 'yes';
91
+                if ($public['expire_date_remote']['enabled']) {
92
+                    $public['expire_date_remote']['days'] = $this->config->getAppValue('core', 'shareapi_remote_expire_after_n_days', '7');
93
+                    $public['expire_date_remote']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_remote_expire_date', 'no') === 'yes';
94
+                }
95
+
96
+                $public['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'no') === 'yes';
97
+                $public['upload'] = $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
98
+                $public['upload_files_drop'] = $public['upload'];
99
+            }
100
+            $res['public'] = $public;
101
+
102
+            $res['resharing'] = $this->config->getAppValue('core', 'shareapi_allow_resharing', 'yes') === 'yes';
103
+
104
+            $res['user']['send_mail'] = false;
105
+            $res['user']['expire_date']['enabled'] = true;
106
+
107
+            // deprecated in favour of 'group', but we need to keep it for now
108
+            // in order to stay compatible with older clients
109
+            $res['group_sharing'] = $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
110
+
111
+            $res['group'] = [];
112
+            $res['group']['enabled'] = $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
113
+            $res['group']['expire_date']['enabled'] = true;
114
+            $res['default_permissions'] = (int)$this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
115
+        }
116
+
117
+        //Federated sharing
118
+        $res['federation'] = [
119
+            'outgoing' => $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes',
120
+            'incoming' => $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'yes',
121
+            // old bogus one, expire_date was not working before, keeping for compatibility
122
+            'expire_date' => ['enabled' => true],
123
+            // the real deal, signifies that expiration date can be set on federated shares
124
+            'expire_date_supported' => ['enabled' => true],
125
+        ];
126
+
127
+        // Sharee searches
128
+        $res['sharee'] = [
129
+            'query_lookup_default' => $this->config->getSystemValueBool('gs.enabled', false),
130
+            'always_show_unique' => $this->config->getAppValue('files_sharing', 'always_show_unique', 'yes') === 'yes',
131
+        ];
132
+
133
+        return [
134
+            'files_sharing' => $res,
135
+        ];
136
+    }
137 137
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/lib/FederatedShareProvider.php 2 patches
Indentation   +1069 added lines, -1069 removed lines patch added patch discarded remove patch
@@ -61,1083 +61,1083 @@
 block discarded – undo
61 61
  * @package OCA\FederatedFileSharing
62 62
  */
63 63
 class FederatedShareProvider implements IShareProvider {
64
-	public const SHARE_TYPE_REMOTE = 6;
65
-
66
-	/** @var IDBConnection */
67
-	private $dbConnection;
68
-
69
-	/** @var AddressHandler */
70
-	private $addressHandler;
71
-
72
-	/** @var Notifications */
73
-	private $notifications;
74
-
75
-	/** @var TokenHandler */
76
-	private $tokenHandler;
77
-
78
-	/** @var IL10N */
79
-	private $l;
80
-
81
-	/** @var ILogger */
82
-	private $logger;
83
-
84
-	/** @var IRootFolder */
85
-	private $rootFolder;
86
-
87
-	/** @var IConfig */
88
-	private $config;
89
-
90
-	/** @var string */
91
-	private $externalShareTable = 'share_external';
92
-
93
-	/** @var IUserManager */
94
-	private $userManager;
95
-
96
-	/** @var ICloudIdManager */
97
-	private $cloudIdManager;
98
-
99
-	/** @var \OCP\GlobalScale\IConfig */
100
-	private $gsConfig;
101
-
102
-	/** @var ICloudFederationProviderManager */
103
-	private $cloudFederationProviderManager;
104
-
105
-	/** @var array list of supported share types */
106
-	private $supportedShareType = [IShare::TYPE_REMOTE_GROUP, IShare::TYPE_REMOTE, IShare::TYPE_CIRCLE];
107
-
108
-	/**
109
-	 * DefaultShareProvider constructor.
110
-	 *
111
-	 * @param IDBConnection $connection
112
-	 * @param AddressHandler $addressHandler
113
-	 * @param Notifications $notifications
114
-	 * @param TokenHandler $tokenHandler
115
-	 * @param IL10N $l10n
116
-	 * @param ILogger $logger
117
-	 * @param IRootFolder $rootFolder
118
-	 * @param IConfig $config
119
-	 * @param IUserManager $userManager
120
-	 * @param ICloudIdManager $cloudIdManager
121
-	 * @param \OCP\GlobalScale\IConfig $globalScaleConfig
122
-	 * @param ICloudFederationProviderManager $cloudFederationProviderManager
123
-	 */
124
-	public function __construct(
125
-			IDBConnection $connection,
126
-			AddressHandler $addressHandler,
127
-			Notifications $notifications,
128
-			TokenHandler $tokenHandler,
129
-			IL10N $l10n,
130
-			ILogger $logger,
131
-			IRootFolder $rootFolder,
132
-			IConfig $config,
133
-			IUserManager $userManager,
134
-			ICloudIdManager $cloudIdManager,
135
-			\OCP\GlobalScale\IConfig $globalScaleConfig,
136
-			ICloudFederationProviderManager $cloudFederationProviderManager
137
-	) {
138
-		$this->dbConnection = $connection;
139
-		$this->addressHandler = $addressHandler;
140
-		$this->notifications = $notifications;
141
-		$this->tokenHandler = $tokenHandler;
142
-		$this->l = $l10n;
143
-		$this->logger = $logger;
144
-		$this->rootFolder = $rootFolder;
145
-		$this->config = $config;
146
-		$this->userManager = $userManager;
147
-		$this->cloudIdManager = $cloudIdManager;
148
-		$this->gsConfig = $globalScaleConfig;
149
-		$this->cloudFederationProviderManager = $cloudFederationProviderManager;
150
-	}
151
-
152
-	/**
153
-	 * Return the identifier of this provider.
154
-	 *
155
-	 * @return string Containing only [a-zA-Z0-9]
156
-	 */
157
-	public function identifier() {
158
-		return 'ocFederatedSharing';
159
-	}
160
-
161
-	/**
162
-	 * Share a path
163
-	 *
164
-	 * @param IShare $share
165
-	 * @return IShare The share object
166
-	 * @throws ShareNotFound
167
-	 * @throws \Exception
168
-	 */
169
-	public function create(IShare $share) {
170
-		$shareWith = $share->getSharedWith();
171
-		$itemSource = $share->getNodeId();
172
-		$itemType = $share->getNodeType();
173
-		$permissions = $share->getPermissions();
174
-		$sharedBy = $share->getSharedBy();
175
-		$shareType = $share->getShareType();
176
-		$expirationDate = $share->getExpirationDate();
177
-
178
-		if ($shareType === IShare::TYPE_REMOTE_GROUP &&
179
-			!$this->isOutgoingServer2serverGroupShareEnabled()
180
-		) {
181
-			$message = 'It is not allowed to send federated group shares from this server.';
182
-			$message_t = $this->l->t('It is not allowed to send federated group shares from this server.');
183
-			$this->logger->debug($message, ['app' => 'Federated File Sharing']);
184
-			throw new \Exception($message_t);
185
-		}
186
-
187
-		/*
64
+    public const SHARE_TYPE_REMOTE = 6;
65
+
66
+    /** @var IDBConnection */
67
+    private $dbConnection;
68
+
69
+    /** @var AddressHandler */
70
+    private $addressHandler;
71
+
72
+    /** @var Notifications */
73
+    private $notifications;
74
+
75
+    /** @var TokenHandler */
76
+    private $tokenHandler;
77
+
78
+    /** @var IL10N */
79
+    private $l;
80
+
81
+    /** @var ILogger */
82
+    private $logger;
83
+
84
+    /** @var IRootFolder */
85
+    private $rootFolder;
86
+
87
+    /** @var IConfig */
88
+    private $config;
89
+
90
+    /** @var string */
91
+    private $externalShareTable = 'share_external';
92
+
93
+    /** @var IUserManager */
94
+    private $userManager;
95
+
96
+    /** @var ICloudIdManager */
97
+    private $cloudIdManager;
98
+
99
+    /** @var \OCP\GlobalScale\IConfig */
100
+    private $gsConfig;
101
+
102
+    /** @var ICloudFederationProviderManager */
103
+    private $cloudFederationProviderManager;
104
+
105
+    /** @var array list of supported share types */
106
+    private $supportedShareType = [IShare::TYPE_REMOTE_GROUP, IShare::TYPE_REMOTE, IShare::TYPE_CIRCLE];
107
+
108
+    /**
109
+     * DefaultShareProvider constructor.
110
+     *
111
+     * @param IDBConnection $connection
112
+     * @param AddressHandler $addressHandler
113
+     * @param Notifications $notifications
114
+     * @param TokenHandler $tokenHandler
115
+     * @param IL10N $l10n
116
+     * @param ILogger $logger
117
+     * @param IRootFolder $rootFolder
118
+     * @param IConfig $config
119
+     * @param IUserManager $userManager
120
+     * @param ICloudIdManager $cloudIdManager
121
+     * @param \OCP\GlobalScale\IConfig $globalScaleConfig
122
+     * @param ICloudFederationProviderManager $cloudFederationProviderManager
123
+     */
124
+    public function __construct(
125
+            IDBConnection $connection,
126
+            AddressHandler $addressHandler,
127
+            Notifications $notifications,
128
+            TokenHandler $tokenHandler,
129
+            IL10N $l10n,
130
+            ILogger $logger,
131
+            IRootFolder $rootFolder,
132
+            IConfig $config,
133
+            IUserManager $userManager,
134
+            ICloudIdManager $cloudIdManager,
135
+            \OCP\GlobalScale\IConfig $globalScaleConfig,
136
+            ICloudFederationProviderManager $cloudFederationProviderManager
137
+    ) {
138
+        $this->dbConnection = $connection;
139
+        $this->addressHandler = $addressHandler;
140
+        $this->notifications = $notifications;
141
+        $this->tokenHandler = $tokenHandler;
142
+        $this->l = $l10n;
143
+        $this->logger = $logger;
144
+        $this->rootFolder = $rootFolder;
145
+        $this->config = $config;
146
+        $this->userManager = $userManager;
147
+        $this->cloudIdManager = $cloudIdManager;
148
+        $this->gsConfig = $globalScaleConfig;
149
+        $this->cloudFederationProviderManager = $cloudFederationProviderManager;
150
+    }
151
+
152
+    /**
153
+     * Return the identifier of this provider.
154
+     *
155
+     * @return string Containing only [a-zA-Z0-9]
156
+     */
157
+    public function identifier() {
158
+        return 'ocFederatedSharing';
159
+    }
160
+
161
+    /**
162
+     * Share a path
163
+     *
164
+     * @param IShare $share
165
+     * @return IShare The share object
166
+     * @throws ShareNotFound
167
+     * @throws \Exception
168
+     */
169
+    public function create(IShare $share) {
170
+        $shareWith = $share->getSharedWith();
171
+        $itemSource = $share->getNodeId();
172
+        $itemType = $share->getNodeType();
173
+        $permissions = $share->getPermissions();
174
+        $sharedBy = $share->getSharedBy();
175
+        $shareType = $share->getShareType();
176
+        $expirationDate = $share->getExpirationDate();
177
+
178
+        if ($shareType === IShare::TYPE_REMOTE_GROUP &&
179
+            !$this->isOutgoingServer2serverGroupShareEnabled()
180
+        ) {
181
+            $message = 'It is not allowed to send federated group shares from this server.';
182
+            $message_t = $this->l->t('It is not allowed to send federated group shares from this server.');
183
+            $this->logger->debug($message, ['app' => 'Federated File Sharing']);
184
+            throw new \Exception($message_t);
185
+        }
186
+
187
+        /*
188 188
 		 * Check if file is not already shared with the remote user
189 189
 		 */
190
-		$alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE, $share->getNode(), 1, 0);
191
-		$alreadySharedGroup = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE_GROUP, $share->getNode(), 1, 0);
192
-		if (!empty($alreadyShared) || !empty($alreadySharedGroup)) {
193
-			$message = 'Sharing %1$s failed, because this item is already shared with %2$s';
194
-			$message_t = $this->l->t('Sharing %1$s failed, because this item is already shared with user %2$s', [$share->getNode()->getName(), $shareWith]);
195
-			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
196
-			throw new \Exception($message_t);
197
-		}
198
-
199
-
200
-		// don't allow federated shares if source and target server are the same
201
-		$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
202
-		$currentServer = $this->addressHandler->generateRemoteURL();
203
-		$currentUser = $sharedBy;
204
-		if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
205
-			$message = 'Not allowed to create a federated share with the same user.';
206
-			$message_t = $this->l->t('Not allowed to create a federated share with the same user');
207
-			$this->logger->debug($message, ['app' => 'Federated File Sharing']);
208
-			throw new \Exception($message_t);
209
-		}
210
-
211
-
212
-		$share->setSharedWith($cloudId->getId());
213
-
214
-		try {
215
-			$remoteShare = $this->getShareFromExternalShareTable($share);
216
-		} catch (ShareNotFound $e) {
217
-			$remoteShare = null;
218
-		}
219
-
220
-		if ($remoteShare) {
221
-			try {
222
-				$ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
223
-				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType, $expirationDate);
224
-				$share->setId($shareId);
225
-				[$token, $remoteId] = $this->askOwnerToReShare($shareWith, $share, $shareId);
226
-				// remote share was create successfully if we get a valid token as return
227
-				$send = is_string($token) && $token !== '';
228
-			} catch (\Exception $e) {
229
-				// fall back to old re-share behavior if the remote server
230
-				// doesn't support flat re-shares (was introduced with Nextcloud 9.1)
231
-				$this->removeShareFromTable($share);
232
-				$shareId = $this->createFederatedShare($share);
233
-			}
234
-			if ($send) {
235
-				$this->updateSuccessfulReshare($shareId, $token);
236
-				$this->storeRemoteId($shareId, $remoteId);
237
-			} else {
238
-				$this->removeShareFromTable($share);
239
-				$message_t = $this->l->t('File is already shared with %s', [$shareWith]);
240
-				throw new \Exception($message_t);
241
-			}
242
-		} else {
243
-			$shareId = $this->createFederatedShare($share);
244
-		}
245
-
246
-		$data = $this->getRawShare($shareId);
247
-		return $this->createShareObject($data);
248
-	}
249
-
250
-	/**
251
-	 * create federated share and inform the recipient
252
-	 *
253
-	 * @param IShare $share
254
-	 * @return int
255
-	 * @throws ShareNotFound
256
-	 * @throws \Exception
257
-	 */
258
-	protected function createFederatedShare(IShare $share) {
259
-		$token = $this->tokenHandler->generateToken();
260
-		$shareId = $this->addShareToDB(
261
-			$share->getNodeId(),
262
-			$share->getNodeType(),
263
-			$share->getSharedWith(),
264
-			$share->getSharedBy(),
265
-			$share->getShareOwner(),
266
-			$share->getPermissions(),
267
-			$token,
268
-			$share->getShareType(),
269
-			$share->getExpirationDate()
270
-		);
271
-
272
-		$failure = false;
273
-
274
-		try {
275
-			$sharedByFederatedId = $share->getSharedBy();
276
-			if ($this->userManager->userExists($sharedByFederatedId)) {
277
-				$cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
278
-				$sharedByFederatedId = $cloudId->getId();
279
-			}
280
-			$ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
281
-			$send = $this->notifications->sendRemoteShare(
282
-				$token,
283
-				$share->getSharedWith(),
284
-				$share->getNode()->getName(),
285
-				$shareId,
286
-				$share->getShareOwner(),
287
-				$ownerCloudId->getId(),
288
-				$share->getSharedBy(),
289
-				$sharedByFederatedId,
290
-				$share->getShareType()
291
-			);
292
-
293
-			if ($send === false) {
294
-				$failure = true;
295
-			}
296
-		} catch (\Exception $e) {
297
-			$this->logger->logException($e, [
298
-				'message' => 'Failed to notify remote server of federated share, removing share.',
299
-				'level' => ILogger::ERROR,
300
-				'app' => 'federatedfilesharing',
301
-			]);
302
-			$failure = true;
303
-		}
304
-
305
-		if ($failure) {
306
-			$this->removeShareFromTableById($shareId);
307
-			$message_t = $this->l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable or uses a self-signed certificate.',
308
-				[$share->getNode()->getName(), $share->getSharedWith()]);
309
-			throw new \Exception($message_t);
310
-		}
311
-
312
-		return $shareId;
313
-	}
314
-
315
-	/**
316
-	 * @param string $shareWith
317
-	 * @param IShare $share
318
-	 * @param string $shareId internal share Id
319
-	 * @return array
320
-	 * @throws \Exception
321
-	 */
322
-	protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
323
-		$remoteShare = $this->getShareFromExternalShareTable($share);
324
-		$token = $remoteShare['share_token'];
325
-		$remoteId = $remoteShare['remote_id'];
326
-		$remote = $remoteShare['remote'];
327
-
328
-		[$token, $remoteId] = $this->notifications->requestReShare(
329
-			$token,
330
-			$remoteId,
331
-			$shareId,
332
-			$remote,
333
-			$shareWith,
334
-			$share->getPermissions(),
335
-			$share->getNode()->getName()
336
-		);
337
-
338
-		return [$token, $remoteId];
339
-	}
340
-
341
-	/**
342
-	 * get federated share from the share_external table but exclude mounted link shares
343
-	 *
344
-	 * @param IShare $share
345
-	 * @return array
346
-	 * @throws ShareNotFound
347
-	 */
348
-	protected function getShareFromExternalShareTable(IShare $share) {
349
-		$query = $this->dbConnection->getQueryBuilder();
350
-		$query->select('*')->from($this->externalShareTable)
351
-			->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
352
-			->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
353
-		$qResult = $query->execute();
354
-		$result = $qResult->fetchAll();
355
-		$qResult->closeCursor();
356
-
357
-		if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
358
-			return $result[0];
359
-		}
360
-
361
-		throw new ShareNotFound('share not found in share_external table');
362
-	}
363
-
364
-	/**
365
-	 * add share to the database and return the ID
366
-	 *
367
-	 * @param int $itemSource
368
-	 * @param string $itemType
369
-	 * @param string $shareWith
370
-	 * @param string $sharedBy
371
-	 * @param string $uidOwner
372
-	 * @param int $permissions
373
-	 * @param string $token
374
-	 * @param int $shareType
375
-	 * @param \DateTime $expirationDate
376
-	 * @return int
377
-	 */
378
-	private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType, $expirationDate) {
379
-		$qb = $this->dbConnection->getQueryBuilder();
380
-		$qb->insert('share')
381
-			->setValue('share_type', $qb->createNamedParameter($shareType))
382
-			->setValue('item_type', $qb->createNamedParameter($itemType))
383
-			->setValue('item_source', $qb->createNamedParameter($itemSource))
384
-			->setValue('file_source', $qb->createNamedParameter($itemSource))
385
-			->setValue('share_with', $qb->createNamedParameter($shareWith))
386
-			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
387
-			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
388
-			->setValue('permissions', $qb->createNamedParameter($permissions))
389
-			->setValue('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATE))
390
-			->setValue('token', $qb->createNamedParameter($token))
391
-			->setValue('stime', $qb->createNamedParameter(time()));
392
-
393
-		/*
190
+        $alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE, $share->getNode(), 1, 0);
191
+        $alreadySharedGroup = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE_GROUP, $share->getNode(), 1, 0);
192
+        if (!empty($alreadyShared) || !empty($alreadySharedGroup)) {
193
+            $message = 'Sharing %1$s failed, because this item is already shared with %2$s';
194
+            $message_t = $this->l->t('Sharing %1$s failed, because this item is already shared with user %2$s', [$share->getNode()->getName(), $shareWith]);
195
+            $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
196
+            throw new \Exception($message_t);
197
+        }
198
+
199
+
200
+        // don't allow federated shares if source and target server are the same
201
+        $cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
202
+        $currentServer = $this->addressHandler->generateRemoteURL();
203
+        $currentUser = $sharedBy;
204
+        if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
205
+            $message = 'Not allowed to create a federated share with the same user.';
206
+            $message_t = $this->l->t('Not allowed to create a federated share with the same user');
207
+            $this->logger->debug($message, ['app' => 'Federated File Sharing']);
208
+            throw new \Exception($message_t);
209
+        }
210
+
211
+
212
+        $share->setSharedWith($cloudId->getId());
213
+
214
+        try {
215
+            $remoteShare = $this->getShareFromExternalShareTable($share);
216
+        } catch (ShareNotFound $e) {
217
+            $remoteShare = null;
218
+        }
219
+
220
+        if ($remoteShare) {
221
+            try {
222
+                $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
223
+                $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType, $expirationDate);
224
+                $share->setId($shareId);
225
+                [$token, $remoteId] = $this->askOwnerToReShare($shareWith, $share, $shareId);
226
+                // remote share was create successfully if we get a valid token as return
227
+                $send = is_string($token) && $token !== '';
228
+            } catch (\Exception $e) {
229
+                // fall back to old re-share behavior if the remote server
230
+                // doesn't support flat re-shares (was introduced with Nextcloud 9.1)
231
+                $this->removeShareFromTable($share);
232
+                $shareId = $this->createFederatedShare($share);
233
+            }
234
+            if ($send) {
235
+                $this->updateSuccessfulReshare($shareId, $token);
236
+                $this->storeRemoteId($shareId, $remoteId);
237
+            } else {
238
+                $this->removeShareFromTable($share);
239
+                $message_t = $this->l->t('File is already shared with %s', [$shareWith]);
240
+                throw new \Exception($message_t);
241
+            }
242
+        } else {
243
+            $shareId = $this->createFederatedShare($share);
244
+        }
245
+
246
+        $data = $this->getRawShare($shareId);
247
+        return $this->createShareObject($data);
248
+    }
249
+
250
+    /**
251
+     * create federated share and inform the recipient
252
+     *
253
+     * @param IShare $share
254
+     * @return int
255
+     * @throws ShareNotFound
256
+     * @throws \Exception
257
+     */
258
+    protected function createFederatedShare(IShare $share) {
259
+        $token = $this->tokenHandler->generateToken();
260
+        $shareId = $this->addShareToDB(
261
+            $share->getNodeId(),
262
+            $share->getNodeType(),
263
+            $share->getSharedWith(),
264
+            $share->getSharedBy(),
265
+            $share->getShareOwner(),
266
+            $share->getPermissions(),
267
+            $token,
268
+            $share->getShareType(),
269
+            $share->getExpirationDate()
270
+        );
271
+
272
+        $failure = false;
273
+
274
+        try {
275
+            $sharedByFederatedId = $share->getSharedBy();
276
+            if ($this->userManager->userExists($sharedByFederatedId)) {
277
+                $cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
278
+                $sharedByFederatedId = $cloudId->getId();
279
+            }
280
+            $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
281
+            $send = $this->notifications->sendRemoteShare(
282
+                $token,
283
+                $share->getSharedWith(),
284
+                $share->getNode()->getName(),
285
+                $shareId,
286
+                $share->getShareOwner(),
287
+                $ownerCloudId->getId(),
288
+                $share->getSharedBy(),
289
+                $sharedByFederatedId,
290
+                $share->getShareType()
291
+            );
292
+
293
+            if ($send === false) {
294
+                $failure = true;
295
+            }
296
+        } catch (\Exception $e) {
297
+            $this->logger->logException($e, [
298
+                'message' => 'Failed to notify remote server of federated share, removing share.',
299
+                'level' => ILogger::ERROR,
300
+                'app' => 'federatedfilesharing',
301
+            ]);
302
+            $failure = true;
303
+        }
304
+
305
+        if ($failure) {
306
+            $this->removeShareFromTableById($shareId);
307
+            $message_t = $this->l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable or uses a self-signed certificate.',
308
+                [$share->getNode()->getName(), $share->getSharedWith()]);
309
+            throw new \Exception($message_t);
310
+        }
311
+
312
+        return $shareId;
313
+    }
314
+
315
+    /**
316
+     * @param string $shareWith
317
+     * @param IShare $share
318
+     * @param string $shareId internal share Id
319
+     * @return array
320
+     * @throws \Exception
321
+     */
322
+    protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
323
+        $remoteShare = $this->getShareFromExternalShareTable($share);
324
+        $token = $remoteShare['share_token'];
325
+        $remoteId = $remoteShare['remote_id'];
326
+        $remote = $remoteShare['remote'];
327
+
328
+        [$token, $remoteId] = $this->notifications->requestReShare(
329
+            $token,
330
+            $remoteId,
331
+            $shareId,
332
+            $remote,
333
+            $shareWith,
334
+            $share->getPermissions(),
335
+            $share->getNode()->getName()
336
+        );
337
+
338
+        return [$token, $remoteId];
339
+    }
340
+
341
+    /**
342
+     * get federated share from the share_external table but exclude mounted link shares
343
+     *
344
+     * @param IShare $share
345
+     * @return array
346
+     * @throws ShareNotFound
347
+     */
348
+    protected function getShareFromExternalShareTable(IShare $share) {
349
+        $query = $this->dbConnection->getQueryBuilder();
350
+        $query->select('*')->from($this->externalShareTable)
351
+            ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
352
+            ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
353
+        $qResult = $query->execute();
354
+        $result = $qResult->fetchAll();
355
+        $qResult->closeCursor();
356
+
357
+        if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
358
+            return $result[0];
359
+        }
360
+
361
+        throw new ShareNotFound('share not found in share_external table');
362
+    }
363
+
364
+    /**
365
+     * add share to the database and return the ID
366
+     *
367
+     * @param int $itemSource
368
+     * @param string $itemType
369
+     * @param string $shareWith
370
+     * @param string $sharedBy
371
+     * @param string $uidOwner
372
+     * @param int $permissions
373
+     * @param string $token
374
+     * @param int $shareType
375
+     * @param \DateTime $expirationDate
376
+     * @return int
377
+     */
378
+    private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType, $expirationDate) {
379
+        $qb = $this->dbConnection->getQueryBuilder();
380
+        $qb->insert('share')
381
+            ->setValue('share_type', $qb->createNamedParameter($shareType))
382
+            ->setValue('item_type', $qb->createNamedParameter($itemType))
383
+            ->setValue('item_source', $qb->createNamedParameter($itemSource))
384
+            ->setValue('file_source', $qb->createNamedParameter($itemSource))
385
+            ->setValue('share_with', $qb->createNamedParameter($shareWith))
386
+            ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
387
+            ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
388
+            ->setValue('permissions', $qb->createNamedParameter($permissions))
389
+            ->setValue('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATE))
390
+            ->setValue('token', $qb->createNamedParameter($token))
391
+            ->setValue('stime', $qb->createNamedParameter(time()));
392
+
393
+        /*
394 394
 		 * Added to fix https://github.com/owncloud/core/issues/22215
395 395
 		 * Can be removed once we get rid of ajax/share.php
396 396
 		 */
397
-		$qb->setValue('file_target', $qb->createNamedParameter(''));
398
-
399
-		$qb->execute();
400
-		return $qb->getLastInsertId();
401
-	}
402
-
403
-	/**
404
-	 * Update a share
405
-	 *
406
-	 * @param IShare $share
407
-	 * @return IShare The share object
408
-	 */
409
-	public function update(IShare $share) {
410
-		/*
397
+        $qb->setValue('file_target', $qb->createNamedParameter(''));
398
+
399
+        $qb->execute();
400
+        return $qb->getLastInsertId();
401
+    }
402
+
403
+    /**
404
+     * Update a share
405
+     *
406
+     * @param IShare $share
407
+     * @return IShare The share object
408
+     */
409
+    public function update(IShare $share) {
410
+        /*
411 411
 		 * We allow updating the permissions of federated shares
412 412
 		 */
413
-		$qb = $this->dbConnection->getQueryBuilder();
414
-		$qb->update('share')
415
-				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
416
-				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
417
-				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
418
-				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
419
-				->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
420
-				->execute();
421
-
422
-		// send the updated permission to the owner/initiator, if they are not the same
423
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
424
-			$this->sendPermissionUpdate($share);
425
-		}
426
-
427
-		return $share;
428
-	}
429
-
430
-	/**
431
-	 * send the updated permission to the owner/initiator, if they are not the same
432
-	 *
433
-	 * @param IShare $share
434
-	 * @throws ShareNotFound
435
-	 * @throws \OC\HintException
436
-	 */
437
-	protected function sendPermissionUpdate(IShare $share) {
438
-		$remoteId = $this->getRemoteId($share);
439
-		// if the local user is the owner we send the permission change to the initiator
440
-		if ($this->userManager->userExists($share->getShareOwner())) {
441
-			[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
442
-		} else { // ... if not we send the permission change to the owner
443
-			[, $remote] = $this->addressHandler->splitUserRemote($share->getShareOwner());
444
-		}
445
-		$this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
446
-	}
447
-
448
-
449
-	/**
450
-	 * update successful reShare with the correct token
451
-	 *
452
-	 * @param int $shareId
453
-	 * @param string $token
454
-	 */
455
-	protected function updateSuccessfulReShare($shareId, $token) {
456
-		$query = $this->dbConnection->getQueryBuilder();
457
-		$query->update('share')
458
-			->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
459
-			->set('token', $query->createNamedParameter($token))
460
-			->execute();
461
-	}
462
-
463
-	/**
464
-	 * store remote ID in federated reShare table
465
-	 *
466
-	 * @param $shareId
467
-	 * @param $remoteId
468
-	 */
469
-	public function storeRemoteId(int $shareId, string $remoteId): void {
470
-		$query = $this->dbConnection->getQueryBuilder();
471
-		$query->insert('federated_reshares')
472
-			->values(
473
-				[
474
-					'share_id' => $query->createNamedParameter($shareId),
475
-					'remote_id' => $query->createNamedParameter($remoteId),
476
-				]
477
-			);
478
-		$query->execute();
479
-	}
480
-
481
-	/**
482
-	 * get share ID on remote server for federated re-shares
483
-	 *
484
-	 * @param IShare $share
485
-	 * @return string
486
-	 * @throws ShareNotFound
487
-	 */
488
-	public function getRemoteId(IShare $share): string {
489
-		$query = $this->dbConnection->getQueryBuilder();
490
-		$query->select('remote_id')->from('federated_reshares')
491
-			->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
492
-		$result = $query->execute();
493
-		$data = $result->fetch();
494
-		$result->closeCursor();
495
-
496
-		if (!is_array($data) || !isset($data['remote_id'])) {
497
-			throw new ShareNotFound();
498
-		}
499
-
500
-		return (string)$data['remote_id'];
501
-	}
502
-
503
-	/**
504
-	 * @inheritdoc
505
-	 */
506
-	public function move(IShare $share, $recipient) {
507
-		/*
413
+        $qb = $this->dbConnection->getQueryBuilder();
414
+        $qb->update('share')
415
+                ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
416
+                ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
417
+                ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
418
+                ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
419
+                ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
420
+                ->execute();
421
+
422
+        // send the updated permission to the owner/initiator, if they are not the same
423
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
424
+            $this->sendPermissionUpdate($share);
425
+        }
426
+
427
+        return $share;
428
+    }
429
+
430
+    /**
431
+     * send the updated permission to the owner/initiator, if they are not the same
432
+     *
433
+     * @param IShare $share
434
+     * @throws ShareNotFound
435
+     * @throws \OC\HintException
436
+     */
437
+    protected function sendPermissionUpdate(IShare $share) {
438
+        $remoteId = $this->getRemoteId($share);
439
+        // if the local user is the owner we send the permission change to the initiator
440
+        if ($this->userManager->userExists($share->getShareOwner())) {
441
+            [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
442
+        } else { // ... if not we send the permission change to the owner
443
+            [, $remote] = $this->addressHandler->splitUserRemote($share->getShareOwner());
444
+        }
445
+        $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
446
+    }
447
+
448
+
449
+    /**
450
+     * update successful reShare with the correct token
451
+     *
452
+     * @param int $shareId
453
+     * @param string $token
454
+     */
455
+    protected function updateSuccessfulReShare($shareId, $token) {
456
+        $query = $this->dbConnection->getQueryBuilder();
457
+        $query->update('share')
458
+            ->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
459
+            ->set('token', $query->createNamedParameter($token))
460
+            ->execute();
461
+    }
462
+
463
+    /**
464
+     * store remote ID in federated reShare table
465
+     *
466
+     * @param $shareId
467
+     * @param $remoteId
468
+     */
469
+    public function storeRemoteId(int $shareId, string $remoteId): void {
470
+        $query = $this->dbConnection->getQueryBuilder();
471
+        $query->insert('federated_reshares')
472
+            ->values(
473
+                [
474
+                    'share_id' => $query->createNamedParameter($shareId),
475
+                    'remote_id' => $query->createNamedParameter($remoteId),
476
+                ]
477
+            );
478
+        $query->execute();
479
+    }
480
+
481
+    /**
482
+     * get share ID on remote server for federated re-shares
483
+     *
484
+     * @param IShare $share
485
+     * @return string
486
+     * @throws ShareNotFound
487
+     */
488
+    public function getRemoteId(IShare $share): string {
489
+        $query = $this->dbConnection->getQueryBuilder();
490
+        $query->select('remote_id')->from('federated_reshares')
491
+            ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
492
+        $result = $query->execute();
493
+        $data = $result->fetch();
494
+        $result->closeCursor();
495
+
496
+        if (!is_array($data) || !isset($data['remote_id'])) {
497
+            throw new ShareNotFound();
498
+        }
499
+
500
+        return (string)$data['remote_id'];
501
+    }
502
+
503
+    /**
504
+     * @inheritdoc
505
+     */
506
+    public function move(IShare $share, $recipient) {
507
+        /*
508 508
 		 * This function does nothing yet as it is just for outgoing
509 509
 		 * federated shares.
510 510
 		 */
511
-		return $share;
512
-	}
513
-
514
-	/**
515
-	 * Get all children of this share
516
-	 *
517
-	 * @param IShare $parent
518
-	 * @return IShare[]
519
-	 */
520
-	public function getChildren(IShare $parent) {
521
-		$children = [];
522
-
523
-		$qb = $this->dbConnection->getQueryBuilder();
524
-		$qb->select('*')
525
-			->from('share')
526
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
527
-			->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
528
-			->orderBy('id');
529
-
530
-		$cursor = $qb->execute();
531
-		while ($data = $cursor->fetch()) {
532
-			$children[] = $this->createShareObject($data);
533
-		}
534
-		$cursor->closeCursor();
535
-
536
-		return $children;
537
-	}
538
-
539
-	/**
540
-	 * Delete a share (owner unShares the file)
541
-	 *
542
-	 * @param IShare $share
543
-	 * @throws ShareNotFound
544
-	 * @throws \OC\HintException
545
-	 */
546
-	public function delete(IShare $share) {
547
-		[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedWith());
548
-
549
-		// if the local user is the owner we can send the unShare request directly...
550
-		if ($this->userManager->userExists($share->getShareOwner())) {
551
-			$this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
552
-			$this->revokeShare($share, true);
553
-		} else { // ... if not we need to correct ID for the unShare request
554
-			$remoteId = $this->getRemoteId($share);
555
-			$this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
556
-			$this->revokeShare($share, false);
557
-		}
558
-
559
-		// only remove the share when all messages are send to not lose information
560
-		// about the share to early
561
-		$this->removeShareFromTable($share);
562
-	}
563
-
564
-	/**
565
-	 * in case of a re-share we need to send the other use (initiator or owner)
566
-	 * a message that the file was unshared
567
-	 *
568
-	 * @param IShare $share
569
-	 * @param bool $isOwner the user can either be the owner or the user who re-sahred it
570
-	 * @throws ShareNotFound
571
-	 * @throws \OC\HintException
572
-	 */
573
-	protected function revokeShare($share, $isOwner) {
574
-		if ($this->userManager->userExists($share->getShareOwner()) && $this->userManager->userExists($share->getSharedBy())) {
575
-			// If both the owner and the initiator of the share are local users we don't have to notify anybody else
576
-			return;
577
-		}
578
-
579
-		// also send a unShare request to the initiator, if this is a different user than the owner
580
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
581
-			if ($isOwner) {
582
-				[, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
583
-			} else {
584
-				[, $remote] = $this->addressHandler->splitUserRemote($share->getShareOwner());
585
-			}
586
-			$remoteId = $this->getRemoteId($share);
587
-			$this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
588
-		}
589
-	}
590
-
591
-	/**
592
-	 * remove share from table
593
-	 *
594
-	 * @param IShare $share
595
-	 */
596
-	public function removeShareFromTable(IShare $share) {
597
-		$this->removeShareFromTableById($share->getId());
598
-	}
599
-
600
-	/**
601
-	 * remove share from table
602
-	 *
603
-	 * @param string $shareId
604
-	 */
605
-	private function removeShareFromTableById($shareId) {
606
-		$qb = $this->dbConnection->getQueryBuilder();
607
-		$qb->delete('share')
608
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)))
609
-			->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(IShare::TYPE_CIRCLE)));
610
-		$qb->execute();
611
-
612
-		$qb->delete('federated_reshares')
613
-			->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
614
-		$qb->execute();
615
-	}
616
-
617
-	/**
618
-	 * @inheritdoc
619
-	 */
620
-	public function deleteFromSelf(IShare $share, $recipient) {
621
-		// nothing to do here. Technically deleteFromSelf in the context of federated
622
-		// shares is a umount of an external storage. This is handled here
623
-		// apps/files_sharing/lib/external/manager.php
624
-		// TODO move this code over to this app
625
-	}
626
-
627
-	public function restore(IShare $share, string $recipient): IShare {
628
-		throw new GenericShareException('not implemented');
629
-	}
630
-
631
-
632
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
633
-		$qb = $this->dbConnection->getQueryBuilder();
634
-		$qb->select('*')
635
-			->from('share', 's')
636
-			->andWhere($qb->expr()->orX(
637
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
638
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
639
-			))
640
-			->andWhere(
641
-				$qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))
642
-			);
643
-
644
-		/**
645
-		 * Reshares for this user are shares where they are the owner.
646
-		 */
647
-		if ($reshares === false) {
648
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
649
-		} else {
650
-			$qb->andWhere(
651
-				$qb->expr()->orX(
652
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
653
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
654
-				)
655
-			);
656
-		}
657
-
658
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
659
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
660
-
661
-		$qb->orderBy('id');
662
-
663
-		$cursor = $qb->execute();
664
-		$shares = [];
665
-		while ($data = $cursor->fetch()) {
666
-			$shares[$data['fileid']][] = $this->createShareObject($data);
667
-		}
668
-		$cursor->closeCursor();
669
-
670
-		return $shares;
671
-	}
672
-
673
-	/**
674
-	 * @inheritdoc
675
-	 */
676
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
677
-		$qb = $this->dbConnection->getQueryBuilder();
678
-		$qb->select('*')
679
-			->from('share');
680
-
681
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
682
-
683
-		/**
684
-		 * Reshares for this user are shares where they are the owner.
685
-		 */
686
-		if ($reshares === false) {
687
-			//Special case for old shares created via the web UI
688
-			$or1 = $qb->expr()->andX(
689
-				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
690
-				$qb->expr()->isNull('uid_initiator')
691
-			);
692
-
693
-			$qb->andWhere(
694
-				$qb->expr()->orX(
695
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
696
-					$or1
697
-				)
698
-			);
699
-		} else {
700
-			$qb->andWhere(
701
-				$qb->expr()->orX(
702
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
703
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
704
-				)
705
-			);
706
-		}
707
-
708
-		if ($node !== null) {
709
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
710
-		}
711
-
712
-		if ($limit !== -1) {
713
-			$qb->setMaxResults($limit);
714
-		}
715
-
716
-		$qb->setFirstResult($offset);
717
-		$qb->orderBy('id');
718
-
719
-		$cursor = $qb->execute();
720
-		$shares = [];
721
-		while ($data = $cursor->fetch()) {
722
-			$shares[] = $this->createShareObject($data);
723
-		}
724
-		$cursor->closeCursor();
725
-
726
-		return $shares;
727
-	}
728
-
729
-	/**
730
-	 * @inheritdoc
731
-	 */
732
-	public function getShareById($id, $recipientId = null) {
733
-		$qb = $this->dbConnection->getQueryBuilder();
734
-
735
-		$qb->select('*')
736
-			->from('share')
737
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
738
-			->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
739
-
740
-		$cursor = $qb->execute();
741
-		$data = $cursor->fetch();
742
-		$cursor->closeCursor();
743
-
744
-		if ($data === false) {
745
-			throw new ShareNotFound('Can not find share with ID: ' . $id);
746
-		}
747
-
748
-		try {
749
-			$share = $this->createShareObject($data);
750
-		} catch (InvalidShare $e) {
751
-			throw new ShareNotFound();
752
-		}
753
-
754
-		return $share;
755
-	}
756
-
757
-	/**
758
-	 * Get shares for a given path
759
-	 *
760
-	 * @param \OCP\Files\Node $path
761
-	 * @return IShare[]
762
-	 */
763
-	public function getSharesByPath(Node $path) {
764
-		$qb = $this->dbConnection->getQueryBuilder();
765
-
766
-		// get federated user shares
767
-		$cursor = $qb->select('*')
768
-			->from('share')
769
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
770
-			->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
771
-			->execute();
772
-
773
-		$shares = [];
774
-		while ($data = $cursor->fetch()) {
775
-			$shares[] = $this->createShareObject($data);
776
-		}
777
-		$cursor->closeCursor();
778
-
779
-		return $shares;
780
-	}
781
-
782
-	/**
783
-	 * @inheritdoc
784
-	 */
785
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
786
-		/** @var IShare[] $shares */
787
-		$shares = [];
788
-
789
-		//Get shares directly with this user
790
-		$qb = $this->dbConnection->getQueryBuilder();
791
-		$qb->select('*')
792
-			->from('share');
793
-
794
-		// Order by id
795
-		$qb->orderBy('id');
796
-
797
-		// Set limit and offset
798
-		if ($limit !== -1) {
799
-			$qb->setMaxResults($limit);
800
-		}
801
-		$qb->setFirstResult($offset);
802
-
803
-		$qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
804
-		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
805
-
806
-		// Filter by node if provided
807
-		if ($node !== null) {
808
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
809
-		}
810
-
811
-		$cursor = $qb->execute();
812
-
813
-		while ($data = $cursor->fetch()) {
814
-			$shares[] = $this->createShareObject($data);
815
-		}
816
-		$cursor->closeCursor();
817
-
818
-
819
-		return $shares;
820
-	}
821
-
822
-	/**
823
-	 * Get a share by token
824
-	 *
825
-	 * @param string $token
826
-	 * @return IShare
827
-	 * @throws ShareNotFound
828
-	 */
829
-	public function getShareByToken($token) {
830
-		$qb = $this->dbConnection->getQueryBuilder();
831
-
832
-		$cursor = $qb->select('*')
833
-			->from('share')
834
-			->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
835
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
836
-			->execute();
837
-
838
-		$data = $cursor->fetch();
839
-
840
-		if ($data === false) {
841
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
842
-		}
843
-
844
-		try {
845
-			$share = $this->createShareObject($data);
846
-		} catch (InvalidShare $e) {
847
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
848
-		}
849
-
850
-		return $share;
851
-	}
852
-
853
-	/**
854
-	 * get database row of a give share
855
-	 *
856
-	 * @param $id
857
-	 * @return array
858
-	 * @throws ShareNotFound
859
-	 */
860
-	private function getRawShare($id) {
861
-
862
-		// Now fetch the inserted share and create a complete share object
863
-		$qb = $this->dbConnection->getQueryBuilder();
864
-		$qb->select('*')
865
-			->from('share')
866
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
867
-
868
-		$cursor = $qb->execute();
869
-		$data = $cursor->fetch();
870
-		$cursor->closeCursor();
871
-
872
-		if ($data === false) {
873
-			throw new ShareNotFound;
874
-		}
875
-
876
-		return $data;
877
-	}
878
-
879
-	/**
880
-	 * Create a share object from an database row
881
-	 *
882
-	 * @param array $data
883
-	 * @return IShare
884
-	 * @throws InvalidShare
885
-	 * @throws ShareNotFound
886
-	 */
887
-	private function createShareObject($data) {
888
-		$share = new Share($this->rootFolder, $this->userManager);
889
-		$share->setId((int)$data['id'])
890
-			->setShareType((int)$data['share_type'])
891
-			->setPermissions((int)$data['permissions'])
892
-			->setTarget($data['file_target'])
893
-			->setMailSend((bool)$data['mail_send'])
894
-			->setToken($data['token']);
895
-
896
-		$shareTime = new \DateTime();
897
-		$shareTime->setTimestamp((int)$data['stime']);
898
-		$share->setShareTime($shareTime);
899
-		$share->setSharedWith($data['share_with']);
900
-
901
-		if ($data['uid_initiator'] !== null) {
902
-			$share->setShareOwner($data['uid_owner']);
903
-			$share->setSharedBy($data['uid_initiator']);
904
-		} else {
905
-			//OLD SHARE
906
-			$share->setSharedBy($data['uid_owner']);
907
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
908
-
909
-			$owner = $path->getOwner();
910
-			$share->setShareOwner($owner->getUID());
911
-		}
912
-
913
-		$share->setNodeId((int)$data['file_source']);
914
-		$share->setNodeType($data['item_type']);
915
-
916
-		$share->setProviderId($this->identifier());
917
-
918
-		if ($data['expiration'] !== null) {
919
-			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
920
-			$share->setExpirationDate($expiration);
921
-		}
922
-
923
-		return $share;
924
-	}
925
-
926
-	/**
927
-	 * Get the node with file $id for $user
928
-	 *
929
-	 * @param string $userId
930
-	 * @param int $id
931
-	 * @return \OCP\Files\File|\OCP\Files\Folder
932
-	 * @throws InvalidShare
933
-	 */
934
-	private function getNode($userId, $id) {
935
-		try {
936
-			$userFolder = $this->rootFolder->getUserFolder($userId);
937
-		} catch (NotFoundException $e) {
938
-			throw new InvalidShare();
939
-		}
940
-
941
-		$nodes = $userFolder->getById($id);
942
-
943
-		if (empty($nodes)) {
944
-			throw new InvalidShare();
945
-		}
946
-
947
-		return $nodes[0];
948
-	}
949
-
950
-	/**
951
-	 * A user is deleted from the system
952
-	 * So clean up the relevant shares.
953
-	 *
954
-	 * @param string $uid
955
-	 * @param int $shareType
956
-	 */
957
-	public function userDeleted($uid, $shareType) {
958
-		//TODO: probabaly a good idea to send unshare info to remote servers
959
-
960
-		$qb = $this->dbConnection->getQueryBuilder();
961
-
962
-		$qb->delete('share')
963
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)))
964
-			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
965
-			->execute();
966
-	}
967
-
968
-	/**
969
-	 * This provider does not handle groups
970
-	 *
971
-	 * @param string $gid
972
-	 */
973
-	public function groupDeleted($gid) {
974
-		// We don't handle groups here
975
-	}
976
-
977
-	/**
978
-	 * This provider does not handle groups
979
-	 *
980
-	 * @param string $uid
981
-	 * @param string $gid
982
-	 */
983
-	public function userDeletedFromGroup($uid, $gid) {
984
-		// We don't handle groups here
985
-	}
986
-
987
-	/**
988
-	 * check if users from other Nextcloud instances are allowed to mount public links share by this instance
989
-	 *
990
-	 * @return bool
991
-	 */
992
-	public function isOutgoingServer2serverShareEnabled() {
993
-		if ($this->gsConfig->onlyInternalFederation()) {
994
-			return false;
995
-		}
996
-		$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
997
-		return ($result === 'yes');
998
-	}
999
-
1000
-	/**
1001
-	 * check if users are allowed to mount public links from other Nextclouds
1002
-	 *
1003
-	 * @return bool
1004
-	 */
1005
-	public function isIncomingServer2serverShareEnabled() {
1006
-		if ($this->gsConfig->onlyInternalFederation()) {
1007
-			return false;
1008
-		}
1009
-		$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
1010
-		return ($result === 'yes');
1011
-	}
1012
-
1013
-
1014
-	/**
1015
-	 * check if users from other Nextcloud instances are allowed to send federated group shares
1016
-	 *
1017
-	 * @return bool
1018
-	 */
1019
-	public function isOutgoingServer2serverGroupShareEnabled() {
1020
-		if ($this->gsConfig->onlyInternalFederation()) {
1021
-			return false;
1022
-		}
1023
-		$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no');
1024
-		return ($result === 'yes');
1025
-	}
1026
-
1027
-	/**
1028
-	 * check if users are allowed to receive federated group shares
1029
-	 *
1030
-	 * @return bool
1031
-	 */
1032
-	public function isIncomingServer2serverGroupShareEnabled() {
1033
-		if ($this->gsConfig->onlyInternalFederation()) {
1034
-			return false;
1035
-		}
1036
-		$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no');
1037
-		return ($result === 'yes');
1038
-	}
1039
-
1040
-	/**
1041
-	 * check if federated group sharing is supported, therefore the OCM API need to be enabled
1042
-	 *
1043
-	 * @return bool
1044
-	 */
1045
-	public function isFederatedGroupSharingSupported() {
1046
-		return $this->cloudFederationProviderManager->isReady();
1047
-	}
1048
-
1049
-	/**
1050
-	 * Check if querying sharees on the lookup server is enabled
1051
-	 *
1052
-	 * @return bool
1053
-	 */
1054
-	public function isLookupServerQueriesEnabled() {
1055
-		// in a global scale setup we should always query the lookup server
1056
-		if ($this->gsConfig->isGlobalScaleEnabled()) {
1057
-			return true;
1058
-		}
1059
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes');
1060
-		return ($result === 'yes');
1061
-	}
1062
-
1063
-
1064
-	/**
1065
-	 * Check if it is allowed to publish user specific data to the lookup server
1066
-	 *
1067
-	 * @return bool
1068
-	 */
1069
-	public function isLookupServerUploadEnabled() {
1070
-		// in a global scale setup the admin is responsible to keep the lookup server up-to-date
1071
-		if ($this->gsConfig->isGlobalScaleEnabled()) {
1072
-			return false;
1073
-		}
1074
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
1075
-		return ($result === 'yes');
1076
-	}
1077
-
1078
-	/**
1079
-	 * @inheritdoc
1080
-	 */
1081
-	public function getAccessList($nodes, $currentAccess) {
1082
-		$ids = [];
1083
-		foreach ($nodes as $node) {
1084
-			$ids[] = $node->getId();
1085
-		}
1086
-
1087
-		$qb = $this->dbConnection->getQueryBuilder();
1088
-		$qb->select('share_with', 'token', 'file_source')
1089
-			->from('share')
1090
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)))
1091
-			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1092
-			->andWhere($qb->expr()->orX(
1093
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1094
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1095
-			));
1096
-		$cursor = $qb->execute();
1097
-
1098
-		if ($currentAccess === false) {
1099
-			$remote = $cursor->fetch() !== false;
1100
-			$cursor->closeCursor();
1101
-
1102
-			return ['remote' => $remote];
1103
-		}
1104
-
1105
-		$remote = [];
1106
-		while ($row = $cursor->fetch()) {
1107
-			$remote[$row['share_with']] = [
1108
-				'node_id' => $row['file_source'],
1109
-				'token' => $row['token'],
1110
-			];
1111
-		}
1112
-		$cursor->closeCursor();
1113
-
1114
-		return ['remote' => $remote];
1115
-	}
1116
-
1117
-	public function getAllShares(): iterable {
1118
-		$qb = $this->dbConnection->getQueryBuilder();
1119
-
1120
-		$qb->select('*')
1121
-			->from('share')
1122
-			->where(
1123
-				$qb->expr()->orX(
1124
-					$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE)),
1125
-					$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE_GROUP))
1126
-				)
1127
-			);
1128
-
1129
-		$cursor = $qb->execute();
1130
-		while ($data = $cursor->fetch()) {
1131
-			try {
1132
-				$share = $this->createShareObject($data);
1133
-			} catch (InvalidShare $e) {
1134
-				continue;
1135
-			} catch (ShareNotFound $e) {
1136
-				continue;
1137
-			}
1138
-
1139
-			yield $share;
1140
-		}
1141
-		$cursor->closeCursor();
1142
-	}
511
+        return $share;
512
+    }
513
+
514
+    /**
515
+     * Get all children of this share
516
+     *
517
+     * @param IShare $parent
518
+     * @return IShare[]
519
+     */
520
+    public function getChildren(IShare $parent) {
521
+        $children = [];
522
+
523
+        $qb = $this->dbConnection->getQueryBuilder();
524
+        $qb->select('*')
525
+            ->from('share')
526
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
527
+            ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
528
+            ->orderBy('id');
529
+
530
+        $cursor = $qb->execute();
531
+        while ($data = $cursor->fetch()) {
532
+            $children[] = $this->createShareObject($data);
533
+        }
534
+        $cursor->closeCursor();
535
+
536
+        return $children;
537
+    }
538
+
539
+    /**
540
+     * Delete a share (owner unShares the file)
541
+     *
542
+     * @param IShare $share
543
+     * @throws ShareNotFound
544
+     * @throws \OC\HintException
545
+     */
546
+    public function delete(IShare $share) {
547
+        [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedWith());
548
+
549
+        // if the local user is the owner we can send the unShare request directly...
550
+        if ($this->userManager->userExists($share->getShareOwner())) {
551
+            $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
552
+            $this->revokeShare($share, true);
553
+        } else { // ... if not we need to correct ID for the unShare request
554
+            $remoteId = $this->getRemoteId($share);
555
+            $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
556
+            $this->revokeShare($share, false);
557
+        }
558
+
559
+        // only remove the share when all messages are send to not lose information
560
+        // about the share to early
561
+        $this->removeShareFromTable($share);
562
+    }
563
+
564
+    /**
565
+     * in case of a re-share we need to send the other use (initiator or owner)
566
+     * a message that the file was unshared
567
+     *
568
+     * @param IShare $share
569
+     * @param bool $isOwner the user can either be the owner or the user who re-sahred it
570
+     * @throws ShareNotFound
571
+     * @throws \OC\HintException
572
+     */
573
+    protected function revokeShare($share, $isOwner) {
574
+        if ($this->userManager->userExists($share->getShareOwner()) && $this->userManager->userExists($share->getSharedBy())) {
575
+            // If both the owner and the initiator of the share are local users we don't have to notify anybody else
576
+            return;
577
+        }
578
+
579
+        // also send a unShare request to the initiator, if this is a different user than the owner
580
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
581
+            if ($isOwner) {
582
+                [, $remote] = $this->addressHandler->splitUserRemote($share->getSharedBy());
583
+            } else {
584
+                [, $remote] = $this->addressHandler->splitUserRemote($share->getShareOwner());
585
+            }
586
+            $remoteId = $this->getRemoteId($share);
587
+            $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
588
+        }
589
+    }
590
+
591
+    /**
592
+     * remove share from table
593
+     *
594
+     * @param IShare $share
595
+     */
596
+    public function removeShareFromTable(IShare $share) {
597
+        $this->removeShareFromTableById($share->getId());
598
+    }
599
+
600
+    /**
601
+     * remove share from table
602
+     *
603
+     * @param string $shareId
604
+     */
605
+    private function removeShareFromTableById($shareId) {
606
+        $qb = $this->dbConnection->getQueryBuilder();
607
+        $qb->delete('share')
608
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)))
609
+            ->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(IShare::TYPE_CIRCLE)));
610
+        $qb->execute();
611
+
612
+        $qb->delete('federated_reshares')
613
+            ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
614
+        $qb->execute();
615
+    }
616
+
617
+    /**
618
+     * @inheritdoc
619
+     */
620
+    public function deleteFromSelf(IShare $share, $recipient) {
621
+        // nothing to do here. Technically deleteFromSelf in the context of federated
622
+        // shares is a umount of an external storage. This is handled here
623
+        // apps/files_sharing/lib/external/manager.php
624
+        // TODO move this code over to this app
625
+    }
626
+
627
+    public function restore(IShare $share, string $recipient): IShare {
628
+        throw new GenericShareException('not implemented');
629
+    }
630
+
631
+
632
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
633
+        $qb = $this->dbConnection->getQueryBuilder();
634
+        $qb->select('*')
635
+            ->from('share', 's')
636
+            ->andWhere($qb->expr()->orX(
637
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
638
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
639
+            ))
640
+            ->andWhere(
641
+                $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))
642
+            );
643
+
644
+        /**
645
+         * Reshares for this user are shares where they are the owner.
646
+         */
647
+        if ($reshares === false) {
648
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
649
+        } else {
650
+            $qb->andWhere(
651
+                $qb->expr()->orX(
652
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
653
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
654
+                )
655
+            );
656
+        }
657
+
658
+        $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
659
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
660
+
661
+        $qb->orderBy('id');
662
+
663
+        $cursor = $qb->execute();
664
+        $shares = [];
665
+        while ($data = $cursor->fetch()) {
666
+            $shares[$data['fileid']][] = $this->createShareObject($data);
667
+        }
668
+        $cursor->closeCursor();
669
+
670
+        return $shares;
671
+    }
672
+
673
+    /**
674
+     * @inheritdoc
675
+     */
676
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
677
+        $qb = $this->dbConnection->getQueryBuilder();
678
+        $qb->select('*')
679
+            ->from('share');
680
+
681
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
682
+
683
+        /**
684
+         * Reshares for this user are shares where they are the owner.
685
+         */
686
+        if ($reshares === false) {
687
+            //Special case for old shares created via the web UI
688
+            $or1 = $qb->expr()->andX(
689
+                $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
690
+                $qb->expr()->isNull('uid_initiator')
691
+            );
692
+
693
+            $qb->andWhere(
694
+                $qb->expr()->orX(
695
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
696
+                    $or1
697
+                )
698
+            );
699
+        } else {
700
+            $qb->andWhere(
701
+                $qb->expr()->orX(
702
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
703
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
704
+                )
705
+            );
706
+        }
707
+
708
+        if ($node !== null) {
709
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
710
+        }
711
+
712
+        if ($limit !== -1) {
713
+            $qb->setMaxResults($limit);
714
+        }
715
+
716
+        $qb->setFirstResult($offset);
717
+        $qb->orderBy('id');
718
+
719
+        $cursor = $qb->execute();
720
+        $shares = [];
721
+        while ($data = $cursor->fetch()) {
722
+            $shares[] = $this->createShareObject($data);
723
+        }
724
+        $cursor->closeCursor();
725
+
726
+        return $shares;
727
+    }
728
+
729
+    /**
730
+     * @inheritdoc
731
+     */
732
+    public function getShareById($id, $recipientId = null) {
733
+        $qb = $this->dbConnection->getQueryBuilder();
734
+
735
+        $qb->select('*')
736
+            ->from('share')
737
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
738
+            ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
739
+
740
+        $cursor = $qb->execute();
741
+        $data = $cursor->fetch();
742
+        $cursor->closeCursor();
743
+
744
+        if ($data === false) {
745
+            throw new ShareNotFound('Can not find share with ID: ' . $id);
746
+        }
747
+
748
+        try {
749
+            $share = $this->createShareObject($data);
750
+        } catch (InvalidShare $e) {
751
+            throw new ShareNotFound();
752
+        }
753
+
754
+        return $share;
755
+    }
756
+
757
+    /**
758
+     * Get shares for a given path
759
+     *
760
+     * @param \OCP\Files\Node $path
761
+     * @return IShare[]
762
+     */
763
+    public function getSharesByPath(Node $path) {
764
+        $qb = $this->dbConnection->getQueryBuilder();
765
+
766
+        // get federated user shares
767
+        $cursor = $qb->select('*')
768
+            ->from('share')
769
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
770
+            ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
771
+            ->execute();
772
+
773
+        $shares = [];
774
+        while ($data = $cursor->fetch()) {
775
+            $shares[] = $this->createShareObject($data);
776
+        }
777
+        $cursor->closeCursor();
778
+
779
+        return $shares;
780
+    }
781
+
782
+    /**
783
+     * @inheritdoc
784
+     */
785
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
786
+        /** @var IShare[] $shares */
787
+        $shares = [];
788
+
789
+        //Get shares directly with this user
790
+        $qb = $this->dbConnection->getQueryBuilder();
791
+        $qb->select('*')
792
+            ->from('share');
793
+
794
+        // Order by id
795
+        $qb->orderBy('id');
796
+
797
+        // Set limit and offset
798
+        if ($limit !== -1) {
799
+            $qb->setMaxResults($limit);
800
+        }
801
+        $qb->setFirstResult($offset);
802
+
803
+        $qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
804
+        $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
805
+
806
+        // Filter by node if provided
807
+        if ($node !== null) {
808
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
809
+        }
810
+
811
+        $cursor = $qb->execute();
812
+
813
+        while ($data = $cursor->fetch()) {
814
+            $shares[] = $this->createShareObject($data);
815
+        }
816
+        $cursor->closeCursor();
817
+
818
+
819
+        return $shares;
820
+    }
821
+
822
+    /**
823
+     * Get a share by token
824
+     *
825
+     * @param string $token
826
+     * @return IShare
827
+     * @throws ShareNotFound
828
+     */
829
+    public function getShareByToken($token) {
830
+        $qb = $this->dbConnection->getQueryBuilder();
831
+
832
+        $cursor = $qb->select('*')
833
+            ->from('share')
834
+            ->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)))
835
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
836
+            ->execute();
837
+
838
+        $data = $cursor->fetch();
839
+
840
+        if ($data === false) {
841
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
842
+        }
843
+
844
+        try {
845
+            $share = $this->createShareObject($data);
846
+        } catch (InvalidShare $e) {
847
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
848
+        }
849
+
850
+        return $share;
851
+    }
852
+
853
+    /**
854
+     * get database row of a give share
855
+     *
856
+     * @param $id
857
+     * @return array
858
+     * @throws ShareNotFound
859
+     */
860
+    private function getRawShare($id) {
861
+
862
+        // Now fetch the inserted share and create a complete share object
863
+        $qb = $this->dbConnection->getQueryBuilder();
864
+        $qb->select('*')
865
+            ->from('share')
866
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
867
+
868
+        $cursor = $qb->execute();
869
+        $data = $cursor->fetch();
870
+        $cursor->closeCursor();
871
+
872
+        if ($data === false) {
873
+            throw new ShareNotFound;
874
+        }
875
+
876
+        return $data;
877
+    }
878
+
879
+    /**
880
+     * Create a share object from an database row
881
+     *
882
+     * @param array $data
883
+     * @return IShare
884
+     * @throws InvalidShare
885
+     * @throws ShareNotFound
886
+     */
887
+    private function createShareObject($data) {
888
+        $share = new Share($this->rootFolder, $this->userManager);
889
+        $share->setId((int)$data['id'])
890
+            ->setShareType((int)$data['share_type'])
891
+            ->setPermissions((int)$data['permissions'])
892
+            ->setTarget($data['file_target'])
893
+            ->setMailSend((bool)$data['mail_send'])
894
+            ->setToken($data['token']);
895
+
896
+        $shareTime = new \DateTime();
897
+        $shareTime->setTimestamp((int)$data['stime']);
898
+        $share->setShareTime($shareTime);
899
+        $share->setSharedWith($data['share_with']);
900
+
901
+        if ($data['uid_initiator'] !== null) {
902
+            $share->setShareOwner($data['uid_owner']);
903
+            $share->setSharedBy($data['uid_initiator']);
904
+        } else {
905
+            //OLD SHARE
906
+            $share->setSharedBy($data['uid_owner']);
907
+            $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
908
+
909
+            $owner = $path->getOwner();
910
+            $share->setShareOwner($owner->getUID());
911
+        }
912
+
913
+        $share->setNodeId((int)$data['file_source']);
914
+        $share->setNodeType($data['item_type']);
915
+
916
+        $share->setProviderId($this->identifier());
917
+
918
+        if ($data['expiration'] !== null) {
919
+            $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
920
+            $share->setExpirationDate($expiration);
921
+        }
922
+
923
+        return $share;
924
+    }
925
+
926
+    /**
927
+     * Get the node with file $id for $user
928
+     *
929
+     * @param string $userId
930
+     * @param int $id
931
+     * @return \OCP\Files\File|\OCP\Files\Folder
932
+     * @throws InvalidShare
933
+     */
934
+    private function getNode($userId, $id) {
935
+        try {
936
+            $userFolder = $this->rootFolder->getUserFolder($userId);
937
+        } catch (NotFoundException $e) {
938
+            throw new InvalidShare();
939
+        }
940
+
941
+        $nodes = $userFolder->getById($id);
942
+
943
+        if (empty($nodes)) {
944
+            throw new InvalidShare();
945
+        }
946
+
947
+        return $nodes[0];
948
+    }
949
+
950
+    /**
951
+     * A user is deleted from the system
952
+     * So clean up the relevant shares.
953
+     *
954
+     * @param string $uid
955
+     * @param int $shareType
956
+     */
957
+    public function userDeleted($uid, $shareType) {
958
+        //TODO: probabaly a good idea to send unshare info to remote servers
959
+
960
+        $qb = $this->dbConnection->getQueryBuilder();
961
+
962
+        $qb->delete('share')
963
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)))
964
+            ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
965
+            ->execute();
966
+    }
967
+
968
+    /**
969
+     * This provider does not handle groups
970
+     *
971
+     * @param string $gid
972
+     */
973
+    public function groupDeleted($gid) {
974
+        // We don't handle groups here
975
+    }
976
+
977
+    /**
978
+     * This provider does not handle groups
979
+     *
980
+     * @param string $uid
981
+     * @param string $gid
982
+     */
983
+    public function userDeletedFromGroup($uid, $gid) {
984
+        // We don't handle groups here
985
+    }
986
+
987
+    /**
988
+     * check if users from other Nextcloud instances are allowed to mount public links share by this instance
989
+     *
990
+     * @return bool
991
+     */
992
+    public function isOutgoingServer2serverShareEnabled() {
993
+        if ($this->gsConfig->onlyInternalFederation()) {
994
+            return false;
995
+        }
996
+        $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
997
+        return ($result === 'yes');
998
+    }
999
+
1000
+    /**
1001
+     * check if users are allowed to mount public links from other Nextclouds
1002
+     *
1003
+     * @return bool
1004
+     */
1005
+    public function isIncomingServer2serverShareEnabled() {
1006
+        if ($this->gsConfig->onlyInternalFederation()) {
1007
+            return false;
1008
+        }
1009
+        $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
1010
+        return ($result === 'yes');
1011
+    }
1012
+
1013
+
1014
+    /**
1015
+     * check if users from other Nextcloud instances are allowed to send federated group shares
1016
+     *
1017
+     * @return bool
1018
+     */
1019
+    public function isOutgoingServer2serverGroupShareEnabled() {
1020
+        if ($this->gsConfig->onlyInternalFederation()) {
1021
+            return false;
1022
+        }
1023
+        $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no');
1024
+        return ($result === 'yes');
1025
+    }
1026
+
1027
+    /**
1028
+     * check if users are allowed to receive federated group shares
1029
+     *
1030
+     * @return bool
1031
+     */
1032
+    public function isIncomingServer2serverGroupShareEnabled() {
1033
+        if ($this->gsConfig->onlyInternalFederation()) {
1034
+            return false;
1035
+        }
1036
+        $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no');
1037
+        return ($result === 'yes');
1038
+    }
1039
+
1040
+    /**
1041
+     * check if federated group sharing is supported, therefore the OCM API need to be enabled
1042
+     *
1043
+     * @return bool
1044
+     */
1045
+    public function isFederatedGroupSharingSupported() {
1046
+        return $this->cloudFederationProviderManager->isReady();
1047
+    }
1048
+
1049
+    /**
1050
+     * Check if querying sharees on the lookup server is enabled
1051
+     *
1052
+     * @return bool
1053
+     */
1054
+    public function isLookupServerQueriesEnabled() {
1055
+        // in a global scale setup we should always query the lookup server
1056
+        if ($this->gsConfig->isGlobalScaleEnabled()) {
1057
+            return true;
1058
+        }
1059
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes');
1060
+        return ($result === 'yes');
1061
+    }
1062
+
1063
+
1064
+    /**
1065
+     * Check if it is allowed to publish user specific data to the lookup server
1066
+     *
1067
+     * @return bool
1068
+     */
1069
+    public function isLookupServerUploadEnabled() {
1070
+        // in a global scale setup the admin is responsible to keep the lookup server up-to-date
1071
+        if ($this->gsConfig->isGlobalScaleEnabled()) {
1072
+            return false;
1073
+        }
1074
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
1075
+        return ($result === 'yes');
1076
+    }
1077
+
1078
+    /**
1079
+     * @inheritdoc
1080
+     */
1081
+    public function getAccessList($nodes, $currentAccess) {
1082
+        $ids = [];
1083
+        foreach ($nodes as $node) {
1084
+            $ids[] = $node->getId();
1085
+        }
1086
+
1087
+        $qb = $this->dbConnection->getQueryBuilder();
1088
+        $qb->select('share_with', 'token', 'file_source')
1089
+            ->from('share')
1090
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)))
1091
+            ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1092
+            ->andWhere($qb->expr()->orX(
1093
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1094
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1095
+            ));
1096
+        $cursor = $qb->execute();
1097
+
1098
+        if ($currentAccess === false) {
1099
+            $remote = $cursor->fetch() !== false;
1100
+            $cursor->closeCursor();
1101
+
1102
+            return ['remote' => $remote];
1103
+        }
1104
+
1105
+        $remote = [];
1106
+        while ($row = $cursor->fetch()) {
1107
+            $remote[$row['share_with']] = [
1108
+                'node_id' => $row['file_source'],
1109
+                'token' => $row['token'],
1110
+            ];
1111
+        }
1112
+        $cursor->closeCursor();
1113
+
1114
+        return ['remote' => $remote];
1115
+    }
1116
+
1117
+    public function getAllShares(): iterable {
1118
+        $qb = $this->dbConnection->getQueryBuilder();
1119
+
1120
+        $qb->select('*')
1121
+            ->from('share')
1122
+            ->where(
1123
+                $qb->expr()->orX(
1124
+                    $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE)),
1125
+                    $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE_GROUP))
1126
+                )
1127
+            );
1128
+
1129
+        $cursor = $qb->execute();
1130
+        while ($data = $cursor->fetch()) {
1131
+            try {
1132
+                $share = $this->createShareObject($data);
1133
+            } catch (InvalidShare $e) {
1134
+                continue;
1135
+            } catch (ShareNotFound $e) {
1136
+                continue;
1137
+            }
1138
+
1139
+            yield $share;
1140
+        }
1141
+        $cursor->closeCursor();
1142
+    }
1143 1143
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -220,7 +220,7 @@  discard block
 block discarded – undo
220 220
 		if ($remoteShare) {
221 221
 			try {
222 222
 				$ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
223
-				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType, $expirationDate);
223
+				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_'.time(), $shareType, $expirationDate);
224 224
 				$share->setId($shareId);
225 225
 				[$token, $remoteId] = $this->askOwnerToReShare($shareWith, $share, $shareId);
226 226
 				// remote share was create successfully if we get a valid token as return
@@ -354,7 +354,7 @@  discard block
 block discarded – undo
354 354
 		$result = $qResult->fetchAll();
355 355
 		$qResult->closeCursor();
356 356
 
357
-		if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
357
+		if (isset($result[0]) && (int) $result[0]['remote_id'] > 0) {
358 358
 			return $result[0];
359 359
 		}
360 360
 
@@ -488,7 +488,7 @@  discard block
 block discarded – undo
488 488
 	public function getRemoteId(IShare $share): string {
489 489
 		$query = $this->dbConnection->getQueryBuilder();
490 490
 		$query->select('remote_id')->from('federated_reshares')
491
-			->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
491
+			->where($query->expr()->eq('share_id', $query->createNamedParameter((int) $share->getId())));
492 492
 		$result = $query->execute();
493 493
 		$data = $result->fetch();
494 494
 		$result->closeCursor();
@@ -497,7 +497,7 @@  discard block
 block discarded – undo
497 497
 			throw new ShareNotFound();
498 498
 		}
499 499
 
500
-		return (string)$data['remote_id'];
500
+		return (string) $data['remote_id'];
501 501
 	}
502 502
 
503 503
 	/**
@@ -655,7 +655,7 @@  discard block
 block discarded – undo
655 655
 			);
656 656
 		}
657 657
 
658
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
658
+		$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
659 659
 		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
660 660
 
661 661
 		$qb->orderBy('id');
@@ -742,7 +742,7 @@  discard block
 block discarded – undo
742 742
 		$cursor->closeCursor();
743 743
 
744 744
 		if ($data === false) {
745
-			throw new ShareNotFound('Can not find share with ID: ' . $id);
745
+			throw new ShareNotFound('Can not find share with ID: '.$id);
746 746
 		}
747 747
 
748 748
 		try {
@@ -886,15 +886,15 @@  discard block
 block discarded – undo
886 886
 	 */
887 887
 	private function createShareObject($data) {
888 888
 		$share = new Share($this->rootFolder, $this->userManager);
889
-		$share->setId((int)$data['id'])
890
-			->setShareType((int)$data['share_type'])
891
-			->setPermissions((int)$data['permissions'])
889
+		$share->setId((int) $data['id'])
890
+			->setShareType((int) $data['share_type'])
891
+			->setPermissions((int) $data['permissions'])
892 892
 			->setTarget($data['file_target'])
893
-			->setMailSend((bool)$data['mail_send'])
893
+			->setMailSend((bool) $data['mail_send'])
894 894
 			->setToken($data['token']);
895 895
 
896 896
 		$shareTime = new \DateTime();
897
-		$shareTime->setTimestamp((int)$data['stime']);
897
+		$shareTime->setTimestamp((int) $data['stime']);
898 898
 		$share->setShareTime($shareTime);
899 899
 		$share->setSharedWith($data['share_with']);
900 900
 
@@ -904,13 +904,13 @@  discard block
 block discarded – undo
904 904
 		} else {
905 905
 			//OLD SHARE
906 906
 			$share->setSharedBy($data['uid_owner']);
907
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
907
+			$path = $this->getNode($share->getSharedBy(), (int) $data['file_source']);
908 908
 
909 909
 			$owner = $path->getOwner();
910 910
 			$share->setShareOwner($owner->getUID());
911 911
 		}
912 912
 
913
-		$share->setNodeId((int)$data['file_source']);
913
+		$share->setNodeId((int) $data['file_source']);
914 914
 		$share->setNodeType($data['item_type']);
915 915
 
916 916
 		$share->setProviderId($this->identifier());
Please login to merge, or discard this patch.