Completed
Push — master ( 031add...ab3599 )
by Morris
40:08 queued 20:01
created
lib/private/Share20/Manager.php 1 patch
Indentation   +1531 added lines, -1531 removed lines patch added patch discarded remove patch
@@ -72,1559 +72,1559 @@
 block discarded – undo
72 72
  */
73 73
 class Manager implements IManager {
74 74
 
75
-	/** @var IProviderFactory */
76
-	private $factory;
77
-	/** @var ILogger */
78
-	private $logger;
79
-	/** @var IConfig */
80
-	private $config;
81
-	/** @var ISecureRandom */
82
-	private $secureRandom;
83
-	/** @var IHasher */
84
-	private $hasher;
85
-	/** @var IMountManager */
86
-	private $mountManager;
87
-	/** @var IGroupManager */
88
-	private $groupManager;
89
-	/** @var IL10N */
90
-	private $l;
91
-	/** @var IFactory */
92
-	private $l10nFactory;
93
-	/** @var IUserManager */
94
-	private $userManager;
95
-	/** @var IRootFolder */
96
-	private $rootFolder;
97
-	/** @var CappedMemoryCache */
98
-	private $sharingDisabledForUsersCache;
99
-	/** @var EventDispatcher */
100
-	private $eventDispatcher;
101
-	/** @var LegacyHooks */
102
-	private $legacyHooks;
103
-	/** @var IMailer */
104
-	private $mailer;
105
-	/** @var IURLGenerator */
106
-	private $urlGenerator;
107
-	/** @var \OC_Defaults */
108
-	private $defaults;
109
-
110
-
111
-	/**
112
-	 * Manager constructor.
113
-	 *
114
-	 * @param ILogger $logger
115
-	 * @param IConfig $config
116
-	 * @param ISecureRandom $secureRandom
117
-	 * @param IHasher $hasher
118
-	 * @param IMountManager $mountManager
119
-	 * @param IGroupManager $groupManager
120
-	 * @param IL10N $l
121
-	 * @param IFactory $l10nFactory
122
-	 * @param IProviderFactory $factory
123
-	 * @param IUserManager $userManager
124
-	 * @param IRootFolder $rootFolder
125
-	 * @param EventDispatcher $eventDispatcher
126
-	 * @param IMailer $mailer
127
-	 * @param IURLGenerator $urlGenerator
128
-	 * @param \OC_Defaults $defaults
129
-	 */
130
-	public function __construct(
131
-			ILogger $logger,
132
-			IConfig $config,
133
-			ISecureRandom $secureRandom,
134
-			IHasher $hasher,
135
-			IMountManager $mountManager,
136
-			IGroupManager $groupManager,
137
-			IL10N $l,
138
-			IFactory $l10nFactory,
139
-			IProviderFactory $factory,
140
-			IUserManager $userManager,
141
-			IRootFolder $rootFolder,
142
-			EventDispatcher $eventDispatcher,
143
-			IMailer $mailer,
144
-			IURLGenerator $urlGenerator,
145
-			\OC_Defaults $defaults
146
-	) {
147
-		$this->logger = $logger;
148
-		$this->config = $config;
149
-		$this->secureRandom = $secureRandom;
150
-		$this->hasher = $hasher;
151
-		$this->mountManager = $mountManager;
152
-		$this->groupManager = $groupManager;
153
-		$this->l = $l;
154
-		$this->l10nFactory = $l10nFactory;
155
-		$this->factory = $factory;
156
-		$this->userManager = $userManager;
157
-		$this->rootFolder = $rootFolder;
158
-		$this->eventDispatcher = $eventDispatcher;
159
-		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
160
-		$this->legacyHooks = new LegacyHooks($this->eventDispatcher);
161
-		$this->mailer = $mailer;
162
-		$this->urlGenerator = $urlGenerator;
163
-		$this->defaults = $defaults;
164
-	}
165
-
166
-	/**
167
-	 * Convert from a full share id to a tuple (providerId, shareId)
168
-	 *
169
-	 * @param string $id
170
-	 * @return string[]
171
-	 */
172
-	private function splitFullId($id) {
173
-		return explode(':', $id, 2);
174
-	}
175
-
176
-	/**
177
-	 * Verify if a password meets all requirements
178
-	 *
179
-	 * @param string $password
180
-	 * @throws \Exception
181
-	 */
182
-	protected function verifyPassword($password) {
183
-		if ($password === null) {
184
-			// No password is set, check if this is allowed.
185
-			if ($this->shareApiLinkEnforcePassword()) {
186
-				throw new \InvalidArgumentException('Passwords are enforced for link shares');
187
-			}
188
-
189
-			return;
190
-		}
191
-
192
-		// Let others verify the password
193
-		try {
194
-			$event = new GenericEvent($password);
195
-			$this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
196
-		} catch (HintException $e) {
197
-			throw new \Exception($e->getHint());
198
-		}
199
-	}
200
-
201
-	/**
202
-	 * Check for generic requirements before creating a share
203
-	 *
204
-	 * @param \OCP\Share\IShare $share
205
-	 * @throws \InvalidArgumentException
206
-	 * @throws GenericShareException
207
-	 *
208
-	 * @suppress PhanUndeclaredClassMethod
209
-	 */
210
-	protected function generalCreateChecks(\OCP\Share\IShare $share) {
211
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
212
-			// We expect a valid user as sharedWith for user shares
213
-			if (!$this->userManager->userExists($share->getSharedWith())) {
214
-				throw new \InvalidArgumentException('SharedWith is not a valid user');
215
-			}
216
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
217
-			// We expect a valid group as sharedWith for group shares
218
-			if (!$this->groupManager->groupExists($share->getSharedWith())) {
219
-				throw new \InvalidArgumentException('SharedWith is not a valid group');
220
-			}
221
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
222
-			if ($share->getSharedWith() !== null) {
223
-				throw new \InvalidArgumentException('SharedWith should be empty');
224
-			}
225
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
226
-			if ($share->getSharedWith() === null) {
227
-				throw new \InvalidArgumentException('SharedWith should not be empty');
228
-			}
229
-		}  else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE_GROUP) {
230
-			if ($share->getSharedWith() === null) {
231
-				throw new \InvalidArgumentException('SharedWith should not be empty');
232
-			}
233
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
234
-			if ($share->getSharedWith() === null) {
235
-				throw new \InvalidArgumentException('SharedWith should not be empty');
236
-			}
237
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
238
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
239
-			if ($circle === null) {
240
-				throw new \InvalidArgumentException('SharedWith is not a valid circle');
241
-			}
242
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_ROOM) {
243
-		} else {
244
-			// We can't handle other types yet
245
-			throw new \InvalidArgumentException('unknown share type');
246
-		}
247
-
248
-		// Verify the initiator of the share is set
249
-		if ($share->getSharedBy() === null) {
250
-			throw new \InvalidArgumentException('SharedBy should be set');
251
-		}
252
-
253
-		// Cannot share with yourself
254
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
255
-			$share->getSharedWith() === $share->getSharedBy()) {
256
-			throw new \InvalidArgumentException('Can’t share with yourself');
257
-		}
258
-
259
-		// The path should be set
260
-		if ($share->getNode() === null) {
261
-			throw new \InvalidArgumentException('Path should be set');
262
-		}
263
-
264
-		// And it should be a file or a folder
265
-		if (!($share->getNode() instanceof \OCP\Files\File) &&
266
-				!($share->getNode() instanceof \OCP\Files\Folder)) {
267
-			throw new \InvalidArgumentException('Path should be either a file or a folder');
268
-		}
269
-
270
-		// And you can't share your rootfolder
271
-		if ($this->userManager->userExists($share->getSharedBy())) {
272
-			$sharedPath = $this->rootFolder->getUserFolder($share->getSharedBy())->getPath();
273
-		} else {
274
-			$sharedPath = $this->rootFolder->getUserFolder($share->getShareOwner())->getPath();
275
-		}
276
-		if ($sharedPath === $share->getNode()->getPath()) {
277
-			throw new \InvalidArgumentException('You can’t share your root folder');
278
-		}
279
-
280
-		// Check if we actually have share permissions
281
-		if (!$share->getNode()->isShareable()) {
282
-			$message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getPath()]);
283
-			throw new GenericShareException($message_t, $message_t, 404);
284
-		}
285
-
286
-		// Permissions should be set
287
-		if ($share->getPermissions() === null) {
288
-			throw new \InvalidArgumentException('A share requires permissions');
289
-		}
290
-
291
-		/*
75
+    /** @var IProviderFactory */
76
+    private $factory;
77
+    /** @var ILogger */
78
+    private $logger;
79
+    /** @var IConfig */
80
+    private $config;
81
+    /** @var ISecureRandom */
82
+    private $secureRandom;
83
+    /** @var IHasher */
84
+    private $hasher;
85
+    /** @var IMountManager */
86
+    private $mountManager;
87
+    /** @var IGroupManager */
88
+    private $groupManager;
89
+    /** @var IL10N */
90
+    private $l;
91
+    /** @var IFactory */
92
+    private $l10nFactory;
93
+    /** @var IUserManager */
94
+    private $userManager;
95
+    /** @var IRootFolder */
96
+    private $rootFolder;
97
+    /** @var CappedMemoryCache */
98
+    private $sharingDisabledForUsersCache;
99
+    /** @var EventDispatcher */
100
+    private $eventDispatcher;
101
+    /** @var LegacyHooks */
102
+    private $legacyHooks;
103
+    /** @var IMailer */
104
+    private $mailer;
105
+    /** @var IURLGenerator */
106
+    private $urlGenerator;
107
+    /** @var \OC_Defaults */
108
+    private $defaults;
109
+
110
+
111
+    /**
112
+     * Manager constructor.
113
+     *
114
+     * @param ILogger $logger
115
+     * @param IConfig $config
116
+     * @param ISecureRandom $secureRandom
117
+     * @param IHasher $hasher
118
+     * @param IMountManager $mountManager
119
+     * @param IGroupManager $groupManager
120
+     * @param IL10N $l
121
+     * @param IFactory $l10nFactory
122
+     * @param IProviderFactory $factory
123
+     * @param IUserManager $userManager
124
+     * @param IRootFolder $rootFolder
125
+     * @param EventDispatcher $eventDispatcher
126
+     * @param IMailer $mailer
127
+     * @param IURLGenerator $urlGenerator
128
+     * @param \OC_Defaults $defaults
129
+     */
130
+    public function __construct(
131
+            ILogger $logger,
132
+            IConfig $config,
133
+            ISecureRandom $secureRandom,
134
+            IHasher $hasher,
135
+            IMountManager $mountManager,
136
+            IGroupManager $groupManager,
137
+            IL10N $l,
138
+            IFactory $l10nFactory,
139
+            IProviderFactory $factory,
140
+            IUserManager $userManager,
141
+            IRootFolder $rootFolder,
142
+            EventDispatcher $eventDispatcher,
143
+            IMailer $mailer,
144
+            IURLGenerator $urlGenerator,
145
+            \OC_Defaults $defaults
146
+    ) {
147
+        $this->logger = $logger;
148
+        $this->config = $config;
149
+        $this->secureRandom = $secureRandom;
150
+        $this->hasher = $hasher;
151
+        $this->mountManager = $mountManager;
152
+        $this->groupManager = $groupManager;
153
+        $this->l = $l;
154
+        $this->l10nFactory = $l10nFactory;
155
+        $this->factory = $factory;
156
+        $this->userManager = $userManager;
157
+        $this->rootFolder = $rootFolder;
158
+        $this->eventDispatcher = $eventDispatcher;
159
+        $this->sharingDisabledForUsersCache = new CappedMemoryCache();
160
+        $this->legacyHooks = new LegacyHooks($this->eventDispatcher);
161
+        $this->mailer = $mailer;
162
+        $this->urlGenerator = $urlGenerator;
163
+        $this->defaults = $defaults;
164
+    }
165
+
166
+    /**
167
+     * Convert from a full share id to a tuple (providerId, shareId)
168
+     *
169
+     * @param string $id
170
+     * @return string[]
171
+     */
172
+    private function splitFullId($id) {
173
+        return explode(':', $id, 2);
174
+    }
175
+
176
+    /**
177
+     * Verify if a password meets all requirements
178
+     *
179
+     * @param string $password
180
+     * @throws \Exception
181
+     */
182
+    protected function verifyPassword($password) {
183
+        if ($password === null) {
184
+            // No password is set, check if this is allowed.
185
+            if ($this->shareApiLinkEnforcePassword()) {
186
+                throw new \InvalidArgumentException('Passwords are enforced for link shares');
187
+            }
188
+
189
+            return;
190
+        }
191
+
192
+        // Let others verify the password
193
+        try {
194
+            $event = new GenericEvent($password);
195
+            $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
196
+        } catch (HintException $e) {
197
+            throw new \Exception($e->getHint());
198
+        }
199
+    }
200
+
201
+    /**
202
+     * Check for generic requirements before creating a share
203
+     *
204
+     * @param \OCP\Share\IShare $share
205
+     * @throws \InvalidArgumentException
206
+     * @throws GenericShareException
207
+     *
208
+     * @suppress PhanUndeclaredClassMethod
209
+     */
210
+    protected function generalCreateChecks(\OCP\Share\IShare $share) {
211
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
212
+            // We expect a valid user as sharedWith for user shares
213
+            if (!$this->userManager->userExists($share->getSharedWith())) {
214
+                throw new \InvalidArgumentException('SharedWith is not a valid user');
215
+            }
216
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
217
+            // We expect a valid group as sharedWith for group shares
218
+            if (!$this->groupManager->groupExists($share->getSharedWith())) {
219
+                throw new \InvalidArgumentException('SharedWith is not a valid group');
220
+            }
221
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
222
+            if ($share->getSharedWith() !== null) {
223
+                throw new \InvalidArgumentException('SharedWith should be empty');
224
+            }
225
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
226
+            if ($share->getSharedWith() === null) {
227
+                throw new \InvalidArgumentException('SharedWith should not be empty');
228
+            }
229
+        }  else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE_GROUP) {
230
+            if ($share->getSharedWith() === null) {
231
+                throw new \InvalidArgumentException('SharedWith should not be empty');
232
+            }
233
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
234
+            if ($share->getSharedWith() === null) {
235
+                throw new \InvalidArgumentException('SharedWith should not be empty');
236
+            }
237
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
238
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
239
+            if ($circle === null) {
240
+                throw new \InvalidArgumentException('SharedWith is not a valid circle');
241
+            }
242
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_ROOM) {
243
+        } else {
244
+            // We can't handle other types yet
245
+            throw new \InvalidArgumentException('unknown share type');
246
+        }
247
+
248
+        // Verify the initiator of the share is set
249
+        if ($share->getSharedBy() === null) {
250
+            throw new \InvalidArgumentException('SharedBy should be set');
251
+        }
252
+
253
+        // Cannot share with yourself
254
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
255
+            $share->getSharedWith() === $share->getSharedBy()) {
256
+            throw new \InvalidArgumentException('Can’t share with yourself');
257
+        }
258
+
259
+        // The path should be set
260
+        if ($share->getNode() === null) {
261
+            throw new \InvalidArgumentException('Path should be set');
262
+        }
263
+
264
+        // And it should be a file or a folder
265
+        if (!($share->getNode() instanceof \OCP\Files\File) &&
266
+                !($share->getNode() instanceof \OCP\Files\Folder)) {
267
+            throw new \InvalidArgumentException('Path should be either a file or a folder');
268
+        }
269
+
270
+        // And you can't share your rootfolder
271
+        if ($this->userManager->userExists($share->getSharedBy())) {
272
+            $sharedPath = $this->rootFolder->getUserFolder($share->getSharedBy())->getPath();
273
+        } else {
274
+            $sharedPath = $this->rootFolder->getUserFolder($share->getShareOwner())->getPath();
275
+        }
276
+        if ($sharedPath === $share->getNode()->getPath()) {
277
+            throw new \InvalidArgumentException('You can’t share your root folder');
278
+        }
279
+
280
+        // Check if we actually have share permissions
281
+        if (!$share->getNode()->isShareable()) {
282
+            $message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getPath()]);
283
+            throw new GenericShareException($message_t, $message_t, 404);
284
+        }
285
+
286
+        // Permissions should be set
287
+        if ($share->getPermissions() === null) {
288
+            throw new \InvalidArgumentException('A share requires permissions');
289
+        }
290
+
291
+        /*
292 292
 		 * Quick fix for #23536
293 293
 		 * Non moveable mount points do not have update and delete permissions
294 294
 		 * while we 'most likely' do have that on the storage.
295 295
 		 */
296
-		$permissions = $share->getNode()->getPermissions();
297
-		$mount = $share->getNode()->getMountPoint();
298
-		if (!($mount instanceof MoveableMount)) {
299
-			$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
300
-		}
301
-
302
-		// Check that we do not share with more permissions than we have
303
-		if ($share->getPermissions() & ~$permissions) {
304
-			$message_t = $this->l->t('Can’t increase permissions of %s', [$share->getNode()->getPath()]);
305
-			throw new GenericShareException($message_t, $message_t, 404);
306
-		}
307
-
308
-
309
-		// Check that read permissions are always set
310
-		// Link shares are allowed to have no read permissions to allow upload to hidden folders
311
-		$noReadPermissionRequired = $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK
312
-			|| $share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL;
313
-		if (!$noReadPermissionRequired &&
314
-			($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
315
-			throw new \InvalidArgumentException('Shares need at least read permissions');
316
-		}
317
-
318
-		if ($share->getNode() instanceof \OCP\Files\File) {
319
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
320
-				$message_t = $this->l->t('Files can’t be shared with delete permissions');
321
-				throw new GenericShareException($message_t);
322
-			}
323
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
324
-				$message_t = $this->l->t('Files can’t be shared with create permissions');
325
-				throw new GenericShareException($message_t);
326
-			}
327
-		}
328
-	}
329
-
330
-	/**
331
-	 * Validate if the expiration date fits the system settings
332
-	 *
333
-	 * @param \OCP\Share\IShare $share The share to validate the expiration date of
334
-	 * @return \OCP\Share\IShare The modified share object
335
-	 * @throws GenericShareException
336
-	 * @throws \InvalidArgumentException
337
-	 * @throws \Exception
338
-	 */
339
-	protected function validateExpirationDate(\OCP\Share\IShare $share) {
340
-
341
-		$expirationDate = $share->getExpirationDate();
342
-
343
-		if ($expirationDate !== null) {
344
-			//Make sure the expiration date is a date
345
-			$expirationDate->setTime(0, 0, 0);
346
-
347
-			$date = new \DateTime();
348
-			$date->setTime(0, 0, 0);
349
-			if ($date >= $expirationDate) {
350
-				$message = $this->l->t('Expiration date is in the past');
351
-				throw new GenericShareException($message, $message, 404);
352
-			}
353
-		}
354
-
355
-		// If expiredate is empty set a default one if there is a default
356
-		$fullId = null;
357
-		try {
358
-			$fullId = $share->getFullId();
359
-		} catch (\UnexpectedValueException $e) {
360
-			// This is a new share
361
-		}
362
-
363
-		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
364
-			$expirationDate = new \DateTime();
365
-			$expirationDate->setTime(0,0,0);
366
-			$expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
367
-		}
368
-
369
-		// If we enforce the expiration date check that is does not exceed
370
-		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
371
-			if ($expirationDate === null) {
372
-				throw new \InvalidArgumentException('Expiration date is enforced');
373
-			}
374
-
375
-			$date = new \DateTime();
376
-			$date->setTime(0, 0, 0);
377
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
378
-			if ($date < $expirationDate) {
379
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
380
-				throw new GenericShareException($message, $message, 404);
381
-			}
382
-		}
383
-
384
-		$accepted = true;
385
-		$message = '';
386
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
387
-			'expirationDate' => &$expirationDate,
388
-			'accepted' => &$accepted,
389
-			'message' => &$message,
390
-			'passwordSet' => $share->getPassword() !== null,
391
-		]);
392
-
393
-		if (!$accepted) {
394
-			throw new \Exception($message);
395
-		}
396
-
397
-		$share->setExpirationDate($expirationDate);
398
-
399
-		return $share;
400
-	}
401
-
402
-	/**
403
-	 * Check for pre share requirements for user shares
404
-	 *
405
-	 * @param \OCP\Share\IShare $share
406
-	 * @throws \Exception
407
-	 */
408
-	protected function userCreateChecks(\OCP\Share\IShare $share) {
409
-		// Check if we can share with group members only
410
-		if ($this->shareWithGroupMembersOnly()) {
411
-			$sharedBy = $this->userManager->get($share->getSharedBy());
412
-			$sharedWith = $this->userManager->get($share->getSharedWith());
413
-			// Verify we can share with this user
414
-			$groups = array_intersect(
415
-					$this->groupManager->getUserGroupIds($sharedBy),
416
-					$this->groupManager->getUserGroupIds($sharedWith)
417
-			);
418
-			if (empty($groups)) {
419
-				throw new \Exception('Sharing is only allowed with group members');
420
-			}
421
-		}
422
-
423
-		/*
296
+        $permissions = $share->getNode()->getPermissions();
297
+        $mount = $share->getNode()->getMountPoint();
298
+        if (!($mount instanceof MoveableMount)) {
299
+            $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
300
+        }
301
+
302
+        // Check that we do not share with more permissions than we have
303
+        if ($share->getPermissions() & ~$permissions) {
304
+            $message_t = $this->l->t('Can’t increase permissions of %s', [$share->getNode()->getPath()]);
305
+            throw new GenericShareException($message_t, $message_t, 404);
306
+        }
307
+
308
+
309
+        // Check that read permissions are always set
310
+        // Link shares are allowed to have no read permissions to allow upload to hidden folders
311
+        $noReadPermissionRequired = $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK
312
+            || $share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL;
313
+        if (!$noReadPermissionRequired &&
314
+            ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
315
+            throw new \InvalidArgumentException('Shares need at least read permissions');
316
+        }
317
+
318
+        if ($share->getNode() instanceof \OCP\Files\File) {
319
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
320
+                $message_t = $this->l->t('Files can’t be shared with delete permissions');
321
+                throw new GenericShareException($message_t);
322
+            }
323
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
324
+                $message_t = $this->l->t('Files can’t be shared with create permissions');
325
+                throw new GenericShareException($message_t);
326
+            }
327
+        }
328
+    }
329
+
330
+    /**
331
+     * Validate if the expiration date fits the system settings
332
+     *
333
+     * @param \OCP\Share\IShare $share The share to validate the expiration date of
334
+     * @return \OCP\Share\IShare The modified share object
335
+     * @throws GenericShareException
336
+     * @throws \InvalidArgumentException
337
+     * @throws \Exception
338
+     */
339
+    protected function validateExpirationDate(\OCP\Share\IShare $share) {
340
+
341
+        $expirationDate = $share->getExpirationDate();
342
+
343
+        if ($expirationDate !== null) {
344
+            //Make sure the expiration date is a date
345
+            $expirationDate->setTime(0, 0, 0);
346
+
347
+            $date = new \DateTime();
348
+            $date->setTime(0, 0, 0);
349
+            if ($date >= $expirationDate) {
350
+                $message = $this->l->t('Expiration date is in the past');
351
+                throw new GenericShareException($message, $message, 404);
352
+            }
353
+        }
354
+
355
+        // If expiredate is empty set a default one if there is a default
356
+        $fullId = null;
357
+        try {
358
+            $fullId = $share->getFullId();
359
+        } catch (\UnexpectedValueException $e) {
360
+            // This is a new share
361
+        }
362
+
363
+        if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
364
+            $expirationDate = new \DateTime();
365
+            $expirationDate->setTime(0,0,0);
366
+            $expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
367
+        }
368
+
369
+        // If we enforce the expiration date check that is does not exceed
370
+        if ($this->shareApiLinkDefaultExpireDateEnforced()) {
371
+            if ($expirationDate === null) {
372
+                throw new \InvalidArgumentException('Expiration date is enforced');
373
+            }
374
+
375
+            $date = new \DateTime();
376
+            $date->setTime(0, 0, 0);
377
+            $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
378
+            if ($date < $expirationDate) {
379
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
380
+                throw new GenericShareException($message, $message, 404);
381
+            }
382
+        }
383
+
384
+        $accepted = true;
385
+        $message = '';
386
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
387
+            'expirationDate' => &$expirationDate,
388
+            'accepted' => &$accepted,
389
+            'message' => &$message,
390
+            'passwordSet' => $share->getPassword() !== null,
391
+        ]);
392
+
393
+        if (!$accepted) {
394
+            throw new \Exception($message);
395
+        }
396
+
397
+        $share->setExpirationDate($expirationDate);
398
+
399
+        return $share;
400
+    }
401
+
402
+    /**
403
+     * Check for pre share requirements for user shares
404
+     *
405
+     * @param \OCP\Share\IShare $share
406
+     * @throws \Exception
407
+     */
408
+    protected function userCreateChecks(\OCP\Share\IShare $share) {
409
+        // Check if we can share with group members only
410
+        if ($this->shareWithGroupMembersOnly()) {
411
+            $sharedBy = $this->userManager->get($share->getSharedBy());
412
+            $sharedWith = $this->userManager->get($share->getSharedWith());
413
+            // Verify we can share with this user
414
+            $groups = array_intersect(
415
+                    $this->groupManager->getUserGroupIds($sharedBy),
416
+                    $this->groupManager->getUserGroupIds($sharedWith)
417
+            );
418
+            if (empty($groups)) {
419
+                throw new \Exception('Sharing is only allowed with group members');
420
+            }
421
+        }
422
+
423
+        /*
424 424
 		 * TODO: Could be costly, fix
425 425
 		 *
426 426
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
427 427
 		 */
428
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
429
-		$existingShares = $provider->getSharesByPath($share->getNode());
430
-		foreach($existingShares as $existingShare) {
431
-			// Ignore if it is the same share
432
-			try {
433
-				if ($existingShare->getFullId() === $share->getFullId()) {
434
-					continue;
435
-				}
436
-			} catch (\UnexpectedValueException $e) {
437
-				//Shares are not identical
438
-			}
439
-
440
-			// Identical share already existst
441
-			if ($existingShare->getSharedWith() === $share->getSharedWith()) {
442
-				throw new \Exception('Path is already shared with this user');
443
-			}
444
-
445
-			// The share is already shared with this user via a group share
446
-			if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
447
-				$group = $this->groupManager->get($existingShare->getSharedWith());
448
-				if (!is_null($group)) {
449
-					$user = $this->userManager->get($share->getSharedWith());
450
-
451
-					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
452
-						throw new \Exception('Path is already shared with this user');
453
-					}
454
-				}
455
-			}
456
-		}
457
-	}
458
-
459
-	/**
460
-	 * Check for pre share requirements for group shares
461
-	 *
462
-	 * @param \OCP\Share\IShare $share
463
-	 * @throws \Exception
464
-	 */
465
-	protected function groupCreateChecks(\OCP\Share\IShare $share) {
466
-		// Verify group shares are allowed
467
-		if (!$this->allowGroupSharing()) {
468
-			throw new \Exception('Group sharing is now allowed');
469
-		}
470
-
471
-		// Verify if the user can share with this group
472
-		if ($this->shareWithGroupMembersOnly()) {
473
-			$sharedBy = $this->userManager->get($share->getSharedBy());
474
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
475
-			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
476
-				throw new \Exception('Sharing is only allowed within your own groups');
477
-			}
478
-		}
479
-
480
-		/*
428
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
429
+        $existingShares = $provider->getSharesByPath($share->getNode());
430
+        foreach($existingShares as $existingShare) {
431
+            // Ignore if it is the same share
432
+            try {
433
+                if ($existingShare->getFullId() === $share->getFullId()) {
434
+                    continue;
435
+                }
436
+            } catch (\UnexpectedValueException $e) {
437
+                //Shares are not identical
438
+            }
439
+
440
+            // Identical share already existst
441
+            if ($existingShare->getSharedWith() === $share->getSharedWith()) {
442
+                throw new \Exception('Path is already shared with this user');
443
+            }
444
+
445
+            // The share is already shared with this user via a group share
446
+            if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
447
+                $group = $this->groupManager->get($existingShare->getSharedWith());
448
+                if (!is_null($group)) {
449
+                    $user = $this->userManager->get($share->getSharedWith());
450
+
451
+                    if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
452
+                        throw new \Exception('Path is already shared with this user');
453
+                    }
454
+                }
455
+            }
456
+        }
457
+    }
458
+
459
+    /**
460
+     * Check for pre share requirements for group shares
461
+     *
462
+     * @param \OCP\Share\IShare $share
463
+     * @throws \Exception
464
+     */
465
+    protected function groupCreateChecks(\OCP\Share\IShare $share) {
466
+        // Verify group shares are allowed
467
+        if (!$this->allowGroupSharing()) {
468
+            throw new \Exception('Group sharing is now allowed');
469
+        }
470
+
471
+        // Verify if the user can share with this group
472
+        if ($this->shareWithGroupMembersOnly()) {
473
+            $sharedBy = $this->userManager->get($share->getSharedBy());
474
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
475
+            if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
476
+                throw new \Exception('Sharing is only allowed within your own groups');
477
+            }
478
+        }
479
+
480
+        /*
481 481
 		 * TODO: Could be costly, fix
482 482
 		 *
483 483
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
484 484
 		 */
485
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
486
-		$existingShares = $provider->getSharesByPath($share->getNode());
487
-		foreach($existingShares as $existingShare) {
488
-			try {
489
-				if ($existingShare->getFullId() === $share->getFullId()) {
490
-					continue;
491
-				}
492
-			} catch (\UnexpectedValueException $e) {
493
-				//It is a new share so just continue
494
-			}
495
-
496
-			if ($existingShare->getSharedWith() === $share->getSharedWith()) {
497
-				throw new \Exception('Path is already shared with this group');
498
-			}
499
-		}
500
-	}
501
-
502
-	/**
503
-	 * Check for pre share requirements for link shares
504
-	 *
505
-	 * @param \OCP\Share\IShare $share
506
-	 * @throws \Exception
507
-	 */
508
-	protected function linkCreateChecks(\OCP\Share\IShare $share) {
509
-		// Are link shares allowed?
510
-		if (!$this->shareApiAllowLinks()) {
511
-			throw new \Exception('Link sharing is not allowed');
512
-		}
513
-
514
-		// Link shares by definition can't have share permissions
515
-		if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
516
-			throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
517
-		}
518
-
519
-		// Check if public upload is allowed
520
-		if (!$this->shareApiLinkAllowPublicUpload() &&
521
-			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
522
-			throw new \InvalidArgumentException('Public upload is not allowed');
523
-		}
524
-	}
525
-
526
-	/**
527
-	 * To make sure we don't get invisible link shares we set the parent
528
-	 * of a link if it is a reshare. This is a quick word around
529
-	 * until we can properly display multiple link shares in the UI
530
-	 *
531
-	 * See: https://github.com/owncloud/core/issues/22295
532
-	 *
533
-	 * FIXME: Remove once multiple link shares can be properly displayed
534
-	 *
535
-	 * @param \OCP\Share\IShare $share
536
-	 */
537
-	protected function setLinkParent(\OCP\Share\IShare $share) {
538
-
539
-		// No sense in checking if the method is not there.
540
-		if (method_exists($share, 'setParent')) {
541
-			$storage = $share->getNode()->getStorage();
542
-			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
543
-				/** @var \OCA\Files_Sharing\SharedStorage $storage */
544
-				$share->setParent($storage->getShareId());
545
-			}
546
-		}
547
-	}
548
-
549
-	/**
550
-	 * @param File|Folder $path
551
-	 */
552
-	protected function pathCreateChecks($path) {
553
-		// Make sure that we do not share a path that contains a shared mountpoint
554
-		if ($path instanceof \OCP\Files\Folder) {
555
-			$mounts = $this->mountManager->findIn($path->getPath());
556
-			foreach($mounts as $mount) {
557
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
558
-					throw new \InvalidArgumentException('Path contains files shared with you');
559
-				}
560
-			}
561
-		}
562
-	}
563
-
564
-	/**
565
-	 * Check if the user that is sharing can actually share
566
-	 *
567
-	 * @param \OCP\Share\IShare $share
568
-	 * @throws \Exception
569
-	 */
570
-	protected function canShare(\OCP\Share\IShare $share) {
571
-		if (!$this->shareApiEnabled()) {
572
-			throw new \Exception('Sharing is disabled');
573
-		}
574
-
575
-		if ($this->sharingDisabledForUser($share->getSharedBy())) {
576
-			throw new \Exception('Sharing is disabled for you');
577
-		}
578
-	}
579
-
580
-	/**
581
-	 * Share a path
582
-	 *
583
-	 * @param \OCP\Share\IShare $share
584
-	 * @return Share The share object
585
-	 * @throws \Exception
586
-	 *
587
-	 * TODO: handle link share permissions or check them
588
-	 */
589
-	public function createShare(\OCP\Share\IShare $share) {
590
-		$this->canShare($share);
591
-
592
-		$this->generalCreateChecks($share);
593
-
594
-		// Verify if there are any issues with the path
595
-		$this->pathCreateChecks($share->getNode());
596
-
597
-		/*
485
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
486
+        $existingShares = $provider->getSharesByPath($share->getNode());
487
+        foreach($existingShares as $existingShare) {
488
+            try {
489
+                if ($existingShare->getFullId() === $share->getFullId()) {
490
+                    continue;
491
+                }
492
+            } catch (\UnexpectedValueException $e) {
493
+                //It is a new share so just continue
494
+            }
495
+
496
+            if ($existingShare->getSharedWith() === $share->getSharedWith()) {
497
+                throw new \Exception('Path is already shared with this group');
498
+            }
499
+        }
500
+    }
501
+
502
+    /**
503
+     * Check for pre share requirements for link shares
504
+     *
505
+     * @param \OCP\Share\IShare $share
506
+     * @throws \Exception
507
+     */
508
+    protected function linkCreateChecks(\OCP\Share\IShare $share) {
509
+        // Are link shares allowed?
510
+        if (!$this->shareApiAllowLinks()) {
511
+            throw new \Exception('Link sharing is not allowed');
512
+        }
513
+
514
+        // Link shares by definition can't have share permissions
515
+        if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
516
+            throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
517
+        }
518
+
519
+        // Check if public upload is allowed
520
+        if (!$this->shareApiLinkAllowPublicUpload() &&
521
+            ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
522
+            throw new \InvalidArgumentException('Public upload is not allowed');
523
+        }
524
+    }
525
+
526
+    /**
527
+     * To make sure we don't get invisible link shares we set the parent
528
+     * of a link if it is a reshare. This is a quick word around
529
+     * until we can properly display multiple link shares in the UI
530
+     *
531
+     * See: https://github.com/owncloud/core/issues/22295
532
+     *
533
+     * FIXME: Remove once multiple link shares can be properly displayed
534
+     *
535
+     * @param \OCP\Share\IShare $share
536
+     */
537
+    protected function setLinkParent(\OCP\Share\IShare $share) {
538
+
539
+        // No sense in checking if the method is not there.
540
+        if (method_exists($share, 'setParent')) {
541
+            $storage = $share->getNode()->getStorage();
542
+            if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
543
+                /** @var \OCA\Files_Sharing\SharedStorage $storage */
544
+                $share->setParent($storage->getShareId());
545
+            }
546
+        }
547
+    }
548
+
549
+    /**
550
+     * @param File|Folder $path
551
+     */
552
+    protected function pathCreateChecks($path) {
553
+        // Make sure that we do not share a path that contains a shared mountpoint
554
+        if ($path instanceof \OCP\Files\Folder) {
555
+            $mounts = $this->mountManager->findIn($path->getPath());
556
+            foreach($mounts as $mount) {
557
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
558
+                    throw new \InvalidArgumentException('Path contains files shared with you');
559
+                }
560
+            }
561
+        }
562
+    }
563
+
564
+    /**
565
+     * Check if the user that is sharing can actually share
566
+     *
567
+     * @param \OCP\Share\IShare $share
568
+     * @throws \Exception
569
+     */
570
+    protected function canShare(\OCP\Share\IShare $share) {
571
+        if (!$this->shareApiEnabled()) {
572
+            throw new \Exception('Sharing is disabled');
573
+        }
574
+
575
+        if ($this->sharingDisabledForUser($share->getSharedBy())) {
576
+            throw new \Exception('Sharing is disabled for you');
577
+        }
578
+    }
579
+
580
+    /**
581
+     * Share a path
582
+     *
583
+     * @param \OCP\Share\IShare $share
584
+     * @return Share The share object
585
+     * @throws \Exception
586
+     *
587
+     * TODO: handle link share permissions or check them
588
+     */
589
+    public function createShare(\OCP\Share\IShare $share) {
590
+        $this->canShare($share);
591
+
592
+        $this->generalCreateChecks($share);
593
+
594
+        // Verify if there are any issues with the path
595
+        $this->pathCreateChecks($share->getNode());
596
+
597
+        /*
598 598
 		 * On creation of a share the owner is always the owner of the path
599 599
 		 * Except for mounted federated shares.
600 600
 		 */
601
-		$storage = $share->getNode()->getStorage();
602
-		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
603
-			$parent = $share->getNode()->getParent();
604
-			while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
605
-				$parent = $parent->getParent();
606
-			}
607
-			$share->setShareOwner($parent->getOwner()->getUID());
608
-		} else {
609
-			$share->setShareOwner($share->getNode()->getOwner()->getUID());
610
-		}
611
-
612
-		//Verify share type
613
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
614
-			$this->userCreateChecks($share);
615
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
616
-			$this->groupCreateChecks($share);
617
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
618
-			$this->linkCreateChecks($share);
619
-			$this->setLinkParent($share);
620
-
621
-			/*
601
+        $storage = $share->getNode()->getStorage();
602
+        if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
603
+            $parent = $share->getNode()->getParent();
604
+            while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
605
+                $parent = $parent->getParent();
606
+            }
607
+            $share->setShareOwner($parent->getOwner()->getUID());
608
+        } else {
609
+            $share->setShareOwner($share->getNode()->getOwner()->getUID());
610
+        }
611
+
612
+        //Verify share type
613
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
614
+            $this->userCreateChecks($share);
615
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
616
+            $this->groupCreateChecks($share);
617
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
618
+            $this->linkCreateChecks($share);
619
+            $this->setLinkParent($share);
620
+
621
+            /*
622 622
 			 * For now ignore a set token.
623 623
 			 */
624
-			$share->setToken(
625
-				$this->secureRandom->generate(
626
-					\OC\Share\Constants::TOKEN_LENGTH,
627
-					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
628
-				)
629
-			);
630
-
631
-			//Verify the expiration date
632
-			$this->validateExpirationDate($share);
633
-
634
-			//Verify the password
635
-			$this->verifyPassword($share->getPassword());
636
-
637
-			// If a password is set. Hash it!
638
-			if ($share->getPassword() !== null) {
639
-				$share->setPassword($this->hasher->hash($share->getPassword()));
640
-			}
641
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
642
-			$share->setToken(
643
-				$this->secureRandom->generate(
644
-					\OC\Share\Constants::TOKEN_LENGTH,
645
-					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
646
-				)
647
-			);
648
-		}
649
-
650
-		// Cannot share with the owner
651
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
652
-			$share->getSharedWith() === $share->getShareOwner()) {
653
-			throw new \InvalidArgumentException('Can’t share with the share owner');
654
-		}
655
-
656
-		// Generate the target
657
-		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
658
-		$target = \OC\Files\Filesystem::normalizePath($target);
659
-		$share->setTarget($target);
660
-
661
-		// Pre share event
662
-		$event = new GenericEvent($share);
663
-		$a = $this->eventDispatcher->dispatch('OCP\Share::preShare', $event);
664
-		if ($event->isPropagationStopped() && $event->hasArgument('error')) {
665
-			throw new \Exception($event->getArgument('error'));
666
-		}
667
-
668
-		$oldShare = $share;
669
-		$provider = $this->factory->getProviderForType($share->getShareType());
670
-		$share = $provider->create($share);
671
-		//reuse the node we already have
672
-		$share->setNode($oldShare->getNode());
673
-
674
-		// Post share event
675
-		$event = new GenericEvent($share);
676
-		$this->eventDispatcher->dispatch('OCP\Share::postShare', $event);
677
-
678
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
679
-			$mailSend = $share->getMailSend();
680
-			if($mailSend === true) {
681
-				$user = $this->userManager->get($share->getSharedWith());
682
-				if ($user !== null) {
683
-					$emailAddress = $user->getEMailAddress();
684
-					if ($emailAddress !== null && $emailAddress !== '') {
685
-						$userLang = $this->config->getUserValue($share->getSharedWith(), 'core', 'lang', null);
686
-						$l = $this->l10nFactory->get('lib', $userLang);
687
-						$this->sendMailNotification(
688
-							$l,
689
-							$share->getNode()->getName(),
690
-							$this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $share->getNode()->getId()]),
691
-							$share->getSharedBy(),
692
-							$emailAddress,
693
-							$share->getExpirationDate()
694
-						);
695
-						$this->logger->debug('Send share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
696
-					} else {
697
-						$this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
698
-					}
699
-				} else {
700
-					$this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
701
-				}
702
-			} else {
703
-				$this->logger->debug('Share notification not send because mailsend is false.', ['app' => 'share']);
704
-			}
705
-		}
706
-
707
-		return $share;
708
-	}
709
-
710
-	/**
711
-	 * @param IL10N $l Language of the recipient
712
-	 * @param string $filename file/folder name
713
-	 * @param string $link link to the file/folder
714
-	 * @param string $initiator user ID of share sender
715
-	 * @param string $shareWith email address of share receiver
716
-	 * @param \DateTime|null $expiration
717
-	 * @throws \Exception If mail couldn't be sent
718
-	 */
719
-	protected function sendMailNotification(IL10N $l,
720
-											$filename,
721
-											$link,
722
-											$initiator,
723
-											$shareWith,
724
-											\DateTime $expiration = null) {
725
-		$initiatorUser = $this->userManager->get($initiator);
726
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
727
-
728
-		$message = $this->mailer->createMessage();
729
-
730
-		$emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
731
-			'filename' => $filename,
732
-			'link' => $link,
733
-			'initiator' => $initiatorDisplayName,
734
-			'expiration' => $expiration,
735
-			'shareWith' => $shareWith,
736
-		]);
737
-
738
-		$emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', array($initiatorDisplayName, $filename)));
739
-		$emailTemplate->addHeader();
740
-		$emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
741
-		$text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
742
-
743
-		$emailTemplate->addBodyText(
744
-			htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
745
-			$text
746
-		);
747
-		$emailTemplate->addBodyButton(
748
-			$l->t('Open »%s«', [$filename]),
749
-			$link
750
-		);
751
-
752
-		$message->setTo([$shareWith]);
753
-
754
-		// The "From" contains the sharers name
755
-		$instanceName = $this->defaults->getName();
756
-		$senderName = $l->t(
757
-			'%1$s via %2$s',
758
-			[
759
-				$initiatorDisplayName,
760
-				$instanceName
761
-			]
762
-		);
763
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
764
-
765
-		// The "Reply-To" is set to the sharer if an mail address is configured
766
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
767
-		$initiatorEmail = $initiatorUser->getEMailAddress();
768
-		if($initiatorEmail !== null) {
769
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
770
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
771
-		} else {
772
-			$emailTemplate->addFooter();
773
-		}
774
-
775
-		$message->useTemplate($emailTemplate);
776
-		$this->mailer->send($message);
777
-	}
778
-
779
-	/**
780
-	 * Update a share
781
-	 *
782
-	 * @param \OCP\Share\IShare $share
783
-	 * @return \OCP\Share\IShare The share object
784
-	 * @throws \InvalidArgumentException
785
-	 */
786
-	public function updateShare(\OCP\Share\IShare $share) {
787
-		$expirationDateUpdated = false;
788
-
789
-		$this->canShare($share);
790
-
791
-		try {
792
-			$originalShare = $this->getShareById($share->getFullId());
793
-		} catch (\UnexpectedValueException $e) {
794
-			throw new \InvalidArgumentException('Share does not have a full id');
795
-		}
796
-
797
-		// We can't change the share type!
798
-		if ($share->getShareType() !== $originalShare->getShareType()) {
799
-			throw new \InvalidArgumentException('Can’t change share type');
800
-		}
801
-
802
-		// We can only change the recipient on user shares
803
-		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
804
-		    $share->getShareType() !== \OCP\Share::SHARE_TYPE_USER) {
805
-			throw new \InvalidArgumentException('Can only update recipient on user shares');
806
-		}
807
-
808
-		// Cannot share with the owner
809
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
810
-			$share->getSharedWith() === $share->getShareOwner()) {
811
-			throw new \InvalidArgumentException('Can’t share with the share owner');
812
-		}
813
-
814
-		$this->generalCreateChecks($share);
815
-
816
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
817
-			$this->userCreateChecks($share);
818
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
819
-			$this->groupCreateChecks($share);
820
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
821
-			$this->linkCreateChecks($share);
822
-
823
-			$this->updateSharePasswordIfNeeded($share, $originalShare);
824
-
825
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
826
-				//Verify the expiration date
827
-				$this->validateExpirationDate($share);
828
-				$expirationDateUpdated = true;
829
-			}
830
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
831
-			// The new password is not set again if it is the same as the old
832
-			// one, unless when switching from sending by Talk to sending by
833
-			// mail.
834
-			$plainTextPassword = $share->getPassword();
835
-			if (!empty($plainTextPassword) && !$this->updateSharePasswordIfNeeded($share, $originalShare) &&
836
-					!($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk())) {
837
-				$plainTextPassword = null;
838
-			}
839
-			if (empty($plainTextPassword) && !$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
840
-				// If the same password was already sent by mail the recipient
841
-				// would already have access to the share without having to call
842
-				// the sharer to verify her identity
843
-				throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
844
-			}
845
-		}
846
-
847
-		$this->pathCreateChecks($share->getNode());
848
-
849
-		// Now update the share!
850
-		$provider = $this->factory->getProviderForType($share->getShareType());
851
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
852
-			$share = $provider->update($share, $plainTextPassword);
853
-		} else {
854
-			$share = $provider->update($share);
855
-		}
856
-
857
-		if ($expirationDateUpdated === true) {
858
-			\OC_Hook::emit(Share::class, 'post_set_expiration_date', [
859
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
860
-				'itemSource' => $share->getNode()->getId(),
861
-				'date' => $share->getExpirationDate(),
862
-				'uidOwner' => $share->getSharedBy(),
863
-			]);
864
-		}
865
-
866
-		if ($share->getPassword() !== $originalShare->getPassword()) {
867
-			\OC_Hook::emit(Share::class, 'post_update_password', [
868
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
869
-				'itemSource' => $share->getNode()->getId(),
870
-				'uidOwner' => $share->getSharedBy(),
871
-				'token' => $share->getToken(),
872
-				'disabled' => is_null($share->getPassword()),
873
-			]);
874
-		}
875
-
876
-		if ($share->getPermissions() !== $originalShare->getPermissions()) {
877
-			if ($this->userManager->userExists($share->getShareOwner())) {
878
-				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
879
-			} else {
880
-				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
881
-			}
882
-			\OC_Hook::emit(Share::class, 'post_update_permissions', array(
883
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
884
-				'itemSource' => $share->getNode()->getId(),
885
-				'shareType' => $share->getShareType(),
886
-				'shareWith' => $share->getSharedWith(),
887
-				'uidOwner' => $share->getSharedBy(),
888
-				'permissions' => $share->getPermissions(),
889
-				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
890
-			));
891
-		}
892
-
893
-		return $share;
894
-	}
895
-
896
-	/**
897
-	 * Updates the password of the given share if it is not the same as the
898
-	 * password of the original share.
899
-	 *
900
-	 * @param \OCP\Share\IShare $share the share to update its password.
901
-	 * @param \OCP\Share\IShare $originalShare the original share to compare its
902
-	 *        password with.
903
-	 * @return boolean whether the password was updated or not.
904
-	 */
905
-	private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
906
-		// Password updated.
907
-		if ($share->getPassword() !== $originalShare->getPassword()) {
908
-			//Verify the password
909
-			$this->verifyPassword($share->getPassword());
910
-
911
-			// If a password is set. Hash it!
912
-			if ($share->getPassword() !== null) {
913
-				$share->setPassword($this->hasher->hash($share->getPassword()));
914
-
915
-				return true;
916
-			}
917
-		}
918
-
919
-		return false;
920
-	}
921
-
922
-	/**
923
-	 * Delete all the children of this share
924
-	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
925
-	 *
926
-	 * @param \OCP\Share\IShare $share
927
-	 * @return \OCP\Share\IShare[] List of deleted shares
928
-	 */
929
-	protected function deleteChildren(\OCP\Share\IShare $share) {
930
-		$deletedShares = [];
931
-
932
-		$provider = $this->factory->getProviderForType($share->getShareType());
933
-
934
-		foreach ($provider->getChildren($share) as $child) {
935
-			$deletedChildren = $this->deleteChildren($child);
936
-			$deletedShares = array_merge($deletedShares, $deletedChildren);
937
-
938
-			$provider->delete($child);
939
-			$deletedShares[] = $child;
940
-		}
941
-
942
-		return $deletedShares;
943
-	}
944
-
945
-	/**
946
-	 * Delete a share
947
-	 *
948
-	 * @param \OCP\Share\IShare $share
949
-	 * @throws ShareNotFound
950
-	 * @throws \InvalidArgumentException
951
-	 */
952
-	public function deleteShare(\OCP\Share\IShare $share) {
953
-
954
-		try {
955
-			$share->getFullId();
956
-		} catch (\UnexpectedValueException $e) {
957
-			throw new \InvalidArgumentException('Share does not have a full id');
958
-		}
959
-
960
-		$event = new GenericEvent($share);
961
-		$this->eventDispatcher->dispatch('OCP\Share::preUnshare', $event);
962
-
963
-		// Get all children and delete them as well
964
-		$deletedShares = $this->deleteChildren($share);
965
-
966
-		// Do the actual delete
967
-		$provider = $this->factory->getProviderForType($share->getShareType());
968
-		$provider->delete($share);
969
-
970
-		// All the deleted shares caused by this delete
971
-		$deletedShares[] = $share;
972
-
973
-		// Emit post hook
974
-		$event->setArgument('deletedShares', $deletedShares);
975
-		$this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
976
-	}
977
-
978
-
979
-	/**
980
-	 * Unshare a file as the recipient.
981
-	 * This can be different from a regular delete for example when one of
982
-	 * the users in a groups deletes that share. But the provider should
983
-	 * handle this.
984
-	 *
985
-	 * @param \OCP\Share\IShare $share
986
-	 * @param string $recipientId
987
-	 */
988
-	public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
989
-		list($providerId, ) = $this->splitFullId($share->getFullId());
990
-		$provider = $this->factory->getProvider($providerId);
991
-
992
-		$provider->deleteFromSelf($share, $recipientId);
993
-		$event = new GenericEvent($share);
994
-		$this->eventDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
995
-	}
996
-
997
-	public function restoreShare(IShare $share, string $recipientId): IShare {
998
-		list($providerId, ) = $this->splitFullId($share->getFullId());
999
-		$provider = $this->factory->getProvider($providerId);
1000
-
1001
-		return $provider->restore($share, $recipientId);
1002
-	}
1003
-
1004
-	/**
1005
-	 * @inheritdoc
1006
-	 */
1007
-	public function moveShare(\OCP\Share\IShare $share, $recipientId) {
1008
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
1009
-			throw new \InvalidArgumentException('Can’t change target of link share');
1010
-		}
1011
-
1012
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
1013
-			throw new \InvalidArgumentException('Invalid recipient');
1014
-		}
1015
-
1016
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
1017
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1018
-			if (is_null($sharedWith)) {
1019
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1020
-			}
1021
-			$recipient = $this->userManager->get($recipientId);
1022
-			if (!$sharedWith->inGroup($recipient)) {
1023
-				throw new \InvalidArgumentException('Invalid recipient');
1024
-			}
1025
-		}
1026
-
1027
-		list($providerId, ) = $this->splitFullId($share->getFullId());
1028
-		$provider = $this->factory->getProvider($providerId);
1029
-
1030
-		$provider->move($share, $recipientId);
1031
-	}
1032
-
1033
-	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1034
-		$providers = $this->factory->getAllProviders();
1035
-
1036
-		return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1037
-			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1038
-			foreach ($newShares as $fid => $data) {
1039
-				if (!isset($shares[$fid])) {
1040
-					$shares[$fid] = [];
1041
-				}
1042
-
1043
-				$shares[$fid] = array_merge($shares[$fid], $data);
1044
-			}
1045
-			return $shares;
1046
-		}, []);
1047
-	}
1048
-
1049
-	/**
1050
-	 * @inheritdoc
1051
-	 */
1052
-	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1053
-		if ($path !== null &&
1054
-				!($path instanceof \OCP\Files\File) &&
1055
-				!($path instanceof \OCP\Files\Folder)) {
1056
-			throw new \InvalidArgumentException('invalid path');
1057
-		}
1058
-
1059
-		try {
1060
-			$provider = $this->factory->getProviderForType($shareType);
1061
-		} catch (ProviderException $e) {
1062
-			return [];
1063
-		}
1064
-
1065
-		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1066
-
1067
-		/*
624
+            $share->setToken(
625
+                $this->secureRandom->generate(
626
+                    \OC\Share\Constants::TOKEN_LENGTH,
627
+                    \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
628
+                )
629
+            );
630
+
631
+            //Verify the expiration date
632
+            $this->validateExpirationDate($share);
633
+
634
+            //Verify the password
635
+            $this->verifyPassword($share->getPassword());
636
+
637
+            // If a password is set. Hash it!
638
+            if ($share->getPassword() !== null) {
639
+                $share->setPassword($this->hasher->hash($share->getPassword()));
640
+            }
641
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
642
+            $share->setToken(
643
+                $this->secureRandom->generate(
644
+                    \OC\Share\Constants::TOKEN_LENGTH,
645
+                    \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
646
+                )
647
+            );
648
+        }
649
+
650
+        // Cannot share with the owner
651
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
652
+            $share->getSharedWith() === $share->getShareOwner()) {
653
+            throw new \InvalidArgumentException('Can’t share with the share owner');
654
+        }
655
+
656
+        // Generate the target
657
+        $target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
658
+        $target = \OC\Files\Filesystem::normalizePath($target);
659
+        $share->setTarget($target);
660
+
661
+        // Pre share event
662
+        $event = new GenericEvent($share);
663
+        $a = $this->eventDispatcher->dispatch('OCP\Share::preShare', $event);
664
+        if ($event->isPropagationStopped() && $event->hasArgument('error')) {
665
+            throw new \Exception($event->getArgument('error'));
666
+        }
667
+
668
+        $oldShare = $share;
669
+        $provider = $this->factory->getProviderForType($share->getShareType());
670
+        $share = $provider->create($share);
671
+        //reuse the node we already have
672
+        $share->setNode($oldShare->getNode());
673
+
674
+        // Post share event
675
+        $event = new GenericEvent($share);
676
+        $this->eventDispatcher->dispatch('OCP\Share::postShare', $event);
677
+
678
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
679
+            $mailSend = $share->getMailSend();
680
+            if($mailSend === true) {
681
+                $user = $this->userManager->get($share->getSharedWith());
682
+                if ($user !== null) {
683
+                    $emailAddress = $user->getEMailAddress();
684
+                    if ($emailAddress !== null && $emailAddress !== '') {
685
+                        $userLang = $this->config->getUserValue($share->getSharedWith(), 'core', 'lang', null);
686
+                        $l = $this->l10nFactory->get('lib', $userLang);
687
+                        $this->sendMailNotification(
688
+                            $l,
689
+                            $share->getNode()->getName(),
690
+                            $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $share->getNode()->getId()]),
691
+                            $share->getSharedBy(),
692
+                            $emailAddress,
693
+                            $share->getExpirationDate()
694
+                        );
695
+                        $this->logger->debug('Send share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
696
+                    } else {
697
+                        $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
698
+                    }
699
+                } else {
700
+                    $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
701
+                }
702
+            } else {
703
+                $this->logger->debug('Share notification not send because mailsend is false.', ['app' => 'share']);
704
+            }
705
+        }
706
+
707
+        return $share;
708
+    }
709
+
710
+    /**
711
+     * @param IL10N $l Language of the recipient
712
+     * @param string $filename file/folder name
713
+     * @param string $link link to the file/folder
714
+     * @param string $initiator user ID of share sender
715
+     * @param string $shareWith email address of share receiver
716
+     * @param \DateTime|null $expiration
717
+     * @throws \Exception If mail couldn't be sent
718
+     */
719
+    protected function sendMailNotification(IL10N $l,
720
+                                            $filename,
721
+                                            $link,
722
+                                            $initiator,
723
+                                            $shareWith,
724
+                                            \DateTime $expiration = null) {
725
+        $initiatorUser = $this->userManager->get($initiator);
726
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
727
+
728
+        $message = $this->mailer->createMessage();
729
+
730
+        $emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
731
+            'filename' => $filename,
732
+            'link' => $link,
733
+            'initiator' => $initiatorDisplayName,
734
+            'expiration' => $expiration,
735
+            'shareWith' => $shareWith,
736
+        ]);
737
+
738
+        $emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', array($initiatorDisplayName, $filename)));
739
+        $emailTemplate->addHeader();
740
+        $emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
741
+        $text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
742
+
743
+        $emailTemplate->addBodyText(
744
+            htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
745
+            $text
746
+        );
747
+        $emailTemplate->addBodyButton(
748
+            $l->t('Open »%s«', [$filename]),
749
+            $link
750
+        );
751
+
752
+        $message->setTo([$shareWith]);
753
+
754
+        // The "From" contains the sharers name
755
+        $instanceName = $this->defaults->getName();
756
+        $senderName = $l->t(
757
+            '%1$s via %2$s',
758
+            [
759
+                $initiatorDisplayName,
760
+                $instanceName
761
+            ]
762
+        );
763
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
764
+
765
+        // The "Reply-To" is set to the sharer if an mail address is configured
766
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
767
+        $initiatorEmail = $initiatorUser->getEMailAddress();
768
+        if($initiatorEmail !== null) {
769
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
770
+            $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
771
+        } else {
772
+            $emailTemplate->addFooter();
773
+        }
774
+
775
+        $message->useTemplate($emailTemplate);
776
+        $this->mailer->send($message);
777
+    }
778
+
779
+    /**
780
+     * Update a share
781
+     *
782
+     * @param \OCP\Share\IShare $share
783
+     * @return \OCP\Share\IShare The share object
784
+     * @throws \InvalidArgumentException
785
+     */
786
+    public function updateShare(\OCP\Share\IShare $share) {
787
+        $expirationDateUpdated = false;
788
+
789
+        $this->canShare($share);
790
+
791
+        try {
792
+            $originalShare = $this->getShareById($share->getFullId());
793
+        } catch (\UnexpectedValueException $e) {
794
+            throw new \InvalidArgumentException('Share does not have a full id');
795
+        }
796
+
797
+        // We can't change the share type!
798
+        if ($share->getShareType() !== $originalShare->getShareType()) {
799
+            throw new \InvalidArgumentException('Can’t change share type');
800
+        }
801
+
802
+        // We can only change the recipient on user shares
803
+        if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
804
+            $share->getShareType() !== \OCP\Share::SHARE_TYPE_USER) {
805
+            throw new \InvalidArgumentException('Can only update recipient on user shares');
806
+        }
807
+
808
+        // Cannot share with the owner
809
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
810
+            $share->getSharedWith() === $share->getShareOwner()) {
811
+            throw new \InvalidArgumentException('Can’t share with the share owner');
812
+        }
813
+
814
+        $this->generalCreateChecks($share);
815
+
816
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
817
+            $this->userCreateChecks($share);
818
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
819
+            $this->groupCreateChecks($share);
820
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
821
+            $this->linkCreateChecks($share);
822
+
823
+            $this->updateSharePasswordIfNeeded($share, $originalShare);
824
+
825
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
826
+                //Verify the expiration date
827
+                $this->validateExpirationDate($share);
828
+                $expirationDateUpdated = true;
829
+            }
830
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
831
+            // The new password is not set again if it is the same as the old
832
+            // one, unless when switching from sending by Talk to sending by
833
+            // mail.
834
+            $plainTextPassword = $share->getPassword();
835
+            if (!empty($plainTextPassword) && !$this->updateSharePasswordIfNeeded($share, $originalShare) &&
836
+                    !($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk())) {
837
+                $plainTextPassword = null;
838
+            }
839
+            if (empty($plainTextPassword) && !$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
840
+                // If the same password was already sent by mail the recipient
841
+                // would already have access to the share without having to call
842
+                // the sharer to verify her identity
843
+                throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
844
+            }
845
+        }
846
+
847
+        $this->pathCreateChecks($share->getNode());
848
+
849
+        // Now update the share!
850
+        $provider = $this->factory->getProviderForType($share->getShareType());
851
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
852
+            $share = $provider->update($share, $plainTextPassword);
853
+        } else {
854
+            $share = $provider->update($share);
855
+        }
856
+
857
+        if ($expirationDateUpdated === true) {
858
+            \OC_Hook::emit(Share::class, 'post_set_expiration_date', [
859
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
860
+                'itemSource' => $share->getNode()->getId(),
861
+                'date' => $share->getExpirationDate(),
862
+                'uidOwner' => $share->getSharedBy(),
863
+            ]);
864
+        }
865
+
866
+        if ($share->getPassword() !== $originalShare->getPassword()) {
867
+            \OC_Hook::emit(Share::class, 'post_update_password', [
868
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
869
+                'itemSource' => $share->getNode()->getId(),
870
+                'uidOwner' => $share->getSharedBy(),
871
+                'token' => $share->getToken(),
872
+                'disabled' => is_null($share->getPassword()),
873
+            ]);
874
+        }
875
+
876
+        if ($share->getPermissions() !== $originalShare->getPermissions()) {
877
+            if ($this->userManager->userExists($share->getShareOwner())) {
878
+                $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
879
+            } else {
880
+                $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
881
+            }
882
+            \OC_Hook::emit(Share::class, 'post_update_permissions', array(
883
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
884
+                'itemSource' => $share->getNode()->getId(),
885
+                'shareType' => $share->getShareType(),
886
+                'shareWith' => $share->getSharedWith(),
887
+                'uidOwner' => $share->getSharedBy(),
888
+                'permissions' => $share->getPermissions(),
889
+                'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
890
+            ));
891
+        }
892
+
893
+        return $share;
894
+    }
895
+
896
+    /**
897
+     * Updates the password of the given share if it is not the same as the
898
+     * password of the original share.
899
+     *
900
+     * @param \OCP\Share\IShare $share the share to update its password.
901
+     * @param \OCP\Share\IShare $originalShare the original share to compare its
902
+     *        password with.
903
+     * @return boolean whether the password was updated or not.
904
+     */
905
+    private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
906
+        // Password updated.
907
+        if ($share->getPassword() !== $originalShare->getPassword()) {
908
+            //Verify the password
909
+            $this->verifyPassword($share->getPassword());
910
+
911
+            // If a password is set. Hash it!
912
+            if ($share->getPassword() !== null) {
913
+                $share->setPassword($this->hasher->hash($share->getPassword()));
914
+
915
+                return true;
916
+            }
917
+        }
918
+
919
+        return false;
920
+    }
921
+
922
+    /**
923
+     * Delete all the children of this share
924
+     * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
925
+     *
926
+     * @param \OCP\Share\IShare $share
927
+     * @return \OCP\Share\IShare[] List of deleted shares
928
+     */
929
+    protected function deleteChildren(\OCP\Share\IShare $share) {
930
+        $deletedShares = [];
931
+
932
+        $provider = $this->factory->getProviderForType($share->getShareType());
933
+
934
+        foreach ($provider->getChildren($share) as $child) {
935
+            $deletedChildren = $this->deleteChildren($child);
936
+            $deletedShares = array_merge($deletedShares, $deletedChildren);
937
+
938
+            $provider->delete($child);
939
+            $deletedShares[] = $child;
940
+        }
941
+
942
+        return $deletedShares;
943
+    }
944
+
945
+    /**
946
+     * Delete a share
947
+     *
948
+     * @param \OCP\Share\IShare $share
949
+     * @throws ShareNotFound
950
+     * @throws \InvalidArgumentException
951
+     */
952
+    public function deleteShare(\OCP\Share\IShare $share) {
953
+
954
+        try {
955
+            $share->getFullId();
956
+        } catch (\UnexpectedValueException $e) {
957
+            throw new \InvalidArgumentException('Share does not have a full id');
958
+        }
959
+
960
+        $event = new GenericEvent($share);
961
+        $this->eventDispatcher->dispatch('OCP\Share::preUnshare', $event);
962
+
963
+        // Get all children and delete them as well
964
+        $deletedShares = $this->deleteChildren($share);
965
+
966
+        // Do the actual delete
967
+        $provider = $this->factory->getProviderForType($share->getShareType());
968
+        $provider->delete($share);
969
+
970
+        // All the deleted shares caused by this delete
971
+        $deletedShares[] = $share;
972
+
973
+        // Emit post hook
974
+        $event->setArgument('deletedShares', $deletedShares);
975
+        $this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
976
+    }
977
+
978
+
979
+    /**
980
+     * Unshare a file as the recipient.
981
+     * This can be different from a regular delete for example when one of
982
+     * the users in a groups deletes that share. But the provider should
983
+     * handle this.
984
+     *
985
+     * @param \OCP\Share\IShare $share
986
+     * @param string $recipientId
987
+     */
988
+    public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
989
+        list($providerId, ) = $this->splitFullId($share->getFullId());
990
+        $provider = $this->factory->getProvider($providerId);
991
+
992
+        $provider->deleteFromSelf($share, $recipientId);
993
+        $event = new GenericEvent($share);
994
+        $this->eventDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
995
+    }
996
+
997
+    public function restoreShare(IShare $share, string $recipientId): IShare {
998
+        list($providerId, ) = $this->splitFullId($share->getFullId());
999
+        $provider = $this->factory->getProvider($providerId);
1000
+
1001
+        return $provider->restore($share, $recipientId);
1002
+    }
1003
+
1004
+    /**
1005
+     * @inheritdoc
1006
+     */
1007
+    public function moveShare(\OCP\Share\IShare $share, $recipientId) {
1008
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
1009
+            throw new \InvalidArgumentException('Can’t change target of link share');
1010
+        }
1011
+
1012
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
1013
+            throw new \InvalidArgumentException('Invalid recipient');
1014
+        }
1015
+
1016
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
1017
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1018
+            if (is_null($sharedWith)) {
1019
+                throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1020
+            }
1021
+            $recipient = $this->userManager->get($recipientId);
1022
+            if (!$sharedWith->inGroup($recipient)) {
1023
+                throw new \InvalidArgumentException('Invalid recipient');
1024
+            }
1025
+        }
1026
+
1027
+        list($providerId, ) = $this->splitFullId($share->getFullId());
1028
+        $provider = $this->factory->getProvider($providerId);
1029
+
1030
+        $provider->move($share, $recipientId);
1031
+    }
1032
+
1033
+    public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1034
+        $providers = $this->factory->getAllProviders();
1035
+
1036
+        return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1037
+            $newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1038
+            foreach ($newShares as $fid => $data) {
1039
+                if (!isset($shares[$fid])) {
1040
+                    $shares[$fid] = [];
1041
+                }
1042
+
1043
+                $shares[$fid] = array_merge($shares[$fid], $data);
1044
+            }
1045
+            return $shares;
1046
+        }, []);
1047
+    }
1048
+
1049
+    /**
1050
+     * @inheritdoc
1051
+     */
1052
+    public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1053
+        if ($path !== null &&
1054
+                !($path instanceof \OCP\Files\File) &&
1055
+                !($path instanceof \OCP\Files\Folder)) {
1056
+            throw new \InvalidArgumentException('invalid path');
1057
+        }
1058
+
1059
+        try {
1060
+            $provider = $this->factory->getProviderForType($shareType);
1061
+        } catch (ProviderException $e) {
1062
+            return [];
1063
+        }
1064
+
1065
+        $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1066
+
1067
+        /*
1068 1068
 		 * Work around so we don't return expired shares but still follow
1069 1069
 		 * proper pagination.
1070 1070
 		 */
1071 1071
 
1072
-		$shares2 = [];
1073
-
1074
-		while(true) {
1075
-			$added = 0;
1076
-			foreach ($shares as $share) {
1077
-
1078
-				try {
1079
-					$this->checkExpireDate($share);
1080
-				} catch (ShareNotFound $e) {
1081
-					//Ignore since this basically means the share is deleted
1082
-					continue;
1083
-				}
1084
-
1085
-				$added++;
1086
-				$shares2[] = $share;
1087
-
1088
-				if (count($shares2) === $limit) {
1089
-					break;
1090
-				}
1091
-			}
1092
-
1093
-			// If we did not fetch more shares than the limit then there are no more shares
1094
-			if (count($shares) < $limit) {
1095
-				break;
1096
-			}
1097
-
1098
-			if (count($shares2) === $limit) {
1099
-				break;
1100
-			}
1101
-
1102
-			// If there was no limit on the select we are done
1103
-			if ($limit === -1) {
1104
-				break;
1105
-			}
1106
-
1107
-			$offset += $added;
1108
-
1109
-			// Fetch again $limit shares
1110
-			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1111
-
1112
-			// No more shares means we are done
1113
-			if (empty($shares)) {
1114
-				break;
1115
-			}
1116
-		}
1117
-
1118
-		$shares = $shares2;
1119
-
1120
-		return $shares;
1121
-	}
1122
-
1123
-	/**
1124
-	 * @inheritdoc
1125
-	 */
1126
-	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1127
-		try {
1128
-			$provider = $this->factory->getProviderForType($shareType);
1129
-		} catch (ProviderException $e) {
1130
-			return [];
1131
-		}
1132
-
1133
-		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1134
-
1135
-		// remove all shares which are already expired
1136
-		foreach ($shares as $key => $share) {
1137
-			try {
1138
-				$this->checkExpireDate($share);
1139
-			} catch (ShareNotFound $e) {
1140
-				unset($shares[$key]);
1141
-			}
1142
-		}
1143
-
1144
-		return $shares;
1145
-	}
1146
-
1147
-	/**
1148
-	 * @inheritdoc
1149
-	 */
1150
-	public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1151
-		$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1152
-
1153
-		// Only get deleted shares
1154
-		$shares = array_filter($shares, function(IShare $share) {
1155
-			return $share->getPermissions() === 0;
1156
-		});
1157
-
1158
-		// Only get shares where the owner still exists
1159
-		$shares = array_filter($shares, function (IShare $share) {
1160
-			return $this->userManager->userExists($share->getShareOwner());
1161
-		});
1162
-
1163
-		return $shares;
1164
-	}
1165
-
1166
-	/**
1167
-	 * @inheritdoc
1168
-	 */
1169
-	public function getShareById($id, $recipient = null) {
1170
-		if ($id === null) {
1171
-			throw new ShareNotFound();
1172
-		}
1173
-
1174
-		list($providerId, $id) = $this->splitFullId($id);
1175
-
1176
-		try {
1177
-			$provider = $this->factory->getProvider($providerId);
1178
-		} catch (ProviderException $e) {
1179
-			throw new ShareNotFound();
1180
-		}
1181
-
1182
-		$share = $provider->getShareById($id, $recipient);
1183
-
1184
-		$this->checkExpireDate($share);
1185
-
1186
-		return $share;
1187
-	}
1188
-
1189
-	/**
1190
-	 * Get all the shares for a given path
1191
-	 *
1192
-	 * @param \OCP\Files\Node $path
1193
-	 * @param int $page
1194
-	 * @param int $perPage
1195
-	 *
1196
-	 * @return Share[]
1197
-	 */
1198
-	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1199
-		return [];
1200
-	}
1201
-
1202
-	/**
1203
-	 * Get the share by token possible with password
1204
-	 *
1205
-	 * @param string $token
1206
-	 * @return Share
1207
-	 *
1208
-	 * @throws ShareNotFound
1209
-	 */
1210
-	public function getShareByToken($token) {
1211
-		// tokens can't be valid local user names
1212
-		if ($this->userManager->userExists($token)) {
1213
-			throw new ShareNotFound();
1214
-		}
1215
-		$share = null;
1216
-		try {
1217
-			if($this->shareApiAllowLinks()) {
1218
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
1219
-				$share = $provider->getShareByToken($token);
1220
-			}
1221
-		} catch (ProviderException $e) {
1222
-		} catch (ShareNotFound $e) {
1223
-		}
1224
-
1225
-
1226
-		// If it is not a link share try to fetch a federated share by token
1227
-		if ($share === null) {
1228
-			try {
1229
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_REMOTE);
1230
-				$share = $provider->getShareByToken($token);
1231
-			} catch (ProviderException $e) {
1232
-			} catch (ShareNotFound $e) {
1233
-			}
1234
-		}
1235
-
1236
-		// If it is not a link share try to fetch a mail share by token
1237
-		if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
1238
-			try {
1239
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_EMAIL);
1240
-				$share = $provider->getShareByToken($token);
1241
-			} catch (ProviderException $e) {
1242
-			} catch (ShareNotFound $e) {
1243
-			}
1244
-		}
1245
-
1246
-		if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
1247
-			try {
1248
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_CIRCLE);
1249
-				$share = $provider->getShareByToken($token);
1250
-			} catch (ProviderException $e) {
1251
-			} catch (ShareNotFound $e) {
1252
-			}
1253
-		}
1254
-
1255
-		if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_ROOM)) {
1256
-			try {
1257
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_ROOM);
1258
-				$share = $provider->getShareByToken($token);
1259
-			} catch (ProviderException $e) {
1260
-			} catch (ShareNotFound $e) {
1261
-			}
1262
-		}
1263
-
1264
-		if ($share === null) {
1265
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1266
-		}
1267
-
1268
-		$this->checkExpireDate($share);
1269
-
1270
-		/*
1072
+        $shares2 = [];
1073
+
1074
+        while(true) {
1075
+            $added = 0;
1076
+            foreach ($shares as $share) {
1077
+
1078
+                try {
1079
+                    $this->checkExpireDate($share);
1080
+                } catch (ShareNotFound $e) {
1081
+                    //Ignore since this basically means the share is deleted
1082
+                    continue;
1083
+                }
1084
+
1085
+                $added++;
1086
+                $shares2[] = $share;
1087
+
1088
+                if (count($shares2) === $limit) {
1089
+                    break;
1090
+                }
1091
+            }
1092
+
1093
+            // If we did not fetch more shares than the limit then there are no more shares
1094
+            if (count($shares) < $limit) {
1095
+                break;
1096
+            }
1097
+
1098
+            if (count($shares2) === $limit) {
1099
+                break;
1100
+            }
1101
+
1102
+            // If there was no limit on the select we are done
1103
+            if ($limit === -1) {
1104
+                break;
1105
+            }
1106
+
1107
+            $offset += $added;
1108
+
1109
+            // Fetch again $limit shares
1110
+            $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1111
+
1112
+            // No more shares means we are done
1113
+            if (empty($shares)) {
1114
+                break;
1115
+            }
1116
+        }
1117
+
1118
+        $shares = $shares2;
1119
+
1120
+        return $shares;
1121
+    }
1122
+
1123
+    /**
1124
+     * @inheritdoc
1125
+     */
1126
+    public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1127
+        try {
1128
+            $provider = $this->factory->getProviderForType($shareType);
1129
+        } catch (ProviderException $e) {
1130
+            return [];
1131
+        }
1132
+
1133
+        $shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1134
+
1135
+        // remove all shares which are already expired
1136
+        foreach ($shares as $key => $share) {
1137
+            try {
1138
+                $this->checkExpireDate($share);
1139
+            } catch (ShareNotFound $e) {
1140
+                unset($shares[$key]);
1141
+            }
1142
+        }
1143
+
1144
+        return $shares;
1145
+    }
1146
+
1147
+    /**
1148
+     * @inheritdoc
1149
+     */
1150
+    public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1151
+        $shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1152
+
1153
+        // Only get deleted shares
1154
+        $shares = array_filter($shares, function(IShare $share) {
1155
+            return $share->getPermissions() === 0;
1156
+        });
1157
+
1158
+        // Only get shares where the owner still exists
1159
+        $shares = array_filter($shares, function (IShare $share) {
1160
+            return $this->userManager->userExists($share->getShareOwner());
1161
+        });
1162
+
1163
+        return $shares;
1164
+    }
1165
+
1166
+    /**
1167
+     * @inheritdoc
1168
+     */
1169
+    public function getShareById($id, $recipient = null) {
1170
+        if ($id === null) {
1171
+            throw new ShareNotFound();
1172
+        }
1173
+
1174
+        list($providerId, $id) = $this->splitFullId($id);
1175
+
1176
+        try {
1177
+            $provider = $this->factory->getProvider($providerId);
1178
+        } catch (ProviderException $e) {
1179
+            throw new ShareNotFound();
1180
+        }
1181
+
1182
+        $share = $provider->getShareById($id, $recipient);
1183
+
1184
+        $this->checkExpireDate($share);
1185
+
1186
+        return $share;
1187
+    }
1188
+
1189
+    /**
1190
+     * Get all the shares for a given path
1191
+     *
1192
+     * @param \OCP\Files\Node $path
1193
+     * @param int $page
1194
+     * @param int $perPage
1195
+     *
1196
+     * @return Share[]
1197
+     */
1198
+    public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1199
+        return [];
1200
+    }
1201
+
1202
+    /**
1203
+     * Get the share by token possible with password
1204
+     *
1205
+     * @param string $token
1206
+     * @return Share
1207
+     *
1208
+     * @throws ShareNotFound
1209
+     */
1210
+    public function getShareByToken($token) {
1211
+        // tokens can't be valid local user names
1212
+        if ($this->userManager->userExists($token)) {
1213
+            throw new ShareNotFound();
1214
+        }
1215
+        $share = null;
1216
+        try {
1217
+            if($this->shareApiAllowLinks()) {
1218
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
1219
+                $share = $provider->getShareByToken($token);
1220
+            }
1221
+        } catch (ProviderException $e) {
1222
+        } catch (ShareNotFound $e) {
1223
+        }
1224
+
1225
+
1226
+        // If it is not a link share try to fetch a federated share by token
1227
+        if ($share === null) {
1228
+            try {
1229
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_REMOTE);
1230
+                $share = $provider->getShareByToken($token);
1231
+            } catch (ProviderException $e) {
1232
+            } catch (ShareNotFound $e) {
1233
+            }
1234
+        }
1235
+
1236
+        // If it is not a link share try to fetch a mail share by token
1237
+        if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
1238
+            try {
1239
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_EMAIL);
1240
+                $share = $provider->getShareByToken($token);
1241
+            } catch (ProviderException $e) {
1242
+            } catch (ShareNotFound $e) {
1243
+            }
1244
+        }
1245
+
1246
+        if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
1247
+            try {
1248
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_CIRCLE);
1249
+                $share = $provider->getShareByToken($token);
1250
+            } catch (ProviderException $e) {
1251
+            } catch (ShareNotFound $e) {
1252
+            }
1253
+        }
1254
+
1255
+        if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_ROOM)) {
1256
+            try {
1257
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_ROOM);
1258
+                $share = $provider->getShareByToken($token);
1259
+            } catch (ProviderException $e) {
1260
+            } catch (ShareNotFound $e) {
1261
+            }
1262
+        }
1263
+
1264
+        if ($share === null) {
1265
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1266
+        }
1267
+
1268
+        $this->checkExpireDate($share);
1269
+
1270
+        /*
1271 1271
 		 * Reduce the permissions for link shares if public upload is not enabled
1272 1272
 		 */
1273
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
1274
-			!$this->shareApiLinkAllowPublicUpload()) {
1275
-			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1276
-		}
1277
-
1278
-		return $share;
1279
-	}
1280
-
1281
-	protected function checkExpireDate($share) {
1282
-		if ($share->getExpirationDate() !== null &&
1283
-			$share->getExpirationDate() <= new \DateTime()) {
1284
-			$this->deleteShare($share);
1285
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1286
-		}
1287
-
1288
-	}
1289
-
1290
-	/**
1291
-	 * Verify the password of a public share
1292
-	 *
1293
-	 * @param \OCP\Share\IShare $share
1294
-	 * @param string $password
1295
-	 * @return bool
1296
-	 */
1297
-	public function checkPassword(\OCP\Share\IShare $share, $password) {
1298
-		$passwordProtected = $share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK
1299
-			|| $share->getShareType() !== \OCP\Share::SHARE_TYPE_EMAIL;
1300
-		if (!$passwordProtected) {
1301
-			//TODO maybe exception?
1302
-			return false;
1303
-		}
1304
-
1305
-		if ($password === null || $share->getPassword() === null) {
1306
-			return false;
1307
-		}
1308
-
1309
-		$newHash = '';
1310
-		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1311
-			return false;
1312
-		}
1313
-
1314
-		if (!empty($newHash)) {
1315
-			$share->setPassword($newHash);
1316
-			$provider = $this->factory->getProviderForType($share->getShareType());
1317
-			$provider->update($share);
1318
-		}
1319
-
1320
-		return true;
1321
-	}
1322
-
1323
-	/**
1324
-	 * @inheritdoc
1325
-	 */
1326
-	public function userDeleted($uid) {
1327
-		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];
1328
-
1329
-		foreach ($types as $type) {
1330
-			try {
1331
-				$provider = $this->factory->getProviderForType($type);
1332
-			} catch (ProviderException $e) {
1333
-				continue;
1334
-			}
1335
-			$provider->userDeleted($uid, $type);
1336
-		}
1337
-	}
1338
-
1339
-	/**
1340
-	 * @inheritdoc
1341
-	 */
1342
-	public function groupDeleted($gid) {
1343
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1344
-		$provider->groupDeleted($gid);
1345
-	}
1346
-
1347
-	/**
1348
-	 * @inheritdoc
1349
-	 */
1350
-	public function userDeletedFromGroup($uid, $gid) {
1351
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1352
-		$provider->userDeletedFromGroup($uid, $gid);
1353
-	}
1354
-
1355
-	/**
1356
-	 * Get access list to a path. This means
1357
-	 * all the users that can access a given path.
1358
-	 *
1359
-	 * Consider:
1360
-	 * -root
1361
-	 * |-folder1 (23)
1362
-	 *  |-folder2 (32)
1363
-	 *   |-fileA (42)
1364
-	 *
1365
-	 * fileA is shared with user1 and user1@server1
1366
-	 * folder2 is shared with group2 (user4 is a member of group2)
1367
-	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1368
-	 *
1369
-	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1370
-	 * [
1371
-	 *  users  => [
1372
-	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1373
-	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1374
-	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1375
-	 *  ],
1376
-	 *  remote => [
1377
-	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1378
-	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1379
-	 *  ],
1380
-	 *  public => bool
1381
-	 *  mail => bool
1382
-	 * ]
1383
-	 *
1384
-	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1385
-	 * [
1386
-	 *  users  => ['user1', 'user2', 'user4'],
1387
-	 *  remote => bool,
1388
-	 *  public => bool
1389
-	 *  mail => bool
1390
-	 * ]
1391
-	 *
1392
-	 * This is required for encryption/activity
1393
-	 *
1394
-	 * @param \OCP\Files\Node $path
1395
-	 * @param bool $recursive Should we check all parent folders as well
1396
-	 * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1397
-	 * @return array
1398
-	 */
1399
-	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1400
-		$owner = $path->getOwner()->getUID();
1401
-
1402
-		if ($currentAccess) {
1403
-			$al = ['users' => [], 'remote' => [], 'public' => false];
1404
-		} else {
1405
-			$al = ['users' => [], 'remote' => false, 'public' => false];
1406
-		}
1407
-		if (!$this->userManager->userExists($owner)) {
1408
-			return $al;
1409
-		}
1410
-
1411
-		//Get node for the owner
1412
-		$userFolder = $this->rootFolder->getUserFolder($owner);
1413
-		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1414
-			$path = $userFolder->getById($path->getId())[0];
1415
-		}
1416
-
1417
-		$providers = $this->factory->getAllProviders();
1418
-
1419
-		/** @var Node[] $nodes */
1420
-		$nodes = [];
1421
-
1422
-
1423
-		if ($currentAccess) {
1424
-			$ownerPath = $path->getPath();
1425
-			$ownerPath = explode('/', $ownerPath, 4);
1426
-			if (count($ownerPath) < 4) {
1427
-				$ownerPath = '';
1428
-			} else {
1429
-				$ownerPath = $ownerPath[3];
1430
-			}
1431
-			$al['users'][$owner] = [
1432
-				'node_id' => $path->getId(),
1433
-				'node_path' => '/' . $ownerPath,
1434
-			];
1435
-		} else {
1436
-			$al['users'][] = $owner;
1437
-		}
1438
-
1439
-		// Collect all the shares
1440
-		while ($path->getPath() !== $userFolder->getPath()) {
1441
-			$nodes[] = $path;
1442
-			if (!$recursive) {
1443
-				break;
1444
-			}
1445
-			$path = $path->getParent();
1446
-		}
1447
-
1448
-		foreach ($providers as $provider) {
1449
-			$tmp = $provider->getAccessList($nodes, $currentAccess);
1450
-
1451
-			foreach ($tmp as $k => $v) {
1452
-				if (isset($al[$k])) {
1453
-					if (is_array($al[$k])) {
1454
-						if ($currentAccess) {
1455
-							$al[$k] += $v;
1456
-						} else {
1457
-							$al[$k] = array_merge($al[$k], $v);
1458
-							$al[$k] = array_unique($al[$k]);
1459
-							$al[$k] = array_values($al[$k]);
1460
-						}
1461
-					} else {
1462
-						$al[$k] = $al[$k] || $v;
1463
-					}
1464
-				} else {
1465
-					$al[$k] = $v;
1466
-				}
1467
-			}
1468
-		}
1469
-
1470
-		return $al;
1471
-	}
1472
-
1473
-	/**
1474
-	 * Create a new share
1475
-	 * @return \OCP\Share\IShare
1476
-	 */
1477
-	public function newShare() {
1478
-		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1479
-	}
1480
-
1481
-	/**
1482
-	 * Is the share API enabled
1483
-	 *
1484
-	 * @return bool
1485
-	 */
1486
-	public function shareApiEnabled() {
1487
-		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1488
-	}
1489
-
1490
-	/**
1491
-	 * Is public link sharing enabled
1492
-	 *
1493
-	 * @return bool
1494
-	 */
1495
-	public function shareApiAllowLinks() {
1496
-		return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1497
-	}
1498
-
1499
-	/**
1500
-	 * Is password on public link requires
1501
-	 *
1502
-	 * @return bool
1503
-	 */
1504
-	public function shareApiLinkEnforcePassword() {
1505
-		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1506
-	}
1507
-
1508
-	/**
1509
-	 * Is default expire date enabled
1510
-	 *
1511
-	 * @return bool
1512
-	 */
1513
-	public function shareApiLinkDefaultExpireDate() {
1514
-		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1515
-	}
1516
-
1517
-	/**
1518
-	 * Is default expire date enforced
1519
-	 *`
1520
-	 * @return bool
1521
-	 */
1522
-	public function shareApiLinkDefaultExpireDateEnforced() {
1523
-		return $this->shareApiLinkDefaultExpireDate() &&
1524
-			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1525
-	}
1526
-
1527
-	/**
1528
-	 * Number of default expire days
1529
-	 *shareApiLinkAllowPublicUpload
1530
-	 * @return int
1531
-	 */
1532
-	public function shareApiLinkDefaultExpireDays() {
1533
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1534
-	}
1535
-
1536
-	/**
1537
-	 * Allow public upload on link shares
1538
-	 *
1539
-	 * @return bool
1540
-	 */
1541
-	public function shareApiLinkAllowPublicUpload() {
1542
-		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1543
-	}
1544
-
1545
-	/**
1546
-	 * check if user can only share with group members
1547
-	 * @return bool
1548
-	 */
1549
-	public function shareWithGroupMembersOnly() {
1550
-		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1551
-	}
1552
-
1553
-	/**
1554
-	 * Check if users can share with groups
1555
-	 * @return bool
1556
-	 */
1557
-	public function allowGroupSharing() {
1558
-		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1559
-	}
1560
-
1561
-	/**
1562
-	 * Copied from \OC_Util::isSharingDisabledForUser
1563
-	 *
1564
-	 * TODO: Deprecate fuction from OC_Util
1565
-	 *
1566
-	 * @param string $userId
1567
-	 * @return bool
1568
-	 */
1569
-	public function sharingDisabledForUser($userId) {
1570
-		if ($userId === null) {
1571
-			return false;
1572
-		}
1573
-
1574
-		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1575
-			return $this->sharingDisabledForUsersCache[$userId];
1576
-		}
1577
-
1578
-		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1579
-			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1580
-			$excludedGroups = json_decode($groupsList);
1581
-			if (is_null($excludedGroups)) {
1582
-				$excludedGroups = explode(',', $groupsList);
1583
-				$newValue = json_encode($excludedGroups);
1584
-				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1585
-			}
1586
-			$user = $this->userManager->get($userId);
1587
-			$usersGroups = $this->groupManager->getUserGroupIds($user);
1588
-			if (!empty($usersGroups)) {
1589
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1590
-				// if the user is only in groups which are disabled for sharing then
1591
-				// sharing is also disabled for the user
1592
-				if (empty($remainingGroups)) {
1593
-					$this->sharingDisabledForUsersCache[$userId] = true;
1594
-					return true;
1595
-				}
1596
-			}
1597
-		}
1598
-
1599
-		$this->sharingDisabledForUsersCache[$userId] = false;
1600
-		return false;
1601
-	}
1602
-
1603
-	/**
1604
-	 * @inheritdoc
1605
-	 */
1606
-	public function outgoingServer2ServerSharesAllowed() {
1607
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1608
-	}
1609
-
1610
-	/**
1611
-	 * @inheritdoc
1612
-	 */
1613
-	public function outgoingServer2ServerGroupSharesAllowed() {
1614
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1615
-	}
1616
-
1617
-	/**
1618
-	 * @inheritdoc
1619
-	 */
1620
-	public function shareProviderExists($shareType) {
1621
-		try {
1622
-			$this->factory->getProviderForType($shareType);
1623
-		} catch (ProviderException $e) {
1624
-			return false;
1625
-		}
1626
-
1627
-		return true;
1628
-	}
1273
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
1274
+            !$this->shareApiLinkAllowPublicUpload()) {
1275
+            $share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1276
+        }
1277
+
1278
+        return $share;
1279
+    }
1280
+
1281
+    protected function checkExpireDate($share) {
1282
+        if ($share->getExpirationDate() !== null &&
1283
+            $share->getExpirationDate() <= new \DateTime()) {
1284
+            $this->deleteShare($share);
1285
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1286
+        }
1287
+
1288
+    }
1289
+
1290
+    /**
1291
+     * Verify the password of a public share
1292
+     *
1293
+     * @param \OCP\Share\IShare $share
1294
+     * @param string $password
1295
+     * @return bool
1296
+     */
1297
+    public function checkPassword(\OCP\Share\IShare $share, $password) {
1298
+        $passwordProtected = $share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK
1299
+            || $share->getShareType() !== \OCP\Share::SHARE_TYPE_EMAIL;
1300
+        if (!$passwordProtected) {
1301
+            //TODO maybe exception?
1302
+            return false;
1303
+        }
1304
+
1305
+        if ($password === null || $share->getPassword() === null) {
1306
+            return false;
1307
+        }
1308
+
1309
+        $newHash = '';
1310
+        if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1311
+            return false;
1312
+        }
1313
+
1314
+        if (!empty($newHash)) {
1315
+            $share->setPassword($newHash);
1316
+            $provider = $this->factory->getProviderForType($share->getShareType());
1317
+            $provider->update($share);
1318
+        }
1319
+
1320
+        return true;
1321
+    }
1322
+
1323
+    /**
1324
+     * @inheritdoc
1325
+     */
1326
+    public function userDeleted($uid) {
1327
+        $types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];
1328
+
1329
+        foreach ($types as $type) {
1330
+            try {
1331
+                $provider = $this->factory->getProviderForType($type);
1332
+            } catch (ProviderException $e) {
1333
+                continue;
1334
+            }
1335
+            $provider->userDeleted($uid, $type);
1336
+        }
1337
+    }
1338
+
1339
+    /**
1340
+     * @inheritdoc
1341
+     */
1342
+    public function groupDeleted($gid) {
1343
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1344
+        $provider->groupDeleted($gid);
1345
+    }
1346
+
1347
+    /**
1348
+     * @inheritdoc
1349
+     */
1350
+    public function userDeletedFromGroup($uid, $gid) {
1351
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1352
+        $provider->userDeletedFromGroup($uid, $gid);
1353
+    }
1354
+
1355
+    /**
1356
+     * Get access list to a path. This means
1357
+     * all the users that can access a given path.
1358
+     *
1359
+     * Consider:
1360
+     * -root
1361
+     * |-folder1 (23)
1362
+     *  |-folder2 (32)
1363
+     *   |-fileA (42)
1364
+     *
1365
+     * fileA is shared with user1 and user1@server1
1366
+     * folder2 is shared with group2 (user4 is a member of group2)
1367
+     * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1368
+     *
1369
+     * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1370
+     * [
1371
+     *  users  => [
1372
+     *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1373
+     *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1374
+     *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1375
+     *  ],
1376
+     *  remote => [
1377
+     *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1378
+     *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1379
+     *  ],
1380
+     *  public => bool
1381
+     *  mail => bool
1382
+     * ]
1383
+     *
1384
+     * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1385
+     * [
1386
+     *  users  => ['user1', 'user2', 'user4'],
1387
+     *  remote => bool,
1388
+     *  public => bool
1389
+     *  mail => bool
1390
+     * ]
1391
+     *
1392
+     * This is required for encryption/activity
1393
+     *
1394
+     * @param \OCP\Files\Node $path
1395
+     * @param bool $recursive Should we check all parent folders as well
1396
+     * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1397
+     * @return array
1398
+     */
1399
+    public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1400
+        $owner = $path->getOwner()->getUID();
1401
+
1402
+        if ($currentAccess) {
1403
+            $al = ['users' => [], 'remote' => [], 'public' => false];
1404
+        } else {
1405
+            $al = ['users' => [], 'remote' => false, 'public' => false];
1406
+        }
1407
+        if (!$this->userManager->userExists($owner)) {
1408
+            return $al;
1409
+        }
1410
+
1411
+        //Get node for the owner
1412
+        $userFolder = $this->rootFolder->getUserFolder($owner);
1413
+        if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1414
+            $path = $userFolder->getById($path->getId())[0];
1415
+        }
1416
+
1417
+        $providers = $this->factory->getAllProviders();
1418
+
1419
+        /** @var Node[] $nodes */
1420
+        $nodes = [];
1421
+
1422
+
1423
+        if ($currentAccess) {
1424
+            $ownerPath = $path->getPath();
1425
+            $ownerPath = explode('/', $ownerPath, 4);
1426
+            if (count($ownerPath) < 4) {
1427
+                $ownerPath = '';
1428
+            } else {
1429
+                $ownerPath = $ownerPath[3];
1430
+            }
1431
+            $al['users'][$owner] = [
1432
+                'node_id' => $path->getId(),
1433
+                'node_path' => '/' . $ownerPath,
1434
+            ];
1435
+        } else {
1436
+            $al['users'][] = $owner;
1437
+        }
1438
+
1439
+        // Collect all the shares
1440
+        while ($path->getPath() !== $userFolder->getPath()) {
1441
+            $nodes[] = $path;
1442
+            if (!$recursive) {
1443
+                break;
1444
+            }
1445
+            $path = $path->getParent();
1446
+        }
1447
+
1448
+        foreach ($providers as $provider) {
1449
+            $tmp = $provider->getAccessList($nodes, $currentAccess);
1450
+
1451
+            foreach ($tmp as $k => $v) {
1452
+                if (isset($al[$k])) {
1453
+                    if (is_array($al[$k])) {
1454
+                        if ($currentAccess) {
1455
+                            $al[$k] += $v;
1456
+                        } else {
1457
+                            $al[$k] = array_merge($al[$k], $v);
1458
+                            $al[$k] = array_unique($al[$k]);
1459
+                            $al[$k] = array_values($al[$k]);
1460
+                        }
1461
+                    } else {
1462
+                        $al[$k] = $al[$k] || $v;
1463
+                    }
1464
+                } else {
1465
+                    $al[$k] = $v;
1466
+                }
1467
+            }
1468
+        }
1469
+
1470
+        return $al;
1471
+    }
1472
+
1473
+    /**
1474
+     * Create a new share
1475
+     * @return \OCP\Share\IShare
1476
+     */
1477
+    public function newShare() {
1478
+        return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1479
+    }
1480
+
1481
+    /**
1482
+     * Is the share API enabled
1483
+     *
1484
+     * @return bool
1485
+     */
1486
+    public function shareApiEnabled() {
1487
+        return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1488
+    }
1489
+
1490
+    /**
1491
+     * Is public link sharing enabled
1492
+     *
1493
+     * @return bool
1494
+     */
1495
+    public function shareApiAllowLinks() {
1496
+        return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1497
+    }
1498
+
1499
+    /**
1500
+     * Is password on public link requires
1501
+     *
1502
+     * @return bool
1503
+     */
1504
+    public function shareApiLinkEnforcePassword() {
1505
+        return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1506
+    }
1507
+
1508
+    /**
1509
+     * Is default expire date enabled
1510
+     *
1511
+     * @return bool
1512
+     */
1513
+    public function shareApiLinkDefaultExpireDate() {
1514
+        return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1515
+    }
1516
+
1517
+    /**
1518
+     * Is default expire date enforced
1519
+     *`
1520
+     * @return bool
1521
+     */
1522
+    public function shareApiLinkDefaultExpireDateEnforced() {
1523
+        return $this->shareApiLinkDefaultExpireDate() &&
1524
+            $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1525
+    }
1526
+
1527
+    /**
1528
+     * Number of default expire days
1529
+     *shareApiLinkAllowPublicUpload
1530
+     * @return int
1531
+     */
1532
+    public function shareApiLinkDefaultExpireDays() {
1533
+        return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1534
+    }
1535
+
1536
+    /**
1537
+     * Allow public upload on link shares
1538
+     *
1539
+     * @return bool
1540
+     */
1541
+    public function shareApiLinkAllowPublicUpload() {
1542
+        return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1543
+    }
1544
+
1545
+    /**
1546
+     * check if user can only share with group members
1547
+     * @return bool
1548
+     */
1549
+    public function shareWithGroupMembersOnly() {
1550
+        return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1551
+    }
1552
+
1553
+    /**
1554
+     * Check if users can share with groups
1555
+     * @return bool
1556
+     */
1557
+    public function allowGroupSharing() {
1558
+        return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1559
+    }
1560
+
1561
+    /**
1562
+     * Copied from \OC_Util::isSharingDisabledForUser
1563
+     *
1564
+     * TODO: Deprecate fuction from OC_Util
1565
+     *
1566
+     * @param string $userId
1567
+     * @return bool
1568
+     */
1569
+    public function sharingDisabledForUser($userId) {
1570
+        if ($userId === null) {
1571
+            return false;
1572
+        }
1573
+
1574
+        if (isset($this->sharingDisabledForUsersCache[$userId])) {
1575
+            return $this->sharingDisabledForUsersCache[$userId];
1576
+        }
1577
+
1578
+        if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1579
+            $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1580
+            $excludedGroups = json_decode($groupsList);
1581
+            if (is_null($excludedGroups)) {
1582
+                $excludedGroups = explode(',', $groupsList);
1583
+                $newValue = json_encode($excludedGroups);
1584
+                $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1585
+            }
1586
+            $user = $this->userManager->get($userId);
1587
+            $usersGroups = $this->groupManager->getUserGroupIds($user);
1588
+            if (!empty($usersGroups)) {
1589
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
1590
+                // if the user is only in groups which are disabled for sharing then
1591
+                // sharing is also disabled for the user
1592
+                if (empty($remainingGroups)) {
1593
+                    $this->sharingDisabledForUsersCache[$userId] = true;
1594
+                    return true;
1595
+                }
1596
+            }
1597
+        }
1598
+
1599
+        $this->sharingDisabledForUsersCache[$userId] = false;
1600
+        return false;
1601
+    }
1602
+
1603
+    /**
1604
+     * @inheritdoc
1605
+     */
1606
+    public function outgoingServer2ServerSharesAllowed() {
1607
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1608
+    }
1609
+
1610
+    /**
1611
+     * @inheritdoc
1612
+     */
1613
+    public function outgoingServer2ServerGroupSharesAllowed() {
1614
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1615
+    }
1616
+
1617
+    /**
1618
+     * @inheritdoc
1619
+     */
1620
+    public function shareProviderExists($shareType) {
1621
+        try {
1622
+            $this->factory->getProviderForType($shareType);
1623
+        } catch (ProviderException $e) {
1624
+            return false;
1625
+        }
1626
+
1627
+        return true;
1628
+    }
1629 1629
 
1630 1630
 }
Please login to merge, or discard this patch.
lib/private/Share/Share.php 1 patch
Indentation   +2067 added lines, -2067 removed lines patch added patch discarded remove patch
@@ -53,2081 +53,2081 @@
 block discarded – undo
53 53
  */
54 54
 class Share extends Constants {
55 55
 
56
-	/** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
57
-	 * Construct permissions for share() and setPermissions with Or (|) e.g.
58
-	 * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
59
-	 *
60
-	 * Check if permission is granted with And (&) e.g. Check if delete is
61
-	 * granted: if ($permissions & PERMISSION_DELETE)
62
-	 *
63
-	 * Remove permissions with And (&) and Not (~) e.g. Remove the update
64
-	 * permission: $permissions &= ~PERMISSION_UPDATE
65
-	 *
66
-	 * Apps are required to handle permissions on their own, this class only
67
-	 * stores and manages the permissions of shares
68
-	 * @see lib/public/constants.php
69
-	 */
70
-
71
-	/**
72
-	 * Register a sharing backend class that implements OCP\Share_Backend for an item type
73
-	 * @param string $itemType Item type
74
-	 * @param string $class Backend class
75
-	 * @param string $collectionOf (optional) Depends on item type
76
-	 * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
77
-	 * @return boolean true if backend is registered or false if error
78
-	 */
79
-	public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
80
-		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') == 'yes') {
81
-			if (!isset(self::$backendTypes[$itemType])) {
82
-				self::$backendTypes[$itemType] = array(
83
-					'class' => $class,
84
-					'collectionOf' => $collectionOf,
85
-					'supportedFileExtensions' => $supportedFileExtensions
86
-				);
87
-				if(count(self::$backendTypes) === 1) {
88
-					Util::addScript('core', 'merged-share-backend');
89
-				}
90
-				return true;
91
-			}
92
-			\OCP\Util::writeLog('OCP\Share',
93
-				'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
94
-				.' is already registered for '.$itemType,
95
-				ILogger::WARN);
96
-		}
97
-		return false;
98
-	}
99
-
100
-	/**
101
-	 * Get the items of item type shared with the current user
102
-	 * @param string $itemType
103
-	 * @param int $format (optional) Format type must be defined by the backend
104
-	 * @param mixed $parameters (optional)
105
-	 * @param int $limit Number of items to return (optional) Returns all by default
106
-	 * @param boolean $includeCollections (optional)
107
-	 * @return mixed Return depends on format
108
-	 */
109
-	public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
110
-											  $parameters = null, $limit = -1, $includeCollections = false) {
111
-		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
112
-			$parameters, $limit, $includeCollections);
113
-	}
114
-
115
-	/**
116
-	 * Get the items of item type shared with a user
117
-	 * @param string $itemType
118
-	 * @param string $user id for which user we want the shares
119
-	 * @param int $format (optional) Format type must be defined by the backend
120
-	 * @param mixed $parameters (optional)
121
-	 * @param int $limit Number of items to return (optional) Returns all by default
122
-	 * @param boolean $includeCollections (optional)
123
-	 * @return mixed Return depends on format
124
-	 */
125
-	public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
126
-												  $parameters = null, $limit = -1, $includeCollections = false) {
127
-		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
128
-			$parameters, $limit, $includeCollections);
129
-	}
130
-
131
-	/**
132
-	 * Get the item of item type shared with a given user by source
133
-	 * @param string $itemType
134
-	 * @param string $itemSource
135
-	 * @param string $user User to whom the item was shared
136
-	 * @param string $owner Owner of the share
137
-	 * @param int $shareType only look for a specific share type
138
-	 * @return array Return list of items with file_target, permissions and expiration
139
-	 */
140
-	public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
141
-		$shares = array();
142
-		$fileDependent = false;
143
-
144
-		$where = 'WHERE';
145
-		$fileDependentWhere = '';
146
-		if ($itemType === 'file' || $itemType === 'folder') {
147
-			$fileDependent = true;
148
-			$column = 'file_source';
149
-			$fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
150
-			$fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
151
-		} else {
152
-			$column = 'item_source';
153
-		}
154
-
155
-		$select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
156
-
157
-		$where .= ' `' . $column . '` = ? AND `item_type` = ? ';
158
-		$arguments = array($itemSource, $itemType);
159
-		// for link shares $user === null
160
-		if ($user !== null) {
161
-			$where .= ' AND `share_with` = ? ';
162
-			$arguments[] = $user;
163
-		}
164
-
165
-		if ($shareType !== null) {
166
-			$where .= ' AND `share_type` = ? ';
167
-			$arguments[] = $shareType;
168
-		}
169
-
170
-		if ($owner !== null) {
171
-			$where .= ' AND `uid_owner` = ? ';
172
-			$arguments[] = $owner;
173
-		}
174
-
175
-		$query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
176
-
177
-		$result = \OC_DB::executeAudited($query, $arguments);
178
-
179
-		while ($row = $result->fetchRow()) {
180
-			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
181
-				continue;
182
-			}
183
-			if ($fileDependent && (int)$row['file_parent'] === -1) {
184
-				// if it is a mount point we need to get the path from the mount manager
185
-				$mountManager = \OC\Files\Filesystem::getMountManager();
186
-				$mountPoint = $mountManager->findByStorageId($row['storage_id']);
187
-				if (!empty($mountPoint)) {
188
-					$path = $mountPoint[0]->getMountPoint();
189
-					$path = trim($path, '/');
190
-					$path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
191
-					$row['path'] = $path;
192
-				} else {
193
-					\OC::$server->getLogger()->warning(
194
-						'Could not resolve mount point for ' . $row['storage_id'],
195
-						['app' => 'OCP\Share']
196
-					);
197
-				}
198
-			}
199
-			$shares[] = $row;
200
-		}
201
-
202
-		//if didn't found a result than let's look for a group share.
203
-		if(empty($shares) && $user !== null) {
204
-			$userObject = \OC::$server->getUserManager()->get($user);
205
-			$groups = [];
206
-			if ($userObject) {
207
-				$groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
208
-			}
209
-
210
-			if (!empty($groups)) {
211
-				$where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
212
-				$arguments = array($itemSource, $itemType, $groups);
213
-				$types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
214
-
215
-				if ($owner !== null) {
216
-					$where .= ' AND `uid_owner` = ?';
217
-					$arguments[] = $owner;
218
-					$types[] = null;
219
-				}
220
-
221
-				// TODO: inject connection, hopefully one day in the future when this
222
-				// class isn't static anymore...
223
-				$conn = \OC::$server->getDatabaseConnection();
224
-				$result = $conn->executeQuery(
225
-					'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
226
-					$arguments,
227
-					$types
228
-				);
229
-
230
-				while ($row = $result->fetch()) {
231
-					$shares[] = $row;
232
-				}
233
-			}
234
-		}
235
-
236
-		return $shares;
237
-
238
-	}
239
-
240
-	/**
241
-	 * Get the item of item type shared with the current user by source
242
-	 * @param string $itemType
243
-	 * @param string $itemSource
244
-	 * @param int $format (optional) Format type must be defined by the backend
245
-	 * @param mixed $parameters
246
-	 * @param boolean $includeCollections
247
-	 * @param string $shareWith (optional) define against which user should be checked, default: current user
248
-	 * @return array
249
-	 */
250
-	public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
251
-													 $parameters = null, $includeCollections = false, $shareWith = null) {
252
-		$shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
253
-		return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
254
-			$parameters, 1, $includeCollections, true);
255
-	}
256
-
257
-	/**
258
-	 * Based on the given token the share information will be returned - password protected shares will be verified
259
-	 * @param string $token
260
-	 * @param bool $checkPasswordProtection
261
-	 * @return array|boolean false will be returned in case the token is unknown or unauthorized
262
-	 */
263
-	public static function getShareByToken($token, $checkPasswordProtection = true) {
264
-		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
265
-		$result = $query->execute(array($token));
266
-		if ($result === false) {
267
-			\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, ILogger::ERROR);
268
-		}
269
-		$row = $result->fetchRow();
270
-		if ($row === false) {
271
-			return false;
272
-		}
273
-		if (is_array($row) and self::expireItem($row)) {
274
-			return false;
275
-		}
276
-
277
-		// password protected shares need to be authenticated
278
-		if ($checkPasswordProtection && !\OC\Share\Share::checkPasswordProtectedShare($row)) {
279
-			return false;
280
-		}
281
-
282
-		return $row;
283
-	}
284
-
285
-	/**
286
-	 * Get the shared items of item type owned by the current user
287
-	 * @param string $itemType
288
-	 * @param int $format (optional) Format type must be defined by the backend
289
-	 * @param mixed $parameters
290
-	 * @param int $limit Number of items to return (optional) Returns all by default
291
-	 * @param boolean $includeCollections
292
-	 * @return mixed Return depends on format
293
-	 */
294
-	public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
295
-										  $limit = -1, $includeCollections = false) {
296
-		return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
297
-			$parameters, $limit, $includeCollections);
298
-	}
299
-
300
-	/**
301
-	 * Get the shared item of item type owned by the current user
302
-	 * @param string $itemType
303
-	 * @param string $itemSource
304
-	 * @param int $format (optional) Format type must be defined by the backend
305
-	 * @param mixed $parameters
306
-	 * @param boolean $includeCollections
307
-	 * @return mixed Return depends on format
308
-	 */
309
-	public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
310
-										 $parameters = null, $includeCollections = false) {
311
-		return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
312
-			$parameters, -1, $includeCollections);
313
-	}
314
-
315
-	/**
316
-	 * Share an item with a user, group, or via private link
317
-	 * @param string $itemType
318
-	 * @param string $itemSource
319
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
320
-	 * @param string $shareWith User or group the item is being shared with
321
-	 * @param int $permissions CRUDS
322
-	 * @param string $itemSourceName
323
-	 * @param \DateTime|null $expirationDate
324
-	 * @param bool|null $passwordChanged
325
-	 * @return boolean|string Returns true on success or false on failure, Returns token on success for links
326
-	 * @throws \OC\HintException when the share type is remote and the shareWith is invalid
327
-	 * @throws \Exception
328
-	 * @since 5.0.0 - parameter $itemSourceName was added in 6.0.0, parameter $expirationDate was added in 7.0.0, parameter $passwordChanged added in 9.0.0
329
-	 * @deprecated 14.0.0 TESTS ONLY - this methods is as of 2018-06 only used by tests
330
-	 */
331
-	public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) {
332
-
333
-		$backend = self::getBackend($itemType);
334
-		$l = \OC::$server->getL10N('lib');
335
-
336
-		if ($backend->isShareTypeAllowed($shareType) === false) {
337
-			$message = 'Sharing %s failed, because the backend does not allow shares from type %i';
338
-			$message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
339
-			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), ILogger::DEBUG);
340
-			throw new \Exception($message_t);
341
-		}
342
-
343
-		$uidOwner = \OC_User::getUser();
344
-		$shareWithinGroupOnly = self::shareWithGroupMembersOnly();
345
-
346
-		if (is_null($itemSourceName)) {
347
-			$itemSourceName = $itemSource;
348
-		}
349
-		$itemName = $itemSourceName;
350
-
351
-		// check if file can be shared
352
-		if ($itemType === 'file' or $itemType === 'folder') {
353
-			$path = \OC\Files\Filesystem::getPath($itemSource);
354
-			$itemName = $path;
355
-
356
-			// verify that the file exists before we try to share it
357
-			if (!$path) {
358
-				$message = 'Sharing %s failed, because the file does not exist';
359
-				$message_t = $l->t('Sharing %s failed, because the file does not exist', array($itemSourceName));
360
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
361
-				throw new \Exception($message_t);
362
-			}
363
-			// verify that the user has share permission
364
-			if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
365
-				$message = 'You are not allowed to share %s';
366
-				$message_t = $l->t('You are not allowed to share %s', [$path]);
367
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $path), ILogger::DEBUG);
368
-				throw new \Exception($message_t);
369
-			}
370
-		}
371
-
372
-		//verify that we don't share a folder which already contains a share mount point
373
-		if ($itemType === 'folder') {
374
-			$path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
375
-			$mountManager = \OC\Files\Filesystem::getMountManager();
376
-			$mounts = $mountManager->findIn($path);
377
-			foreach ($mounts as $mount) {
378
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
379
-					$message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
380
-					\OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);
381
-					throw new \Exception($message);
382
-				}
383
-
384
-			}
385
-		}
386
-
387
-		// single file shares should never have delete permissions
388
-		if ($itemType === 'file') {
389
-			$permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
390
-		}
391
-
392
-		//Validate expirationDate
393
-		if ($expirationDate !== null) {
394
-			try {
395
-				/*
56
+    /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
57
+     * Construct permissions for share() and setPermissions with Or (|) e.g.
58
+     * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
59
+     *
60
+     * Check if permission is granted with And (&) e.g. Check if delete is
61
+     * granted: if ($permissions & PERMISSION_DELETE)
62
+     *
63
+     * Remove permissions with And (&) and Not (~) e.g. Remove the update
64
+     * permission: $permissions &= ~PERMISSION_UPDATE
65
+     *
66
+     * Apps are required to handle permissions on their own, this class only
67
+     * stores and manages the permissions of shares
68
+     * @see lib/public/constants.php
69
+     */
70
+
71
+    /**
72
+     * Register a sharing backend class that implements OCP\Share_Backend for an item type
73
+     * @param string $itemType Item type
74
+     * @param string $class Backend class
75
+     * @param string $collectionOf (optional) Depends on item type
76
+     * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
77
+     * @return boolean true if backend is registered or false if error
78
+     */
79
+    public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
80
+        if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') == 'yes') {
81
+            if (!isset(self::$backendTypes[$itemType])) {
82
+                self::$backendTypes[$itemType] = array(
83
+                    'class' => $class,
84
+                    'collectionOf' => $collectionOf,
85
+                    'supportedFileExtensions' => $supportedFileExtensions
86
+                );
87
+                if(count(self::$backendTypes) === 1) {
88
+                    Util::addScript('core', 'merged-share-backend');
89
+                }
90
+                return true;
91
+            }
92
+            \OCP\Util::writeLog('OCP\Share',
93
+                'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
94
+                .' is already registered for '.$itemType,
95
+                ILogger::WARN);
96
+        }
97
+        return false;
98
+    }
99
+
100
+    /**
101
+     * Get the items of item type shared with the current user
102
+     * @param string $itemType
103
+     * @param int $format (optional) Format type must be defined by the backend
104
+     * @param mixed $parameters (optional)
105
+     * @param int $limit Number of items to return (optional) Returns all by default
106
+     * @param boolean $includeCollections (optional)
107
+     * @return mixed Return depends on format
108
+     */
109
+    public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
110
+                                                $parameters = null, $limit = -1, $includeCollections = false) {
111
+        return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
112
+            $parameters, $limit, $includeCollections);
113
+    }
114
+
115
+    /**
116
+     * Get the items of item type shared with a user
117
+     * @param string $itemType
118
+     * @param string $user id for which user we want the shares
119
+     * @param int $format (optional) Format type must be defined by the backend
120
+     * @param mixed $parameters (optional)
121
+     * @param int $limit Number of items to return (optional) Returns all by default
122
+     * @param boolean $includeCollections (optional)
123
+     * @return mixed Return depends on format
124
+     */
125
+    public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
126
+                                                    $parameters = null, $limit = -1, $includeCollections = false) {
127
+        return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
128
+            $parameters, $limit, $includeCollections);
129
+    }
130
+
131
+    /**
132
+     * Get the item of item type shared with a given user by source
133
+     * @param string $itemType
134
+     * @param string $itemSource
135
+     * @param string $user User to whom the item was shared
136
+     * @param string $owner Owner of the share
137
+     * @param int $shareType only look for a specific share type
138
+     * @return array Return list of items with file_target, permissions and expiration
139
+     */
140
+    public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
141
+        $shares = array();
142
+        $fileDependent = false;
143
+
144
+        $where = 'WHERE';
145
+        $fileDependentWhere = '';
146
+        if ($itemType === 'file' || $itemType === 'folder') {
147
+            $fileDependent = true;
148
+            $column = 'file_source';
149
+            $fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
150
+            $fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
151
+        } else {
152
+            $column = 'item_source';
153
+        }
154
+
155
+        $select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
156
+
157
+        $where .= ' `' . $column . '` = ? AND `item_type` = ? ';
158
+        $arguments = array($itemSource, $itemType);
159
+        // for link shares $user === null
160
+        if ($user !== null) {
161
+            $where .= ' AND `share_with` = ? ';
162
+            $arguments[] = $user;
163
+        }
164
+
165
+        if ($shareType !== null) {
166
+            $where .= ' AND `share_type` = ? ';
167
+            $arguments[] = $shareType;
168
+        }
169
+
170
+        if ($owner !== null) {
171
+            $where .= ' AND `uid_owner` = ? ';
172
+            $arguments[] = $owner;
173
+        }
174
+
175
+        $query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
176
+
177
+        $result = \OC_DB::executeAudited($query, $arguments);
178
+
179
+        while ($row = $result->fetchRow()) {
180
+            if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
181
+                continue;
182
+            }
183
+            if ($fileDependent && (int)$row['file_parent'] === -1) {
184
+                // if it is a mount point we need to get the path from the mount manager
185
+                $mountManager = \OC\Files\Filesystem::getMountManager();
186
+                $mountPoint = $mountManager->findByStorageId($row['storage_id']);
187
+                if (!empty($mountPoint)) {
188
+                    $path = $mountPoint[0]->getMountPoint();
189
+                    $path = trim($path, '/');
190
+                    $path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
191
+                    $row['path'] = $path;
192
+                } else {
193
+                    \OC::$server->getLogger()->warning(
194
+                        'Could not resolve mount point for ' . $row['storage_id'],
195
+                        ['app' => 'OCP\Share']
196
+                    );
197
+                }
198
+            }
199
+            $shares[] = $row;
200
+        }
201
+
202
+        //if didn't found a result than let's look for a group share.
203
+        if(empty($shares) && $user !== null) {
204
+            $userObject = \OC::$server->getUserManager()->get($user);
205
+            $groups = [];
206
+            if ($userObject) {
207
+                $groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
208
+            }
209
+
210
+            if (!empty($groups)) {
211
+                $where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
212
+                $arguments = array($itemSource, $itemType, $groups);
213
+                $types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
214
+
215
+                if ($owner !== null) {
216
+                    $where .= ' AND `uid_owner` = ?';
217
+                    $arguments[] = $owner;
218
+                    $types[] = null;
219
+                }
220
+
221
+                // TODO: inject connection, hopefully one day in the future when this
222
+                // class isn't static anymore...
223
+                $conn = \OC::$server->getDatabaseConnection();
224
+                $result = $conn->executeQuery(
225
+                    'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
226
+                    $arguments,
227
+                    $types
228
+                );
229
+
230
+                while ($row = $result->fetch()) {
231
+                    $shares[] = $row;
232
+                }
233
+            }
234
+        }
235
+
236
+        return $shares;
237
+
238
+    }
239
+
240
+    /**
241
+     * Get the item of item type shared with the current user by source
242
+     * @param string $itemType
243
+     * @param string $itemSource
244
+     * @param int $format (optional) Format type must be defined by the backend
245
+     * @param mixed $parameters
246
+     * @param boolean $includeCollections
247
+     * @param string $shareWith (optional) define against which user should be checked, default: current user
248
+     * @return array
249
+     */
250
+    public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
251
+                                                        $parameters = null, $includeCollections = false, $shareWith = null) {
252
+        $shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
253
+        return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
254
+            $parameters, 1, $includeCollections, true);
255
+    }
256
+
257
+    /**
258
+     * Based on the given token the share information will be returned - password protected shares will be verified
259
+     * @param string $token
260
+     * @param bool $checkPasswordProtection
261
+     * @return array|boolean false will be returned in case the token is unknown or unauthorized
262
+     */
263
+    public static function getShareByToken($token, $checkPasswordProtection = true) {
264
+        $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
265
+        $result = $query->execute(array($token));
266
+        if ($result === false) {
267
+            \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, ILogger::ERROR);
268
+        }
269
+        $row = $result->fetchRow();
270
+        if ($row === false) {
271
+            return false;
272
+        }
273
+        if (is_array($row) and self::expireItem($row)) {
274
+            return false;
275
+        }
276
+
277
+        // password protected shares need to be authenticated
278
+        if ($checkPasswordProtection && !\OC\Share\Share::checkPasswordProtectedShare($row)) {
279
+            return false;
280
+        }
281
+
282
+        return $row;
283
+    }
284
+
285
+    /**
286
+     * Get the shared items of item type owned by the current user
287
+     * @param string $itemType
288
+     * @param int $format (optional) Format type must be defined by the backend
289
+     * @param mixed $parameters
290
+     * @param int $limit Number of items to return (optional) Returns all by default
291
+     * @param boolean $includeCollections
292
+     * @return mixed Return depends on format
293
+     */
294
+    public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
295
+                                            $limit = -1, $includeCollections = false) {
296
+        return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
297
+            $parameters, $limit, $includeCollections);
298
+    }
299
+
300
+    /**
301
+     * Get the shared item of item type owned by the current user
302
+     * @param string $itemType
303
+     * @param string $itemSource
304
+     * @param int $format (optional) Format type must be defined by the backend
305
+     * @param mixed $parameters
306
+     * @param boolean $includeCollections
307
+     * @return mixed Return depends on format
308
+     */
309
+    public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
310
+                                            $parameters = null, $includeCollections = false) {
311
+        return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
312
+            $parameters, -1, $includeCollections);
313
+    }
314
+
315
+    /**
316
+     * Share an item with a user, group, or via private link
317
+     * @param string $itemType
318
+     * @param string $itemSource
319
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
320
+     * @param string $shareWith User or group the item is being shared with
321
+     * @param int $permissions CRUDS
322
+     * @param string $itemSourceName
323
+     * @param \DateTime|null $expirationDate
324
+     * @param bool|null $passwordChanged
325
+     * @return boolean|string Returns true on success or false on failure, Returns token on success for links
326
+     * @throws \OC\HintException when the share type is remote and the shareWith is invalid
327
+     * @throws \Exception
328
+     * @since 5.0.0 - parameter $itemSourceName was added in 6.0.0, parameter $expirationDate was added in 7.0.0, parameter $passwordChanged added in 9.0.0
329
+     * @deprecated 14.0.0 TESTS ONLY - this methods is as of 2018-06 only used by tests
330
+     */
331
+    public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) {
332
+
333
+        $backend = self::getBackend($itemType);
334
+        $l = \OC::$server->getL10N('lib');
335
+
336
+        if ($backend->isShareTypeAllowed($shareType) === false) {
337
+            $message = 'Sharing %s failed, because the backend does not allow shares from type %i';
338
+            $message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
339
+            \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), ILogger::DEBUG);
340
+            throw new \Exception($message_t);
341
+        }
342
+
343
+        $uidOwner = \OC_User::getUser();
344
+        $shareWithinGroupOnly = self::shareWithGroupMembersOnly();
345
+
346
+        if (is_null($itemSourceName)) {
347
+            $itemSourceName = $itemSource;
348
+        }
349
+        $itemName = $itemSourceName;
350
+
351
+        // check if file can be shared
352
+        if ($itemType === 'file' or $itemType === 'folder') {
353
+            $path = \OC\Files\Filesystem::getPath($itemSource);
354
+            $itemName = $path;
355
+
356
+            // verify that the file exists before we try to share it
357
+            if (!$path) {
358
+                $message = 'Sharing %s failed, because the file does not exist';
359
+                $message_t = $l->t('Sharing %s failed, because the file does not exist', array($itemSourceName));
360
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
361
+                throw new \Exception($message_t);
362
+            }
363
+            // verify that the user has share permission
364
+            if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
365
+                $message = 'You are not allowed to share %s';
366
+                $message_t = $l->t('You are not allowed to share %s', [$path]);
367
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $path), ILogger::DEBUG);
368
+                throw new \Exception($message_t);
369
+            }
370
+        }
371
+
372
+        //verify that we don't share a folder which already contains a share mount point
373
+        if ($itemType === 'folder') {
374
+            $path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
375
+            $mountManager = \OC\Files\Filesystem::getMountManager();
376
+            $mounts = $mountManager->findIn($path);
377
+            foreach ($mounts as $mount) {
378
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
379
+                    $message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
380
+                    \OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);
381
+                    throw new \Exception($message);
382
+                }
383
+
384
+            }
385
+        }
386
+
387
+        // single file shares should never have delete permissions
388
+        if ($itemType === 'file') {
389
+            $permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
390
+        }
391
+
392
+        //Validate expirationDate
393
+        if ($expirationDate !== null) {
394
+            try {
395
+                /*
396 396
 				 * Reuse the validateExpireDate.
397 397
 				 * We have to pass time() since the second arg is the time
398 398
 				 * the file was shared, since it is not shared yet we just use
399 399
 				 * the current time.
400 400
 				 */
401
-				$expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
402
-			} catch (\Exception $e) {
403
-				throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
404
-			}
405
-		}
406
-
407
-		// Verify share type and sharing conditions are met
408
-		if ($shareType === self::SHARE_TYPE_USER) {
409
-			if ($shareWith == $uidOwner) {
410
-				$message = 'Sharing %s failed, because you can not share with yourself';
411
-				$message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]);
412
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
413
-				throw new \Exception($message_t);
414
-			}
415
-			if (!\OC::$server->getUserManager()->userExists($shareWith)) {
416
-				$message = 'Sharing %1$s failed, because the user %2$s does not exist';
417
-				$message_t = $l->t('Sharing %1$s failed, because the user %2$s does not exist', array($itemSourceName, $shareWith));
418
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
419
-				throw new \Exception($message_t);
420
-			}
421
-			if ($shareWithinGroupOnly) {
422
-				$userManager = \OC::$server->getUserManager();
423
-				$groupManager = \OC::$server->getGroupManager();
424
-				$userOwner = $userManager->get($uidOwner);
425
-				$userShareWith = $userManager->get($shareWith);
426
-				$groupsOwner = [];
427
-				$groupsShareWith = [];
428
-				if ($userOwner) {
429
-					$groupsOwner = $groupManager->getUserGroupIds($userOwner);
430
-				}
431
-				if ($userShareWith) {
432
-					$groupsShareWith = $groupManager->getUserGroupIds($userShareWith);
433
-				}
434
-				$inGroup = array_intersect($groupsOwner, $groupsShareWith);
435
-				if (empty($inGroup)) {
436
-					$message = 'Sharing %1$s failed, because the user '
437
-						.'%2$s is not a member of any groups that %3$s is a member of';
438
-					$message_t = $l->t('Sharing %1$s failed, because the user %2$s is not a member of any groups that %3$s is a member of', array($itemName, $shareWith, $uidOwner));
439
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), ILogger::DEBUG);
440
-					throw new \Exception($message_t);
441
-				}
442
-			}
443
-			// Check if the item source is already shared with the user, either from the same owner or a different user
444
-			if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
445
-				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
446
-				// Only allow the same share to occur again if it is the same
447
-				// owner and is not a user share, this use case is for increasing
448
-				// permissions for a specific user
449
-				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
450
-					$message = 'Sharing %1$s failed, because this item is already shared with %2$s';
451
-					$message_t = $l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($itemSourceName, $shareWith));
452
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
453
-					throw new \Exception($message_t);
454
-				}
455
-			}
456
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
457
-				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
458
-				// Only allow the same share to occur again if it is the same
459
-				// owner and is not a user share, this use case is for increasing
460
-				// permissions for a specific user
461
-				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
462
-					$message = 'Sharing %1$s failed, because this item is already shared with user %2$s';
463
-					$message_t = $l->t('Sharing %1$s failed, because this item is already shared with user %2$s', array($itemSourceName, $shareWith));
464
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::ERROR);
465
-					throw new \Exception($message_t);
466
-				}
467
-			}
468
-		} else if ($shareType === self::SHARE_TYPE_GROUP) {
469
-			if (!\OC::$server->getGroupManager()->groupExists($shareWith)) {
470
-				$message = 'Sharing %1$s failed, because the group %2$s does not exist';
471
-				$message_t = $l->t('Sharing %1$s failed, because the group %2$s does not exist', array($itemSourceName, $shareWith));
472
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
473
-				throw new \Exception($message_t);
474
-			}
475
-			if ($shareWithinGroupOnly) {
476
-				$group = \OC::$server->getGroupManager()->get($shareWith);
477
-				$user = \OC::$server->getUserManager()->get($uidOwner);
478
-				if (!$group || !$user || !$group->inGroup($user)) {
479
-					$message = 'Sharing %1$s failed, because '
480
-						. '%2$s is not a member of the group %3$s';
481
-					$message_t = $l->t('Sharing %1$s failed, because %2$s is not a member of the group %3$s', array($itemSourceName, $uidOwner, $shareWith));
482
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), ILogger::DEBUG);
483
-					throw new \Exception($message_t);
484
-				}
485
-			}
486
-			// Check if the item source is already shared with the group, either from the same owner or a different user
487
-			// The check for each user in the group is done inside the put() function
488
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
489
-				null, self::FORMAT_NONE, null, 1, true, true)) {
490
-
491
-				if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
492
-					$message = 'Sharing %1$s failed, because this item is already shared with %2$s';
493
-					$message_t = $l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($itemSourceName, $shareWith));
494
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
495
-					throw new \Exception($message_t);
496
-				}
497
-			}
498
-			// Convert share with into an array with the keys group and users
499
-			$group = $shareWith;
500
-			$shareWith = array();
501
-			$shareWith['group'] = $group;
502
-
503
-
504
-			$groupObject = \OC::$server->getGroupManager()->get($group);
505
-			$userIds = [];
506
-			if ($groupObject) {
507
-				$users = $groupObject->searchUsers('', -1, 0);
508
-				foreach ($users as $user) {
509
-					$userIds[] = $user->getUID();
510
-				}
511
-			}
512
-
513
-			$shareWith['users'] = array_diff($userIds, array($uidOwner));
514
-		} else if ($shareType === self::SHARE_TYPE_LINK) {
515
-			$updateExistingShare = false;
516
-			if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
517
-
518
-				// IF the password is changed via the old ajax endpoint verify it before deleting the old share
519
-				if ($passwordChanged === true) {
520
-					self::verifyPassword($shareWith);
521
-				}
522
-
523
-				// when updating a link share
524
-				// FIXME Don't delete link if we update it
525
-				if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
526
-					$uidOwner, self::FORMAT_NONE, null, 1)) {
527
-					// remember old token
528
-					$oldToken = $checkExists['token'];
529
-					$oldPermissions = $checkExists['permissions'];
530
-					//delete the old share
531
-					Helper::delete($checkExists['id']);
532
-					$updateExistingShare = true;
533
-				}
534
-
535
-				if ($passwordChanged === null) {
536
-					// Generate hash of password - same method as user passwords
537
-					if (is_string($shareWith) && $shareWith !== '') {
538
-						self::verifyPassword($shareWith);
539
-						$shareWith = \OC::$server->getHasher()->hash($shareWith);
540
-					} else {
541
-						// reuse the already set password, but only if we change permissions
542
-						// otherwise the user disabled the password protection
543
-						if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
544
-							$shareWith = $checkExists['share_with'];
545
-						}
546
-					}
547
-				} else {
548
-					if ($passwordChanged === true) {
549
-						if (is_string($shareWith) && $shareWith !== '') {
550
-							self::verifyPassword($shareWith);
551
-							$shareWith = \OC::$server->getHasher()->hash($shareWith);
552
-						}
553
-					} else if ($updateExistingShare) {
554
-						$shareWith = $checkExists['share_with'];
555
-					}
556
-				}
557
-
558
-				if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
559
-					$message = 'You need to provide a password to create a public link, only protected links are allowed';
560
-					$message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
561
-					\OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);
562
-					throw new \Exception($message_t);
563
-				}
564
-
565
-				if ($updateExistingShare === false &&
566
-					self::isDefaultExpireDateEnabled() &&
567
-					empty($expirationDate)) {
568
-					$expirationDate = Helper::calcExpireDate();
569
-				}
570
-
571
-				// Generate token
572
-				if (isset($oldToken)) {
573
-					$token = $oldToken;
574
-				} else {
575
-					$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
576
-						\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
577
-					);
578
-				}
579
-				$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
580
-					null, $token, $itemSourceName, $expirationDate);
581
-				if ($result) {
582
-					return $token;
583
-				} else {
584
-					return false;
585
-				}
586
-			}
587
-			$message = 'Sharing %s failed, because sharing with links is not allowed';
588
-			$message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
589
-			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
590
-			throw new \Exception($message_t);
591
-		} else if ($shareType === self::SHARE_TYPE_REMOTE) {
592
-
593
-			/*
401
+                $expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
402
+            } catch (\Exception $e) {
403
+                throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
404
+            }
405
+        }
406
+
407
+        // Verify share type and sharing conditions are met
408
+        if ($shareType === self::SHARE_TYPE_USER) {
409
+            if ($shareWith == $uidOwner) {
410
+                $message = 'Sharing %s failed, because you can not share with yourself';
411
+                $message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]);
412
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
413
+                throw new \Exception($message_t);
414
+            }
415
+            if (!\OC::$server->getUserManager()->userExists($shareWith)) {
416
+                $message = 'Sharing %1$s failed, because the user %2$s does not exist';
417
+                $message_t = $l->t('Sharing %1$s failed, because the user %2$s does not exist', array($itemSourceName, $shareWith));
418
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
419
+                throw new \Exception($message_t);
420
+            }
421
+            if ($shareWithinGroupOnly) {
422
+                $userManager = \OC::$server->getUserManager();
423
+                $groupManager = \OC::$server->getGroupManager();
424
+                $userOwner = $userManager->get($uidOwner);
425
+                $userShareWith = $userManager->get($shareWith);
426
+                $groupsOwner = [];
427
+                $groupsShareWith = [];
428
+                if ($userOwner) {
429
+                    $groupsOwner = $groupManager->getUserGroupIds($userOwner);
430
+                }
431
+                if ($userShareWith) {
432
+                    $groupsShareWith = $groupManager->getUserGroupIds($userShareWith);
433
+                }
434
+                $inGroup = array_intersect($groupsOwner, $groupsShareWith);
435
+                if (empty($inGroup)) {
436
+                    $message = 'Sharing %1$s failed, because the user '
437
+                        .'%2$s is not a member of any groups that %3$s is a member of';
438
+                    $message_t = $l->t('Sharing %1$s failed, because the user %2$s is not a member of any groups that %3$s is a member of', array($itemName, $shareWith, $uidOwner));
439
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), ILogger::DEBUG);
440
+                    throw new \Exception($message_t);
441
+                }
442
+            }
443
+            // Check if the item source is already shared with the user, either from the same owner or a different user
444
+            if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
445
+                $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
446
+                // Only allow the same share to occur again if it is the same
447
+                // owner and is not a user share, this use case is for increasing
448
+                // permissions for a specific user
449
+                if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
450
+                    $message = 'Sharing %1$s failed, because this item is already shared with %2$s';
451
+                    $message_t = $l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($itemSourceName, $shareWith));
452
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
453
+                    throw new \Exception($message_t);
454
+                }
455
+            }
456
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
457
+                $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
458
+                // Only allow the same share to occur again if it is the same
459
+                // owner and is not a user share, this use case is for increasing
460
+                // permissions for a specific user
461
+                if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
462
+                    $message = 'Sharing %1$s failed, because this item is already shared with user %2$s';
463
+                    $message_t = $l->t('Sharing %1$s failed, because this item is already shared with user %2$s', array($itemSourceName, $shareWith));
464
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::ERROR);
465
+                    throw new \Exception($message_t);
466
+                }
467
+            }
468
+        } else if ($shareType === self::SHARE_TYPE_GROUP) {
469
+            if (!\OC::$server->getGroupManager()->groupExists($shareWith)) {
470
+                $message = 'Sharing %1$s failed, because the group %2$s does not exist';
471
+                $message_t = $l->t('Sharing %1$s failed, because the group %2$s does not exist', array($itemSourceName, $shareWith));
472
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
473
+                throw new \Exception($message_t);
474
+            }
475
+            if ($shareWithinGroupOnly) {
476
+                $group = \OC::$server->getGroupManager()->get($shareWith);
477
+                $user = \OC::$server->getUserManager()->get($uidOwner);
478
+                if (!$group || !$user || !$group->inGroup($user)) {
479
+                    $message = 'Sharing %1$s failed, because '
480
+                        . '%2$s is not a member of the group %3$s';
481
+                    $message_t = $l->t('Sharing %1$s failed, because %2$s is not a member of the group %3$s', array($itemSourceName, $uidOwner, $shareWith));
482
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), ILogger::DEBUG);
483
+                    throw new \Exception($message_t);
484
+                }
485
+            }
486
+            // Check if the item source is already shared with the group, either from the same owner or a different user
487
+            // The check for each user in the group is done inside the put() function
488
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
489
+                null, self::FORMAT_NONE, null, 1, true, true)) {
490
+
491
+                if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
492
+                    $message = 'Sharing %1$s failed, because this item is already shared with %2$s';
493
+                    $message_t = $l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($itemSourceName, $shareWith));
494
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
495
+                    throw new \Exception($message_t);
496
+                }
497
+            }
498
+            // Convert share with into an array with the keys group and users
499
+            $group = $shareWith;
500
+            $shareWith = array();
501
+            $shareWith['group'] = $group;
502
+
503
+
504
+            $groupObject = \OC::$server->getGroupManager()->get($group);
505
+            $userIds = [];
506
+            if ($groupObject) {
507
+                $users = $groupObject->searchUsers('', -1, 0);
508
+                foreach ($users as $user) {
509
+                    $userIds[] = $user->getUID();
510
+                }
511
+            }
512
+
513
+            $shareWith['users'] = array_diff($userIds, array($uidOwner));
514
+        } else if ($shareType === self::SHARE_TYPE_LINK) {
515
+            $updateExistingShare = false;
516
+            if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
517
+
518
+                // IF the password is changed via the old ajax endpoint verify it before deleting the old share
519
+                if ($passwordChanged === true) {
520
+                    self::verifyPassword($shareWith);
521
+                }
522
+
523
+                // when updating a link share
524
+                // FIXME Don't delete link if we update it
525
+                if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
526
+                    $uidOwner, self::FORMAT_NONE, null, 1)) {
527
+                    // remember old token
528
+                    $oldToken = $checkExists['token'];
529
+                    $oldPermissions = $checkExists['permissions'];
530
+                    //delete the old share
531
+                    Helper::delete($checkExists['id']);
532
+                    $updateExistingShare = true;
533
+                }
534
+
535
+                if ($passwordChanged === null) {
536
+                    // Generate hash of password - same method as user passwords
537
+                    if (is_string($shareWith) && $shareWith !== '') {
538
+                        self::verifyPassword($shareWith);
539
+                        $shareWith = \OC::$server->getHasher()->hash($shareWith);
540
+                    } else {
541
+                        // reuse the already set password, but only if we change permissions
542
+                        // otherwise the user disabled the password protection
543
+                        if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
544
+                            $shareWith = $checkExists['share_with'];
545
+                        }
546
+                    }
547
+                } else {
548
+                    if ($passwordChanged === true) {
549
+                        if (is_string($shareWith) && $shareWith !== '') {
550
+                            self::verifyPassword($shareWith);
551
+                            $shareWith = \OC::$server->getHasher()->hash($shareWith);
552
+                        }
553
+                    } else if ($updateExistingShare) {
554
+                        $shareWith = $checkExists['share_with'];
555
+                    }
556
+                }
557
+
558
+                if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
559
+                    $message = 'You need to provide a password to create a public link, only protected links are allowed';
560
+                    $message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
561
+                    \OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);
562
+                    throw new \Exception($message_t);
563
+                }
564
+
565
+                if ($updateExistingShare === false &&
566
+                    self::isDefaultExpireDateEnabled() &&
567
+                    empty($expirationDate)) {
568
+                    $expirationDate = Helper::calcExpireDate();
569
+                }
570
+
571
+                // Generate token
572
+                if (isset($oldToken)) {
573
+                    $token = $oldToken;
574
+                } else {
575
+                    $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
576
+                        \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
577
+                    );
578
+                }
579
+                $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
580
+                    null, $token, $itemSourceName, $expirationDate);
581
+                if ($result) {
582
+                    return $token;
583
+                } else {
584
+                    return false;
585
+                }
586
+            }
587
+            $message = 'Sharing %s failed, because sharing with links is not allowed';
588
+            $message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
589
+            \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
590
+            throw new \Exception($message_t);
591
+        } else if ($shareType === self::SHARE_TYPE_REMOTE) {
592
+
593
+            /*
594 594
 			 * Check if file is not already shared with the remote user
595 595
 			 */
596
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_REMOTE,
597
-				$shareWith, $uidOwner, self::FORMAT_NONE, null, 1, true, true)) {
598
-					$message = 'Sharing %1$s failed, because this item is already shared with %2$s';
599
-					$message_t = $l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($itemSourceName, $shareWith));
600
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
601
-					throw new \Exception($message_t);
602
-			}
603
-
604
-			// don't allow federated shares if source and target server are the same
605
-			list($user, $remote) = Helper::splitUserRemote($shareWith);
606
-			$currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
607
-			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
608
-			if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
609
-				$message = 'Not allowed to create a federated share with the same user.';
610
-				$message_t = $l->t('Not allowed to create a federated share with the same user');
611
-				\OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);
612
-				throw new \Exception($message_t);
613
-			}
614
-
615
-			$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
616
-				\OCP\Security\ISecureRandom::CHAR_DIGITS);
617
-
618
-			$shareWith = $user . '@' . $remote;
619
-			$shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
620
-
621
-			$send = false;
622
-			if ($shareId) {
623
-				$send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
624
-			}
625
-
626
-			if ($send === false) {
627
-				$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
628
-				self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
629
-				$message_t = $l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
630
-				throw new \Exception($message_t);
631
-			}
632
-
633
-			return $send;
634
-		} else {
635
-			// Future share types need to include their own conditions
636
-			$message = 'Share type %1$s is not valid for %2$s';
637
-			$message_t = $l->t('Share type %1$s is not valid for %2$s', array($shareType, $itemSource));
638
-			\OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), ILogger::DEBUG);
639
-			throw new \Exception($message_t);
640
-		}
641
-
642
-		// Put the item into the database
643
-		$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
644
-
645
-		return $result ? true : false;
646
-	}
647
-
648
-	/**
649
-	 * Unshare an item from a user, group, or delete a private link
650
-	 * @param string $itemType
651
-	 * @param string $itemSource
652
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
653
-	 * @param string $shareWith User or group the item is being shared with
654
-	 * @param string $owner owner of the share, if null the current user is used
655
-	 * @return boolean true on success or false on failure
656
-	 */
657
-	public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
658
-
659
-		// check if it is a valid itemType
660
-		self::getBackend($itemType);
661
-
662
-		$items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
663
-
664
-		$toDelete = array();
665
-		$newParent = null;
666
-		$currentUser = $owner ? $owner : \OC_User::getUser();
667
-		foreach ($items as $item) {
668
-			// delete the item with the expected share_type and owner
669
-			if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
670
-				$toDelete = $item;
671
-				// if there is more then one result we don't have to delete the children
672
-				// but update their parent. For group shares the new parent should always be
673
-				// the original group share and not the db entry with the unique name
674
-			} else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
675
-				$newParent = $item['parent'];
676
-			} else {
677
-				$newParent = $item['id'];
678
-			}
679
-		}
680
-
681
-		if (!empty($toDelete)) {
682
-			self::unshareItem($toDelete, $newParent);
683
-			return true;
684
-		}
685
-		return false;
686
-	}
687
-
688
-	/**
689
-	 * sent status if users got informed by mail about share
690
-	 * @param string $itemType
691
-	 * @param string $itemSource
692
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
693
-	 * @param string $recipient with whom was the file shared
694
-	 * @param boolean $status
695
-	 */
696
-	public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
697
-		$status = $status ? 1 : 0;
698
-
699
-		$query = \OC_DB::prepare(
700
-			'UPDATE `*PREFIX*share`
596
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_REMOTE,
597
+                $shareWith, $uidOwner, self::FORMAT_NONE, null, 1, true, true)) {
598
+                    $message = 'Sharing %1$s failed, because this item is already shared with %2$s';
599
+                    $message_t = $l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($itemSourceName, $shareWith));
600
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
601
+                    throw new \Exception($message_t);
602
+            }
603
+
604
+            // don't allow federated shares if source and target server are the same
605
+            list($user, $remote) = Helper::splitUserRemote($shareWith);
606
+            $currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
607
+            $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
608
+            if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
609
+                $message = 'Not allowed to create a federated share with the same user.';
610
+                $message_t = $l->t('Not allowed to create a federated share with the same user');
611
+                \OCP\Util::writeLog('OCP\Share', $message, ILogger::DEBUG);
612
+                throw new \Exception($message_t);
613
+            }
614
+
615
+            $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
616
+                \OCP\Security\ISecureRandom::CHAR_DIGITS);
617
+
618
+            $shareWith = $user . '@' . $remote;
619
+            $shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
620
+
621
+            $send = false;
622
+            if ($shareId) {
623
+                $send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
624
+            }
625
+
626
+            if ($send === false) {
627
+                $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
628
+                self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
629
+                $message_t = $l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
630
+                throw new \Exception($message_t);
631
+            }
632
+
633
+            return $send;
634
+        } else {
635
+            // Future share types need to include their own conditions
636
+            $message = 'Share type %1$s is not valid for %2$s';
637
+            $message_t = $l->t('Share type %1$s is not valid for %2$s', array($shareType, $itemSource));
638
+            \OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), ILogger::DEBUG);
639
+            throw new \Exception($message_t);
640
+        }
641
+
642
+        // Put the item into the database
643
+        $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
644
+
645
+        return $result ? true : false;
646
+    }
647
+
648
+    /**
649
+     * Unshare an item from a user, group, or delete a private link
650
+     * @param string $itemType
651
+     * @param string $itemSource
652
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
653
+     * @param string $shareWith User or group the item is being shared with
654
+     * @param string $owner owner of the share, if null the current user is used
655
+     * @return boolean true on success or false on failure
656
+     */
657
+    public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
658
+
659
+        // check if it is a valid itemType
660
+        self::getBackend($itemType);
661
+
662
+        $items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
663
+
664
+        $toDelete = array();
665
+        $newParent = null;
666
+        $currentUser = $owner ? $owner : \OC_User::getUser();
667
+        foreach ($items as $item) {
668
+            // delete the item with the expected share_type and owner
669
+            if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
670
+                $toDelete = $item;
671
+                // if there is more then one result we don't have to delete the children
672
+                // but update their parent. For group shares the new parent should always be
673
+                // the original group share and not the db entry with the unique name
674
+            } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
675
+                $newParent = $item['parent'];
676
+            } else {
677
+                $newParent = $item['id'];
678
+            }
679
+        }
680
+
681
+        if (!empty($toDelete)) {
682
+            self::unshareItem($toDelete, $newParent);
683
+            return true;
684
+        }
685
+        return false;
686
+    }
687
+
688
+    /**
689
+     * sent status if users got informed by mail about share
690
+     * @param string $itemType
691
+     * @param string $itemSource
692
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
693
+     * @param string $recipient with whom was the file shared
694
+     * @param boolean $status
695
+     */
696
+    public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
697
+        $status = $status ? 1 : 0;
698
+
699
+        $query = \OC_DB::prepare(
700
+            'UPDATE `*PREFIX*share`
701 701
 					SET `mail_send` = ?
702 702
 					WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ? AND `share_with` = ?');
703 703
 
704
-		$result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient));
705
-
706
-		if($result === false) {
707
-			\OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', ILogger::ERROR);
708
-		}
709
-	}
710
-
711
-	/**
712
-	 * validate expiration date if it meets all constraints
713
-	 *
714
-	 * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY"
715
-	 * @param string $shareTime timestamp when the file was shared
716
-	 * @param string $itemType
717
-	 * @param string $itemSource
718
-	 * @return \DateTime validated date
719
-	 * @throws \Exception when the expire date is in the past or further in the future then the enforced date
720
-	 */
721
-	private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
722
-		$l = \OC::$server->getL10N('lib');
723
-		$date = new \DateTime($expireDate);
724
-		$today = new \DateTime('now');
725
-
726
-		// if the user doesn't provide a share time we need to get it from the database
727
-		// fall-back mode to keep API stable, because the $shareTime parameter was added later
728
-		$defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
729
-		if ($defaultExpireDateEnforced && $shareTime === null) {
730
-			$items = self::getItemShared($itemType, $itemSource);
731
-			$firstItem = reset($items);
732
-			$shareTime = (int)$firstItem['stime'];
733
-		}
734
-
735
-		if ($defaultExpireDateEnforced) {
736
-			// initialize max date with share time
737
-			$maxDate = new \DateTime();
738
-			$maxDate->setTimestamp($shareTime);
739
-			$maxDays = \OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
740
-			$maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
741
-			if ($date > $maxDate) {
742
-				$warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared';
743
-				$warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays));
744
-				\OCP\Util::writeLog('OCP\Share', $warning, ILogger::WARN);
745
-				throw new \Exception($warning_t);
746
-			}
747
-		}
748
-
749
-		if ($date < $today) {
750
-			$message = 'Cannot set expiration date. Expiration date is in the past';
751
-			$message_t = $l->t('Cannot set expiration date. Expiration date is in the past');
752
-			\OCP\Util::writeLog('OCP\Share', $message, ILogger::WARN);
753
-			throw new \Exception($message_t);
754
-		}
755
-
756
-		return $date;
757
-	}
758
-
759
-	/**
760
-	 * Checks whether a share has expired, calls unshareItem() if yes.
761
-	 * @param array $item Share data (usually database row)
762
-	 * @return boolean True if item was expired, false otherwise.
763
-	 */
764
-	protected static function expireItem(array $item) {
765
-
766
-		$result = false;
767
-
768
-		// only use default expiration date for link shares
769
-		if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
770
-
771
-			// calculate expiration date
772
-			if (!empty($item['expiration'])) {
773
-				$userDefinedExpire = new \DateTime($item['expiration']);
774
-				$expires = $userDefinedExpire->getTimestamp();
775
-			} else {
776
-				$expires = null;
777
-			}
778
-
779
-
780
-			// get default expiration settings
781
-			$defaultSettings = Helper::getDefaultExpireSetting();
782
-			$expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
783
-
784
-
785
-			if (is_int($expires)) {
786
-				$now = time();
787
-				if ($now > $expires) {
788
-					self::unshareItem($item);
789
-					$result = true;
790
-				}
791
-			}
792
-		}
793
-		return $result;
794
-	}
795
-
796
-	/**
797
-	 * Unshares a share given a share data array
798
-	 * @param array $item Share data (usually database row)
799
-	 * @param int $newParent parent ID
800
-	 * @return null
801
-	 */
802
-	protected static function unshareItem(array $item, $newParent = null) {
803
-
804
-		$shareType = (int)$item['share_type'];
805
-		$shareWith = null;
806
-		if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
807
-			$shareWith = $item['share_with'];
808
-		}
809
-
810
-		// Pass all the vars we have for now, they may be useful
811
-		$hookParams = array(
812
-			'id'            => $item['id'],
813
-			'itemType'      => $item['item_type'],
814
-			'itemSource'    => $item['item_source'],
815
-			'shareType'     => $shareType,
816
-			'shareWith'     => $shareWith,
817
-			'itemParent'    => $item['parent'],
818
-			'uidOwner'      => $item['uid_owner'],
819
-		);
820
-		if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
821
-			$hookParams['fileSource'] = $item['file_source'];
822
-			$hookParams['fileTarget'] = $item['file_target'];
823
-		}
824
-
825
-		\OC_Hook::emit(\OCP\Share::class, 'pre_unshare', $hookParams);
826
-		$deletedShares = Helper::delete($item['id'], false, null, $newParent);
827
-		$deletedShares[] = $hookParams;
828
-		$hookParams['deletedShares'] = $deletedShares;
829
-		\OC_Hook::emit(\OCP\Share::class, 'post_unshare', $hookParams);
830
-		if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
831
-			list(, $remote) = Helper::splitUserRemote($item['share_with']);
832
-			self::sendRemoteUnshare($remote, $item['id'], $item['token']);
833
-		}
834
-	}
835
-
836
-	/**
837
-	 * Get the backend class for the specified item type
838
-	 * @param string $itemType
839
-	 * @throws \Exception
840
-	 * @return \OCP\Share_Backend
841
-	 */
842
-	public static function getBackend($itemType) {
843
-		$l = \OC::$server->getL10N('lib');
844
-		if (isset(self::$backends[$itemType])) {
845
-			return self::$backends[$itemType];
846
-		} else if (isset(self::$backendTypes[$itemType]['class'])) {
847
-			$class = self::$backendTypes[$itemType]['class'];
848
-			if (class_exists($class)) {
849
-				self::$backends[$itemType] = new $class;
850
-				if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
851
-					$message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
852
-					$message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', array($class));
853
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
854
-					throw new \Exception($message_t);
855
-				}
856
-				return self::$backends[$itemType];
857
-			} else {
858
-				$message = 'Sharing backend %s not found';
859
-				$message_t = $l->t('Sharing backend %s not found', array($class));
860
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
861
-				throw new \Exception($message_t);
862
-			}
863
-		}
864
-		$message = 'Sharing backend for %s not found';
865
-		$message_t = $l->t('Sharing backend for %s not found', array($itemType));
866
-		\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), ILogger::ERROR);
867
-		throw new \Exception($message_t);
868
-	}
869
-
870
-	/**
871
-	 * Check if resharing is allowed
872
-	 * @return boolean true if allowed or false
873
-	 *
874
-	 * Resharing is allowed by default if not configured
875
-	 */
876
-	public static function isResharingAllowed() {
877
-		if (!isset(self::$isResharingAllowed)) {
878
-			if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
879
-				self::$isResharingAllowed = true;
880
-			} else {
881
-				self::$isResharingAllowed = false;
882
-			}
883
-		}
884
-		return self::$isResharingAllowed;
885
-	}
886
-
887
-	/**
888
-	 * Get a list of collection item types for the specified item type
889
-	 * @param string $itemType
890
-	 * @return array
891
-	 */
892
-	private static function getCollectionItemTypes($itemType) {
893
-		$collectionTypes = array($itemType);
894
-		foreach (self::$backendTypes as $type => $backend) {
895
-			if (in_array($backend['collectionOf'], $collectionTypes)) {
896
-				$collectionTypes[] = $type;
897
-			}
898
-		}
899
-		// TODO Add option for collections to be collection of themselves, only 'folder' does it now...
900
-		if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
901
-			unset($collectionTypes[0]);
902
-		}
903
-		// Return array if collections were found or the item type is a
904
-		// collection itself - collections can be inside collections
905
-		if (count($collectionTypes) > 0) {
906
-			return $collectionTypes;
907
-		}
908
-		return false;
909
-	}
910
-
911
-	/**
912
-	 * Get the owners of items shared with a user.
913
-	 *
914
-	 * @param string $user The user the items are shared with.
915
-	 * @param string $type The type of the items shared with the user.
916
-	 * @param boolean $includeCollections Include collection item types (optional)
917
-	 * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
918
-	 * @return array
919
-	 */
920
-	public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
921
-		// First, we find out if $type is part of a collection (and if that collection is part of
922
-		// another one and so on).
923
-		$collectionTypes = array();
924
-		if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
925
-			$collectionTypes[] = $type;
926
-		}
927
-
928
-		// Of these collection types, along with our original $type, we make a
929
-		// list of the ones for which a sharing backend has been registered.
930
-		// FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
931
-		// with its $includeCollections parameter set to true. Unfortunately, this fails currently.
932
-		$allMaybeSharedItems = array();
933
-		foreach ($collectionTypes as $collectionType) {
934
-			if (isset(self::$backends[$collectionType])) {
935
-				$allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
936
-					$collectionType,
937
-					$user,
938
-					self::FORMAT_NONE
939
-				);
940
-			}
941
-		}
942
-
943
-		$owners = array();
944
-		if ($includeOwner) {
945
-			$owners[] = $user;
946
-		}
947
-
948
-		// We take a look at all shared items of the given $type (or of the collections it is part of)
949
-		// and find out their owners. Then, we gather the tags for the original $type from all owners,
950
-		// and return them as elements of a list that look like "Tag (owner)".
951
-		foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
952
-			foreach ($maybeSharedItems as $sharedItem) {
953
-				if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
954
-					$owners[] = $sharedItem['uid_owner'];
955
-				}
956
-			}
957
-		}
958
-
959
-		return $owners;
960
-	}
961
-
962
-	/**
963
-	 * Get shared items from the database
964
-	 * @param string $itemType
965
-	 * @param string $item Item source or target (optional)
966
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
967
-	 * @param string $shareWith User or group the item is being shared with
968
-	 * @param string $uidOwner User that is the owner of shared items (optional)
969
-	 * @param int $format Format to convert items to with formatItems() (optional)
970
-	 * @param mixed $parameters to pass to formatItems() (optional)
971
-	 * @param int $limit Number of items to return, -1 to return all matches (optional)
972
-	 * @param boolean $includeCollections Include collection item types (optional)
973
-	 * @param boolean $itemShareWithBySource (optional)
974
-	 * @param boolean $checkExpireDate
975
-	 * @return array
976
-	 *
977
-	 * See public functions getItem(s)... for parameter usage
978
-	 *
979
-	 */
980
-	public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
981
-									$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
982
-									$includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
983
-		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
984
-			return array();
985
-		}
986
-		$backend = self::getBackend($itemType);
987
-		$collectionTypes = false;
988
-		// Get filesystem root to add it to the file target and remove from the
989
-		// file source, match file_source with the file cache
990
-		if ($itemType == 'file' || $itemType == 'folder') {
991
-			if(!is_null($uidOwner)) {
992
-				$root = \OC\Files\Filesystem::getRoot();
993
-			} else {
994
-				$root = '';
995
-			}
996
-			$where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
997
-			if (!isset($item)) {
998
-				$where .= ' AND `file_target` IS NOT NULL ';
999
-			}
1000
-			$where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
1001
-			$fileDependent = true;
1002
-			$queryArgs = array();
1003
-		} else {
1004
-			$fileDependent = false;
1005
-			$root = '';
1006
-			$collectionTypes = self::getCollectionItemTypes($itemType);
1007
-			if ($includeCollections && !isset($item) && $collectionTypes) {
1008
-				// If includeCollections is true, find collections of this item type, e.g. a music album contains songs
1009
-				if (!in_array($itemType, $collectionTypes)) {
1010
-					$itemTypes = array_merge(array($itemType), $collectionTypes);
1011
-				} else {
1012
-					$itemTypes = $collectionTypes;
1013
-				}
1014
-				$placeholders = implode(',', array_fill(0, count($itemTypes), '?'));
1015
-				$where = ' WHERE `item_type` IN ('.$placeholders.'))';
1016
-				$queryArgs = $itemTypes;
1017
-			} else {
1018
-				$where = ' WHERE `item_type` = ?';
1019
-				$queryArgs = array($itemType);
1020
-			}
1021
-		}
1022
-		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
1023
-			$where .= ' AND `share_type` != ?';
1024
-			$queryArgs[] = self::SHARE_TYPE_LINK;
1025
-		}
1026
-		if (isset($shareType)) {
1027
-			// Include all user and group items
1028
-			if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
1029
-				$where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
1030
-				$queryArgs[] = self::SHARE_TYPE_USER;
1031
-				$queryArgs[] = self::$shareTypeGroupUserUnique;
1032
-				$queryArgs[] = $shareWith;
1033
-
1034
-				$user = \OC::$server->getUserManager()->get($shareWith);
1035
-				$groups = [];
1036
-				if ($user) {
1037
-					$groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
1038
-				}
1039
-				if (!empty($groups)) {
1040
-					$placeholders = implode(',', array_fill(0, count($groups), '?'));
1041
-					$where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
1042
-					$queryArgs[] = self::SHARE_TYPE_GROUP;
1043
-					$queryArgs = array_merge($queryArgs, $groups);
1044
-				}
1045
-				$where .= ')';
1046
-				// Don't include own group shares
1047
-				$where .= ' AND `uid_owner` != ?';
1048
-				$queryArgs[] = $shareWith;
1049
-			} else {
1050
-				$where .= ' AND `share_type` = ?';
1051
-				$queryArgs[] = $shareType;
1052
-				if (isset($shareWith)) {
1053
-					$where .= ' AND `share_with` = ?';
1054
-					$queryArgs[] = $shareWith;
1055
-				}
1056
-			}
1057
-		}
1058
-		if (isset($uidOwner)) {
1059
-			$where .= ' AND `uid_owner` = ?';
1060
-			$queryArgs[] = $uidOwner;
1061
-			if (!isset($shareType)) {
1062
-				// Prevent unique user targets for group shares from being selected
1063
-				$where .= ' AND `share_type` != ?';
1064
-				$queryArgs[] = self::$shareTypeGroupUserUnique;
1065
-			}
1066
-			if ($fileDependent) {
1067
-				$column = 'file_source';
1068
-			} else {
1069
-				$column = 'item_source';
1070
-			}
1071
-		} else {
1072
-			if ($fileDependent) {
1073
-				$column = 'file_target';
1074
-			} else {
1075
-				$column = 'item_target';
1076
-			}
1077
-		}
1078
-		if (isset($item)) {
1079
-			$collectionTypes = self::getCollectionItemTypes($itemType);
1080
-			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1081
-				$where .= ' AND (';
1082
-			} else {
1083
-				$where .= ' AND';
1084
-			}
1085
-			// If looking for own shared items, check item_source else check item_target
1086
-			if (isset($uidOwner) || $itemShareWithBySource) {
1087
-				// If item type is a file, file source needs to be checked in case the item was converted
1088
-				if ($fileDependent) {
1089
-					$where .= ' `file_source` = ?';
1090
-					$column = 'file_source';
1091
-				} else {
1092
-					$where .= ' `item_source` = ?';
1093
-					$column = 'item_source';
1094
-				}
1095
-			} else {
1096
-				if ($fileDependent) {
1097
-					$where .= ' `file_target` = ?';
1098
-					$item = \OC\Files\Filesystem::normalizePath($item);
1099
-				} else {
1100
-					$where .= ' `item_target` = ?';
1101
-				}
1102
-			}
1103
-			$queryArgs[] = $item;
1104
-			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1105
-				$placeholders = implode(',', array_fill(0, count($collectionTypes), '?'));
1106
-				$where .= ' OR `item_type` IN ('.$placeholders.'))';
1107
-				$queryArgs = array_merge($queryArgs, $collectionTypes);
1108
-			}
1109
-		}
1110
-
1111
-		if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
1112
-			// Make sure the unique user target is returned if it exists,
1113
-			// unique targets should follow the group share in the database
1114
-			// If the limit is not 1, the filtering can be done later
1115
-			$where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
1116
-		} else {
1117
-			$where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
1118
-		}
1119
-
1120
-		if ($limit != -1 && !$includeCollections) {
1121
-			// The limit must be at least 3, because filtering needs to be done
1122
-			if ($limit < 3) {
1123
-				$queryLimit = 3;
1124
-			} else {
1125
-				$queryLimit = $limit;
1126
-			}
1127
-		} else {
1128
-			$queryLimit = null;
1129
-		}
1130
-		$select = self::createSelectStatement($format, $fileDependent, $uidOwner);
1131
-		$root = strlen($root);
1132
-		$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
1133
-		$result = $query->execute($queryArgs);
1134
-		if ($result === false) {
1135
-			\OCP\Util::writeLog('OCP\Share',
1136
-				\OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
1137
-				ILogger::ERROR);
1138
-		}
1139
-		$items = array();
1140
-		$targets = array();
1141
-		$switchedItems = array();
1142
-		$mounts = array();
1143
-		while ($row = $result->fetchRow()) {
1144
-			self::transformDBResults($row);
1145
-			// Filter out duplicate group shares for users with unique targets
1146
-			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
1147
-				continue;
1148
-			}
1149
-			if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
1150
-				$row['share_type'] = self::SHARE_TYPE_GROUP;
1151
-				$row['unique_name'] = true; // remember that we use a unique name for this user
1152
-				$row['share_with'] = $items[$row['parent']]['share_with'];
1153
-				// if the group share was unshared from the user we keep the permission, otherwise
1154
-				// we take the permission from the parent because this is always the up-to-date
1155
-				// permission for the group share
1156
-				if ($row['permissions'] > 0) {
1157
-					$row['permissions'] = $items[$row['parent']]['permissions'];
1158
-				}
1159
-				// Remove the parent group share
1160
-				unset($items[$row['parent']]);
1161
-				if ($row['permissions'] == 0) {
1162
-					continue;
1163
-				}
1164
-			} else if (!isset($uidOwner)) {
1165
-				// Check if the same target already exists
1166
-				if (isset($targets[$row['id']])) {
1167
-					// Check if the same owner shared with the user twice
1168
-					// through a group and user share - this is allowed
1169
-					$id = $targets[$row['id']];
1170
-					if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
1171
-						// Switch to group share type to ensure resharing conditions aren't bypassed
1172
-						if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
1173
-							$items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
1174
-							$items[$id]['share_with'] = $row['share_with'];
1175
-						}
1176
-						// Switch ids if sharing permission is granted on only
1177
-						// one share to ensure correct parent is used if resharing
1178
-						if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
1179
-							&& (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1180
-							$items[$row['id']] = $items[$id];
1181
-							$switchedItems[$id] = $row['id'];
1182
-							unset($items[$id]);
1183
-							$id = $row['id'];
1184
-						}
1185
-						$items[$id]['permissions'] |= (int)$row['permissions'];
1186
-
1187
-					}
1188
-					continue;
1189
-				} elseif (!empty($row['parent'])) {
1190
-					$targets[$row['parent']] = $row['id'];
1191
-				}
1192
-			}
1193
-			// Remove root from file source paths if retrieving own shared items
1194
-			if (isset($uidOwner) && isset($row['path'])) {
1195
-				if (isset($row['parent'])) {
1196
-					$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
1197
-					$parentResult = $query->execute(array($row['parent']));
1198
-					if ($result === false) {
1199
-						\OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
1200
-							\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
1201
-							ILogger::ERROR);
1202
-					} else {
1203
-						$parentRow = $parentResult->fetchRow();
1204
-						$tmpPath = $parentRow['file_target'];
1205
-						// find the right position where the row path continues from the target path
1206
-						$pos = strrpos($row['path'], $parentRow['file_target']);
1207
-						$subPath = substr($row['path'], $pos);
1208
-						$splitPath = explode('/', $subPath);
1209
-						foreach (array_slice($splitPath, 2) as $pathPart) {
1210
-							$tmpPath = $tmpPath . '/' . $pathPart;
1211
-						}
1212
-						$row['path'] = $tmpPath;
1213
-					}
1214
-				} else {
1215
-					if (!isset($mounts[$row['storage']])) {
1216
-						$mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
1217
-						if (is_array($mountPoints) && !empty($mountPoints)) {
1218
-							$mounts[$row['storage']] = current($mountPoints);
1219
-						}
1220
-					}
1221
-					if (!empty($mounts[$row['storage']])) {
1222
-						$path = $mounts[$row['storage']]->getMountPoint().$row['path'];
1223
-						$relPath = substr($path, $root); // path relative to data/user
1224
-						$row['path'] = rtrim($relPath, '/');
1225
-					}
1226
-				}
1227
-			}
1228
-
1229
-			if($checkExpireDate) {
1230
-				if (self::expireItem($row)) {
1231
-					continue;
1232
-				}
1233
-			}
1234
-			// Check if resharing is allowed, if not remove share permission
1235
-			if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
1236
-				$row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
1237
-			}
1238
-			// Add display names to result
1239
-			$row['share_with_displayname'] = $row['share_with'];
1240
-			if ( isset($row['share_with']) && $row['share_with'] != '' &&
1241
-				$row['share_type'] === self::SHARE_TYPE_USER) {
1242
-				$shareWithUser = \OC::$server->getUserManager()->get($row['share_with']);
1243
-				$row['share_with_displayname'] = $shareWithUser === null ? $row['share_with'] : $shareWithUser->getDisplayName();
1244
-			} else if(isset($row['share_with']) && $row['share_with'] != '' &&
1245
-				$row['share_type'] === self::SHARE_TYPE_REMOTE) {
1246
-				$addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
1247
-				foreach ($addressBookEntries as $entry) {
1248
-					foreach ($entry['CLOUD'] as $cloudID) {
1249
-						if ($cloudID === $row['share_with']) {
1250
-							$row['share_with_displayname'] = $entry['FN'];
1251
-						}
1252
-					}
1253
-				}
1254
-			}
1255
-			if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
1256
-				$ownerUser = \OC::$server->getUserManager()->get($row['uid_owner']);
1257
-				$row['displayname_owner'] = $ownerUser === null ? $row['uid_owner'] : $ownerUser->getDisplayName();
1258
-			}
1259
-
1260
-			if ($row['permissions'] > 0) {
1261
-				$items[$row['id']] = $row;
1262
-			}
1263
-
1264
-		}
1265
-
1266
-		// group items if we are looking for items shared with the current user
1267
-		if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
1268
-			$items = self::groupItems($items, $itemType);
1269
-		}
1270
-
1271
-		if (!empty($items)) {
1272
-			$collectionItems = array();
1273
-			foreach ($items as &$row) {
1274
-				// Return only the item instead of a 2-dimensional array
1275
-				if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
1276
-					if ($format == self::FORMAT_NONE) {
1277
-						return $row;
1278
-					} else {
1279
-						break;
1280
-					}
1281
-				}
1282
-				// Check if this is a collection of the requested item type
1283
-				if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
1284
-					if (($collectionBackend = self::getBackend($row['item_type']))
1285
-						&& $collectionBackend instanceof \OCP\Share_Backend_Collection) {
1286
-						// Collections can be inside collections, check if the item is a collection
1287
-						if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
1288
-							$collectionItems[] = $row;
1289
-						} else {
1290
-							$collection = array();
1291
-							$collection['item_type'] = $row['item_type'];
1292
-							if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1293
-								$collection['path'] = basename($row['path']);
1294
-							}
1295
-							$row['collection'] = $collection;
1296
-							// Fetch all of the children sources
1297
-							$children = $collectionBackend->getChildren($row[$column]);
1298
-							foreach ($children as $child) {
1299
-								$childItem = $row;
1300
-								$childItem['item_type'] = $itemType;
1301
-								if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
1302
-									$childItem['item_source'] = $child['source'];
1303
-									$childItem['item_target'] = $child['target'];
1304
-								}
1305
-								if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1306
-									if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1307
-										$childItem['file_source'] = $child['source'];
1308
-									} else { // TODO is this really needed if we already know that we use the file backend?
1309
-										$meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
1310
-										$childItem['file_source'] = $meta['fileid'];
1311
-									}
1312
-									$childItem['file_target'] =
1313
-										\OC\Files\Filesystem::normalizePath($child['file_path']);
1314
-								}
1315
-								if (isset($item)) {
1316
-									if ($childItem[$column] == $item) {
1317
-										// Return only the item instead of a 2-dimensional array
1318
-										if ($limit == 1) {
1319
-											if ($format == self::FORMAT_NONE) {
1320
-												return $childItem;
1321
-											} else {
1322
-												// Unset the items array and break out of both loops
1323
-												$items = array();
1324
-												$items[] = $childItem;
1325
-												break 2;
1326
-											}
1327
-										} else {
1328
-											$collectionItems[] = $childItem;
1329
-										}
1330
-									}
1331
-								} else {
1332
-									$collectionItems[] = $childItem;
1333
-								}
1334
-							}
1335
-						}
1336
-					}
1337
-					// Remove collection item
1338
-					$toRemove = $row['id'];
1339
-					if (array_key_exists($toRemove, $switchedItems)) {
1340
-						$toRemove = $switchedItems[$toRemove];
1341
-					}
1342
-					unset($items[$toRemove]);
1343
-				} elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
1344
-					// FIXME: Thats a dirty hack to improve file sharing performance,
1345
-					// see github issue #10588 for more details
1346
-					// Need to find a solution which works for all back-ends
1347
-					$collectionBackend = self::getBackend($row['item_type']);
1348
-					$sharedParents = $collectionBackend->getParents($row['item_source']);
1349
-					foreach ($sharedParents as $parent) {
1350
-						$collectionItems[] = $parent;
1351
-					}
1352
-				}
1353
-			}
1354
-			if (!empty($collectionItems)) {
1355
-				$collectionItems = array_unique($collectionItems, SORT_REGULAR);
1356
-				$items = array_merge($items, $collectionItems);
1357
-			}
1358
-
1359
-			// filter out invalid items, these can appear when subshare entries exist
1360
-			// for a group in which the requested user isn't a member any more
1361
-			$items = array_filter($items, function($item) {
1362
-				return $item['share_type'] !== self::$shareTypeGroupUserUnique;
1363
-			});
1364
-
1365
-			return self::formatResult($items, $column, $backend, $format, $parameters);
1366
-		} elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
1367
-			// FIXME: Thats a dirty hack to improve file sharing performance,
1368
-			// see github issue #10588 for more details
1369
-			// Need to find a solution which works for all back-ends
1370
-			$collectionItems = array();
1371
-			$collectionBackend = self::getBackend('folder');
1372
-			$sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
1373
-			foreach ($sharedParents as $parent) {
1374
-				$collectionItems[] = $parent;
1375
-			}
1376
-			if ($limit === 1) {
1377
-				return reset($collectionItems);
1378
-			}
1379
-			return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
1380
-		}
1381
-
1382
-		return array();
1383
-	}
1384
-
1385
-	/**
1386
-	 * group items with link to the same source
1387
-	 *
1388
-	 * @param array $items
1389
-	 * @param string $itemType
1390
-	 * @return array of grouped items
1391
-	 */
1392
-	protected static function groupItems($items, $itemType) {
1393
-
1394
-		$fileSharing = $itemType === 'file' || $itemType === 'folder';
1395
-
1396
-		$result = array();
1397
-
1398
-		foreach ($items as $item) {
1399
-			$grouped = false;
1400
-			foreach ($result as $key => $r) {
1401
-				// for file/folder shares we need to compare file_source, otherwise we compare item_source
1402
-				// only group shares if they already point to the same target, otherwise the file where shared
1403
-				// before grouping of shares was added. In this case we don't group them toi avoid confusions
1404
-				if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
1405
-					(!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
1406
-					// add the first item to the list of grouped shares
1407
-					if (!isset($result[$key]['grouped'])) {
1408
-						$result[$key]['grouped'][] = $result[$key];
1409
-					}
1410
-					$result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
1411
-					$result[$key]['grouped'][] = $item;
1412
-					$grouped = true;
1413
-					break;
1414
-				}
1415
-			}
1416
-
1417
-			if (!$grouped) {
1418
-				$result[] = $item;
1419
-			}
1420
-
1421
-		}
1422
-
1423
-		return $result;
1424
-	}
1425
-
1426
-	/**
1427
-	 * Put shared item into the database
1428
-	 * @param string $itemType Item type
1429
-	 * @param string $itemSource Item source
1430
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1431
-	 * @param string $shareWith User or group the item is being shared with
1432
-	 * @param string $uidOwner User that is the owner of shared item
1433
-	 * @param int $permissions CRUDS permissions
1434
-	 * @param boolean|array $parentFolder Parent folder target (optional)
1435
-	 * @param string $token (optional)
1436
-	 * @param string $itemSourceName name of the source item (optional)
1437
-	 * @param \DateTime $expirationDate (optional)
1438
-	 * @throws \Exception
1439
-	 * @return mixed id of the new share or false
1440
-	 */
1441
-	private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1442
-								$permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
1443
-
1444
-		$queriesToExecute = array();
1445
-		$suggestedItemTarget = null;
1446
-		$groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
1447
-		$groupItemTarget = $itemTarget = $fileSource = $parent = 0;
1448
-
1449
-		$result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate);
1450
-		if(!empty($result)) {
1451
-			$parent = $result['parent'];
1452
-			$itemSource = $result['itemSource'];
1453
-			$fileSource = $result['fileSource'];
1454
-			$suggestedItemTarget = $result['suggestedItemTarget'];
1455
-			$suggestedFileTarget = $result['suggestedFileTarget'];
1456
-			$filePath = $result['filePath'];
1457
-		}
1458
-
1459
-		$isGroupShare = false;
1460
-		if ($shareType == self::SHARE_TYPE_GROUP) {
1461
-			$isGroupShare = true;
1462
-			if (isset($shareWith['users'])) {
1463
-				$users = $shareWith['users'];
1464
-			} else {
1465
-				$group = \OC::$server->getGroupManager()->get($shareWith['group']);
1466
-				if ($group) {
1467
-					$users = $group->searchUsers('', -1, 0);
1468
-					$userIds = [];
1469
-					foreach ($users as $user) {
1470
-						$userIds[] = $user->getUID();
1471
-					}
1472
-					$users = $userIds;
1473
-				} else {
1474
-					$users = [];
1475
-				}
1476
-			}
1477
-			// remove current user from list
1478
-			if (in_array(\OCP\User::getUser(), $users)) {
1479
-				unset($users[array_search(\OCP\User::getUser(), $users)]);
1480
-			}
1481
-			$groupItemTarget = Helper::generateTarget($itemType, $itemSource,
1482
-				$shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
1483
-			$groupFileTarget = Helper::generateTarget($itemType, $itemSource,
1484
-				$shareType, $shareWith['group'], $uidOwner, $filePath);
1485
-
1486
-			// add group share to table and remember the id as parent
1487
-			$queriesToExecute['groupShare'] = array(
1488
-				'itemType'			=> $itemType,
1489
-				'itemSource'		=> $itemSource,
1490
-				'itemTarget'		=> $groupItemTarget,
1491
-				'shareType'			=> $shareType,
1492
-				'shareWith'			=> $shareWith['group'],
1493
-				'uidOwner'			=> $uidOwner,
1494
-				'permissions'		=> $permissions,
1495
-				'shareTime'			=> time(),
1496
-				'fileSource'		=> $fileSource,
1497
-				'fileTarget'		=> $groupFileTarget,
1498
-				'token'				=> $token,
1499
-				'parent'			=> $parent,
1500
-				'expiration'		=> $expirationDate,
1501
-			);
1502
-
1503
-		} else {
1504
-			$users = array($shareWith);
1505
-			$itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1506
-				$suggestedItemTarget);
1507
-		}
1508
-
1509
-		$run = true;
1510
-		$error = '';
1511
-		$preHookData = array(
1512
-			'itemType' => $itemType,
1513
-			'itemSource' => $itemSource,
1514
-			'shareType' => $shareType,
1515
-			'uidOwner' => $uidOwner,
1516
-			'permissions' => $permissions,
1517
-			'fileSource' => $fileSource,
1518
-			'expiration' => $expirationDate,
1519
-			'token' => $token,
1520
-			'run' => &$run,
1521
-			'error' => &$error
1522
-		);
1523
-
1524
-		$preHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget;
1525
-		$preHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith;
1526
-
1527
-		\OC_Hook::emit(\OCP\Share::class, 'pre_shared', $preHookData);
1528
-
1529
-		if ($run === false) {
1530
-			throw new \Exception($error);
1531
-		}
1532
-
1533
-		foreach ($users as $user) {
1534
-			$sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
1535
-			$sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
1536
-
1537
-			$userShareType = $isGroupShare ? self::$shareTypeGroupUserUnique : $shareType;
1538
-
1539
-			if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
1540
-				$fileTarget = $sourceExists['file_target'];
1541
-				$itemTarget = $sourceExists['item_target'];
1542
-
1543
-				// for group shares we don't need a additional entry if the target is the same
1544
-				if($isGroupShare && $groupItemTarget === $itemTarget) {
1545
-					continue;
1546
-				}
1547
-
1548
-			} elseif(!$sourceExists && !$isGroupShare)  {
1549
-
1550
-				$itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
1551
-					$uidOwner, $suggestedItemTarget, $parent);
1552
-				if (isset($fileSource)) {
1553
-					if ($parentFolder) {
1554
-						if ($parentFolder === true) {
1555
-							$fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user,
1556
-								$uidOwner, $suggestedFileTarget, $parent);
1557
-							if ($fileTarget != $groupFileTarget) {
1558
-								$parentFolders[$user]['folder'] = $fileTarget;
1559
-							}
1560
-						} else if (isset($parentFolder[$user])) {
1561
-							$fileTarget = $parentFolder[$user]['folder'].$itemSource;
1562
-							$parent = $parentFolder[$user]['id'];
1563
-						}
1564
-					} else {
1565
-						$fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
1566
-							$user, $uidOwner, $suggestedFileTarget, $parent);
1567
-					}
1568
-				} else {
1569
-					$fileTarget = null;
1570
-				}
1571
-
1572
-			} else {
1573
-
1574
-				// group share which doesn't exists until now, check if we need a unique target for this user
1575
-
1576
-				$itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
1577
-					$uidOwner, $suggestedItemTarget, $parent);
1578
-
1579
-				// do we also need a file target
1580
-				if (isset($fileSource)) {
1581
-					$fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
1582
-						$uidOwner, $suggestedFileTarget, $parent);
1583
-				} else {
1584
-					$fileTarget = null;
1585
-				}
1586
-
1587
-				if (($itemTarget === $groupItemTarget) &&
1588
-					(!isset($fileSource) || $fileTarget === $groupFileTarget)) {
1589
-					continue;
1590
-				}
1591
-			}
1592
-
1593
-			$queriesToExecute[] = array(
1594
-				'itemType'			=> $itemType,
1595
-				'itemSource'		=> $itemSource,
1596
-				'itemTarget'		=> $itemTarget,
1597
-				'shareType'			=> $userShareType,
1598
-				'shareWith'			=> $user,
1599
-				'uidOwner'			=> $uidOwner,
1600
-				'permissions'		=> $permissions,
1601
-				'shareTime'			=> time(),
1602
-				'fileSource'		=> $fileSource,
1603
-				'fileTarget'		=> $fileTarget,
1604
-				'token'				=> $token,
1605
-				'parent'			=> $parent,
1606
-				'expiration'		=> $expirationDate,
1607
-			);
1608
-
1609
-		}
1610
-
1611
-		$id = false;
1612
-		if ($isGroupShare) {
1613
-			$id = self::insertShare($queriesToExecute['groupShare']);
1614
-			// Save this id, any extra rows for this group share will need to reference it
1615
-			$parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1616
-			unset($queriesToExecute['groupShare']);
1617
-		}
1618
-
1619
-		foreach ($queriesToExecute as $shareQuery) {
1620
-			$shareQuery['parent'] = $parent;
1621
-			$id = self::insertShare($shareQuery);
1622
-		}
1623
-
1624
-		$postHookData = array(
1625
-			'itemType' => $itemType,
1626
-			'itemSource' => $itemSource,
1627
-			'parent' => $parent,
1628
-			'shareType' => $shareType,
1629
-			'uidOwner' => $uidOwner,
1630
-			'permissions' => $permissions,
1631
-			'fileSource' => $fileSource,
1632
-			'id' => $parent,
1633
-			'token' => $token,
1634
-			'expirationDate' => $expirationDate,
1635
-		);
1636
-
1637
-		$postHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith;
1638
-		$postHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget;
1639
-		$postHookData['fileTarget'] = $isGroupShare ? $groupFileTarget : $fileTarget;
1640
-
1641
-		\OC_Hook::emit(\OCP\Share::class, 'post_shared', $postHookData);
1642
-
1643
-
1644
-		return $id ? $id : false;
1645
-	}
1646
-
1647
-	/**
1648
-	 * @param string $itemType
1649
-	 * @param string $itemSource
1650
-	 * @param int $shareType
1651
-	 * @param string $shareWith
1652
-	 * @param string $uidOwner
1653
-	 * @param int $permissions
1654
-	 * @param string|null $itemSourceName
1655
-	 * @param null|\DateTime $expirationDate
1656
-	 */
1657
-	private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
1658
-		$backend = self::getBackend($itemType);
1659
-
1660
-		$l = \OC::$server->getL10N('lib');
1661
-		$result = array();
1662
-
1663
-		$column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
1664
-
1665
-		$checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
1666
-		if ($checkReshare) {
1667
-			// Check if attempting to share back to owner
1668
-			if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
1669
-				$message = 'Sharing %1$s failed, because the user %2$s is the original sharer';
1670
-				$message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]);
1671
-
1672
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
1673
-				throw new \Exception($message_t);
1674
-			}
1675
-		}
1676
-
1677
-		if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
1678
-			// Check if share permissions is granted
1679
-			if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1680
-				if (~(int)$checkReshare['permissions'] & $permissions) {
1681
-					$message = 'Sharing %1$s failed, because the permissions exceed permissions granted to %2$s';
1682
-					$message_t = $l->t('Sharing %1$s failed, because the permissions exceed permissions granted to %2$s', array($itemSourceName, $uidOwner));
1683
-
1684
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), ILogger::DEBUG);
1685
-					throw new \Exception($message_t);
1686
-				} else {
1687
-					// TODO Don't check if inside folder
1688
-					$result['parent'] = $checkReshare['id'];
1689
-
1690
-					$result['expirationDate'] = $expirationDate;
1691
-					// $checkReshare['expiration'] could be null and then is always less than any value
1692
-					if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
1693
-						$result['expirationDate'] = $checkReshare['expiration'];
1694
-					}
1695
-
1696
-					// only suggest the same name as new target if it is a reshare of the
1697
-					// same file/folder and not the reshare of a child
1698
-					if ($checkReshare[$column] === $itemSource) {
1699
-						$result['filePath'] = $checkReshare['file_target'];
1700
-						$result['itemSource'] = $checkReshare['item_source'];
1701
-						$result['fileSource'] = $checkReshare['file_source'];
1702
-						$result['suggestedItemTarget'] = $checkReshare['item_target'];
1703
-						$result['suggestedFileTarget'] = $checkReshare['file_target'];
1704
-					} else {
1705
-						$result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
1706
-						$result['suggestedItemTarget'] = null;
1707
-						$result['suggestedFileTarget'] = null;
1708
-						$result['itemSource'] = $itemSource;
1709
-						$result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
1710
-					}
1711
-				}
1712
-			} else {
1713
-				$message = 'Sharing %s failed, because resharing is not allowed';
1714
-				$message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName));
1715
-
1716
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
1717
-				throw new \Exception($message_t);
1718
-			}
1719
-		} else {
1720
-			$result['parent'] = null;
1721
-			$result['suggestedItemTarget'] = null;
1722
-			$result['suggestedFileTarget'] = null;
1723
-			$result['itemSource'] = $itemSource;
1724
-			$result['expirationDate'] = $expirationDate;
1725
-			if (!$backend->isValidSource($itemSource, $uidOwner)) {
1726
-				$message = 'Sharing %1$s failed, because the sharing backend for '
1727
-					.'%2$s could not find its source';
1728
-				$message_t = $l->t('Sharing %1$s failed, because the sharing backend for %2$s could not find its source', array($itemSource, $itemType));
1729
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), ILogger::DEBUG);
1730
-				throw new \Exception($message_t);
1731
-			}
1732
-			if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1733
-				$result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
1734
-				if ($itemType == 'file' || $itemType == 'folder') {
1735
-					$result['fileSource'] = $itemSource;
1736
-				} else {
1737
-					$meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
1738
-					$result['fileSource'] = $meta['fileid'];
1739
-				}
1740
-				if ($result['fileSource'] == -1) {
1741
-					$message = 'Sharing %s failed, because the file could not be found in the file cache';
1742
-					$message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource));
1743
-
1744
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), ILogger::DEBUG);
1745
-					throw new \Exception($message_t);
1746
-				}
1747
-			} else {
1748
-				$result['filePath'] = null;
1749
-				$result['fileSource'] = null;
1750
-			}
1751
-		}
1752
-
1753
-		return $result;
1754
-	}
1755
-
1756
-	/**
1757
-	 *
1758
-	 * @param array $shareData
1759
-	 * @return mixed false in case of a failure or the id of the new share
1760
-	 */
1761
-	private static function insertShare(array $shareData) {
1762
-
1763
-		$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
1764
-			.' `item_type`, `item_source`, `item_target`, `share_type`,'
1765
-			.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
1766
-			.' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
1767
-		$query->bindValue(1, $shareData['itemType']);
1768
-		$query->bindValue(2, $shareData['itemSource']);
1769
-		$query->bindValue(3, $shareData['itemTarget']);
1770
-		$query->bindValue(4, $shareData['shareType']);
1771
-		$query->bindValue(5, $shareData['shareWith']);
1772
-		$query->bindValue(6, $shareData['uidOwner']);
1773
-		$query->bindValue(7, $shareData['permissions']);
1774
-		$query->bindValue(8, $shareData['shareTime']);
1775
-		$query->bindValue(9, $shareData['fileSource']);
1776
-		$query->bindValue(10, $shareData['fileTarget']);
1777
-		$query->bindValue(11, $shareData['token']);
1778
-		$query->bindValue(12, $shareData['parent']);
1779
-		$query->bindValue(13, $shareData['expiration'], 'datetime');
1780
-		$result = $query->execute();
1781
-
1782
-		$id = false;
1783
-		if ($result) {
1784
-			$id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1785
-		}
1786
-
1787
-		return $id;
1788
-
1789
-	}
1790
-
1791
-	/**
1792
-	 * In case a password protected link is not yet authenticated this function will return false
1793
-	 *
1794
-	 * @param array $linkItem
1795
-	 * @return boolean
1796
-	 */
1797
-	public static function checkPasswordProtectedShare(array $linkItem) {
1798
-		if (!isset($linkItem['share_with'])) {
1799
-			return true;
1800
-		}
1801
-		if (!isset($linkItem['share_type'])) {
1802
-			return true;
1803
-		}
1804
-		if (!isset($linkItem['id'])) {
1805
-			return true;
1806
-		}
1807
-
1808
-		if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
1809
-			return true;
1810
-		}
1811
-
1812
-		if ( \OC::$server->getSession()->exists('public_link_authenticated')
1813
-			&& \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id'] ) {
1814
-			return true;
1815
-		}
1816
-
1817
-		return false;
1818
-	}
1819
-
1820
-	/**
1821
-	 * construct select statement
1822
-	 * @param int $format
1823
-	 * @param boolean $fileDependent ist it a file/folder share or a generla share
1824
-	 * @param string $uidOwner
1825
-	 * @return string select statement
1826
-	 */
1827
-	private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
1828
-		$select = '*';
1829
-		if ($format == self::FORMAT_STATUSES) {
1830
-			if ($fileDependent) {
1831
-				$select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
1832
-					. '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
1833
-					. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1834
-					. '`uid_initiator`';
1835
-			} else {
1836
-				$select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
1837
-			}
1838
-		} else {
1839
-			if (isset($uidOwner)) {
1840
-				if ($fileDependent) {
1841
-					$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
1842
-						. ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
1843
-						. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
1844
-						. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1845
-				} else {
1846
-					$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
1847
-						. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
1848
-				}
1849
-			} else {
1850
-				if ($fileDependent) {
1851
-					if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
1852
-						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
1853
-							. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
1854
-							. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1855
-							. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
1856
-					} else {
1857
-						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
1858
-							. '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
1859
-							. '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
1860
-						    . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
1861
-							. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1862
-					}
1863
-				}
1864
-			}
1865
-		}
1866
-		return $select;
1867
-	}
1868
-
1869
-
1870
-	/**
1871
-	 * transform db results
1872
-	 * @param array $row result
1873
-	 */
1874
-	private static function transformDBResults(&$row) {
1875
-		if (isset($row['id'])) {
1876
-			$row['id'] = (int) $row['id'];
1877
-		}
1878
-		if (isset($row['share_type'])) {
1879
-			$row['share_type'] = (int) $row['share_type'];
1880
-		}
1881
-		if (isset($row['parent'])) {
1882
-			$row['parent'] = (int) $row['parent'];
1883
-		}
1884
-		if (isset($row['file_parent'])) {
1885
-			$row['file_parent'] = (int) $row['file_parent'];
1886
-		}
1887
-		if (isset($row['file_source'])) {
1888
-			$row['file_source'] = (int) $row['file_source'];
1889
-		}
1890
-		if (isset($row['permissions'])) {
1891
-			$row['permissions'] = (int) $row['permissions'];
1892
-		}
1893
-		if (isset($row['storage'])) {
1894
-			$row['storage'] = (int) $row['storage'];
1895
-		}
1896
-		if (isset($row['stime'])) {
1897
-			$row['stime'] = (int) $row['stime'];
1898
-		}
1899
-		if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
1900
-			// discard expiration date for non-link shares, which might have been
1901
-			// set by ancient bugs
1902
-			$row['expiration'] = null;
1903
-		}
1904
-	}
1905
-
1906
-	/**
1907
-	 * format result
1908
-	 * @param array $items result
1909
-	 * @param string $column is it a file share or a general share ('file_target' or 'item_target')
1910
-	 * @param \OCP\Share_Backend $backend sharing backend
1911
-	 * @param int $format
1912
-	 * @param array $parameters additional format parameters
1913
-	 * @return array format result
1914
-	 */
1915
-	private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
1916
-		if ($format === self::FORMAT_NONE) {
1917
-			return $items;
1918
-		} else if ($format === self::FORMAT_STATUSES) {
1919
-			$statuses = array();
1920
-			foreach ($items as $item) {
1921
-				if ($item['share_type'] === self::SHARE_TYPE_LINK) {
1922
-					if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
1923
-						continue;
1924
-					}
1925
-					$statuses[$item[$column]]['link'] = true;
1926
-				} else if (!isset($statuses[$item[$column]])) {
1927
-					$statuses[$item[$column]]['link'] = false;
1928
-				}
1929
-				if (!empty($item['file_target'])) {
1930
-					$statuses[$item[$column]]['path'] = $item['path'];
1931
-				}
1932
-			}
1933
-			return $statuses;
1934
-		} else {
1935
-			return $backend->formatItems($items, $format, $parameters);
1936
-		}
1937
-	}
1938
-
1939
-	/**
1940
-	 * remove protocol from URL
1941
-	 *
1942
-	 * @param string $url
1943
-	 * @return string
1944
-	 */
1945
-	public static function removeProtocolFromUrl($url) {
1946
-		if (strpos($url, 'https://') === 0) {
1947
-			return substr($url, strlen('https://'));
1948
-		} else if (strpos($url, 'http://') === 0) {
1949
-			return substr($url, strlen('http://'));
1950
-		}
1951
-
1952
-		return $url;
1953
-	}
1954
-
1955
-	/**
1956
-	 * try http post first with https and then with http as a fallback
1957
-	 *
1958
-	 * @param string $remoteDomain
1959
-	 * @param string $urlSuffix
1960
-	 * @param array $fields post parameters
1961
-	 * @return array
1962
-	 */
1963
-	private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
1964
-		$protocol = 'https://';
1965
-		$result = [
1966
-			'success' => false,
1967
-			'result' => '',
1968
-		];
1969
-		$try = 0;
1970
-		$discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
1971
-		while ($result['success'] === false && $try < 2) {
1972
-			$federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
1973
-			$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
1974
-			$client = \OC::$server->getHTTPClientService()->newClient();
1975
-
1976
-			try {
1977
-				$response = $client->post(
1978
-					$protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT,
1979
-					[
1980
-						'body' => $fields,
1981
-						'connect_timeout' => 10,
1982
-					]
1983
-				);
1984
-
1985
-				$result = ['success' => true, 'result' => $response->getBody()];
1986
-			} catch (\Exception $e) {
1987
-				$result = ['success' => false, 'result' => $e->getMessage()];
1988
-			}
1989
-
1990
-			$try++;
1991
-			$protocol = 'http://';
1992
-		}
1993
-
1994
-		return $result;
1995
-	}
1996
-
1997
-	/**
1998
-	 * send server-to-server share to remote server
1999
-	 *
2000
-	 * @param string $token
2001
-	 * @param string $shareWith
2002
-	 * @param string $name
2003
-	 * @param int $remote_id
2004
-	 * @param string $owner
2005
-	 * @return bool
2006
-	 */
2007
-	private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
2008
-
2009
-		list($user, $remote) = Helper::splitUserRemote($shareWith);
2010
-
2011
-		if ($user && $remote) {
2012
-			$url = $remote;
2013
-
2014
-			$local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
2015
-
2016
-			$fields = array(
2017
-				'shareWith' => $user,
2018
-				'token' => $token,
2019
-				'name' => $name,
2020
-				'remoteId' => $remote_id,
2021
-				'owner' => $owner,
2022
-				'remote' => $local,
2023
-			);
2024
-
2025
-			$url = self::removeProtocolFromUrl($url);
2026
-			$result = self::tryHttpPostToShareEndpoint($url, '', $fields);
2027
-			$status = json_decode($result['result'], true);
2028
-
2029
-			if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
2030
-				\OC_Hook::emit(\OCP\Share::class, 'federated_share_added', ['server' => $remote]);
2031
-				return true;
2032
-			}
2033
-
2034
-		}
2035
-
2036
-		return false;
2037
-	}
2038
-
2039
-	/**
2040
-	 * send server-to-server unshare to remote server
2041
-	 *
2042
-	 * @param string $remote url
2043
-	 * @param int $id share id
2044
-	 * @param string $token
2045
-	 * @return bool
2046
-	 */
2047
-	private static function sendRemoteUnshare($remote, $id, $token) {
2048
-		$url = rtrim($remote, '/');
2049
-		$fields = array('token' => $token, 'format' => 'json');
2050
-		$url = self::removeProtocolFromUrl($url);
2051
-		$result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
2052
-		$status = json_decode($result['result'], true);
2053
-
2054
-		return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
2055
-	}
2056
-
2057
-	/**
2058
-	 * check if user can only share with group members
2059
-	 * @return bool
2060
-	 */
2061
-	public static function shareWithGroupMembersOnly() {
2062
-		$value = \OC::$server->getConfig()->getAppValue('core', 'shareapi_only_share_with_group_members', 'no');
2063
-		return $value === 'yes';
2064
-	}
2065
-
2066
-	/**
2067
-	 * @return bool
2068
-	 */
2069
-	public static function isDefaultExpireDateEnabled() {
2070
-		$defaultExpireDateEnabled = \OC::$server->getConfig()->getAppValue('core', 'shareapi_default_expire_date', 'no');
2071
-		return $defaultExpireDateEnabled === 'yes';
2072
-	}
2073
-
2074
-	/**
2075
-	 * @return int
2076
-	 */
2077
-	public static function getExpireInterval() {
2078
-		return (int)\OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
2079
-	}
2080
-
2081
-	/**
2082
-	 * Checks whether the given path is reachable for the given owner
2083
-	 *
2084
-	 * @param string $path path relative to files
2085
-	 * @param string $ownerStorageId storage id of the owner
2086
-	 *
2087
-	 * @return boolean true if file is reachable, false otherwise
2088
-	 */
2089
-	private static function isFileReachable($path, $ownerStorageId) {
2090
-		// if outside the home storage, file is always considered reachable
2091
-		if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
2092
-			substr($ownerStorageId, 0, 13) === 'object::user:'
2093
-		)) {
2094
-			return true;
2095
-		}
2096
-
2097
-		// if inside the home storage, the file has to be under "/files/"
2098
-		$path = ltrim($path, '/');
2099
-		if (substr($path, 0, 6) === 'files/') {
2100
-			return true;
2101
-		}
2102
-
2103
-		return false;
2104
-	}
2105
-
2106
-	/**
2107
-	 * @param IConfig $config
2108
-	 * @return bool
2109
-	 */
2110
-	public static function enforcePassword(IConfig $config) {
2111
-		$enforcePassword = $config->getAppValue('core', 'shareapi_enforce_links_password', 'no');
2112
-		return $enforcePassword === 'yes';
2113
-	}
2114
-
2115
-	/**
2116
-	 * @param string $password
2117
-	 * @throws \Exception
2118
-	 */
2119
-	private static function verifyPassword($password) {
2120
-
2121
-		$accepted = true;
2122
-		$message = '';
2123
-		\OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
2124
-			'password' => $password,
2125
-			'accepted' => &$accepted,
2126
-			'message' => &$message
2127
-		]);
2128
-
2129
-		if (!$accepted) {
2130
-			throw new \Exception($message);
2131
-		}
2132
-	}
704
+        $result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient));
705
+
706
+        if($result === false) {
707
+            \OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', ILogger::ERROR);
708
+        }
709
+    }
710
+
711
+    /**
712
+     * validate expiration date if it meets all constraints
713
+     *
714
+     * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY"
715
+     * @param string $shareTime timestamp when the file was shared
716
+     * @param string $itemType
717
+     * @param string $itemSource
718
+     * @return \DateTime validated date
719
+     * @throws \Exception when the expire date is in the past or further in the future then the enforced date
720
+     */
721
+    private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
722
+        $l = \OC::$server->getL10N('lib');
723
+        $date = new \DateTime($expireDate);
724
+        $today = new \DateTime('now');
725
+
726
+        // if the user doesn't provide a share time we need to get it from the database
727
+        // fall-back mode to keep API stable, because the $shareTime parameter was added later
728
+        $defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
729
+        if ($defaultExpireDateEnforced && $shareTime === null) {
730
+            $items = self::getItemShared($itemType, $itemSource);
731
+            $firstItem = reset($items);
732
+            $shareTime = (int)$firstItem['stime'];
733
+        }
734
+
735
+        if ($defaultExpireDateEnforced) {
736
+            // initialize max date with share time
737
+            $maxDate = new \DateTime();
738
+            $maxDate->setTimestamp($shareTime);
739
+            $maxDays = \OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
740
+            $maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
741
+            if ($date > $maxDate) {
742
+                $warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared';
743
+                $warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays));
744
+                \OCP\Util::writeLog('OCP\Share', $warning, ILogger::WARN);
745
+                throw new \Exception($warning_t);
746
+            }
747
+        }
748
+
749
+        if ($date < $today) {
750
+            $message = 'Cannot set expiration date. Expiration date is in the past';
751
+            $message_t = $l->t('Cannot set expiration date. Expiration date is in the past');
752
+            \OCP\Util::writeLog('OCP\Share', $message, ILogger::WARN);
753
+            throw new \Exception($message_t);
754
+        }
755
+
756
+        return $date;
757
+    }
758
+
759
+    /**
760
+     * Checks whether a share has expired, calls unshareItem() if yes.
761
+     * @param array $item Share data (usually database row)
762
+     * @return boolean True if item was expired, false otherwise.
763
+     */
764
+    protected static function expireItem(array $item) {
765
+
766
+        $result = false;
767
+
768
+        // only use default expiration date for link shares
769
+        if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
770
+
771
+            // calculate expiration date
772
+            if (!empty($item['expiration'])) {
773
+                $userDefinedExpire = new \DateTime($item['expiration']);
774
+                $expires = $userDefinedExpire->getTimestamp();
775
+            } else {
776
+                $expires = null;
777
+            }
778
+
779
+
780
+            // get default expiration settings
781
+            $defaultSettings = Helper::getDefaultExpireSetting();
782
+            $expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
783
+
784
+
785
+            if (is_int($expires)) {
786
+                $now = time();
787
+                if ($now > $expires) {
788
+                    self::unshareItem($item);
789
+                    $result = true;
790
+                }
791
+            }
792
+        }
793
+        return $result;
794
+    }
795
+
796
+    /**
797
+     * Unshares a share given a share data array
798
+     * @param array $item Share data (usually database row)
799
+     * @param int $newParent parent ID
800
+     * @return null
801
+     */
802
+    protected static function unshareItem(array $item, $newParent = null) {
803
+
804
+        $shareType = (int)$item['share_type'];
805
+        $shareWith = null;
806
+        if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
807
+            $shareWith = $item['share_with'];
808
+        }
809
+
810
+        // Pass all the vars we have for now, they may be useful
811
+        $hookParams = array(
812
+            'id'            => $item['id'],
813
+            'itemType'      => $item['item_type'],
814
+            'itemSource'    => $item['item_source'],
815
+            'shareType'     => $shareType,
816
+            'shareWith'     => $shareWith,
817
+            'itemParent'    => $item['parent'],
818
+            'uidOwner'      => $item['uid_owner'],
819
+        );
820
+        if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
821
+            $hookParams['fileSource'] = $item['file_source'];
822
+            $hookParams['fileTarget'] = $item['file_target'];
823
+        }
824
+
825
+        \OC_Hook::emit(\OCP\Share::class, 'pre_unshare', $hookParams);
826
+        $deletedShares = Helper::delete($item['id'], false, null, $newParent);
827
+        $deletedShares[] = $hookParams;
828
+        $hookParams['deletedShares'] = $deletedShares;
829
+        \OC_Hook::emit(\OCP\Share::class, 'post_unshare', $hookParams);
830
+        if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
831
+            list(, $remote) = Helper::splitUserRemote($item['share_with']);
832
+            self::sendRemoteUnshare($remote, $item['id'], $item['token']);
833
+        }
834
+    }
835
+
836
+    /**
837
+     * Get the backend class for the specified item type
838
+     * @param string $itemType
839
+     * @throws \Exception
840
+     * @return \OCP\Share_Backend
841
+     */
842
+    public static function getBackend($itemType) {
843
+        $l = \OC::$server->getL10N('lib');
844
+        if (isset(self::$backends[$itemType])) {
845
+            return self::$backends[$itemType];
846
+        } else if (isset(self::$backendTypes[$itemType]['class'])) {
847
+            $class = self::$backendTypes[$itemType]['class'];
848
+            if (class_exists($class)) {
849
+                self::$backends[$itemType] = new $class;
850
+                if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
851
+                    $message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
852
+                    $message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', array($class));
853
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
854
+                    throw new \Exception($message_t);
855
+                }
856
+                return self::$backends[$itemType];
857
+            } else {
858
+                $message = 'Sharing backend %s not found';
859
+                $message_t = $l->t('Sharing backend %s not found', array($class));
860
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), ILogger::ERROR);
861
+                throw new \Exception($message_t);
862
+            }
863
+        }
864
+        $message = 'Sharing backend for %s not found';
865
+        $message_t = $l->t('Sharing backend for %s not found', array($itemType));
866
+        \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), ILogger::ERROR);
867
+        throw new \Exception($message_t);
868
+    }
869
+
870
+    /**
871
+     * Check if resharing is allowed
872
+     * @return boolean true if allowed or false
873
+     *
874
+     * Resharing is allowed by default if not configured
875
+     */
876
+    public static function isResharingAllowed() {
877
+        if (!isset(self::$isResharingAllowed)) {
878
+            if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
879
+                self::$isResharingAllowed = true;
880
+            } else {
881
+                self::$isResharingAllowed = false;
882
+            }
883
+        }
884
+        return self::$isResharingAllowed;
885
+    }
886
+
887
+    /**
888
+     * Get a list of collection item types for the specified item type
889
+     * @param string $itemType
890
+     * @return array
891
+     */
892
+    private static function getCollectionItemTypes($itemType) {
893
+        $collectionTypes = array($itemType);
894
+        foreach (self::$backendTypes as $type => $backend) {
895
+            if (in_array($backend['collectionOf'], $collectionTypes)) {
896
+                $collectionTypes[] = $type;
897
+            }
898
+        }
899
+        // TODO Add option for collections to be collection of themselves, only 'folder' does it now...
900
+        if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
901
+            unset($collectionTypes[0]);
902
+        }
903
+        // Return array if collections were found or the item type is a
904
+        // collection itself - collections can be inside collections
905
+        if (count($collectionTypes) > 0) {
906
+            return $collectionTypes;
907
+        }
908
+        return false;
909
+    }
910
+
911
+    /**
912
+     * Get the owners of items shared with a user.
913
+     *
914
+     * @param string $user The user the items are shared with.
915
+     * @param string $type The type of the items shared with the user.
916
+     * @param boolean $includeCollections Include collection item types (optional)
917
+     * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
918
+     * @return array
919
+     */
920
+    public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
921
+        // First, we find out if $type is part of a collection (and if that collection is part of
922
+        // another one and so on).
923
+        $collectionTypes = array();
924
+        if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
925
+            $collectionTypes[] = $type;
926
+        }
927
+
928
+        // Of these collection types, along with our original $type, we make a
929
+        // list of the ones for which a sharing backend has been registered.
930
+        // FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
931
+        // with its $includeCollections parameter set to true. Unfortunately, this fails currently.
932
+        $allMaybeSharedItems = array();
933
+        foreach ($collectionTypes as $collectionType) {
934
+            if (isset(self::$backends[$collectionType])) {
935
+                $allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
936
+                    $collectionType,
937
+                    $user,
938
+                    self::FORMAT_NONE
939
+                );
940
+            }
941
+        }
942
+
943
+        $owners = array();
944
+        if ($includeOwner) {
945
+            $owners[] = $user;
946
+        }
947
+
948
+        // We take a look at all shared items of the given $type (or of the collections it is part of)
949
+        // and find out their owners. Then, we gather the tags for the original $type from all owners,
950
+        // and return them as elements of a list that look like "Tag (owner)".
951
+        foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
952
+            foreach ($maybeSharedItems as $sharedItem) {
953
+                if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
954
+                    $owners[] = $sharedItem['uid_owner'];
955
+                }
956
+            }
957
+        }
958
+
959
+        return $owners;
960
+    }
961
+
962
+    /**
963
+     * Get shared items from the database
964
+     * @param string $itemType
965
+     * @param string $item Item source or target (optional)
966
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
967
+     * @param string $shareWith User or group the item is being shared with
968
+     * @param string $uidOwner User that is the owner of shared items (optional)
969
+     * @param int $format Format to convert items to with formatItems() (optional)
970
+     * @param mixed $parameters to pass to formatItems() (optional)
971
+     * @param int $limit Number of items to return, -1 to return all matches (optional)
972
+     * @param boolean $includeCollections Include collection item types (optional)
973
+     * @param boolean $itemShareWithBySource (optional)
974
+     * @param boolean $checkExpireDate
975
+     * @return array
976
+     *
977
+     * See public functions getItem(s)... for parameter usage
978
+     *
979
+     */
980
+    public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
981
+                                    $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
982
+                                    $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
983
+        if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
984
+            return array();
985
+        }
986
+        $backend = self::getBackend($itemType);
987
+        $collectionTypes = false;
988
+        // Get filesystem root to add it to the file target and remove from the
989
+        // file source, match file_source with the file cache
990
+        if ($itemType == 'file' || $itemType == 'folder') {
991
+            if(!is_null($uidOwner)) {
992
+                $root = \OC\Files\Filesystem::getRoot();
993
+            } else {
994
+                $root = '';
995
+            }
996
+            $where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
997
+            if (!isset($item)) {
998
+                $where .= ' AND `file_target` IS NOT NULL ';
999
+            }
1000
+            $where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
1001
+            $fileDependent = true;
1002
+            $queryArgs = array();
1003
+        } else {
1004
+            $fileDependent = false;
1005
+            $root = '';
1006
+            $collectionTypes = self::getCollectionItemTypes($itemType);
1007
+            if ($includeCollections && !isset($item) && $collectionTypes) {
1008
+                // If includeCollections is true, find collections of this item type, e.g. a music album contains songs
1009
+                if (!in_array($itemType, $collectionTypes)) {
1010
+                    $itemTypes = array_merge(array($itemType), $collectionTypes);
1011
+                } else {
1012
+                    $itemTypes = $collectionTypes;
1013
+                }
1014
+                $placeholders = implode(',', array_fill(0, count($itemTypes), '?'));
1015
+                $where = ' WHERE `item_type` IN ('.$placeholders.'))';
1016
+                $queryArgs = $itemTypes;
1017
+            } else {
1018
+                $where = ' WHERE `item_type` = ?';
1019
+                $queryArgs = array($itemType);
1020
+            }
1021
+        }
1022
+        if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
1023
+            $where .= ' AND `share_type` != ?';
1024
+            $queryArgs[] = self::SHARE_TYPE_LINK;
1025
+        }
1026
+        if (isset($shareType)) {
1027
+            // Include all user and group items
1028
+            if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
1029
+                $where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
1030
+                $queryArgs[] = self::SHARE_TYPE_USER;
1031
+                $queryArgs[] = self::$shareTypeGroupUserUnique;
1032
+                $queryArgs[] = $shareWith;
1033
+
1034
+                $user = \OC::$server->getUserManager()->get($shareWith);
1035
+                $groups = [];
1036
+                if ($user) {
1037
+                    $groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
1038
+                }
1039
+                if (!empty($groups)) {
1040
+                    $placeholders = implode(',', array_fill(0, count($groups), '?'));
1041
+                    $where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
1042
+                    $queryArgs[] = self::SHARE_TYPE_GROUP;
1043
+                    $queryArgs = array_merge($queryArgs, $groups);
1044
+                }
1045
+                $where .= ')';
1046
+                // Don't include own group shares
1047
+                $where .= ' AND `uid_owner` != ?';
1048
+                $queryArgs[] = $shareWith;
1049
+            } else {
1050
+                $where .= ' AND `share_type` = ?';
1051
+                $queryArgs[] = $shareType;
1052
+                if (isset($shareWith)) {
1053
+                    $where .= ' AND `share_with` = ?';
1054
+                    $queryArgs[] = $shareWith;
1055
+                }
1056
+            }
1057
+        }
1058
+        if (isset($uidOwner)) {
1059
+            $where .= ' AND `uid_owner` = ?';
1060
+            $queryArgs[] = $uidOwner;
1061
+            if (!isset($shareType)) {
1062
+                // Prevent unique user targets for group shares from being selected
1063
+                $where .= ' AND `share_type` != ?';
1064
+                $queryArgs[] = self::$shareTypeGroupUserUnique;
1065
+            }
1066
+            if ($fileDependent) {
1067
+                $column = 'file_source';
1068
+            } else {
1069
+                $column = 'item_source';
1070
+            }
1071
+        } else {
1072
+            if ($fileDependent) {
1073
+                $column = 'file_target';
1074
+            } else {
1075
+                $column = 'item_target';
1076
+            }
1077
+        }
1078
+        if (isset($item)) {
1079
+            $collectionTypes = self::getCollectionItemTypes($itemType);
1080
+            if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1081
+                $where .= ' AND (';
1082
+            } else {
1083
+                $where .= ' AND';
1084
+            }
1085
+            // If looking for own shared items, check item_source else check item_target
1086
+            if (isset($uidOwner) || $itemShareWithBySource) {
1087
+                // If item type is a file, file source needs to be checked in case the item was converted
1088
+                if ($fileDependent) {
1089
+                    $where .= ' `file_source` = ?';
1090
+                    $column = 'file_source';
1091
+                } else {
1092
+                    $where .= ' `item_source` = ?';
1093
+                    $column = 'item_source';
1094
+                }
1095
+            } else {
1096
+                if ($fileDependent) {
1097
+                    $where .= ' `file_target` = ?';
1098
+                    $item = \OC\Files\Filesystem::normalizePath($item);
1099
+                } else {
1100
+                    $where .= ' `item_target` = ?';
1101
+                }
1102
+            }
1103
+            $queryArgs[] = $item;
1104
+            if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1105
+                $placeholders = implode(',', array_fill(0, count($collectionTypes), '?'));
1106
+                $where .= ' OR `item_type` IN ('.$placeholders.'))';
1107
+                $queryArgs = array_merge($queryArgs, $collectionTypes);
1108
+            }
1109
+        }
1110
+
1111
+        if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
1112
+            // Make sure the unique user target is returned if it exists,
1113
+            // unique targets should follow the group share in the database
1114
+            // If the limit is not 1, the filtering can be done later
1115
+            $where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
1116
+        } else {
1117
+            $where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
1118
+        }
1119
+
1120
+        if ($limit != -1 && !$includeCollections) {
1121
+            // The limit must be at least 3, because filtering needs to be done
1122
+            if ($limit < 3) {
1123
+                $queryLimit = 3;
1124
+            } else {
1125
+                $queryLimit = $limit;
1126
+            }
1127
+        } else {
1128
+            $queryLimit = null;
1129
+        }
1130
+        $select = self::createSelectStatement($format, $fileDependent, $uidOwner);
1131
+        $root = strlen($root);
1132
+        $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
1133
+        $result = $query->execute($queryArgs);
1134
+        if ($result === false) {
1135
+            \OCP\Util::writeLog('OCP\Share',
1136
+                \OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
1137
+                ILogger::ERROR);
1138
+        }
1139
+        $items = array();
1140
+        $targets = array();
1141
+        $switchedItems = array();
1142
+        $mounts = array();
1143
+        while ($row = $result->fetchRow()) {
1144
+            self::transformDBResults($row);
1145
+            // Filter out duplicate group shares for users with unique targets
1146
+            if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
1147
+                continue;
1148
+            }
1149
+            if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
1150
+                $row['share_type'] = self::SHARE_TYPE_GROUP;
1151
+                $row['unique_name'] = true; // remember that we use a unique name for this user
1152
+                $row['share_with'] = $items[$row['parent']]['share_with'];
1153
+                // if the group share was unshared from the user we keep the permission, otherwise
1154
+                // we take the permission from the parent because this is always the up-to-date
1155
+                // permission for the group share
1156
+                if ($row['permissions'] > 0) {
1157
+                    $row['permissions'] = $items[$row['parent']]['permissions'];
1158
+                }
1159
+                // Remove the parent group share
1160
+                unset($items[$row['parent']]);
1161
+                if ($row['permissions'] == 0) {
1162
+                    continue;
1163
+                }
1164
+            } else if (!isset($uidOwner)) {
1165
+                // Check if the same target already exists
1166
+                if (isset($targets[$row['id']])) {
1167
+                    // Check if the same owner shared with the user twice
1168
+                    // through a group and user share - this is allowed
1169
+                    $id = $targets[$row['id']];
1170
+                    if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
1171
+                        // Switch to group share type to ensure resharing conditions aren't bypassed
1172
+                        if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
1173
+                            $items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
1174
+                            $items[$id]['share_with'] = $row['share_with'];
1175
+                        }
1176
+                        // Switch ids if sharing permission is granted on only
1177
+                        // one share to ensure correct parent is used if resharing
1178
+                        if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
1179
+                            && (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1180
+                            $items[$row['id']] = $items[$id];
1181
+                            $switchedItems[$id] = $row['id'];
1182
+                            unset($items[$id]);
1183
+                            $id = $row['id'];
1184
+                        }
1185
+                        $items[$id]['permissions'] |= (int)$row['permissions'];
1186
+
1187
+                    }
1188
+                    continue;
1189
+                } elseif (!empty($row['parent'])) {
1190
+                    $targets[$row['parent']] = $row['id'];
1191
+                }
1192
+            }
1193
+            // Remove root from file source paths if retrieving own shared items
1194
+            if (isset($uidOwner) && isset($row['path'])) {
1195
+                if (isset($row['parent'])) {
1196
+                    $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
1197
+                    $parentResult = $query->execute(array($row['parent']));
1198
+                    if ($result === false) {
1199
+                        \OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
1200
+                            \OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
1201
+                            ILogger::ERROR);
1202
+                    } else {
1203
+                        $parentRow = $parentResult->fetchRow();
1204
+                        $tmpPath = $parentRow['file_target'];
1205
+                        // find the right position where the row path continues from the target path
1206
+                        $pos = strrpos($row['path'], $parentRow['file_target']);
1207
+                        $subPath = substr($row['path'], $pos);
1208
+                        $splitPath = explode('/', $subPath);
1209
+                        foreach (array_slice($splitPath, 2) as $pathPart) {
1210
+                            $tmpPath = $tmpPath . '/' . $pathPart;
1211
+                        }
1212
+                        $row['path'] = $tmpPath;
1213
+                    }
1214
+                } else {
1215
+                    if (!isset($mounts[$row['storage']])) {
1216
+                        $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
1217
+                        if (is_array($mountPoints) && !empty($mountPoints)) {
1218
+                            $mounts[$row['storage']] = current($mountPoints);
1219
+                        }
1220
+                    }
1221
+                    if (!empty($mounts[$row['storage']])) {
1222
+                        $path = $mounts[$row['storage']]->getMountPoint().$row['path'];
1223
+                        $relPath = substr($path, $root); // path relative to data/user
1224
+                        $row['path'] = rtrim($relPath, '/');
1225
+                    }
1226
+                }
1227
+            }
1228
+
1229
+            if($checkExpireDate) {
1230
+                if (self::expireItem($row)) {
1231
+                    continue;
1232
+                }
1233
+            }
1234
+            // Check if resharing is allowed, if not remove share permission
1235
+            if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
1236
+                $row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
1237
+            }
1238
+            // Add display names to result
1239
+            $row['share_with_displayname'] = $row['share_with'];
1240
+            if ( isset($row['share_with']) && $row['share_with'] != '' &&
1241
+                $row['share_type'] === self::SHARE_TYPE_USER) {
1242
+                $shareWithUser = \OC::$server->getUserManager()->get($row['share_with']);
1243
+                $row['share_with_displayname'] = $shareWithUser === null ? $row['share_with'] : $shareWithUser->getDisplayName();
1244
+            } else if(isset($row['share_with']) && $row['share_with'] != '' &&
1245
+                $row['share_type'] === self::SHARE_TYPE_REMOTE) {
1246
+                $addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
1247
+                foreach ($addressBookEntries as $entry) {
1248
+                    foreach ($entry['CLOUD'] as $cloudID) {
1249
+                        if ($cloudID === $row['share_with']) {
1250
+                            $row['share_with_displayname'] = $entry['FN'];
1251
+                        }
1252
+                    }
1253
+                }
1254
+            }
1255
+            if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
1256
+                $ownerUser = \OC::$server->getUserManager()->get($row['uid_owner']);
1257
+                $row['displayname_owner'] = $ownerUser === null ? $row['uid_owner'] : $ownerUser->getDisplayName();
1258
+            }
1259
+
1260
+            if ($row['permissions'] > 0) {
1261
+                $items[$row['id']] = $row;
1262
+            }
1263
+
1264
+        }
1265
+
1266
+        // group items if we are looking for items shared with the current user
1267
+        if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
1268
+            $items = self::groupItems($items, $itemType);
1269
+        }
1270
+
1271
+        if (!empty($items)) {
1272
+            $collectionItems = array();
1273
+            foreach ($items as &$row) {
1274
+                // Return only the item instead of a 2-dimensional array
1275
+                if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
1276
+                    if ($format == self::FORMAT_NONE) {
1277
+                        return $row;
1278
+                    } else {
1279
+                        break;
1280
+                    }
1281
+                }
1282
+                // Check if this is a collection of the requested item type
1283
+                if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
1284
+                    if (($collectionBackend = self::getBackend($row['item_type']))
1285
+                        && $collectionBackend instanceof \OCP\Share_Backend_Collection) {
1286
+                        // Collections can be inside collections, check if the item is a collection
1287
+                        if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
1288
+                            $collectionItems[] = $row;
1289
+                        } else {
1290
+                            $collection = array();
1291
+                            $collection['item_type'] = $row['item_type'];
1292
+                            if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1293
+                                $collection['path'] = basename($row['path']);
1294
+                            }
1295
+                            $row['collection'] = $collection;
1296
+                            // Fetch all of the children sources
1297
+                            $children = $collectionBackend->getChildren($row[$column]);
1298
+                            foreach ($children as $child) {
1299
+                                $childItem = $row;
1300
+                                $childItem['item_type'] = $itemType;
1301
+                                if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
1302
+                                    $childItem['item_source'] = $child['source'];
1303
+                                    $childItem['item_target'] = $child['target'];
1304
+                                }
1305
+                                if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1306
+                                    if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1307
+                                        $childItem['file_source'] = $child['source'];
1308
+                                    } else { // TODO is this really needed if we already know that we use the file backend?
1309
+                                        $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
1310
+                                        $childItem['file_source'] = $meta['fileid'];
1311
+                                    }
1312
+                                    $childItem['file_target'] =
1313
+                                        \OC\Files\Filesystem::normalizePath($child['file_path']);
1314
+                                }
1315
+                                if (isset($item)) {
1316
+                                    if ($childItem[$column] == $item) {
1317
+                                        // Return only the item instead of a 2-dimensional array
1318
+                                        if ($limit == 1) {
1319
+                                            if ($format == self::FORMAT_NONE) {
1320
+                                                return $childItem;
1321
+                                            } else {
1322
+                                                // Unset the items array and break out of both loops
1323
+                                                $items = array();
1324
+                                                $items[] = $childItem;
1325
+                                                break 2;
1326
+                                            }
1327
+                                        } else {
1328
+                                            $collectionItems[] = $childItem;
1329
+                                        }
1330
+                                    }
1331
+                                } else {
1332
+                                    $collectionItems[] = $childItem;
1333
+                                }
1334
+                            }
1335
+                        }
1336
+                    }
1337
+                    // Remove collection item
1338
+                    $toRemove = $row['id'];
1339
+                    if (array_key_exists($toRemove, $switchedItems)) {
1340
+                        $toRemove = $switchedItems[$toRemove];
1341
+                    }
1342
+                    unset($items[$toRemove]);
1343
+                } elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
1344
+                    // FIXME: Thats a dirty hack to improve file sharing performance,
1345
+                    // see github issue #10588 for more details
1346
+                    // Need to find a solution which works for all back-ends
1347
+                    $collectionBackend = self::getBackend($row['item_type']);
1348
+                    $sharedParents = $collectionBackend->getParents($row['item_source']);
1349
+                    foreach ($sharedParents as $parent) {
1350
+                        $collectionItems[] = $parent;
1351
+                    }
1352
+                }
1353
+            }
1354
+            if (!empty($collectionItems)) {
1355
+                $collectionItems = array_unique($collectionItems, SORT_REGULAR);
1356
+                $items = array_merge($items, $collectionItems);
1357
+            }
1358
+
1359
+            // filter out invalid items, these can appear when subshare entries exist
1360
+            // for a group in which the requested user isn't a member any more
1361
+            $items = array_filter($items, function($item) {
1362
+                return $item['share_type'] !== self::$shareTypeGroupUserUnique;
1363
+            });
1364
+
1365
+            return self::formatResult($items, $column, $backend, $format, $parameters);
1366
+        } elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
1367
+            // FIXME: Thats a dirty hack to improve file sharing performance,
1368
+            // see github issue #10588 for more details
1369
+            // Need to find a solution which works for all back-ends
1370
+            $collectionItems = array();
1371
+            $collectionBackend = self::getBackend('folder');
1372
+            $sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
1373
+            foreach ($sharedParents as $parent) {
1374
+                $collectionItems[] = $parent;
1375
+            }
1376
+            if ($limit === 1) {
1377
+                return reset($collectionItems);
1378
+            }
1379
+            return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
1380
+        }
1381
+
1382
+        return array();
1383
+    }
1384
+
1385
+    /**
1386
+     * group items with link to the same source
1387
+     *
1388
+     * @param array $items
1389
+     * @param string $itemType
1390
+     * @return array of grouped items
1391
+     */
1392
+    protected static function groupItems($items, $itemType) {
1393
+
1394
+        $fileSharing = $itemType === 'file' || $itemType === 'folder';
1395
+
1396
+        $result = array();
1397
+
1398
+        foreach ($items as $item) {
1399
+            $grouped = false;
1400
+            foreach ($result as $key => $r) {
1401
+                // for file/folder shares we need to compare file_source, otherwise we compare item_source
1402
+                // only group shares if they already point to the same target, otherwise the file where shared
1403
+                // before grouping of shares was added. In this case we don't group them toi avoid confusions
1404
+                if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
1405
+                    (!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
1406
+                    // add the first item to the list of grouped shares
1407
+                    if (!isset($result[$key]['grouped'])) {
1408
+                        $result[$key]['grouped'][] = $result[$key];
1409
+                    }
1410
+                    $result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
1411
+                    $result[$key]['grouped'][] = $item;
1412
+                    $grouped = true;
1413
+                    break;
1414
+                }
1415
+            }
1416
+
1417
+            if (!$grouped) {
1418
+                $result[] = $item;
1419
+            }
1420
+
1421
+        }
1422
+
1423
+        return $result;
1424
+    }
1425
+
1426
+    /**
1427
+     * Put shared item into the database
1428
+     * @param string $itemType Item type
1429
+     * @param string $itemSource Item source
1430
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1431
+     * @param string $shareWith User or group the item is being shared with
1432
+     * @param string $uidOwner User that is the owner of shared item
1433
+     * @param int $permissions CRUDS permissions
1434
+     * @param boolean|array $parentFolder Parent folder target (optional)
1435
+     * @param string $token (optional)
1436
+     * @param string $itemSourceName name of the source item (optional)
1437
+     * @param \DateTime $expirationDate (optional)
1438
+     * @throws \Exception
1439
+     * @return mixed id of the new share or false
1440
+     */
1441
+    private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1442
+                                $permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
1443
+
1444
+        $queriesToExecute = array();
1445
+        $suggestedItemTarget = null;
1446
+        $groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
1447
+        $groupItemTarget = $itemTarget = $fileSource = $parent = 0;
1448
+
1449
+        $result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate);
1450
+        if(!empty($result)) {
1451
+            $parent = $result['parent'];
1452
+            $itemSource = $result['itemSource'];
1453
+            $fileSource = $result['fileSource'];
1454
+            $suggestedItemTarget = $result['suggestedItemTarget'];
1455
+            $suggestedFileTarget = $result['suggestedFileTarget'];
1456
+            $filePath = $result['filePath'];
1457
+        }
1458
+
1459
+        $isGroupShare = false;
1460
+        if ($shareType == self::SHARE_TYPE_GROUP) {
1461
+            $isGroupShare = true;
1462
+            if (isset($shareWith['users'])) {
1463
+                $users = $shareWith['users'];
1464
+            } else {
1465
+                $group = \OC::$server->getGroupManager()->get($shareWith['group']);
1466
+                if ($group) {
1467
+                    $users = $group->searchUsers('', -1, 0);
1468
+                    $userIds = [];
1469
+                    foreach ($users as $user) {
1470
+                        $userIds[] = $user->getUID();
1471
+                    }
1472
+                    $users = $userIds;
1473
+                } else {
1474
+                    $users = [];
1475
+                }
1476
+            }
1477
+            // remove current user from list
1478
+            if (in_array(\OCP\User::getUser(), $users)) {
1479
+                unset($users[array_search(\OCP\User::getUser(), $users)]);
1480
+            }
1481
+            $groupItemTarget = Helper::generateTarget($itemType, $itemSource,
1482
+                $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
1483
+            $groupFileTarget = Helper::generateTarget($itemType, $itemSource,
1484
+                $shareType, $shareWith['group'], $uidOwner, $filePath);
1485
+
1486
+            // add group share to table and remember the id as parent
1487
+            $queriesToExecute['groupShare'] = array(
1488
+                'itemType'			=> $itemType,
1489
+                'itemSource'		=> $itemSource,
1490
+                'itemTarget'		=> $groupItemTarget,
1491
+                'shareType'			=> $shareType,
1492
+                'shareWith'			=> $shareWith['group'],
1493
+                'uidOwner'			=> $uidOwner,
1494
+                'permissions'		=> $permissions,
1495
+                'shareTime'			=> time(),
1496
+                'fileSource'		=> $fileSource,
1497
+                'fileTarget'		=> $groupFileTarget,
1498
+                'token'				=> $token,
1499
+                'parent'			=> $parent,
1500
+                'expiration'		=> $expirationDate,
1501
+            );
1502
+
1503
+        } else {
1504
+            $users = array($shareWith);
1505
+            $itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1506
+                $suggestedItemTarget);
1507
+        }
1508
+
1509
+        $run = true;
1510
+        $error = '';
1511
+        $preHookData = array(
1512
+            'itemType' => $itemType,
1513
+            'itemSource' => $itemSource,
1514
+            'shareType' => $shareType,
1515
+            'uidOwner' => $uidOwner,
1516
+            'permissions' => $permissions,
1517
+            'fileSource' => $fileSource,
1518
+            'expiration' => $expirationDate,
1519
+            'token' => $token,
1520
+            'run' => &$run,
1521
+            'error' => &$error
1522
+        );
1523
+
1524
+        $preHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget;
1525
+        $preHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith;
1526
+
1527
+        \OC_Hook::emit(\OCP\Share::class, 'pre_shared', $preHookData);
1528
+
1529
+        if ($run === false) {
1530
+            throw new \Exception($error);
1531
+        }
1532
+
1533
+        foreach ($users as $user) {
1534
+            $sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
1535
+            $sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
1536
+
1537
+            $userShareType = $isGroupShare ? self::$shareTypeGroupUserUnique : $shareType;
1538
+
1539
+            if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
1540
+                $fileTarget = $sourceExists['file_target'];
1541
+                $itemTarget = $sourceExists['item_target'];
1542
+
1543
+                // for group shares we don't need a additional entry if the target is the same
1544
+                if($isGroupShare && $groupItemTarget === $itemTarget) {
1545
+                    continue;
1546
+                }
1547
+
1548
+            } elseif(!$sourceExists && !$isGroupShare)  {
1549
+
1550
+                $itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
1551
+                    $uidOwner, $suggestedItemTarget, $parent);
1552
+                if (isset($fileSource)) {
1553
+                    if ($parentFolder) {
1554
+                        if ($parentFolder === true) {
1555
+                            $fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user,
1556
+                                $uidOwner, $suggestedFileTarget, $parent);
1557
+                            if ($fileTarget != $groupFileTarget) {
1558
+                                $parentFolders[$user]['folder'] = $fileTarget;
1559
+                            }
1560
+                        } else if (isset($parentFolder[$user])) {
1561
+                            $fileTarget = $parentFolder[$user]['folder'].$itemSource;
1562
+                            $parent = $parentFolder[$user]['id'];
1563
+                        }
1564
+                    } else {
1565
+                        $fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
1566
+                            $user, $uidOwner, $suggestedFileTarget, $parent);
1567
+                    }
1568
+                } else {
1569
+                    $fileTarget = null;
1570
+                }
1571
+
1572
+            } else {
1573
+
1574
+                // group share which doesn't exists until now, check if we need a unique target for this user
1575
+
1576
+                $itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
1577
+                    $uidOwner, $suggestedItemTarget, $parent);
1578
+
1579
+                // do we also need a file target
1580
+                if (isset($fileSource)) {
1581
+                    $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
1582
+                        $uidOwner, $suggestedFileTarget, $parent);
1583
+                } else {
1584
+                    $fileTarget = null;
1585
+                }
1586
+
1587
+                if (($itemTarget === $groupItemTarget) &&
1588
+                    (!isset($fileSource) || $fileTarget === $groupFileTarget)) {
1589
+                    continue;
1590
+                }
1591
+            }
1592
+
1593
+            $queriesToExecute[] = array(
1594
+                'itemType'			=> $itemType,
1595
+                'itemSource'		=> $itemSource,
1596
+                'itemTarget'		=> $itemTarget,
1597
+                'shareType'			=> $userShareType,
1598
+                'shareWith'			=> $user,
1599
+                'uidOwner'			=> $uidOwner,
1600
+                'permissions'		=> $permissions,
1601
+                'shareTime'			=> time(),
1602
+                'fileSource'		=> $fileSource,
1603
+                'fileTarget'		=> $fileTarget,
1604
+                'token'				=> $token,
1605
+                'parent'			=> $parent,
1606
+                'expiration'		=> $expirationDate,
1607
+            );
1608
+
1609
+        }
1610
+
1611
+        $id = false;
1612
+        if ($isGroupShare) {
1613
+            $id = self::insertShare($queriesToExecute['groupShare']);
1614
+            // Save this id, any extra rows for this group share will need to reference it
1615
+            $parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1616
+            unset($queriesToExecute['groupShare']);
1617
+        }
1618
+
1619
+        foreach ($queriesToExecute as $shareQuery) {
1620
+            $shareQuery['parent'] = $parent;
1621
+            $id = self::insertShare($shareQuery);
1622
+        }
1623
+
1624
+        $postHookData = array(
1625
+            'itemType' => $itemType,
1626
+            'itemSource' => $itemSource,
1627
+            'parent' => $parent,
1628
+            'shareType' => $shareType,
1629
+            'uidOwner' => $uidOwner,
1630
+            'permissions' => $permissions,
1631
+            'fileSource' => $fileSource,
1632
+            'id' => $parent,
1633
+            'token' => $token,
1634
+            'expirationDate' => $expirationDate,
1635
+        );
1636
+
1637
+        $postHookData['shareWith'] = $isGroupShare ? $shareWith['group'] : $shareWith;
1638
+        $postHookData['itemTarget'] = $isGroupShare ? $groupItemTarget : $itemTarget;
1639
+        $postHookData['fileTarget'] = $isGroupShare ? $groupFileTarget : $fileTarget;
1640
+
1641
+        \OC_Hook::emit(\OCP\Share::class, 'post_shared', $postHookData);
1642
+
1643
+
1644
+        return $id ? $id : false;
1645
+    }
1646
+
1647
+    /**
1648
+     * @param string $itemType
1649
+     * @param string $itemSource
1650
+     * @param int $shareType
1651
+     * @param string $shareWith
1652
+     * @param string $uidOwner
1653
+     * @param int $permissions
1654
+     * @param string|null $itemSourceName
1655
+     * @param null|\DateTime $expirationDate
1656
+     */
1657
+    private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
1658
+        $backend = self::getBackend($itemType);
1659
+
1660
+        $l = \OC::$server->getL10N('lib');
1661
+        $result = array();
1662
+
1663
+        $column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
1664
+
1665
+        $checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
1666
+        if ($checkReshare) {
1667
+            // Check if attempting to share back to owner
1668
+            if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
1669
+                $message = 'Sharing %1$s failed, because the user %2$s is the original sharer';
1670
+                $message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]);
1671
+
1672
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), ILogger::DEBUG);
1673
+                throw new \Exception($message_t);
1674
+            }
1675
+        }
1676
+
1677
+        if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
1678
+            // Check if share permissions is granted
1679
+            if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1680
+                if (~(int)$checkReshare['permissions'] & $permissions) {
1681
+                    $message = 'Sharing %1$s failed, because the permissions exceed permissions granted to %2$s';
1682
+                    $message_t = $l->t('Sharing %1$s failed, because the permissions exceed permissions granted to %2$s', array($itemSourceName, $uidOwner));
1683
+
1684
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), ILogger::DEBUG);
1685
+                    throw new \Exception($message_t);
1686
+                } else {
1687
+                    // TODO Don't check if inside folder
1688
+                    $result['parent'] = $checkReshare['id'];
1689
+
1690
+                    $result['expirationDate'] = $expirationDate;
1691
+                    // $checkReshare['expiration'] could be null and then is always less than any value
1692
+                    if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
1693
+                        $result['expirationDate'] = $checkReshare['expiration'];
1694
+                    }
1695
+
1696
+                    // only suggest the same name as new target if it is a reshare of the
1697
+                    // same file/folder and not the reshare of a child
1698
+                    if ($checkReshare[$column] === $itemSource) {
1699
+                        $result['filePath'] = $checkReshare['file_target'];
1700
+                        $result['itemSource'] = $checkReshare['item_source'];
1701
+                        $result['fileSource'] = $checkReshare['file_source'];
1702
+                        $result['suggestedItemTarget'] = $checkReshare['item_target'];
1703
+                        $result['suggestedFileTarget'] = $checkReshare['file_target'];
1704
+                    } else {
1705
+                        $result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
1706
+                        $result['suggestedItemTarget'] = null;
1707
+                        $result['suggestedFileTarget'] = null;
1708
+                        $result['itemSource'] = $itemSource;
1709
+                        $result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
1710
+                    }
1711
+                }
1712
+            } else {
1713
+                $message = 'Sharing %s failed, because resharing is not allowed';
1714
+                $message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName));
1715
+
1716
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), ILogger::DEBUG);
1717
+                throw new \Exception($message_t);
1718
+            }
1719
+        } else {
1720
+            $result['parent'] = null;
1721
+            $result['suggestedItemTarget'] = null;
1722
+            $result['suggestedFileTarget'] = null;
1723
+            $result['itemSource'] = $itemSource;
1724
+            $result['expirationDate'] = $expirationDate;
1725
+            if (!$backend->isValidSource($itemSource, $uidOwner)) {
1726
+                $message = 'Sharing %1$s failed, because the sharing backend for '
1727
+                    .'%2$s could not find its source';
1728
+                $message_t = $l->t('Sharing %1$s failed, because the sharing backend for %2$s could not find its source', array($itemSource, $itemType));
1729
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), ILogger::DEBUG);
1730
+                throw new \Exception($message_t);
1731
+            }
1732
+            if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1733
+                $result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
1734
+                if ($itemType == 'file' || $itemType == 'folder') {
1735
+                    $result['fileSource'] = $itemSource;
1736
+                } else {
1737
+                    $meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
1738
+                    $result['fileSource'] = $meta['fileid'];
1739
+                }
1740
+                if ($result['fileSource'] == -1) {
1741
+                    $message = 'Sharing %s failed, because the file could not be found in the file cache';
1742
+                    $message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource));
1743
+
1744
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), ILogger::DEBUG);
1745
+                    throw new \Exception($message_t);
1746
+                }
1747
+            } else {
1748
+                $result['filePath'] = null;
1749
+                $result['fileSource'] = null;
1750
+            }
1751
+        }
1752
+
1753
+        return $result;
1754
+    }
1755
+
1756
+    /**
1757
+     *
1758
+     * @param array $shareData
1759
+     * @return mixed false in case of a failure or the id of the new share
1760
+     */
1761
+    private static function insertShare(array $shareData) {
1762
+
1763
+        $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
1764
+            .' `item_type`, `item_source`, `item_target`, `share_type`,'
1765
+            .' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
1766
+            .' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
1767
+        $query->bindValue(1, $shareData['itemType']);
1768
+        $query->bindValue(2, $shareData['itemSource']);
1769
+        $query->bindValue(3, $shareData['itemTarget']);
1770
+        $query->bindValue(4, $shareData['shareType']);
1771
+        $query->bindValue(5, $shareData['shareWith']);
1772
+        $query->bindValue(6, $shareData['uidOwner']);
1773
+        $query->bindValue(7, $shareData['permissions']);
1774
+        $query->bindValue(8, $shareData['shareTime']);
1775
+        $query->bindValue(9, $shareData['fileSource']);
1776
+        $query->bindValue(10, $shareData['fileTarget']);
1777
+        $query->bindValue(11, $shareData['token']);
1778
+        $query->bindValue(12, $shareData['parent']);
1779
+        $query->bindValue(13, $shareData['expiration'], 'datetime');
1780
+        $result = $query->execute();
1781
+
1782
+        $id = false;
1783
+        if ($result) {
1784
+            $id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1785
+        }
1786
+
1787
+        return $id;
1788
+
1789
+    }
1790
+
1791
+    /**
1792
+     * In case a password protected link is not yet authenticated this function will return false
1793
+     *
1794
+     * @param array $linkItem
1795
+     * @return boolean
1796
+     */
1797
+    public static function checkPasswordProtectedShare(array $linkItem) {
1798
+        if (!isset($linkItem['share_with'])) {
1799
+            return true;
1800
+        }
1801
+        if (!isset($linkItem['share_type'])) {
1802
+            return true;
1803
+        }
1804
+        if (!isset($linkItem['id'])) {
1805
+            return true;
1806
+        }
1807
+
1808
+        if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
1809
+            return true;
1810
+        }
1811
+
1812
+        if ( \OC::$server->getSession()->exists('public_link_authenticated')
1813
+            && \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id'] ) {
1814
+            return true;
1815
+        }
1816
+
1817
+        return false;
1818
+    }
1819
+
1820
+    /**
1821
+     * construct select statement
1822
+     * @param int $format
1823
+     * @param boolean $fileDependent ist it a file/folder share or a generla share
1824
+     * @param string $uidOwner
1825
+     * @return string select statement
1826
+     */
1827
+    private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
1828
+        $select = '*';
1829
+        if ($format == self::FORMAT_STATUSES) {
1830
+            if ($fileDependent) {
1831
+                $select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
1832
+                    . '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
1833
+                    . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1834
+                    . '`uid_initiator`';
1835
+            } else {
1836
+                $select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
1837
+            }
1838
+        } else {
1839
+            if (isset($uidOwner)) {
1840
+                if ($fileDependent) {
1841
+                    $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
1842
+                        . ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
1843
+                        . ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
1844
+                        . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1845
+                } else {
1846
+                    $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
1847
+                        . ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
1848
+                }
1849
+            } else {
1850
+                if ($fileDependent) {
1851
+                    if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
1852
+                        $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
1853
+                            . '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
1854
+                            . '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1855
+                            . '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
1856
+                    } else {
1857
+                        $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
1858
+                            . '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
1859
+                            . '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
1860
+                            . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
1861
+                            . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1862
+                    }
1863
+                }
1864
+            }
1865
+        }
1866
+        return $select;
1867
+    }
1868
+
1869
+
1870
+    /**
1871
+     * transform db results
1872
+     * @param array $row result
1873
+     */
1874
+    private static function transformDBResults(&$row) {
1875
+        if (isset($row['id'])) {
1876
+            $row['id'] = (int) $row['id'];
1877
+        }
1878
+        if (isset($row['share_type'])) {
1879
+            $row['share_type'] = (int) $row['share_type'];
1880
+        }
1881
+        if (isset($row['parent'])) {
1882
+            $row['parent'] = (int) $row['parent'];
1883
+        }
1884
+        if (isset($row['file_parent'])) {
1885
+            $row['file_parent'] = (int) $row['file_parent'];
1886
+        }
1887
+        if (isset($row['file_source'])) {
1888
+            $row['file_source'] = (int) $row['file_source'];
1889
+        }
1890
+        if (isset($row['permissions'])) {
1891
+            $row['permissions'] = (int) $row['permissions'];
1892
+        }
1893
+        if (isset($row['storage'])) {
1894
+            $row['storage'] = (int) $row['storage'];
1895
+        }
1896
+        if (isset($row['stime'])) {
1897
+            $row['stime'] = (int) $row['stime'];
1898
+        }
1899
+        if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
1900
+            // discard expiration date for non-link shares, which might have been
1901
+            // set by ancient bugs
1902
+            $row['expiration'] = null;
1903
+        }
1904
+    }
1905
+
1906
+    /**
1907
+     * format result
1908
+     * @param array $items result
1909
+     * @param string $column is it a file share or a general share ('file_target' or 'item_target')
1910
+     * @param \OCP\Share_Backend $backend sharing backend
1911
+     * @param int $format
1912
+     * @param array $parameters additional format parameters
1913
+     * @return array format result
1914
+     */
1915
+    private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
1916
+        if ($format === self::FORMAT_NONE) {
1917
+            return $items;
1918
+        } else if ($format === self::FORMAT_STATUSES) {
1919
+            $statuses = array();
1920
+            foreach ($items as $item) {
1921
+                if ($item['share_type'] === self::SHARE_TYPE_LINK) {
1922
+                    if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
1923
+                        continue;
1924
+                    }
1925
+                    $statuses[$item[$column]]['link'] = true;
1926
+                } else if (!isset($statuses[$item[$column]])) {
1927
+                    $statuses[$item[$column]]['link'] = false;
1928
+                }
1929
+                if (!empty($item['file_target'])) {
1930
+                    $statuses[$item[$column]]['path'] = $item['path'];
1931
+                }
1932
+            }
1933
+            return $statuses;
1934
+        } else {
1935
+            return $backend->formatItems($items, $format, $parameters);
1936
+        }
1937
+    }
1938
+
1939
+    /**
1940
+     * remove protocol from URL
1941
+     *
1942
+     * @param string $url
1943
+     * @return string
1944
+     */
1945
+    public static function removeProtocolFromUrl($url) {
1946
+        if (strpos($url, 'https://') === 0) {
1947
+            return substr($url, strlen('https://'));
1948
+        } else if (strpos($url, 'http://') === 0) {
1949
+            return substr($url, strlen('http://'));
1950
+        }
1951
+
1952
+        return $url;
1953
+    }
1954
+
1955
+    /**
1956
+     * try http post first with https and then with http as a fallback
1957
+     *
1958
+     * @param string $remoteDomain
1959
+     * @param string $urlSuffix
1960
+     * @param array $fields post parameters
1961
+     * @return array
1962
+     */
1963
+    private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
1964
+        $protocol = 'https://';
1965
+        $result = [
1966
+            'success' => false,
1967
+            'result' => '',
1968
+        ];
1969
+        $try = 0;
1970
+        $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
1971
+        while ($result['success'] === false && $try < 2) {
1972
+            $federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
1973
+            $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
1974
+            $client = \OC::$server->getHTTPClientService()->newClient();
1975
+
1976
+            try {
1977
+                $response = $client->post(
1978
+                    $protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT,
1979
+                    [
1980
+                        'body' => $fields,
1981
+                        'connect_timeout' => 10,
1982
+                    ]
1983
+                );
1984
+
1985
+                $result = ['success' => true, 'result' => $response->getBody()];
1986
+            } catch (\Exception $e) {
1987
+                $result = ['success' => false, 'result' => $e->getMessage()];
1988
+            }
1989
+
1990
+            $try++;
1991
+            $protocol = 'http://';
1992
+        }
1993
+
1994
+        return $result;
1995
+    }
1996
+
1997
+    /**
1998
+     * send server-to-server share to remote server
1999
+     *
2000
+     * @param string $token
2001
+     * @param string $shareWith
2002
+     * @param string $name
2003
+     * @param int $remote_id
2004
+     * @param string $owner
2005
+     * @return bool
2006
+     */
2007
+    private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
2008
+
2009
+        list($user, $remote) = Helper::splitUserRemote($shareWith);
2010
+
2011
+        if ($user && $remote) {
2012
+            $url = $remote;
2013
+
2014
+            $local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
2015
+
2016
+            $fields = array(
2017
+                'shareWith' => $user,
2018
+                'token' => $token,
2019
+                'name' => $name,
2020
+                'remoteId' => $remote_id,
2021
+                'owner' => $owner,
2022
+                'remote' => $local,
2023
+            );
2024
+
2025
+            $url = self::removeProtocolFromUrl($url);
2026
+            $result = self::tryHttpPostToShareEndpoint($url, '', $fields);
2027
+            $status = json_decode($result['result'], true);
2028
+
2029
+            if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
2030
+                \OC_Hook::emit(\OCP\Share::class, 'federated_share_added', ['server' => $remote]);
2031
+                return true;
2032
+            }
2033
+
2034
+        }
2035
+
2036
+        return false;
2037
+    }
2038
+
2039
+    /**
2040
+     * send server-to-server unshare to remote server
2041
+     *
2042
+     * @param string $remote url
2043
+     * @param int $id share id
2044
+     * @param string $token
2045
+     * @return bool
2046
+     */
2047
+    private static function sendRemoteUnshare($remote, $id, $token) {
2048
+        $url = rtrim($remote, '/');
2049
+        $fields = array('token' => $token, 'format' => 'json');
2050
+        $url = self::removeProtocolFromUrl($url);
2051
+        $result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
2052
+        $status = json_decode($result['result'], true);
2053
+
2054
+        return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
2055
+    }
2056
+
2057
+    /**
2058
+     * check if user can only share with group members
2059
+     * @return bool
2060
+     */
2061
+    public static function shareWithGroupMembersOnly() {
2062
+        $value = \OC::$server->getConfig()->getAppValue('core', 'shareapi_only_share_with_group_members', 'no');
2063
+        return $value === 'yes';
2064
+    }
2065
+
2066
+    /**
2067
+     * @return bool
2068
+     */
2069
+    public static function isDefaultExpireDateEnabled() {
2070
+        $defaultExpireDateEnabled = \OC::$server->getConfig()->getAppValue('core', 'shareapi_default_expire_date', 'no');
2071
+        return $defaultExpireDateEnabled === 'yes';
2072
+    }
2073
+
2074
+    /**
2075
+     * @return int
2076
+     */
2077
+    public static function getExpireInterval() {
2078
+        return (int)\OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
2079
+    }
2080
+
2081
+    /**
2082
+     * Checks whether the given path is reachable for the given owner
2083
+     *
2084
+     * @param string $path path relative to files
2085
+     * @param string $ownerStorageId storage id of the owner
2086
+     *
2087
+     * @return boolean true if file is reachable, false otherwise
2088
+     */
2089
+    private static function isFileReachable($path, $ownerStorageId) {
2090
+        // if outside the home storage, file is always considered reachable
2091
+        if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
2092
+            substr($ownerStorageId, 0, 13) === 'object::user:'
2093
+        )) {
2094
+            return true;
2095
+        }
2096
+
2097
+        // if inside the home storage, the file has to be under "/files/"
2098
+        $path = ltrim($path, '/');
2099
+        if (substr($path, 0, 6) === 'files/') {
2100
+            return true;
2101
+        }
2102
+
2103
+        return false;
2104
+    }
2105
+
2106
+    /**
2107
+     * @param IConfig $config
2108
+     * @return bool
2109
+     */
2110
+    public static function enforcePassword(IConfig $config) {
2111
+        $enforcePassword = $config->getAppValue('core', 'shareapi_enforce_links_password', 'no');
2112
+        return $enforcePassword === 'yes';
2113
+    }
2114
+
2115
+    /**
2116
+     * @param string $password
2117
+     * @throws \Exception
2118
+     */
2119
+    private static function verifyPassword($password) {
2120
+
2121
+        $accepted = true;
2122
+        $message = '';
2123
+        \OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
2124
+            'password' => $password,
2125
+            'accepted' => &$accepted,
2126
+            'message' => &$message
2127
+        ]);
2128
+
2129
+        if (!$accepted) {
2130
+            throw new \Exception($message);
2131
+        }
2132
+    }
2133 2133
 }
Please login to merge, or discard this patch.
core/ajax/update.php 1 patch
Indentation   +182 added lines, -182 removed lines patch added patch discarded remove patch
@@ -33,7 +33,7 @@  discard block
 block discarded – undo
33 33
 use Symfony\Component\EventDispatcher\GenericEvent;
34 34
 
35 35
 if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
36
-	@set_time_limit(0);
36
+    @set_time_limit(0);
37 37
 }
38 38
 
39 39
 require_once '../../lib/base.php';
@@ -47,192 +47,192 @@  discard block
 block discarded – undo
47 47
 $eventSource->send('success', (string)$l->t('Preparing update'));
48 48
 
49 49
 class FeedBackHandler {
50
-	/** @var integer */
51
-	private $progressStateMax = 100;
52
-	/** @var integer */
53
-	private $progressStateStep = 0;
54
-	/** @var string */
55
-	private $currentStep;
56
-	/** @var \OCP\IEventSource */
57
-	private $eventSource;
58
-	/** @var \OCP\IL10N */
59
-	private $l10n;
60
-
61
-	public function __construct(\OCP\IEventSource $eventSource, \OCP\IL10N $l10n) {
62
-		$this->eventSource = $eventSource;
63
-		$this->l10n = $l10n;
64
-	}
65
-
66
-	public function handleRepairFeedback($event) {
67
-		if (!$event instanceof GenericEvent) {
68
-			return;
69
-		}
70
-
71
-		switch ($event->getSubject()) {
72
-			case '\OC\Repair::startProgress':
73
-				$this->progressStateMax = $event->getArgument(0);
74
-				$this->progressStateStep = 0;
75
-				$this->currentStep = $event->getArgument(1);
76
-				break;
77
-			case '\OC\Repair::advance':
78
-				$this->progressStateStep += $event->getArgument(0);
79
-				$desc = $event->getArgument(1);
80
-				if (empty($desc)) {
81
-					$desc = $this->currentStep;
82
-				}
83
-				$this->eventSource->send('success', (string)$this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $desc]));
84
-				break;
85
-			case '\OC\Repair::finishProgress':
86
-				$this->progressStateMax = $this->progressStateStep;
87
-				$this->eventSource->send('success', (string)$this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $this->currentStep]));
88
-				break;
89
-			case '\OC\Repair::step':
90
-				break;
91
-			case '\OC\Repair::info':
92
-				break;
93
-			case '\OC\Repair::warning':
94
-				$this->eventSource->send('notice', (string)$this->l10n->t('Repair warning: ') . $event->getArgument(0));
95
-				break;
96
-			case '\OC\Repair::error':
97
-				$this->eventSource->send('notice', (string)$this->l10n->t('Repair error: ') . $event->getArgument(0));
98
-				break;
99
-		}
100
-	}
50
+    /** @var integer */
51
+    private $progressStateMax = 100;
52
+    /** @var integer */
53
+    private $progressStateStep = 0;
54
+    /** @var string */
55
+    private $currentStep;
56
+    /** @var \OCP\IEventSource */
57
+    private $eventSource;
58
+    /** @var \OCP\IL10N */
59
+    private $l10n;
60
+
61
+    public function __construct(\OCP\IEventSource $eventSource, \OCP\IL10N $l10n) {
62
+        $this->eventSource = $eventSource;
63
+        $this->l10n = $l10n;
64
+    }
65
+
66
+    public function handleRepairFeedback($event) {
67
+        if (!$event instanceof GenericEvent) {
68
+            return;
69
+        }
70
+
71
+        switch ($event->getSubject()) {
72
+            case '\OC\Repair::startProgress':
73
+                $this->progressStateMax = $event->getArgument(0);
74
+                $this->progressStateStep = 0;
75
+                $this->currentStep = $event->getArgument(1);
76
+                break;
77
+            case '\OC\Repair::advance':
78
+                $this->progressStateStep += $event->getArgument(0);
79
+                $desc = $event->getArgument(1);
80
+                if (empty($desc)) {
81
+                    $desc = $this->currentStep;
82
+                }
83
+                $this->eventSource->send('success', (string)$this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $desc]));
84
+                break;
85
+            case '\OC\Repair::finishProgress':
86
+                $this->progressStateMax = $this->progressStateStep;
87
+                $this->eventSource->send('success', (string)$this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $this->currentStep]));
88
+                break;
89
+            case '\OC\Repair::step':
90
+                break;
91
+            case '\OC\Repair::info':
92
+                break;
93
+            case '\OC\Repair::warning':
94
+                $this->eventSource->send('notice', (string)$this->l10n->t('Repair warning: ') . $event->getArgument(0));
95
+                break;
96
+            case '\OC\Repair::error':
97
+                $this->eventSource->send('notice', (string)$this->l10n->t('Repair error: ') . $event->getArgument(0));
98
+                break;
99
+        }
100
+    }
101 101
 }
102 102
 
103 103
 if (\OCP\Util::needUpgrade()) {
104 104
 
105
-	$config = \OC::$server->getSystemConfig();
106
-	if ($config->getValue('upgrade.disable-web', false)) {
107
-		$eventSource->send('failure', (string)$l->t('Please use the command line updater because automatic updating is disabled in the config.php.'));
108
-		$eventSource->close();
109
-		exit();
110
-	}
111
-
112
-	// if a user is currently logged in, their session must be ignored to
113
-	// avoid side effects
114
-	\OC_User::setIncognitoMode(true);
115
-
116
-	$logger = \OC::$server->getLogger();
117
-	$config = \OC::$server->getConfig();
118
-	$updater = new \OC\Updater(
119
-			$config,
120
-			\OC::$server->getIntegrityCodeChecker(),
121
-			$logger,
122
-			\OC::$server->query(\OC\Installer::class),
123
-			\OC::$server->getJobList()
124
-	);
125
-	$incompatibleApps = [];
126
-
127
-	$dispatcher = \OC::$server->getEventDispatcher();
128
-	$dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($eventSource, $l) {
129
-		if ($event instanceof GenericEvent) {
130
-			$eventSource->send('success', (string)$l->t('[%d / %d]: %s', [$event[0], $event[1], $event->getSubject()]));
131
-		}
132
-	});
133
-	$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($eventSource, $l) {
134
-		if ($event instanceof GenericEvent) {
135
-			$eventSource->send('success', (string)$l->t('[%d / %d]: Checking table %s', [$event[0], $event[1], $event->getSubject()]));
136
-		}
137
-	});
138
-	$feedBack = new FeedBackHandler($eventSource, $l);
139
-	$dispatcher->addListener('\OC\Repair::startProgress', [$feedBack, 'handleRepairFeedback']);
140
-	$dispatcher->addListener('\OC\Repair::advance', [$feedBack, 'handleRepairFeedback']);
141
-	$dispatcher->addListener('\OC\Repair::finishProgress', [$feedBack, 'handleRepairFeedback']);
142
-	$dispatcher->addListener('\OC\Repair::step', [$feedBack, 'handleRepairFeedback']);
143
-	$dispatcher->addListener('\OC\Repair::info', [$feedBack, 'handleRepairFeedback']);
144
-	$dispatcher->addListener('\OC\Repair::warning', [$feedBack, 'handleRepairFeedback']);
145
-	$dispatcher->addListener('\OC\Repair::error', [$feedBack, 'handleRepairFeedback']);
146
-
147
-	$updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($eventSource, $l) {
148
-		$eventSource->send('success', (string)$l->t('Turned on maintenance mode'));
149
-	});
150
-	$updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($eventSource, $l) {
151
-		$eventSource->send('success', (string)$l->t('Turned off maintenance mode'));
152
-	});
153
-	$updater->listen('\OC\Updater', 'maintenanceActive', function () use ($eventSource, $l) {
154
-		$eventSource->send('success', (string)$l->t('Maintenance mode is kept active'));
155
-	});
156
-	$updater->listen('\OC\Updater', 'waitForCronToFinish', function () use ($eventSource, $l) {
157
-		$eventSource->send('success', (string)$l->t('Waiting for cron to finish (checks again in 5 seconds) …'));
158
-	});
159
-	$updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use($eventSource, $l) {
160
-		$eventSource->send('success', (string)$l->t('Updating database schema'));
161
-	});
162
-	$updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l) {
163
-		$eventSource->send('success', (string)$l->t('Updated database'));
164
-	});
165
-	$updater->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($eventSource, $l) {
166
-		$eventSource->send('success', (string)$l->t('Checking whether the database schema can be updated (this can take a long time depending on the database size)'));
167
-	});
168
-	$updater->listen('\OC\Updater', 'dbSimulateUpgrade', function () use ($eventSource, $l) {
169
-		$eventSource->send('success', (string)$l->t('Checked database schema update'));
170
-	});
171
-	$updater->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($eventSource, $l) {
172
-		$eventSource->send('success', (string)$l->t('Checking updates of apps'));
173
-	});
174
-	$updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($eventSource, $l) {
175
-		$eventSource->send('success', (string)$l->t('Checking for update of app "%s" in appstore', [$app]));
176
-	});
177
-	$updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($eventSource, $l) {
178
-		$eventSource->send('success', (string)$l->t('Update app "%s" from appstore', [$app]));
179
-	});
180
-	$updater->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($eventSource, $l) {
181
-		$eventSource->send('success', (string)$l->t('Checked for update of app "%s" in appstore', [$app]));
182
-	});
183
-	$updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($eventSource, $l) {
184
-		$eventSource->send('success', (string)$l->t('Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)', [$app]));
185
-	});
186
-	$updater->listen('\OC\Updater', 'appUpgradeCheck', function () use ($eventSource, $l) {
187
-		$eventSource->send('success', (string)$l->t('Checked database schema update for apps'));
188
-	});
189
-	$updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l) {
190
-		$eventSource->send('success', (string)$l->t('Updated "%1$s" to %2$s', array($app, $version)));
191
-	});
192
-	$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps) {
193
-		$incompatibleApps[]= $app;
194
-	});
195
-	$updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource, $config) {
196
-		$eventSource->send('failure', $message);
197
-		$eventSource->close();
198
-		$config->setSystemValue('maintenance', false);
199
-	});
200
-	$updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use($eventSource, $l) {
201
-		$eventSource->send('success', (string)$l->t('Set log level to debug'));
202
-	});
203
-	$updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($eventSource, $l) {
204
-		$eventSource->send('success', (string)$l->t('Reset log level'));
205
-	});
206
-	$updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($eventSource, $l) {
207
-		$eventSource->send('success', (string)$l->t('Starting code integrity check'));
208
-	});
209
-	$updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($eventSource, $l) {
210
-		$eventSource->send('success', (string)$l->t('Finished code integrity check'));
211
-	});
212
-
213
-	try {
214
-		$updater->upgrade();
215
-	} catch (\Exception $e) {
216
-		\OC::$server->getLogger()->logException($e, [
217
-			'level' => ILogger::ERROR,
218
-			'app' => 'update',
219
-		]);
220
-		$eventSource->send('failure', get_class($e) . ': ' . $e->getMessage());
221
-		$eventSource->close();
222
-		exit();
223
-	}
224
-
225
-	$disabledApps = [];
226
-	foreach ($incompatibleApps as $app) {
227
-		$disabledApps[$app] = (string) $l->t('%s (incompatible)', [$app]);
228
-	}
229
-
230
-	if (!empty($disabledApps)) {
231
-		$eventSource->send('notice',
232
-			(string)$l->t('Following apps have been disabled: %s', [implode(', ', $disabledApps)]));
233
-	}
105
+    $config = \OC::$server->getSystemConfig();
106
+    if ($config->getValue('upgrade.disable-web', false)) {
107
+        $eventSource->send('failure', (string)$l->t('Please use the command line updater because automatic updating is disabled in the config.php.'));
108
+        $eventSource->close();
109
+        exit();
110
+    }
111
+
112
+    // if a user is currently logged in, their session must be ignored to
113
+    // avoid side effects
114
+    \OC_User::setIncognitoMode(true);
115
+
116
+    $logger = \OC::$server->getLogger();
117
+    $config = \OC::$server->getConfig();
118
+    $updater = new \OC\Updater(
119
+            $config,
120
+            \OC::$server->getIntegrityCodeChecker(),
121
+            $logger,
122
+            \OC::$server->query(\OC\Installer::class),
123
+            \OC::$server->getJobList()
124
+    );
125
+    $incompatibleApps = [];
126
+
127
+    $dispatcher = \OC::$server->getEventDispatcher();
128
+    $dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($eventSource, $l) {
129
+        if ($event instanceof GenericEvent) {
130
+            $eventSource->send('success', (string)$l->t('[%d / %d]: %s', [$event[0], $event[1], $event->getSubject()]));
131
+        }
132
+    });
133
+    $dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($eventSource, $l) {
134
+        if ($event instanceof GenericEvent) {
135
+            $eventSource->send('success', (string)$l->t('[%d / %d]: Checking table %s', [$event[0], $event[1], $event->getSubject()]));
136
+        }
137
+    });
138
+    $feedBack = new FeedBackHandler($eventSource, $l);
139
+    $dispatcher->addListener('\OC\Repair::startProgress', [$feedBack, 'handleRepairFeedback']);
140
+    $dispatcher->addListener('\OC\Repair::advance', [$feedBack, 'handleRepairFeedback']);
141
+    $dispatcher->addListener('\OC\Repair::finishProgress', [$feedBack, 'handleRepairFeedback']);
142
+    $dispatcher->addListener('\OC\Repair::step', [$feedBack, 'handleRepairFeedback']);
143
+    $dispatcher->addListener('\OC\Repair::info', [$feedBack, 'handleRepairFeedback']);
144
+    $dispatcher->addListener('\OC\Repair::warning', [$feedBack, 'handleRepairFeedback']);
145
+    $dispatcher->addListener('\OC\Repair::error', [$feedBack, 'handleRepairFeedback']);
146
+
147
+    $updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($eventSource, $l) {
148
+        $eventSource->send('success', (string)$l->t('Turned on maintenance mode'));
149
+    });
150
+    $updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($eventSource, $l) {
151
+        $eventSource->send('success', (string)$l->t('Turned off maintenance mode'));
152
+    });
153
+    $updater->listen('\OC\Updater', 'maintenanceActive', function () use ($eventSource, $l) {
154
+        $eventSource->send('success', (string)$l->t('Maintenance mode is kept active'));
155
+    });
156
+    $updater->listen('\OC\Updater', 'waitForCronToFinish', function () use ($eventSource, $l) {
157
+        $eventSource->send('success', (string)$l->t('Waiting for cron to finish (checks again in 5 seconds) …'));
158
+    });
159
+    $updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use($eventSource, $l) {
160
+        $eventSource->send('success', (string)$l->t('Updating database schema'));
161
+    });
162
+    $updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l) {
163
+        $eventSource->send('success', (string)$l->t('Updated database'));
164
+    });
165
+    $updater->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($eventSource, $l) {
166
+        $eventSource->send('success', (string)$l->t('Checking whether the database schema can be updated (this can take a long time depending on the database size)'));
167
+    });
168
+    $updater->listen('\OC\Updater', 'dbSimulateUpgrade', function () use ($eventSource, $l) {
169
+        $eventSource->send('success', (string)$l->t('Checked database schema update'));
170
+    });
171
+    $updater->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($eventSource, $l) {
172
+        $eventSource->send('success', (string)$l->t('Checking updates of apps'));
173
+    });
174
+    $updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($eventSource, $l) {
175
+        $eventSource->send('success', (string)$l->t('Checking for update of app "%s" in appstore', [$app]));
176
+    });
177
+    $updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($eventSource, $l) {
178
+        $eventSource->send('success', (string)$l->t('Update app "%s" from appstore', [$app]));
179
+    });
180
+    $updater->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($eventSource, $l) {
181
+        $eventSource->send('success', (string)$l->t('Checked for update of app "%s" in appstore', [$app]));
182
+    });
183
+    $updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($eventSource, $l) {
184
+        $eventSource->send('success', (string)$l->t('Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)', [$app]));
185
+    });
186
+    $updater->listen('\OC\Updater', 'appUpgradeCheck', function () use ($eventSource, $l) {
187
+        $eventSource->send('success', (string)$l->t('Checked database schema update for apps'));
188
+    });
189
+    $updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l) {
190
+        $eventSource->send('success', (string)$l->t('Updated "%1$s" to %2$s', array($app, $version)));
191
+    });
192
+    $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps) {
193
+        $incompatibleApps[]= $app;
194
+    });
195
+    $updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource, $config) {
196
+        $eventSource->send('failure', $message);
197
+        $eventSource->close();
198
+        $config->setSystemValue('maintenance', false);
199
+    });
200
+    $updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use($eventSource, $l) {
201
+        $eventSource->send('success', (string)$l->t('Set log level to debug'));
202
+    });
203
+    $updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($eventSource, $l) {
204
+        $eventSource->send('success', (string)$l->t('Reset log level'));
205
+    });
206
+    $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($eventSource, $l) {
207
+        $eventSource->send('success', (string)$l->t('Starting code integrity check'));
208
+    });
209
+    $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($eventSource, $l) {
210
+        $eventSource->send('success', (string)$l->t('Finished code integrity check'));
211
+    });
212
+
213
+    try {
214
+        $updater->upgrade();
215
+    } catch (\Exception $e) {
216
+        \OC::$server->getLogger()->logException($e, [
217
+            'level' => ILogger::ERROR,
218
+            'app' => 'update',
219
+        ]);
220
+        $eventSource->send('failure', get_class($e) . ': ' . $e->getMessage());
221
+        $eventSource->close();
222
+        exit();
223
+    }
224
+
225
+    $disabledApps = [];
226
+    foreach ($incompatibleApps as $app) {
227
+        $disabledApps[$app] = (string) $l->t('%s (incompatible)', [$app]);
228
+    }
229
+
230
+    if (!empty($disabledApps)) {
231
+        $eventSource->send('notice',
232
+            (string)$l->t('Following apps have been disabled: %s', [implode(', ', $disabledApps)]));
233
+    }
234 234
 } else {
235
-	$eventSource->send('notice', (string)$l->t('Already up to date'));
235
+    $eventSource->send('notice', (string)$l->t('Already up to date'));
236 236
 }
237 237
 
238 238
 $eventSource->send('done', '');
Please login to merge, or discard this patch.
core/templates/loginflow/authpicker.php 1 patch
Indentation   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -31,9 +31,9 @@
 block discarded – undo
31 31
 	<h2><?php p($l->t('Connect to your account')) ?></h2>
32 32
 	<p class="info">
33 33
 		<?php print_unescaped($l->t('Please log in before granting %1$s access to your %2$s account.', [
34
-								'<strong>' . \OCP\Util::sanitizeHTML($_['client']) . '</strong>',
35
-								\OCP\Util::sanitizeHTML($_['instanceName'])
36
-							])) ?>
34
+                                '<strong>' . \OCP\Util::sanitizeHTML($_['client']) . '</strong>',
35
+                                \OCP\Util::sanitizeHTML($_['instanceName'])
36
+                            ])) ?>
37 37
 	</p>
38 38
 
39 39
 	<br/>
Please login to merge, or discard this patch.
core/templates/loginflow/grant.php 1 patch
Indentation   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -31,9 +31,9 @@
 block discarded – undo
31 31
 	<h2><?php p($l->t('Account access')) ?></h2>
32 32
 	<p class="info">
33 33
 		<?php print_unescaped($l->t('You are about to grant %1$s access to your %2$s account.', [
34
-								'<strong>' . \OCP\Util::sanitizeHTML($_['client']) . '</strong>',
35
-								\OCP\Util::sanitizeHTML($_['instanceName'])
36
-							])) ?>
34
+                                '<strong>' . \OCP\Util::sanitizeHTML($_['client']) . '</strong>',
35
+                                \OCP\Util::sanitizeHTML($_['instanceName'])
36
+                            ])) ?>
37 37
 	</p>
38 38
 
39 39
 	<br/>
Please login to merge, or discard this patch.
core/templates/update.admin.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@
 block discarded – undo
4 4
 		<h2 class="title"><?php p($l->t('App update required')); ?></h2>
5 5
 		<?php } else { ?>
6 6
 		<h2 class="title"><?php p($l->t('%1$s will be updated to version %2$s',
7
-			array($_['productName'], $_['version']))); ?></h2>
7
+            array($_['productName'], $_['version']))); ?></h2>
8 8
 		<?php } ?>
9 9
 		<?php if (!empty($_['appsToUpgrade'])) { ?>
10 10
 		<div class="infogroup">
Please login to merge, or discard this patch.
settings/templates/settings/personal/personal.info.php 1 patch
Indentation   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -26,10 +26,10 @@  discard block
 block discarded – undo
26 26
 /** @var array $_ */
27 27
 
28 28
 script('settings', [
29
-	'usersettings',
30
-	'federationsettingsview',
31
-	'federationscopemenu',
32
-	'settings/personalInfo',
29
+    'usersettings',
30
+    'federationsettingsview',
31
+    'federationscopemenu',
32
+    'settings/personalInfo',
33 33
 ]);
34 34
 vendor_script('jcrop/js/jquery.Jcrop');
35 35
 vendor_style('jcrop/css/jquery.Jcrop');
@@ -87,10 +87,10 @@  discard block
 block discarded – undo
87 87
 					<p class="quotatext">
88 88
 						<?php if ($_['quota'] === \OCP\Files\FileInfo::SPACE_UNLIMITED): ?>
89 89
 							<?php print_unescaped($l->t('You are using <strong>%s</strong>',
90
-								[$_['usage']]));?>
90
+                                [$_['usage']]));?>
91 91
 						<?php else: ?>
92 92
 							<?php print_unescaped($l->t('You are using <strong>%1$s</strong> of <strong>%2$s</strong> (<strong>%3$s %%</strong>)',
93
-								[$_['usage'], $_['total_space'],  $_['usage_relative']]));?>
93
+                                [$_['usage'], $_['total_space'],  $_['usage_relative']]));?>
94 94
 						<?php endif ?>
95 95
 					</p>
96 96
 				</div>
@@ -137,17 +137,17 @@  discard block
 block discarded – undo
137 137
 				<div class="verify <?php if ($_['email'] === ''  || $_['emailScope'] !== 'public') p('hidden'); ?>">
138 138
 					<img id="verify-email" title="<?php p($_['emailMessage']); ?>" data-status="<?php p($_['emailVerification']) ?>" src="
139 139
 				<?php
140
-					switch($_['emailVerification']) {
141
-						case \OC\Accounts\AccountManager::VERIFICATION_IN_PROGRESS:
142
-							p(image_path('core', 'actions/verifying.svg'));
143
-							break;
144
-						case \OC\Accounts\AccountManager::VERIFIED:
145
-							p(image_path('core', 'actions/verified.svg'));
146
-							break;
147
-						default:
148
-							p(image_path('core', 'actions/verify.svg'));
149
-					}
150
-					?>">
140
+                    switch($_['emailVerification']) {
141
+                        case \OC\Accounts\AccountManager::VERIFICATION_IN_PROGRESS:
142
+                            p(image_path('core', 'actions/verifying.svg'));
143
+                            break;
144
+                        case \OC\Accounts\AccountManager::VERIFIED:
145
+                            p(image_path('core', 'actions/verified.svg'));
146
+                            break;
147
+                        default:
148
+                            p(image_path('core', 'actions/verify.svg'));
149
+                    }
150
+                    ?>">
151 151
 				</div>
152 152
 				<input type="email" name="email" id="email" value="<?php p($_['email']); ?>"
153 153
 					<?php if(!$_['displayNameChangeSupported']) { print_unescaped('class="hidden"'); } ?>
@@ -225,17 +225,17 @@  discard block
 block discarded – undo
225 225
 				<div class="verify <?php if ($_['website'] === ''  || $_['websiteScope'] !== 'public') p('hidden'); ?>">
226 226
 					<img id="verify-website" title="<?php p($_['websiteMessage']); ?>" data-status="<?php p($_['websiteVerification']) ?>" src="
227 227
 					<?php
228
-					switch($_['websiteVerification']) {
229
-						case \OC\Accounts\AccountManager::VERIFICATION_IN_PROGRESS:
230
-							p(image_path('core', 'actions/verifying.svg'));
231
-							break;
232
-						case \OC\Accounts\AccountManager::VERIFIED:
233
-							p(image_path('core', 'actions/verified.svg'));
234
-							break;
235
-						default:
236
-							p(image_path('core', 'actions/verify.svg'));
237
-					}
238
-					?>"
228
+                    switch($_['websiteVerification']) {
229
+                        case \OC\Accounts\AccountManager::VERIFICATION_IN_PROGRESS:
230
+                            p(image_path('core', 'actions/verifying.svg'));
231
+                            break;
232
+                        case \OC\Accounts\AccountManager::VERIFIED:
233
+                            p(image_path('core', 'actions/verified.svg'));
234
+                            break;
235
+                        default:
236
+                            p(image_path('core', 'actions/verify.svg'));
237
+                    }
238
+                    ?>"
239 239
 					<?php if($_['websiteVerification'] === \OC\Accounts\AccountManager::VERIFICATION_IN_PROGRESS || $_['websiteVerification'] === \OC\Accounts\AccountManager::NOT_VERIFIED) print_unescaped(' class="verify-action"') ?>
240 240
 					>
241 241
 					<div class="verification-dialog popovermenu bubble menu">
@@ -274,17 +274,17 @@  discard block
 block discarded – undo
274 274
 				<div class="verify <?php if ($_['twitter'] === ''  || $_['twitterScope'] !== 'public') p('hidden'); ?>">
275 275
 					<img id="verify-twitter" title="<?php p($_['twitterMessage']); ?>" data-status="<?php p($_['twitterVerification']) ?>" src="
276 276
 					<?php
277
-					switch($_['twitterVerification']) {
278
-						case \OC\Accounts\AccountManager::VERIFICATION_IN_PROGRESS:
279
-							p(image_path('core', 'actions/verifying.svg'));
280
-							break;
281
-						case \OC\Accounts\AccountManager::VERIFIED:
282
-							p(image_path('core', 'actions/verified.svg'));
283
-							break;
284
-						default:
285
-							p(image_path('core', 'actions/verify.svg'));
286
-					}
287
-					?>"
277
+                    switch($_['twitterVerification']) {
278
+                        case \OC\Accounts\AccountManager::VERIFICATION_IN_PROGRESS:
279
+                            p(image_path('core', 'actions/verifying.svg'));
280
+                            break;
281
+                        case \OC\Accounts\AccountManager::VERIFIED:
282
+                            p(image_path('core', 'actions/verified.svg'));
283
+                            break;
284
+                        default:
285
+                            p(image_path('core', 'actions/verify.svg'));
286
+                    }
287
+                    ?>"
288 288
 					<?php if($_['twitterVerification'] === \OC\Accounts\AccountManager::VERIFICATION_IN_PROGRESS || $_['twitterVerification'] === \OC\Accounts\AccountManager::NOT_VERIFIED) print_unescaped(' class="verify-action"') ?>
289 289
 					>
290 290
 					<div class="verification-dialog popovermenu bubble menu">
Please login to merge, or discard this patch.
settings/Controller/CheckSetupController.php 1 patch
Indentation   +553 added lines, -553 removed lines patch added patch discarded remove patch
@@ -63,294 +63,294 @@  discard block
 block discarded – undo
63 63
  * @package OC\Settings\Controller
64 64
  */
65 65
 class CheckSetupController extends Controller {
66
-	/** @var IConfig */
67
-	private $config;
68
-	/** @var IClientService */
69
-	private $clientService;
70
-	/** @var \OC_Util */
71
-	private $util;
72
-	/** @var IURLGenerator */
73
-	private $urlGenerator;
74
-	/** @var IL10N */
75
-	private $l10n;
76
-	/** @var Checker */
77
-	private $checker;
78
-	/** @var ILogger */
79
-	private $logger;
80
-	/** @var EventDispatcherInterface */
81
-	private $dispatcher;
82
-	/** @var IDBConnection|Connection */
83
-	private $db;
84
-	/** @var ILockingProvider */
85
-	private $lockingProvider;
86
-	/** @var IDateTimeFormatter */
87
-	private $dateTimeFormatter;
88
-	/** @var MemoryInfo */
89
-	private $memoryInfo;
90
-	/** @var ISecureRandom */
91
-	private $secureRandom;
92
-
93
-	public function __construct($AppName,
94
-								IRequest $request,
95
-								IConfig $config,
96
-								IClientService $clientService,
97
-								IURLGenerator $urlGenerator,
98
-								\OC_Util $util,
99
-								IL10N $l10n,
100
-								Checker $checker,
101
-								ILogger $logger,
102
-								EventDispatcherInterface $dispatcher,
103
-								IDBConnection $db,
104
-								ILockingProvider $lockingProvider,
105
-								IDateTimeFormatter $dateTimeFormatter,
106
-								MemoryInfo $memoryInfo,
107
-								ISecureRandom $secureRandom) {
108
-		parent::__construct($AppName, $request);
109
-		$this->config = $config;
110
-		$this->clientService = $clientService;
111
-		$this->util = $util;
112
-		$this->urlGenerator = $urlGenerator;
113
-		$this->l10n = $l10n;
114
-		$this->checker = $checker;
115
-		$this->logger = $logger;
116
-		$this->dispatcher = $dispatcher;
117
-		$this->db = $db;
118
-		$this->lockingProvider = $lockingProvider;
119
-		$this->dateTimeFormatter = $dateTimeFormatter;
120
-		$this->memoryInfo = $memoryInfo;
121
-		$this->secureRandom = $secureRandom;
122
-	}
123
-
124
-	/**
125
-	 * Checks if the server can connect to the internet using HTTPS and HTTP
126
-	 * @return bool
127
-	 */
128
-	private function isInternetConnectionWorking() {
129
-		if ($this->config->getSystemValue('has_internet_connection', true) === false) {
130
-			return false;
131
-		}
132
-
133
-		$siteArray = ['www.nextcloud.com',
134
-						'www.startpage.com',
135
-						'www.eff.org',
136
-						'www.edri.org',
137
-			];
138
-
139
-		foreach($siteArray as $site) {
140
-			if ($this->isSiteReachable($site)) {
141
-				return true;
142
-			}
143
-		}
144
-		return false;
145
-	}
146
-
147
-	/**
148
-	* Checks if the Nextcloud server can connect to a specific URL using both HTTPS and HTTP
149
-	* @return bool
150
-	*/
151
-	private function isSiteReachable($sitename) {
152
-		$httpSiteName = 'http://' . $sitename . '/';
153
-		$httpsSiteName = 'https://' . $sitename . '/';
154
-
155
-		try {
156
-			$client = $this->clientService->newClient();
157
-			$client->get($httpSiteName);
158
-			$client->get($httpsSiteName);
159
-		} catch (\Exception $e) {
160
-			$this->logger->logException($e, ['app' => 'internet_connection_check']);
161
-			return false;
162
-		}
163
-		return true;
164
-	}
165
-
166
-	/**
167
-	 * Checks whether a local memcache is installed or not
168
-	 * @return bool
169
-	 */
170
-	private function isMemcacheConfigured() {
171
-		return $this->config->getSystemValue('memcache.local', null) !== null;
172
-	}
173
-
174
-	/**
175
-	 * Whether PHP can generate "secure" pseudorandom integers
176
-	 *
177
-	 * @return bool
178
-	 */
179
-	private function isRandomnessSecure() {
180
-		try {
181
-			$this->secureRandom->generate(1);
182
-		} catch (\Exception $ex) {
183
-			return false;
184
-		}
185
-		return true;
186
-	}
187
-
188
-	/**
189
-	 * Public for the sake of unit-testing
190
-	 *
191
-	 * @return array
192
-	 */
193
-	protected function getCurlVersion() {
194
-		return curl_version();
195
-	}
196
-
197
-	/**
198
-	 * Check if the used  SSL lib is outdated. Older OpenSSL and NSS versions do
199
-	 * have multiple bugs which likely lead to problems in combination with
200
-	 * functionality required by ownCloud such as SNI.
201
-	 *
202
-	 * @link https://github.com/owncloud/core/issues/17446#issuecomment-122877546
203
-	 * @link https://bugzilla.redhat.com/show_bug.cgi?id=1241172
204
-	 * @return string
205
-	 */
206
-	private function isUsedTlsLibOutdated() {
207
-		// Don't run check when:
208
-		// 1. Server has `has_internet_connection` set to false
209
-		// 2. AppStore AND S2S is disabled
210
-		if(!$this->config->getSystemValue('has_internet_connection', true)) {
211
-			return '';
212
-		}
213
-		if(!$this->config->getSystemValue('appstoreenabled', true)
214
-			&& $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'no'
215
-			&& $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'no') {
216
-			return '';
217
-		}
218
-
219
-		$versionString = $this->getCurlVersion();
220
-		if(isset($versionString['ssl_version'])) {
221
-			$versionString = $versionString['ssl_version'];
222
-		} else {
223
-			return '';
224
-		}
225
-
226
-		$features = (string)$this->l10n->t('installing and updating apps via the app store or Federated Cloud Sharing');
227
-		if(!$this->config->getSystemValue('appstoreenabled', true)) {
228
-			$features = (string)$this->l10n->t('Federated Cloud Sharing');
229
-		}
230
-
231
-		// Check if at least OpenSSL after 1.01d or 1.0.2b
232
-		if(strpos($versionString, 'OpenSSL/') === 0) {
233
-			$majorVersion = substr($versionString, 8, 5);
234
-			$patchRelease = substr($versionString, 13, 6);
235
-
236
-			if(($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
237
-				($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) {
238
-				return $this->l10n->t('cURL is using an outdated %1$s version (%2$s). Please update your operating system or features such as %3$s will not work reliably.', ['OpenSSL', $versionString, $features]);
239
-			}
240
-		}
241
-
242
-		// Check if NSS and perform heuristic check
243
-		if(strpos($versionString, 'NSS/') === 0) {
244
-			try {
245
-				$firstClient = $this->clientService->newClient();
246
-				$firstClient->get('https://nextcloud.com/');
247
-
248
-				$secondClient = $this->clientService->newClient();
249
-				$secondClient->get('https://nextcloud.com/');
250
-			} catch (ClientException $e) {
251
-				if($e->getResponse()->getStatusCode() === 400) {
252
-					return $this->l10n->t('cURL is using an outdated %1$s version (%2$s). Please update your operating system or features such as %3$s will not work reliably.', ['NSS', $versionString, $features]);
253
-				}
254
-			}
255
-		}
256
-
257
-		return '';
258
-	}
259
-
260
-	/**
261
-	 * Whether the version is outdated
262
-	 *
263
-	 * @return bool
264
-	 */
265
-	protected function isPhpOutdated() {
266
-		if (version_compare(PHP_VERSION, '7.0.0', '<')) {
267
-			return true;
268
-		}
269
-
270
-		return false;
271
-	}
272
-
273
-	/**
274
-	 * Whether the php version is still supported (at time of release)
275
-	 * according to: https://secure.php.net/supported-versions.php
276
-	 *
277
-	 * @return array
278
-	 */
279
-	private function isPhpSupported() {
280
-		return ['eol' => $this->isPhpOutdated(), 'version' => PHP_VERSION];
281
-	}
282
-
283
-	/**
284
-	 * Check if the reverse proxy configuration is working as expected
285
-	 *
286
-	 * @return bool
287
-	 */
288
-	private function forwardedForHeadersWorking() {
289
-		$trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
290
-		$remoteAddress = $this->request->getRemoteAddress();
291
-
292
-		if (is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) {
293
-			return false;
294
-		}
295
-
296
-		// either not enabled or working correctly
297
-		return true;
298
-	}
299
-
300
-	/**
301
-	 * Checks if the correct memcache module for PHP is installed. Only
302
-	 * fails if memcached is configured and the working module is not installed.
303
-	 *
304
-	 * @return bool
305
-	 */
306
-	private function isCorrectMemcachedPHPModuleInstalled() {
307
-		if ($this->config->getSystemValue('memcache.distributed', null) !== '\OC\Memcache\Memcached') {
308
-			return true;
309
-		}
310
-
311
-		// there are two different memcached modules for PHP
312
-		// we only support memcached and not memcache
313
-		// https://code.google.com/p/memcached/wiki/PHPClientComparison
314
-		return !(!extension_loaded('memcached') && extension_loaded('memcache'));
315
-	}
316
-
317
-	/**
318
-	 * Checks if set_time_limit is not disabled.
319
-	 *
320
-	 * @return bool
321
-	 */
322
-	private function isSettimelimitAvailable() {
323
-		if (function_exists('set_time_limit')
324
-			&& strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
325
-			return true;
326
-		}
327
-
328
-		return false;
329
-	}
330
-
331
-	/**
332
-	 * @return RedirectResponse
333
-	 */
334
-	public function rescanFailedIntegrityCheck() {
335
-		$this->checker->runInstanceVerification();
336
-		return new RedirectResponse(
337
-			$this->urlGenerator->linkToRoute('settings.AdminSettings.index')
338
-		);
339
-	}
340
-
341
-	/**
342
-	 * @NoCSRFRequired
343
-	 * @return DataResponse
344
-	 */
345
-	public function getFailedIntegrityCheckFiles() {
346
-		if(!$this->checker->isCodeCheckEnforced()) {
347
-			return new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.');
348
-		}
349
-
350
-		$completeResults = $this->checker->getResults();
351
-
352
-		if(!empty($completeResults)) {
353
-			$formattedTextResponse = 'Technical information
66
+    /** @var IConfig */
67
+    private $config;
68
+    /** @var IClientService */
69
+    private $clientService;
70
+    /** @var \OC_Util */
71
+    private $util;
72
+    /** @var IURLGenerator */
73
+    private $urlGenerator;
74
+    /** @var IL10N */
75
+    private $l10n;
76
+    /** @var Checker */
77
+    private $checker;
78
+    /** @var ILogger */
79
+    private $logger;
80
+    /** @var EventDispatcherInterface */
81
+    private $dispatcher;
82
+    /** @var IDBConnection|Connection */
83
+    private $db;
84
+    /** @var ILockingProvider */
85
+    private $lockingProvider;
86
+    /** @var IDateTimeFormatter */
87
+    private $dateTimeFormatter;
88
+    /** @var MemoryInfo */
89
+    private $memoryInfo;
90
+    /** @var ISecureRandom */
91
+    private $secureRandom;
92
+
93
+    public function __construct($AppName,
94
+                                IRequest $request,
95
+                                IConfig $config,
96
+                                IClientService $clientService,
97
+                                IURLGenerator $urlGenerator,
98
+                                \OC_Util $util,
99
+                                IL10N $l10n,
100
+                                Checker $checker,
101
+                                ILogger $logger,
102
+                                EventDispatcherInterface $dispatcher,
103
+                                IDBConnection $db,
104
+                                ILockingProvider $lockingProvider,
105
+                                IDateTimeFormatter $dateTimeFormatter,
106
+                                MemoryInfo $memoryInfo,
107
+                                ISecureRandom $secureRandom) {
108
+        parent::__construct($AppName, $request);
109
+        $this->config = $config;
110
+        $this->clientService = $clientService;
111
+        $this->util = $util;
112
+        $this->urlGenerator = $urlGenerator;
113
+        $this->l10n = $l10n;
114
+        $this->checker = $checker;
115
+        $this->logger = $logger;
116
+        $this->dispatcher = $dispatcher;
117
+        $this->db = $db;
118
+        $this->lockingProvider = $lockingProvider;
119
+        $this->dateTimeFormatter = $dateTimeFormatter;
120
+        $this->memoryInfo = $memoryInfo;
121
+        $this->secureRandom = $secureRandom;
122
+    }
123
+
124
+    /**
125
+     * Checks if the server can connect to the internet using HTTPS and HTTP
126
+     * @return bool
127
+     */
128
+    private function isInternetConnectionWorking() {
129
+        if ($this->config->getSystemValue('has_internet_connection', true) === false) {
130
+            return false;
131
+        }
132
+
133
+        $siteArray = ['www.nextcloud.com',
134
+                        'www.startpage.com',
135
+                        'www.eff.org',
136
+                        'www.edri.org',
137
+            ];
138
+
139
+        foreach($siteArray as $site) {
140
+            if ($this->isSiteReachable($site)) {
141
+                return true;
142
+            }
143
+        }
144
+        return false;
145
+    }
146
+
147
+    /**
148
+     * Checks if the Nextcloud server can connect to a specific URL using both HTTPS and HTTP
149
+     * @return bool
150
+     */
151
+    private function isSiteReachable($sitename) {
152
+        $httpSiteName = 'http://' . $sitename . '/';
153
+        $httpsSiteName = 'https://' . $sitename . '/';
154
+
155
+        try {
156
+            $client = $this->clientService->newClient();
157
+            $client->get($httpSiteName);
158
+            $client->get($httpsSiteName);
159
+        } catch (\Exception $e) {
160
+            $this->logger->logException($e, ['app' => 'internet_connection_check']);
161
+            return false;
162
+        }
163
+        return true;
164
+    }
165
+
166
+    /**
167
+     * Checks whether a local memcache is installed or not
168
+     * @return bool
169
+     */
170
+    private function isMemcacheConfigured() {
171
+        return $this->config->getSystemValue('memcache.local', null) !== null;
172
+    }
173
+
174
+    /**
175
+     * Whether PHP can generate "secure" pseudorandom integers
176
+     *
177
+     * @return bool
178
+     */
179
+    private function isRandomnessSecure() {
180
+        try {
181
+            $this->secureRandom->generate(1);
182
+        } catch (\Exception $ex) {
183
+            return false;
184
+        }
185
+        return true;
186
+    }
187
+
188
+    /**
189
+     * Public for the sake of unit-testing
190
+     *
191
+     * @return array
192
+     */
193
+    protected function getCurlVersion() {
194
+        return curl_version();
195
+    }
196
+
197
+    /**
198
+     * Check if the used  SSL lib is outdated. Older OpenSSL and NSS versions do
199
+     * have multiple bugs which likely lead to problems in combination with
200
+     * functionality required by ownCloud such as SNI.
201
+     *
202
+     * @link https://github.com/owncloud/core/issues/17446#issuecomment-122877546
203
+     * @link https://bugzilla.redhat.com/show_bug.cgi?id=1241172
204
+     * @return string
205
+     */
206
+    private function isUsedTlsLibOutdated() {
207
+        // Don't run check when:
208
+        // 1. Server has `has_internet_connection` set to false
209
+        // 2. AppStore AND S2S is disabled
210
+        if(!$this->config->getSystemValue('has_internet_connection', true)) {
211
+            return '';
212
+        }
213
+        if(!$this->config->getSystemValue('appstoreenabled', true)
214
+            && $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'no'
215
+            && $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'no') {
216
+            return '';
217
+        }
218
+
219
+        $versionString = $this->getCurlVersion();
220
+        if(isset($versionString['ssl_version'])) {
221
+            $versionString = $versionString['ssl_version'];
222
+        } else {
223
+            return '';
224
+        }
225
+
226
+        $features = (string)$this->l10n->t('installing and updating apps via the app store or Federated Cloud Sharing');
227
+        if(!$this->config->getSystemValue('appstoreenabled', true)) {
228
+            $features = (string)$this->l10n->t('Federated Cloud Sharing');
229
+        }
230
+
231
+        // Check if at least OpenSSL after 1.01d or 1.0.2b
232
+        if(strpos($versionString, 'OpenSSL/') === 0) {
233
+            $majorVersion = substr($versionString, 8, 5);
234
+            $patchRelease = substr($versionString, 13, 6);
235
+
236
+            if(($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
237
+                ($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) {
238
+                return $this->l10n->t('cURL is using an outdated %1$s version (%2$s). Please update your operating system or features such as %3$s will not work reliably.', ['OpenSSL', $versionString, $features]);
239
+            }
240
+        }
241
+
242
+        // Check if NSS and perform heuristic check
243
+        if(strpos($versionString, 'NSS/') === 0) {
244
+            try {
245
+                $firstClient = $this->clientService->newClient();
246
+                $firstClient->get('https://nextcloud.com/');
247
+
248
+                $secondClient = $this->clientService->newClient();
249
+                $secondClient->get('https://nextcloud.com/');
250
+            } catch (ClientException $e) {
251
+                if($e->getResponse()->getStatusCode() === 400) {
252
+                    return $this->l10n->t('cURL is using an outdated %1$s version (%2$s). Please update your operating system or features such as %3$s will not work reliably.', ['NSS', $versionString, $features]);
253
+                }
254
+            }
255
+        }
256
+
257
+        return '';
258
+    }
259
+
260
+    /**
261
+     * Whether the version is outdated
262
+     *
263
+     * @return bool
264
+     */
265
+    protected function isPhpOutdated() {
266
+        if (version_compare(PHP_VERSION, '7.0.0', '<')) {
267
+            return true;
268
+        }
269
+
270
+        return false;
271
+    }
272
+
273
+    /**
274
+     * Whether the php version is still supported (at time of release)
275
+     * according to: https://secure.php.net/supported-versions.php
276
+     *
277
+     * @return array
278
+     */
279
+    private function isPhpSupported() {
280
+        return ['eol' => $this->isPhpOutdated(), 'version' => PHP_VERSION];
281
+    }
282
+
283
+    /**
284
+     * Check if the reverse proxy configuration is working as expected
285
+     *
286
+     * @return bool
287
+     */
288
+    private function forwardedForHeadersWorking() {
289
+        $trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
290
+        $remoteAddress = $this->request->getRemoteAddress();
291
+
292
+        if (is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) {
293
+            return false;
294
+        }
295
+
296
+        // either not enabled or working correctly
297
+        return true;
298
+    }
299
+
300
+    /**
301
+     * Checks if the correct memcache module for PHP is installed. Only
302
+     * fails if memcached is configured and the working module is not installed.
303
+     *
304
+     * @return bool
305
+     */
306
+    private function isCorrectMemcachedPHPModuleInstalled() {
307
+        if ($this->config->getSystemValue('memcache.distributed', null) !== '\OC\Memcache\Memcached') {
308
+            return true;
309
+        }
310
+
311
+        // there are two different memcached modules for PHP
312
+        // we only support memcached and not memcache
313
+        // https://code.google.com/p/memcached/wiki/PHPClientComparison
314
+        return !(!extension_loaded('memcached') && extension_loaded('memcache'));
315
+    }
316
+
317
+    /**
318
+     * Checks if set_time_limit is not disabled.
319
+     *
320
+     * @return bool
321
+     */
322
+    private function isSettimelimitAvailable() {
323
+        if (function_exists('set_time_limit')
324
+            && strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
325
+            return true;
326
+        }
327
+
328
+        return false;
329
+    }
330
+
331
+    /**
332
+     * @return RedirectResponse
333
+     */
334
+    public function rescanFailedIntegrityCheck() {
335
+        $this->checker->runInstanceVerification();
336
+        return new RedirectResponse(
337
+            $this->urlGenerator->linkToRoute('settings.AdminSettings.index')
338
+        );
339
+    }
340
+
341
+    /**
342
+     * @NoCSRFRequired
343
+     * @return DataResponse
344
+     */
345
+    public function getFailedIntegrityCheckFiles() {
346
+        if(!$this->checker->isCodeCheckEnforced()) {
347
+            return new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.');
348
+        }
349
+
350
+        $completeResults = $this->checker->getResults();
351
+
352
+        if(!empty($completeResults)) {
353
+            $formattedTextResponse = 'Technical information
354 354
 =====================
355 355
 The following list covers which files have failed the integrity check. Please read
356 356
 the previous linked documentation to learn more about the errors and how to fix
@@ -359,272 +359,272 @@  discard block
 block discarded – undo
359 359
 Results
360 360
 =======
361 361
 ';
362
-			foreach($completeResults as $context => $contextResult) {
363
-				$formattedTextResponse .= "- $context\n";
364
-
365
-				foreach($contextResult as $category => $result) {
366
-					$formattedTextResponse .= "\t- $category\n";
367
-					if($category !== 'EXCEPTION') {
368
-						foreach ($result as $key => $results) {
369
-							$formattedTextResponse .= "\t\t- $key\n";
370
-						}
371
-					} else {
372
-						foreach ($result as $key => $results) {
373
-							$formattedTextResponse .= "\t\t- $results\n";
374
-						}
375
-					}
376
-
377
-				}
378
-			}
379
-
380
-			$formattedTextResponse .= '
362
+            foreach($completeResults as $context => $contextResult) {
363
+                $formattedTextResponse .= "- $context\n";
364
+
365
+                foreach($contextResult as $category => $result) {
366
+                    $formattedTextResponse .= "\t- $category\n";
367
+                    if($category !== 'EXCEPTION') {
368
+                        foreach ($result as $key => $results) {
369
+                            $formattedTextResponse .= "\t\t- $key\n";
370
+                        }
371
+                    } else {
372
+                        foreach ($result as $key => $results) {
373
+                            $formattedTextResponse .= "\t\t- $results\n";
374
+                        }
375
+                    }
376
+
377
+                }
378
+            }
379
+
380
+            $formattedTextResponse .= '
381 381
 Raw output
382 382
 ==========
383 383
 ';
384
-			$formattedTextResponse .= print_r($completeResults, true);
385
-		} else {
386
-			$formattedTextResponse = 'No errors have been found.';
387
-		}
388
-
389
-
390
-		$response = new DataDisplayResponse(
391
-			$formattedTextResponse,
392
-			Http::STATUS_OK,
393
-			[
394
-				'Content-Type' => 'text/plain',
395
-			]
396
-		);
397
-
398
-		return $response;
399
-	}
400
-
401
-	/**
402
-	 * Checks whether a PHP opcache is properly set up
403
-	 * @return bool
404
-	 */
405
-	protected function isOpcacheProperlySetup() {
406
-		$iniWrapper = new IniGetWrapper();
407
-
408
-		if(!$iniWrapper->getBool('opcache.enable')) {
409
-			return false;
410
-		}
411
-
412
-		if(!$iniWrapper->getBool('opcache.save_comments')) {
413
-			return false;
414
-		}
415
-
416
-		if(!$iniWrapper->getBool('opcache.enable_cli')) {
417
-			return false;
418
-		}
419
-
420
-		if($iniWrapper->getNumeric('opcache.max_accelerated_files') < 10000) {
421
-			return false;
422
-		}
423
-
424
-		if($iniWrapper->getNumeric('opcache.memory_consumption') < 128) {
425
-			return false;
426
-		}
427
-
428
-		if($iniWrapper->getNumeric('opcache.interned_strings_buffer') < 8) {
429
-			return false;
430
-		}
431
-
432
-		return true;
433
-	}
434
-
435
-	/**
436
-	 * Check if the required FreeType functions are present
437
-	 * @return bool
438
-	 */
439
-	protected function hasFreeTypeSupport() {
440
-		return function_exists('imagettfbbox') && function_exists('imagettftext');
441
-	}
442
-
443
-	protected function hasMissingIndexes(): array {
444
-		$indexInfo = new MissingIndexInformation();
445
-		// Dispatch event so apps can also hint for pending index updates if needed
446
-		$event = new GenericEvent($indexInfo);
447
-		$this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_INDEXES_EVENT, $event);
448
-
449
-		return $indexInfo->getListOfMissingIndexes();
450
-	}
451
-
452
-	/**
453
-	 * warn if outdated version of a memcache module is used
454
-	 */
455
-	protected function getOutdatedCaches(): array {
456
-		$caches = [
457
-			'apcu'	=> ['name' => 'APCu', 'version' => '4.0.6'],
458
-			'redis'	=> ['name' => 'Redis', 'version' => '2.2.5'],
459
-		];
460
-		$outdatedCaches = [];
461
-		foreach ($caches as $php_module => $data) {
462
-			$isOutdated = extension_loaded($php_module) && version_compare(phpversion($php_module), $data['version'], '<');
463
-			if ($isOutdated) {
464
-				$outdatedCaches[] = $data;
465
-			}
466
-		}
467
-
468
-		return $outdatedCaches;
469
-	}
470
-
471
-	protected function isSqliteUsed() {
472
-		return strpos($this->config->getSystemValue('dbtype'), 'sqlite') !== false;
473
-	}
474
-
475
-	protected function isReadOnlyConfig(): bool {
476
-		return \OC_Helper::isReadOnlyConfigEnabled();
477
-	}
478
-
479
-	protected function hasValidTransactionIsolationLevel(): bool {
480
-		try {
481
-			if ($this->db->getDatabasePlatform() instanceof SqlitePlatform) {
482
-				return true;
483
-			}
484
-
485
-			return $this->db->getTransactionIsolation() === Connection::TRANSACTION_READ_COMMITTED;
486
-		} catch (DBALException $e) {
487
-			// ignore
488
-		}
489
-
490
-		return true;
491
-	}
492
-
493
-	protected function hasFileinfoInstalled(): bool {
494
-		return \OC_Util::fileInfoLoaded();
495
-	}
496
-
497
-	protected function hasWorkingFileLocking(): bool {
498
-		return !($this->lockingProvider instanceof NoopLockingProvider);
499
-	}
500
-
501
-	protected function getSuggestedOverwriteCliURL(): string {
502
-		$suggestedOverwriteCliUrl = '';
503
-		if ($this->config->getSystemValue('overwrite.cli.url', '') === '') {
504
-			$suggestedOverwriteCliUrl = $this->request->getServerProtocol() . '://' . $this->request->getInsecureServerHost() . \OC::$WEBROOT;
505
-			if (!$this->config->getSystemValue('config_is_read_only', false)) {
506
-				// Set the overwrite URL when it was not set yet.
507
-				$this->config->setSystemValue('overwrite.cli.url', $suggestedOverwriteCliUrl);
508
-				$suggestedOverwriteCliUrl = '';
509
-			}
510
-		}
511
-		return $suggestedOverwriteCliUrl;
512
-	}
513
-
514
-	protected function getLastCronInfo(): array {
515
-		$lastCronRun = $this->config->getAppValue('core', 'lastcron', 0);
516
-		return [
517
-			'diffInSeconds' => time() - $lastCronRun,
518
-			'relativeTime' => $this->dateTimeFormatter->formatTimeSpan($lastCronRun),
519
-			'backgroundJobsUrl' => $this->urlGenerator->linkToRoute('settings.AdminSettings.index', ['section' => 'server']) . '#backgroundjobs',
520
-		];
521
-	}
522
-
523
-	protected function getCronErrors() {
524
-		$errors = json_decode($this->config->getAppValue('core', 'cronErrors', ''), true);
525
-
526
-		if (is_array($errors)) {
527
-			return $errors;
528
-		}
529
-
530
-		return [];
531
-	}
532
-
533
-	protected function isPhpMailerUsed(): bool {
534
-		return $this->config->getSystemValue('mail_smtpmode', 'php') === 'php';
535
-	}
536
-
537
-	protected function hasOpcacheLoaded(): bool {
538
-		return function_exists('opcache_get_status');
539
-	}
540
-
541
-	/**
542
-	 * Iterates through the configured app roots and
543
-	 * tests if the subdirectories are owned by the same user than the current user.
544
-	 *
545
-	 * @return array
546
-	 */
547
-	protected function getAppDirsWithDifferentOwner(): array {
548
-		$currentUser = posix_getuid();
549
-		$appDirsWithDifferentOwner = [[]];
550
-
551
-		foreach (OC::$APPSROOTS as $appRoot) {
552
-			if ($appRoot['writable'] === true) {
553
-				$appDirsWithDifferentOwner[] = $this->getAppDirsWithDifferentOwnerForAppRoot($currentUser, $appRoot);
554
-			}
555
-		}
556
-
557
-		$appDirsWithDifferentOwner = array_merge(...$appDirsWithDifferentOwner);
558
-		sort($appDirsWithDifferentOwner);
559
-
560
-		return $appDirsWithDifferentOwner;
561
-	}
562
-
563
-	/**
564
-	 * Tests if the directories for one apps directory are writable by the current user.
565
-	 *
566
-	 * @param int $currentUser The current user
567
-	 * @param array $appRoot The app root config
568
-	 * @return string[] The none writable directory paths inside the app root
569
-	 */
570
-	private function getAppDirsWithDifferentOwnerForAppRoot(int $currentUser, array $appRoot): array {
571
-		$appDirsWithDifferentOwner = [];
572
-		$appsPath = $appRoot['path'];
573
-		$appsDir = new DirectoryIterator($appRoot['path']);
574
-
575
-		foreach ($appsDir as $fileInfo) {
576
-			if ($fileInfo->isDir() && !$fileInfo->isDot()) {
577
-				$absAppPath = $appsPath . DIRECTORY_SEPARATOR . $fileInfo->getFilename();
578
-				$appDirUser = fileowner($absAppPath);
579
-				if ($appDirUser !== $currentUser) {
580
-					$appDirsWithDifferentOwner[] = $absAppPath;
581
-				}
582
-			}
583
-		}
584
-
585
-		return $appDirsWithDifferentOwner;
586
-	}
587
-
588
-	/**
589
-	 * @return DataResponse
590
-	 */
591
-	public function check() {
592
-		return new DataResponse(
593
-			[
594
-				'isGetenvServerWorking' => !empty(getenv('PATH')),
595
-				'isReadOnlyConfig' => $this->isReadOnlyConfig(),
596
-				'hasValidTransactionIsolationLevel' => $this->hasValidTransactionIsolationLevel(),
597
-				'outdatedCaches' => $this->getOutdatedCaches(),
598
-				'hasFileinfoInstalled' => $this->hasFileinfoInstalled(),
599
-				'hasWorkingFileLocking' => $this->hasWorkingFileLocking(),
600
-				'suggestedOverwriteCliURL' => $this->getSuggestedOverwriteCliURL(),
601
-				'cronInfo' => $this->getLastCronInfo(),
602
-				'cronErrors' => $this->getCronErrors(),
603
-				'serverHasInternetConnection' => $this->isInternetConnectionWorking(),
604
-				'isMemcacheConfigured' => $this->isMemcacheConfigured(),
605
-				'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
606
-				'isRandomnessSecure' => $this->isRandomnessSecure(),
607
-				'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'),
608
-				'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(),
609
-				'phpSupported' => $this->isPhpSupported(),
610
-				'forwardedForHeadersWorking' => $this->forwardedForHeadersWorking(),
611
-				'reverseProxyDocs' => $this->urlGenerator->linkToDocs('admin-reverse-proxy'),
612
-				'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled(),
613
-				'hasPassedCodeIntegrityCheck' => $this->checker->hasPassedCheck(),
614
-				'codeIntegrityCheckerDocumentation' => $this->urlGenerator->linkToDocs('admin-code-integrity'),
615
-				'isOpcacheProperlySetup' => $this->isOpcacheProperlySetup(),
616
-				'hasOpcacheLoaded' => $this->hasOpcacheLoaded(),
617
-				'phpOpcacheDocumentation' => $this->urlGenerator->linkToDocs('admin-php-opcache'),
618
-				'isSettimelimitAvailable' => $this->isSettimelimitAvailable(),
619
-				'hasFreeTypeSupport' => $this->hasFreeTypeSupport(),
620
-				'missingIndexes' => $this->hasMissingIndexes(),
621
-				'isSqliteUsed' => $this->isSqliteUsed(),
622
-				'databaseConversionDocumentation' => $this->urlGenerator->linkToDocs('admin-db-conversion'),
623
-				'isPhpMailerUsed' => $this->isPhpMailerUsed(),
624
-				'mailSettingsDocumentation' => $this->urlGenerator->getAbsoluteURL('index.php/settings/admin'),
625
-				'isMemoryLimitSufficient' => $this->memoryInfo->isMemoryLimitSufficient(),
626
-				'appDirsWithDifferentOwner' => $this->getAppDirsWithDifferentOwner(),
627
-			]
628
-		);
629
-	}
384
+            $formattedTextResponse .= print_r($completeResults, true);
385
+        } else {
386
+            $formattedTextResponse = 'No errors have been found.';
387
+        }
388
+
389
+
390
+        $response = new DataDisplayResponse(
391
+            $formattedTextResponse,
392
+            Http::STATUS_OK,
393
+            [
394
+                'Content-Type' => 'text/plain',
395
+            ]
396
+        );
397
+
398
+        return $response;
399
+    }
400
+
401
+    /**
402
+     * Checks whether a PHP opcache is properly set up
403
+     * @return bool
404
+     */
405
+    protected function isOpcacheProperlySetup() {
406
+        $iniWrapper = new IniGetWrapper();
407
+
408
+        if(!$iniWrapper->getBool('opcache.enable')) {
409
+            return false;
410
+        }
411
+
412
+        if(!$iniWrapper->getBool('opcache.save_comments')) {
413
+            return false;
414
+        }
415
+
416
+        if(!$iniWrapper->getBool('opcache.enable_cli')) {
417
+            return false;
418
+        }
419
+
420
+        if($iniWrapper->getNumeric('opcache.max_accelerated_files') < 10000) {
421
+            return false;
422
+        }
423
+
424
+        if($iniWrapper->getNumeric('opcache.memory_consumption') < 128) {
425
+            return false;
426
+        }
427
+
428
+        if($iniWrapper->getNumeric('opcache.interned_strings_buffer') < 8) {
429
+            return false;
430
+        }
431
+
432
+        return true;
433
+    }
434
+
435
+    /**
436
+     * Check if the required FreeType functions are present
437
+     * @return bool
438
+     */
439
+    protected function hasFreeTypeSupport() {
440
+        return function_exists('imagettfbbox') && function_exists('imagettftext');
441
+    }
442
+
443
+    protected function hasMissingIndexes(): array {
444
+        $indexInfo = new MissingIndexInformation();
445
+        // Dispatch event so apps can also hint for pending index updates if needed
446
+        $event = new GenericEvent($indexInfo);
447
+        $this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_INDEXES_EVENT, $event);
448
+
449
+        return $indexInfo->getListOfMissingIndexes();
450
+    }
451
+
452
+    /**
453
+     * warn if outdated version of a memcache module is used
454
+     */
455
+    protected function getOutdatedCaches(): array {
456
+        $caches = [
457
+            'apcu'	=> ['name' => 'APCu', 'version' => '4.0.6'],
458
+            'redis'	=> ['name' => 'Redis', 'version' => '2.2.5'],
459
+        ];
460
+        $outdatedCaches = [];
461
+        foreach ($caches as $php_module => $data) {
462
+            $isOutdated = extension_loaded($php_module) && version_compare(phpversion($php_module), $data['version'], '<');
463
+            if ($isOutdated) {
464
+                $outdatedCaches[] = $data;
465
+            }
466
+        }
467
+
468
+        return $outdatedCaches;
469
+    }
470
+
471
+    protected function isSqliteUsed() {
472
+        return strpos($this->config->getSystemValue('dbtype'), 'sqlite') !== false;
473
+    }
474
+
475
+    protected function isReadOnlyConfig(): bool {
476
+        return \OC_Helper::isReadOnlyConfigEnabled();
477
+    }
478
+
479
+    protected function hasValidTransactionIsolationLevel(): bool {
480
+        try {
481
+            if ($this->db->getDatabasePlatform() instanceof SqlitePlatform) {
482
+                return true;
483
+            }
484
+
485
+            return $this->db->getTransactionIsolation() === Connection::TRANSACTION_READ_COMMITTED;
486
+        } catch (DBALException $e) {
487
+            // ignore
488
+        }
489
+
490
+        return true;
491
+    }
492
+
493
+    protected function hasFileinfoInstalled(): bool {
494
+        return \OC_Util::fileInfoLoaded();
495
+    }
496
+
497
+    protected function hasWorkingFileLocking(): bool {
498
+        return !($this->lockingProvider instanceof NoopLockingProvider);
499
+    }
500
+
501
+    protected function getSuggestedOverwriteCliURL(): string {
502
+        $suggestedOverwriteCliUrl = '';
503
+        if ($this->config->getSystemValue('overwrite.cli.url', '') === '') {
504
+            $suggestedOverwriteCliUrl = $this->request->getServerProtocol() . '://' . $this->request->getInsecureServerHost() . \OC::$WEBROOT;
505
+            if (!$this->config->getSystemValue('config_is_read_only', false)) {
506
+                // Set the overwrite URL when it was not set yet.
507
+                $this->config->setSystemValue('overwrite.cli.url', $suggestedOverwriteCliUrl);
508
+                $suggestedOverwriteCliUrl = '';
509
+            }
510
+        }
511
+        return $suggestedOverwriteCliUrl;
512
+    }
513
+
514
+    protected function getLastCronInfo(): array {
515
+        $lastCronRun = $this->config->getAppValue('core', 'lastcron', 0);
516
+        return [
517
+            'diffInSeconds' => time() - $lastCronRun,
518
+            'relativeTime' => $this->dateTimeFormatter->formatTimeSpan($lastCronRun),
519
+            'backgroundJobsUrl' => $this->urlGenerator->linkToRoute('settings.AdminSettings.index', ['section' => 'server']) . '#backgroundjobs',
520
+        ];
521
+    }
522
+
523
+    protected function getCronErrors() {
524
+        $errors = json_decode($this->config->getAppValue('core', 'cronErrors', ''), true);
525
+
526
+        if (is_array($errors)) {
527
+            return $errors;
528
+        }
529
+
530
+        return [];
531
+    }
532
+
533
+    protected function isPhpMailerUsed(): bool {
534
+        return $this->config->getSystemValue('mail_smtpmode', 'php') === 'php';
535
+    }
536
+
537
+    protected function hasOpcacheLoaded(): bool {
538
+        return function_exists('opcache_get_status');
539
+    }
540
+
541
+    /**
542
+     * Iterates through the configured app roots and
543
+     * tests if the subdirectories are owned by the same user than the current user.
544
+     *
545
+     * @return array
546
+     */
547
+    protected function getAppDirsWithDifferentOwner(): array {
548
+        $currentUser = posix_getuid();
549
+        $appDirsWithDifferentOwner = [[]];
550
+
551
+        foreach (OC::$APPSROOTS as $appRoot) {
552
+            if ($appRoot['writable'] === true) {
553
+                $appDirsWithDifferentOwner[] = $this->getAppDirsWithDifferentOwnerForAppRoot($currentUser, $appRoot);
554
+            }
555
+        }
556
+
557
+        $appDirsWithDifferentOwner = array_merge(...$appDirsWithDifferentOwner);
558
+        sort($appDirsWithDifferentOwner);
559
+
560
+        return $appDirsWithDifferentOwner;
561
+    }
562
+
563
+    /**
564
+     * Tests if the directories for one apps directory are writable by the current user.
565
+     *
566
+     * @param int $currentUser The current user
567
+     * @param array $appRoot The app root config
568
+     * @return string[] The none writable directory paths inside the app root
569
+     */
570
+    private function getAppDirsWithDifferentOwnerForAppRoot(int $currentUser, array $appRoot): array {
571
+        $appDirsWithDifferentOwner = [];
572
+        $appsPath = $appRoot['path'];
573
+        $appsDir = new DirectoryIterator($appRoot['path']);
574
+
575
+        foreach ($appsDir as $fileInfo) {
576
+            if ($fileInfo->isDir() && !$fileInfo->isDot()) {
577
+                $absAppPath = $appsPath . DIRECTORY_SEPARATOR . $fileInfo->getFilename();
578
+                $appDirUser = fileowner($absAppPath);
579
+                if ($appDirUser !== $currentUser) {
580
+                    $appDirsWithDifferentOwner[] = $absAppPath;
581
+                }
582
+            }
583
+        }
584
+
585
+        return $appDirsWithDifferentOwner;
586
+    }
587
+
588
+    /**
589
+     * @return DataResponse
590
+     */
591
+    public function check() {
592
+        return new DataResponse(
593
+            [
594
+                'isGetenvServerWorking' => !empty(getenv('PATH')),
595
+                'isReadOnlyConfig' => $this->isReadOnlyConfig(),
596
+                'hasValidTransactionIsolationLevel' => $this->hasValidTransactionIsolationLevel(),
597
+                'outdatedCaches' => $this->getOutdatedCaches(),
598
+                'hasFileinfoInstalled' => $this->hasFileinfoInstalled(),
599
+                'hasWorkingFileLocking' => $this->hasWorkingFileLocking(),
600
+                'suggestedOverwriteCliURL' => $this->getSuggestedOverwriteCliURL(),
601
+                'cronInfo' => $this->getLastCronInfo(),
602
+                'cronErrors' => $this->getCronErrors(),
603
+                'serverHasInternetConnection' => $this->isInternetConnectionWorking(),
604
+                'isMemcacheConfigured' => $this->isMemcacheConfigured(),
605
+                'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
606
+                'isRandomnessSecure' => $this->isRandomnessSecure(),
607
+                'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'),
608
+                'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(),
609
+                'phpSupported' => $this->isPhpSupported(),
610
+                'forwardedForHeadersWorking' => $this->forwardedForHeadersWorking(),
611
+                'reverseProxyDocs' => $this->urlGenerator->linkToDocs('admin-reverse-proxy'),
612
+                'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled(),
613
+                'hasPassedCodeIntegrityCheck' => $this->checker->hasPassedCheck(),
614
+                'codeIntegrityCheckerDocumentation' => $this->urlGenerator->linkToDocs('admin-code-integrity'),
615
+                'isOpcacheProperlySetup' => $this->isOpcacheProperlySetup(),
616
+                'hasOpcacheLoaded' => $this->hasOpcacheLoaded(),
617
+                'phpOpcacheDocumentation' => $this->urlGenerator->linkToDocs('admin-php-opcache'),
618
+                'isSettimelimitAvailable' => $this->isSettimelimitAvailable(),
619
+                'hasFreeTypeSupport' => $this->hasFreeTypeSupport(),
620
+                'missingIndexes' => $this->hasMissingIndexes(),
621
+                'isSqliteUsed' => $this->isSqliteUsed(),
622
+                'databaseConversionDocumentation' => $this->urlGenerator->linkToDocs('admin-db-conversion'),
623
+                'isPhpMailerUsed' => $this->isPhpMailerUsed(),
624
+                'mailSettingsDocumentation' => $this->urlGenerator->getAbsoluteURL('index.php/settings/admin'),
625
+                'isMemoryLimitSufficient' => $this->memoryInfo->isMemoryLimitSufficient(),
626
+                'appDirsWithDifferentOwner' => $this->getAppDirsWithDifferentOwner(),
627
+            ]
628
+        );
629
+    }
630 630
 }
Please login to merge, or discard this patch.