Completed
Pull Request — master (#5776)
by Lukas
50:10 queued 32:42
created
lib/private/Share20/ProviderFactory.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -176,7 +176,7 @@
 block discarded – undo
176 176
 	/**
177 177
 	 * Create the circle share provider
178 178
 	 *
179
-	 * @return FederatedShareProvider
179
+	 * @return null|\OCA\Circles\ShareByCircleProvider
180 180
 	 *
181 181
 	 * @suppress PhanUndeclaredClassMethod
182 182
 	 */
Please login to merge, or discard this patch.
Indentation   +222 added lines, -222 removed lines patch added patch discarded remove patch
@@ -43,233 +43,233 @@
 block discarded – undo
43 43
  */
44 44
 class ProviderFactory implements IProviderFactory {
45 45
 
46
-	/** @var IServerContainer */
47
-	private $serverContainer;
48
-	/** @var DefaultShareProvider */
49
-	private $defaultProvider = null;
50
-	/** @var FederatedShareProvider */
51
-	private $federatedProvider = null;
52
-	/** @var  ShareByMailProvider */
53
-	private $shareByMailProvider;
54
-	/** @var  \OCA\Circles\ShareByCircleProvider */
55
-	private $shareByCircleProvider = null;
56
-	/** @var bool */
57
-	private $circlesAreNotAvailable = false;
58
-
59
-	/**
60
-	 * IProviderFactory constructor.
61
-	 *
62
-	 * @param IServerContainer $serverContainer
63
-	 */
64
-	public function __construct(IServerContainer $serverContainer) {
65
-		$this->serverContainer = $serverContainer;
66
-	}
67
-
68
-	/**
69
-	 * Create the default share provider.
70
-	 *
71
-	 * @return DefaultShareProvider
72
-	 */
73
-	protected function defaultShareProvider() {
74
-		if ($this->defaultProvider === null) {
75
-			$this->defaultProvider = new DefaultShareProvider(
76
-				$this->serverContainer->getDatabaseConnection(),
77
-				$this->serverContainer->getUserManager(),
78
-				$this->serverContainer->getGroupManager(),
79
-				$this->serverContainer->getLazyRootFolder()
80
-			);
81
-		}
82
-
83
-		return $this->defaultProvider;
84
-	}
85
-
86
-	/**
87
-	 * Create the federated share provider
88
-	 *
89
-	 * @return FederatedShareProvider
90
-	 */
91
-	protected function federatedShareProvider() {
92
-		if ($this->federatedProvider === null) {
93
-			/*
46
+    /** @var IServerContainer */
47
+    private $serverContainer;
48
+    /** @var DefaultShareProvider */
49
+    private $defaultProvider = null;
50
+    /** @var FederatedShareProvider */
51
+    private $federatedProvider = null;
52
+    /** @var  ShareByMailProvider */
53
+    private $shareByMailProvider;
54
+    /** @var  \OCA\Circles\ShareByCircleProvider */
55
+    private $shareByCircleProvider = null;
56
+    /** @var bool */
57
+    private $circlesAreNotAvailable = false;
58
+
59
+    /**
60
+     * IProviderFactory constructor.
61
+     *
62
+     * @param IServerContainer $serverContainer
63
+     */
64
+    public function __construct(IServerContainer $serverContainer) {
65
+        $this->serverContainer = $serverContainer;
66
+    }
67
+
68
+    /**
69
+     * Create the default share provider.
70
+     *
71
+     * @return DefaultShareProvider
72
+     */
73
+    protected function defaultShareProvider() {
74
+        if ($this->defaultProvider === null) {
75
+            $this->defaultProvider = new DefaultShareProvider(
76
+                $this->serverContainer->getDatabaseConnection(),
77
+                $this->serverContainer->getUserManager(),
78
+                $this->serverContainer->getGroupManager(),
79
+                $this->serverContainer->getLazyRootFolder()
80
+            );
81
+        }
82
+
83
+        return $this->defaultProvider;
84
+    }
85
+
86
+    /**
87
+     * Create the federated share provider
88
+     *
89
+     * @return FederatedShareProvider
90
+     */
91
+    protected function federatedShareProvider() {
92
+        if ($this->federatedProvider === null) {
93
+            /*
94 94
 			 * Check if the app is enabled
95 95
 			 */
96
-			$appManager = $this->serverContainer->getAppManager();
97
-			if (!$appManager->isEnabledForUser('federatedfilesharing')) {
98
-				return null;
99
-			}
96
+            $appManager = $this->serverContainer->getAppManager();
97
+            if (!$appManager->isEnabledForUser('federatedfilesharing')) {
98
+                return null;
99
+            }
100 100
 
101
-			/*
101
+            /*
102 102
 			 * TODO: add factory to federated sharing app
103 103
 			 */
104
-			$l = $this->serverContainer->getL10N('federatedfilessharing');
105
-			$addressHandler = new AddressHandler(
106
-				$this->serverContainer->getURLGenerator(),
107
-				$l,
108
-				$this->serverContainer->getCloudIdManager()
109
-			);
110
-			$notifications = new Notifications(
111
-				$addressHandler,
112
-				$this->serverContainer->getHTTPClientService(),
113
-				$this->serverContainer->query(\OCP\OCS\IDiscoveryService::class),
114
-				$this->serverContainer->getJobList()
115
-			);
116
-			$tokenHandler = new TokenHandler(
117
-				$this->serverContainer->getSecureRandom()
118
-			);
119
-
120
-			$this->federatedProvider = new FederatedShareProvider(
121
-				$this->serverContainer->getDatabaseConnection(),
122
-				$addressHandler,
123
-				$notifications,
124
-				$tokenHandler,
125
-				$l,
126
-				$this->serverContainer->getLogger(),
127
-				$this->serverContainer->getLazyRootFolder(),
128
-				$this->serverContainer->getConfig(),
129
-				$this->serverContainer->getUserManager(),
130
-				$this->serverContainer->getCloudIdManager(),
131
-				$this->serverContainer->query(Config::class)
132
-			);
133
-		}
134
-
135
-		return $this->federatedProvider;
136
-	}
137
-
138
-	/**
139
-	 * Create the federated share provider
140
-	 *
141
-	 * @return ShareByMailProvider
142
-	 */
143
-	protected function getShareByMailProvider() {
144
-		if ($this->shareByMailProvider === null) {
145
-			/*
104
+            $l = $this->serverContainer->getL10N('federatedfilessharing');
105
+            $addressHandler = new AddressHandler(
106
+                $this->serverContainer->getURLGenerator(),
107
+                $l,
108
+                $this->serverContainer->getCloudIdManager()
109
+            );
110
+            $notifications = new Notifications(
111
+                $addressHandler,
112
+                $this->serverContainer->getHTTPClientService(),
113
+                $this->serverContainer->query(\OCP\OCS\IDiscoveryService::class),
114
+                $this->serverContainer->getJobList()
115
+            );
116
+            $tokenHandler = new TokenHandler(
117
+                $this->serverContainer->getSecureRandom()
118
+            );
119
+
120
+            $this->federatedProvider = new FederatedShareProvider(
121
+                $this->serverContainer->getDatabaseConnection(),
122
+                $addressHandler,
123
+                $notifications,
124
+                $tokenHandler,
125
+                $l,
126
+                $this->serverContainer->getLogger(),
127
+                $this->serverContainer->getLazyRootFolder(),
128
+                $this->serverContainer->getConfig(),
129
+                $this->serverContainer->getUserManager(),
130
+                $this->serverContainer->getCloudIdManager(),
131
+                $this->serverContainer->query(Config::class)
132
+            );
133
+        }
134
+
135
+        return $this->federatedProvider;
136
+    }
137
+
138
+    /**
139
+     * Create the federated share provider
140
+     *
141
+     * @return ShareByMailProvider
142
+     */
143
+    protected function getShareByMailProvider() {
144
+        if ($this->shareByMailProvider === null) {
145
+            /*
146 146
 			 * Check if the app is enabled
147 147
 			 */
148
-			$appManager = $this->serverContainer->getAppManager();
149
-			if (!$appManager->isEnabledForUser('sharebymail')) {
150
-				return null;
151
-			}
152
-
153
-			$settingsManager = new SettingsManager($this->serverContainer->getConfig());
154
-
155
-			$this->shareByMailProvider = new ShareByMailProvider(
156
-				$this->serverContainer->getDatabaseConnection(),
157
-				$this->serverContainer->getSecureRandom(),
158
-				$this->serverContainer->getUserManager(),
159
-				$this->serverContainer->getLazyRootFolder(),
160
-				$this->serverContainer->getL10N('sharebymail'),
161
-				$this->serverContainer->getLogger(),
162
-				$this->serverContainer->getMailer(),
163
-				$this->serverContainer->getURLGenerator(),
164
-				$this->serverContainer->getActivityManager(),
165
-				$settingsManager,
166
-				$this->serverContainer->query(Defaults::class),
167
-				$this->serverContainer->getHasher(),
168
-				$this->serverContainer->query(CapabilitiesManager::class)
169
-			);
170
-		}
171
-
172
-		return $this->shareByMailProvider;
173
-	}
174
-
175
-
176
-	/**
177
-	 * Create the circle share provider
178
-	 *
179
-	 * @return FederatedShareProvider
180
-	 *
181
-	 * @suppress PhanUndeclaredClassMethod
182
-	 */
183
-	protected function getShareByCircleProvider() {
184
-
185
-		if ($this->circlesAreNotAvailable) {
186
-			return null;
187
-		}
188
-
189
-		if (!$this->serverContainer->getAppManager()->isEnabledForUser('circles') ||
190
-			!class_exists('\OCA\Circles\ShareByCircleProvider')
191
-		) {
192
-			$this->circlesAreNotAvailable = true;
193
-			return null;
194
-		}
195
-
196
-		if ($this->shareByCircleProvider === null) {
197
-
198
-			$this->shareByCircleProvider = new \OCA\Circles\ShareByCircleProvider(
199
-				$this->serverContainer->getDatabaseConnection(),
200
-				$this->serverContainer->getSecureRandom(),
201
-				$this->serverContainer->getUserManager(),
202
-				$this->serverContainer->getLazyRootFolder(),
203
-				$this->serverContainer->getL10N('circles'),
204
-				$this->serverContainer->getLogger(),
205
-				$this->serverContainer->getURLGenerator()
206
-			);
207
-		}
208
-
209
-		return $this->shareByCircleProvider;
210
-	}
211
-
212
-
213
-	/**
214
-	 * @inheritdoc
215
-	 */
216
-	public function getProvider($id) {
217
-		$provider = null;
218
-		if ($id === 'ocinternal') {
219
-			$provider = $this->defaultShareProvider();
220
-		} else if ($id === 'ocFederatedSharing') {
221
-			$provider = $this->federatedShareProvider();
222
-		} else if ($id === 'ocMailShare') {
223
-			$provider = $this->getShareByMailProvider();
224
-		} else if ($id === 'ocCircleShare') {
225
-			$provider = $this->getShareByCircleProvider();
226
-		}
227
-
228
-		if ($provider === null) {
229
-			throw new ProviderException('No provider with id .' . $id . ' found.');
230
-		}
231
-
232
-		return $provider;
233
-	}
234
-
235
-	/**
236
-	 * @inheritdoc
237
-	 */
238
-	public function getProviderForType($shareType) {
239
-		$provider = null;
240
-
241
-		if ($shareType === \OCP\Share::SHARE_TYPE_USER ||
242
-			$shareType === \OCP\Share::SHARE_TYPE_GROUP ||
243
-			$shareType === \OCP\Share::SHARE_TYPE_LINK
244
-		) {
245
-			$provider = $this->defaultShareProvider();
246
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
247
-			$provider = $this->federatedShareProvider();
248
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_EMAIL) {
249
-			$provider = $this->getShareByMailProvider();
250
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_CIRCLE) {
251
-			$provider = $this->getShareByCircleProvider();
252
-		}
253
-
254
-
255
-		if ($provider === null) {
256
-			throw new ProviderException('No share provider for share type ' . $shareType);
257
-		}
258
-
259
-		return $provider;
260
-	}
261
-
262
-	public function getAllProviders() {
263
-		$shares = [$this->defaultShareProvider(), $this->federatedShareProvider()];
264
-		$shareByMail = $this->getShareByMailProvider();
265
-		if ($shareByMail !== null) {
266
-			$shares[] = $shareByMail;
267
-		}
268
-		$shareByCircle = $this->getShareByCircleProvider();
269
-		if ($shareByCircle !== null) {
270
-			$shares[] = $shareByCircle;
271
-		}
272
-
273
-		return $shares;
274
-	}
148
+            $appManager = $this->serverContainer->getAppManager();
149
+            if (!$appManager->isEnabledForUser('sharebymail')) {
150
+                return null;
151
+            }
152
+
153
+            $settingsManager = new SettingsManager($this->serverContainer->getConfig());
154
+
155
+            $this->shareByMailProvider = new ShareByMailProvider(
156
+                $this->serverContainer->getDatabaseConnection(),
157
+                $this->serverContainer->getSecureRandom(),
158
+                $this->serverContainer->getUserManager(),
159
+                $this->serverContainer->getLazyRootFolder(),
160
+                $this->serverContainer->getL10N('sharebymail'),
161
+                $this->serverContainer->getLogger(),
162
+                $this->serverContainer->getMailer(),
163
+                $this->serverContainer->getURLGenerator(),
164
+                $this->serverContainer->getActivityManager(),
165
+                $settingsManager,
166
+                $this->serverContainer->query(Defaults::class),
167
+                $this->serverContainer->getHasher(),
168
+                $this->serverContainer->query(CapabilitiesManager::class)
169
+            );
170
+        }
171
+
172
+        return $this->shareByMailProvider;
173
+    }
174
+
175
+
176
+    /**
177
+     * Create the circle share provider
178
+     *
179
+     * @return FederatedShareProvider
180
+     *
181
+     * @suppress PhanUndeclaredClassMethod
182
+     */
183
+    protected function getShareByCircleProvider() {
184
+
185
+        if ($this->circlesAreNotAvailable) {
186
+            return null;
187
+        }
188
+
189
+        if (!$this->serverContainer->getAppManager()->isEnabledForUser('circles') ||
190
+            !class_exists('\OCA\Circles\ShareByCircleProvider')
191
+        ) {
192
+            $this->circlesAreNotAvailable = true;
193
+            return null;
194
+        }
195
+
196
+        if ($this->shareByCircleProvider === null) {
197
+
198
+            $this->shareByCircleProvider = new \OCA\Circles\ShareByCircleProvider(
199
+                $this->serverContainer->getDatabaseConnection(),
200
+                $this->serverContainer->getSecureRandom(),
201
+                $this->serverContainer->getUserManager(),
202
+                $this->serverContainer->getLazyRootFolder(),
203
+                $this->serverContainer->getL10N('circles'),
204
+                $this->serverContainer->getLogger(),
205
+                $this->serverContainer->getURLGenerator()
206
+            );
207
+        }
208
+
209
+        return $this->shareByCircleProvider;
210
+    }
211
+
212
+
213
+    /**
214
+     * @inheritdoc
215
+     */
216
+    public function getProvider($id) {
217
+        $provider = null;
218
+        if ($id === 'ocinternal') {
219
+            $provider = $this->defaultShareProvider();
220
+        } else if ($id === 'ocFederatedSharing') {
221
+            $provider = $this->federatedShareProvider();
222
+        } else if ($id === 'ocMailShare') {
223
+            $provider = $this->getShareByMailProvider();
224
+        } else if ($id === 'ocCircleShare') {
225
+            $provider = $this->getShareByCircleProvider();
226
+        }
227
+
228
+        if ($provider === null) {
229
+            throw new ProviderException('No provider with id .' . $id . ' found.');
230
+        }
231
+
232
+        return $provider;
233
+    }
234
+
235
+    /**
236
+     * @inheritdoc
237
+     */
238
+    public function getProviderForType($shareType) {
239
+        $provider = null;
240
+
241
+        if ($shareType === \OCP\Share::SHARE_TYPE_USER ||
242
+            $shareType === \OCP\Share::SHARE_TYPE_GROUP ||
243
+            $shareType === \OCP\Share::SHARE_TYPE_LINK
244
+        ) {
245
+            $provider = $this->defaultShareProvider();
246
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
247
+            $provider = $this->federatedShareProvider();
248
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_EMAIL) {
249
+            $provider = $this->getShareByMailProvider();
250
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_CIRCLE) {
251
+            $provider = $this->getShareByCircleProvider();
252
+        }
253
+
254
+
255
+        if ($provider === null) {
256
+            throw new ProviderException('No share provider for share type ' . $shareType);
257
+        }
258
+
259
+        return $provider;
260
+    }
261
+
262
+    public function getAllProviders() {
263
+        $shares = [$this->defaultShareProvider(), $this->federatedShareProvider()];
264
+        $shareByMail = $this->getShareByMailProvider();
265
+        if ($shareByMail !== null) {
266
+            $shares[] = $shareByMail;
267
+        }
268
+        $shareByCircle = $this->getShareByCircleProvider();
269
+        if ($shareByCircle !== null) {
270
+            $shares[] = $shareByCircle;
271
+        }
272
+
273
+        return $shares;
274
+    }
275 275
 }
Please login to merge, or discard this patch.
lib/private/Share20/Manager.php 1 patch
Indentation   +1364 added lines, -1364 removed lines patch added patch discarded remove patch
@@ -56,1392 +56,1392 @@
 block discarded – undo
56 56
  */
57 57
 class Manager implements IManager {
58 58
 
59
-	/** @var IProviderFactory */
60
-	private $factory;
61
-	/** @var ILogger */
62
-	private $logger;
63
-	/** @var IConfig */
64
-	private $config;
65
-	/** @var ISecureRandom */
66
-	private $secureRandom;
67
-	/** @var IHasher */
68
-	private $hasher;
69
-	/** @var IMountManager */
70
-	private $mountManager;
71
-	/** @var IGroupManager */
72
-	private $groupManager;
73
-	/** @var IL10N */
74
-	private $l;
75
-	/** @var IUserManager */
76
-	private $userManager;
77
-	/** @var IRootFolder */
78
-	private $rootFolder;
79
-	/** @var CappedMemoryCache */
80
-	private $sharingDisabledForUsersCache;
81
-	/** @var EventDispatcher */
82
-	private $eventDispatcher;
83
-	/** @var LegacyHooks */
84
-	private $legacyHooks;
85
-
86
-
87
-	/**
88
-	 * Manager constructor.
89
-	 *
90
-	 * @param ILogger $logger
91
-	 * @param IConfig $config
92
-	 * @param ISecureRandom $secureRandom
93
-	 * @param IHasher $hasher
94
-	 * @param IMountManager $mountManager
95
-	 * @param IGroupManager $groupManager
96
-	 * @param IL10N $l
97
-	 * @param IProviderFactory $factory
98
-	 * @param IUserManager $userManager
99
-	 * @param IRootFolder $rootFolder
100
-	 * @param EventDispatcher $eventDispatcher
101
-	 */
102
-	public function __construct(
103
-			ILogger $logger,
104
-			IConfig $config,
105
-			ISecureRandom $secureRandom,
106
-			IHasher $hasher,
107
-			IMountManager $mountManager,
108
-			IGroupManager $groupManager,
109
-			IL10N $l,
110
-			IProviderFactory $factory,
111
-			IUserManager $userManager,
112
-			IRootFolder $rootFolder,
113
-			EventDispatcher $eventDispatcher
114
-	) {
115
-		$this->logger = $logger;
116
-		$this->config = $config;
117
-		$this->secureRandom = $secureRandom;
118
-		$this->hasher = $hasher;
119
-		$this->mountManager = $mountManager;
120
-		$this->groupManager = $groupManager;
121
-		$this->l = $l;
122
-		$this->factory = $factory;
123
-		$this->userManager = $userManager;
124
-		$this->rootFolder = $rootFolder;
125
-		$this->eventDispatcher = $eventDispatcher;
126
-		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
127
-		$this->legacyHooks = new LegacyHooks($this->eventDispatcher);
128
-	}
129
-
130
-	/**
131
-	 * Convert from a full share id to a tuple (providerId, shareId)
132
-	 *
133
-	 * @param string $id
134
-	 * @return string[]
135
-	 */
136
-	private function splitFullId($id) {
137
-		return explode(':', $id, 2);
138
-	}
139
-
140
-	/**
141
-	 * Verify if a password meets all requirements
142
-	 *
143
-	 * @param string $password
144
-	 * @throws \Exception
145
-	 */
146
-	protected function verifyPassword($password) {
147
-		if ($password === null) {
148
-			// No password is set, check if this is allowed.
149
-			if ($this->shareApiLinkEnforcePassword()) {
150
-				throw new \InvalidArgumentException('Passwords are enforced for link shares');
151
-			}
152
-
153
-			return;
154
-		}
155
-
156
-		// Let others verify the password
157
-		try {
158
-			$event = new GenericEvent($password);
159
-			$this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
160
-		} catch (HintException $e) {
161
-			throw new \Exception($e->getHint());
162
-		}
163
-	}
164
-
165
-	/**
166
-	 * Check for generic requirements before creating a share
167
-	 *
168
-	 * @param \OCP\Share\IShare $share
169
-	 * @throws \InvalidArgumentException
170
-	 * @throws GenericShareException
171
-	 *
172
-	 * @suppress PhanUndeclaredClassMethod
173
-	 */
174
-	protected function generalCreateChecks(\OCP\Share\IShare $share) {
175
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
176
-			// We expect a valid user as sharedWith for user shares
177
-			if (!$this->userManager->userExists($share->getSharedWith())) {
178
-				throw new \InvalidArgumentException('SharedWith is not a valid user');
179
-			}
180
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
181
-			// We expect a valid group as sharedWith for group shares
182
-			if (!$this->groupManager->groupExists($share->getSharedWith())) {
183
-				throw new \InvalidArgumentException('SharedWith is not a valid group');
184
-			}
185
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
186
-			if ($share->getSharedWith() !== null) {
187
-				throw new \InvalidArgumentException('SharedWith should be empty');
188
-			}
189
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
190
-			if ($share->getSharedWith() === null) {
191
-				throw new \InvalidArgumentException('SharedWith should not be empty');
192
-			}
193
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
194
-			if ($share->getSharedWith() === null) {
195
-				throw new \InvalidArgumentException('SharedWith should not be empty');
196
-			}
197
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
198
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
199
-			if ($circle === null) {
200
-				throw new \InvalidArgumentException('SharedWith is not a valid circle');
201
-			}
202
-		} else {
203
-			// We can't handle other types yet
204
-			throw new \InvalidArgumentException('unknown share type');
205
-		}
206
-
207
-		// Verify the initiator of the share is set
208
-		if ($share->getSharedBy() === null) {
209
-			throw new \InvalidArgumentException('SharedBy should be set');
210
-		}
211
-
212
-		// Cannot share with yourself
213
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
214
-			$share->getSharedWith() === $share->getSharedBy()) {
215
-			throw new \InvalidArgumentException('Can’t share with yourself');
216
-		}
217
-
218
-		// The path should be set
219
-		if ($share->getNode() === null) {
220
-			throw new \InvalidArgumentException('Path should be set');
221
-		}
222
-
223
-		// And it should be a file or a folder
224
-		if (!($share->getNode() instanceof \OCP\Files\File) &&
225
-				!($share->getNode() instanceof \OCP\Files\Folder)) {
226
-			throw new \InvalidArgumentException('Path should be either a file or a folder');
227
-		}
228
-
229
-		// And you can't share your rootfolder
230
-		if ($this->userManager->userExists($share->getSharedBy())) {
231
-			$sharedPath = $this->rootFolder->getUserFolder($share->getSharedBy())->getPath();
232
-		} else {
233
-			$sharedPath = $this->rootFolder->getUserFolder($share->getShareOwner())->getPath();
234
-		}
235
-		if ($sharedPath === $share->getNode()->getPath()) {
236
-			throw new \InvalidArgumentException('You can’t share your root folder');
237
-		}
238
-
239
-		// Check if we actually have share permissions
240
-		if (!$share->getNode()->isShareable()) {
241
-			$message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getPath()]);
242
-			throw new GenericShareException($message_t, $message_t, 404);
243
-		}
244
-
245
-		// Permissions should be set
246
-		if ($share->getPermissions() === null) {
247
-			throw new \InvalidArgumentException('A share requires permissions');
248
-		}
249
-
250
-		/*
59
+    /** @var IProviderFactory */
60
+    private $factory;
61
+    /** @var ILogger */
62
+    private $logger;
63
+    /** @var IConfig */
64
+    private $config;
65
+    /** @var ISecureRandom */
66
+    private $secureRandom;
67
+    /** @var IHasher */
68
+    private $hasher;
69
+    /** @var IMountManager */
70
+    private $mountManager;
71
+    /** @var IGroupManager */
72
+    private $groupManager;
73
+    /** @var IL10N */
74
+    private $l;
75
+    /** @var IUserManager */
76
+    private $userManager;
77
+    /** @var IRootFolder */
78
+    private $rootFolder;
79
+    /** @var CappedMemoryCache */
80
+    private $sharingDisabledForUsersCache;
81
+    /** @var EventDispatcher */
82
+    private $eventDispatcher;
83
+    /** @var LegacyHooks */
84
+    private $legacyHooks;
85
+
86
+
87
+    /**
88
+     * Manager constructor.
89
+     *
90
+     * @param ILogger $logger
91
+     * @param IConfig $config
92
+     * @param ISecureRandom $secureRandom
93
+     * @param IHasher $hasher
94
+     * @param IMountManager $mountManager
95
+     * @param IGroupManager $groupManager
96
+     * @param IL10N $l
97
+     * @param IProviderFactory $factory
98
+     * @param IUserManager $userManager
99
+     * @param IRootFolder $rootFolder
100
+     * @param EventDispatcher $eventDispatcher
101
+     */
102
+    public function __construct(
103
+            ILogger $logger,
104
+            IConfig $config,
105
+            ISecureRandom $secureRandom,
106
+            IHasher $hasher,
107
+            IMountManager $mountManager,
108
+            IGroupManager $groupManager,
109
+            IL10N $l,
110
+            IProviderFactory $factory,
111
+            IUserManager $userManager,
112
+            IRootFolder $rootFolder,
113
+            EventDispatcher $eventDispatcher
114
+    ) {
115
+        $this->logger = $logger;
116
+        $this->config = $config;
117
+        $this->secureRandom = $secureRandom;
118
+        $this->hasher = $hasher;
119
+        $this->mountManager = $mountManager;
120
+        $this->groupManager = $groupManager;
121
+        $this->l = $l;
122
+        $this->factory = $factory;
123
+        $this->userManager = $userManager;
124
+        $this->rootFolder = $rootFolder;
125
+        $this->eventDispatcher = $eventDispatcher;
126
+        $this->sharingDisabledForUsersCache = new CappedMemoryCache();
127
+        $this->legacyHooks = new LegacyHooks($this->eventDispatcher);
128
+    }
129
+
130
+    /**
131
+     * Convert from a full share id to a tuple (providerId, shareId)
132
+     *
133
+     * @param string $id
134
+     * @return string[]
135
+     */
136
+    private function splitFullId($id) {
137
+        return explode(':', $id, 2);
138
+    }
139
+
140
+    /**
141
+     * Verify if a password meets all requirements
142
+     *
143
+     * @param string $password
144
+     * @throws \Exception
145
+     */
146
+    protected function verifyPassword($password) {
147
+        if ($password === null) {
148
+            // No password is set, check if this is allowed.
149
+            if ($this->shareApiLinkEnforcePassword()) {
150
+                throw new \InvalidArgumentException('Passwords are enforced for link shares');
151
+            }
152
+
153
+            return;
154
+        }
155
+
156
+        // Let others verify the password
157
+        try {
158
+            $event = new GenericEvent($password);
159
+            $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
160
+        } catch (HintException $e) {
161
+            throw new \Exception($e->getHint());
162
+        }
163
+    }
164
+
165
+    /**
166
+     * Check for generic requirements before creating a share
167
+     *
168
+     * @param \OCP\Share\IShare $share
169
+     * @throws \InvalidArgumentException
170
+     * @throws GenericShareException
171
+     *
172
+     * @suppress PhanUndeclaredClassMethod
173
+     */
174
+    protected function generalCreateChecks(\OCP\Share\IShare $share) {
175
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
176
+            // We expect a valid user as sharedWith for user shares
177
+            if (!$this->userManager->userExists($share->getSharedWith())) {
178
+                throw new \InvalidArgumentException('SharedWith is not a valid user');
179
+            }
180
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
181
+            // We expect a valid group as sharedWith for group shares
182
+            if (!$this->groupManager->groupExists($share->getSharedWith())) {
183
+                throw new \InvalidArgumentException('SharedWith is not a valid group');
184
+            }
185
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
186
+            if ($share->getSharedWith() !== null) {
187
+                throw new \InvalidArgumentException('SharedWith should be empty');
188
+            }
189
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
190
+            if ($share->getSharedWith() === null) {
191
+                throw new \InvalidArgumentException('SharedWith should not be empty');
192
+            }
193
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
194
+            if ($share->getSharedWith() === null) {
195
+                throw new \InvalidArgumentException('SharedWith should not be empty');
196
+            }
197
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
198
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
199
+            if ($circle === null) {
200
+                throw new \InvalidArgumentException('SharedWith is not a valid circle');
201
+            }
202
+        } else {
203
+            // We can't handle other types yet
204
+            throw new \InvalidArgumentException('unknown share type');
205
+        }
206
+
207
+        // Verify the initiator of the share is set
208
+        if ($share->getSharedBy() === null) {
209
+            throw new \InvalidArgumentException('SharedBy should be set');
210
+        }
211
+
212
+        // Cannot share with yourself
213
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
214
+            $share->getSharedWith() === $share->getSharedBy()) {
215
+            throw new \InvalidArgumentException('Can’t share with yourself');
216
+        }
217
+
218
+        // The path should be set
219
+        if ($share->getNode() === null) {
220
+            throw new \InvalidArgumentException('Path should be set');
221
+        }
222
+
223
+        // And it should be a file or a folder
224
+        if (!($share->getNode() instanceof \OCP\Files\File) &&
225
+                !($share->getNode() instanceof \OCP\Files\Folder)) {
226
+            throw new \InvalidArgumentException('Path should be either a file or a folder');
227
+        }
228
+
229
+        // And you can't share your rootfolder
230
+        if ($this->userManager->userExists($share->getSharedBy())) {
231
+            $sharedPath = $this->rootFolder->getUserFolder($share->getSharedBy())->getPath();
232
+        } else {
233
+            $sharedPath = $this->rootFolder->getUserFolder($share->getShareOwner())->getPath();
234
+        }
235
+        if ($sharedPath === $share->getNode()->getPath()) {
236
+            throw new \InvalidArgumentException('You can’t share your root folder');
237
+        }
238
+
239
+        // Check if we actually have share permissions
240
+        if (!$share->getNode()->isShareable()) {
241
+            $message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getPath()]);
242
+            throw new GenericShareException($message_t, $message_t, 404);
243
+        }
244
+
245
+        // Permissions should be set
246
+        if ($share->getPermissions() === null) {
247
+            throw new \InvalidArgumentException('A share requires permissions');
248
+        }
249
+
250
+        /*
251 251
 		 * Quick fix for #23536
252 252
 		 * Non moveable mount points do not have update and delete permissions
253 253
 		 * while we 'most likely' do have that on the storage.
254 254
 		 */
255
-		$permissions = $share->getNode()->getPermissions();
256
-		$mount = $share->getNode()->getMountPoint();
257
-		if (!($mount instanceof MoveableMount)) {
258
-			$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
259
-		}
260
-
261
-		// Check that we do not share with more permissions than we have
262
-		if ($share->getPermissions() & ~$permissions) {
263
-			$message_t = $this->l->t('Can’t increase permissions of %s', [$share->getNode()->getPath()]);
264
-			throw new GenericShareException($message_t, $message_t, 404);
265
-		}
266
-
267
-
268
-		// Check that read permissions are always set
269
-		// Link shares are allowed to have no read permissions to allow upload to hidden folders
270
-		$noReadPermissionRequired = $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK
271
-			|| $share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL;
272
-		if (!$noReadPermissionRequired &&
273
-			($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
274
-			throw new \InvalidArgumentException('Shares need at least read permissions');
275
-		}
276
-
277
-		if ($share->getNode() instanceof \OCP\Files\File) {
278
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
279
-				$message_t = $this->l->t('Files can’t be shared with delete permissions');
280
-				throw new GenericShareException($message_t);
281
-			}
282
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
283
-				$message_t = $this->l->t('Files can’t be shared with create permissions');
284
-				throw new GenericShareException($message_t);
285
-			}
286
-		}
287
-	}
288
-
289
-	/**
290
-	 * Validate if the expiration date fits the system settings
291
-	 *
292
-	 * @param \OCP\Share\IShare $share The share to validate the expiration date of
293
-	 * @return \OCP\Share\IShare The modified share object
294
-	 * @throws GenericShareException
295
-	 * @throws \InvalidArgumentException
296
-	 * @throws \Exception
297
-	 */
298
-	protected function validateExpirationDate(\OCP\Share\IShare $share) {
299
-
300
-		$expirationDate = $share->getExpirationDate();
301
-
302
-		if ($expirationDate !== null) {
303
-			//Make sure the expiration date is a date
304
-			$expirationDate->setTime(0, 0, 0);
305
-
306
-			$date = new \DateTime();
307
-			$date->setTime(0, 0, 0);
308
-			if ($date >= $expirationDate) {
309
-				$message = $this->l->t('Expiration date is in the past');
310
-				throw new GenericShareException($message, $message, 404);
311
-			}
312
-		}
313
-
314
-		// If expiredate is empty set a default one if there is a default
315
-		$fullId = null;
316
-		try {
317
-			$fullId = $share->getFullId();
318
-		} catch (\UnexpectedValueException $e) {
319
-			// This is a new share
320
-		}
321
-
322
-		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
323
-			$expirationDate = new \DateTime();
324
-			$expirationDate->setTime(0,0,0);
325
-			$expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
326
-		}
327
-
328
-		// If we enforce the expiration date check that is does not exceed
329
-		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
330
-			if ($expirationDate === null) {
331
-				throw new \InvalidArgumentException('Expiration date is enforced');
332
-			}
333
-
334
-			$date = new \DateTime();
335
-			$date->setTime(0, 0, 0);
336
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
337
-			if ($date < $expirationDate) {
338
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
339
-				throw new GenericShareException($message, $message, 404);
340
-			}
341
-		}
342
-
343
-		$accepted = true;
344
-		$message = '';
345
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
346
-			'expirationDate' => &$expirationDate,
347
-			'accepted' => &$accepted,
348
-			'message' => &$message,
349
-			'passwordSet' => $share->getPassword() !== null,
350
-		]);
351
-
352
-		if (!$accepted) {
353
-			throw new \Exception($message);
354
-		}
355
-
356
-		$share->setExpirationDate($expirationDate);
357
-
358
-		return $share;
359
-	}
360
-
361
-	/**
362
-	 * Check for pre share requirements for user shares
363
-	 *
364
-	 * @param \OCP\Share\IShare $share
365
-	 * @throws \Exception
366
-	 */
367
-	protected function userCreateChecks(\OCP\Share\IShare $share) {
368
-		// Check if we can share with group members only
369
-		if ($this->shareWithGroupMembersOnly()) {
370
-			$sharedBy = $this->userManager->get($share->getSharedBy());
371
-			$sharedWith = $this->userManager->get($share->getSharedWith());
372
-			// Verify we can share with this user
373
-			$groups = array_intersect(
374
-					$this->groupManager->getUserGroupIds($sharedBy),
375
-					$this->groupManager->getUserGroupIds($sharedWith)
376
-			);
377
-			if (empty($groups)) {
378
-				throw new \Exception('Sharing is only allowed with group members');
379
-			}
380
-		}
381
-
382
-		/*
255
+        $permissions = $share->getNode()->getPermissions();
256
+        $mount = $share->getNode()->getMountPoint();
257
+        if (!($mount instanceof MoveableMount)) {
258
+            $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
259
+        }
260
+
261
+        // Check that we do not share with more permissions than we have
262
+        if ($share->getPermissions() & ~$permissions) {
263
+            $message_t = $this->l->t('Can’t increase permissions of %s', [$share->getNode()->getPath()]);
264
+            throw new GenericShareException($message_t, $message_t, 404);
265
+        }
266
+
267
+
268
+        // Check that read permissions are always set
269
+        // Link shares are allowed to have no read permissions to allow upload to hidden folders
270
+        $noReadPermissionRequired = $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK
271
+            || $share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL;
272
+        if (!$noReadPermissionRequired &&
273
+            ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
274
+            throw new \InvalidArgumentException('Shares need at least read permissions');
275
+        }
276
+
277
+        if ($share->getNode() instanceof \OCP\Files\File) {
278
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
279
+                $message_t = $this->l->t('Files can’t be shared with delete permissions');
280
+                throw new GenericShareException($message_t);
281
+            }
282
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
283
+                $message_t = $this->l->t('Files can’t be shared with create permissions');
284
+                throw new GenericShareException($message_t);
285
+            }
286
+        }
287
+    }
288
+
289
+    /**
290
+     * Validate if the expiration date fits the system settings
291
+     *
292
+     * @param \OCP\Share\IShare $share The share to validate the expiration date of
293
+     * @return \OCP\Share\IShare The modified share object
294
+     * @throws GenericShareException
295
+     * @throws \InvalidArgumentException
296
+     * @throws \Exception
297
+     */
298
+    protected function validateExpirationDate(\OCP\Share\IShare $share) {
299
+
300
+        $expirationDate = $share->getExpirationDate();
301
+
302
+        if ($expirationDate !== null) {
303
+            //Make sure the expiration date is a date
304
+            $expirationDate->setTime(0, 0, 0);
305
+
306
+            $date = new \DateTime();
307
+            $date->setTime(0, 0, 0);
308
+            if ($date >= $expirationDate) {
309
+                $message = $this->l->t('Expiration date is in the past');
310
+                throw new GenericShareException($message, $message, 404);
311
+            }
312
+        }
313
+
314
+        // If expiredate is empty set a default one if there is a default
315
+        $fullId = null;
316
+        try {
317
+            $fullId = $share->getFullId();
318
+        } catch (\UnexpectedValueException $e) {
319
+            // This is a new share
320
+        }
321
+
322
+        if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
323
+            $expirationDate = new \DateTime();
324
+            $expirationDate->setTime(0,0,0);
325
+            $expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
326
+        }
327
+
328
+        // If we enforce the expiration date check that is does not exceed
329
+        if ($this->shareApiLinkDefaultExpireDateEnforced()) {
330
+            if ($expirationDate === null) {
331
+                throw new \InvalidArgumentException('Expiration date is enforced');
332
+            }
333
+
334
+            $date = new \DateTime();
335
+            $date->setTime(0, 0, 0);
336
+            $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
337
+            if ($date < $expirationDate) {
338
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
339
+                throw new GenericShareException($message, $message, 404);
340
+            }
341
+        }
342
+
343
+        $accepted = true;
344
+        $message = '';
345
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
346
+            'expirationDate' => &$expirationDate,
347
+            'accepted' => &$accepted,
348
+            'message' => &$message,
349
+            'passwordSet' => $share->getPassword() !== null,
350
+        ]);
351
+
352
+        if (!$accepted) {
353
+            throw new \Exception($message);
354
+        }
355
+
356
+        $share->setExpirationDate($expirationDate);
357
+
358
+        return $share;
359
+    }
360
+
361
+    /**
362
+     * Check for pre share requirements for user shares
363
+     *
364
+     * @param \OCP\Share\IShare $share
365
+     * @throws \Exception
366
+     */
367
+    protected function userCreateChecks(\OCP\Share\IShare $share) {
368
+        // Check if we can share with group members only
369
+        if ($this->shareWithGroupMembersOnly()) {
370
+            $sharedBy = $this->userManager->get($share->getSharedBy());
371
+            $sharedWith = $this->userManager->get($share->getSharedWith());
372
+            // Verify we can share with this user
373
+            $groups = array_intersect(
374
+                    $this->groupManager->getUserGroupIds($sharedBy),
375
+                    $this->groupManager->getUserGroupIds($sharedWith)
376
+            );
377
+            if (empty($groups)) {
378
+                throw new \Exception('Sharing is only allowed with group members');
379
+            }
380
+        }
381
+
382
+        /*
383 383
 		 * TODO: Could be costly, fix
384 384
 		 *
385 385
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
386 386
 		 */
387
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
388
-		$existingShares = $provider->getSharesByPath($share->getNode());
389
-		foreach($existingShares as $existingShare) {
390
-			// Ignore if it is the same share
391
-			try {
392
-				if ($existingShare->getFullId() === $share->getFullId()) {
393
-					continue;
394
-				}
395
-			} catch (\UnexpectedValueException $e) {
396
-				//Shares are not identical
397
-			}
398
-
399
-			// Identical share already existst
400
-			if ($existingShare->getSharedWith() === $share->getSharedWith()) {
401
-				throw new \Exception('Path is already shared with this user');
402
-			}
403
-
404
-			// The share is already shared with this user via a group share
405
-			if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
406
-				$group = $this->groupManager->get($existingShare->getSharedWith());
407
-				if (!is_null($group)) {
408
-					$user = $this->userManager->get($share->getSharedWith());
409
-
410
-					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
411
-						throw new \Exception('Path is already shared with this user');
412
-					}
413
-				}
414
-			}
415
-		}
416
-	}
417
-
418
-	/**
419
-	 * Check for pre share requirements for group shares
420
-	 *
421
-	 * @param \OCP\Share\IShare $share
422
-	 * @throws \Exception
423
-	 */
424
-	protected function groupCreateChecks(\OCP\Share\IShare $share) {
425
-		// Verify group shares are allowed
426
-		if (!$this->allowGroupSharing()) {
427
-			throw new \Exception('Group sharing is now allowed');
428
-		}
429
-
430
-		// Verify if the user can share with this group
431
-		if ($this->shareWithGroupMembersOnly()) {
432
-			$sharedBy = $this->userManager->get($share->getSharedBy());
433
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
434
-			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
435
-				throw new \Exception('Sharing is only allowed within your own groups');
436
-			}
437
-		}
438
-
439
-		/*
387
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
388
+        $existingShares = $provider->getSharesByPath($share->getNode());
389
+        foreach($existingShares as $existingShare) {
390
+            // Ignore if it is the same share
391
+            try {
392
+                if ($existingShare->getFullId() === $share->getFullId()) {
393
+                    continue;
394
+                }
395
+            } catch (\UnexpectedValueException $e) {
396
+                //Shares are not identical
397
+            }
398
+
399
+            // Identical share already existst
400
+            if ($existingShare->getSharedWith() === $share->getSharedWith()) {
401
+                throw new \Exception('Path is already shared with this user');
402
+            }
403
+
404
+            // The share is already shared with this user via a group share
405
+            if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
406
+                $group = $this->groupManager->get($existingShare->getSharedWith());
407
+                if (!is_null($group)) {
408
+                    $user = $this->userManager->get($share->getSharedWith());
409
+
410
+                    if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
411
+                        throw new \Exception('Path is already shared with this user');
412
+                    }
413
+                }
414
+            }
415
+        }
416
+    }
417
+
418
+    /**
419
+     * Check for pre share requirements for group shares
420
+     *
421
+     * @param \OCP\Share\IShare $share
422
+     * @throws \Exception
423
+     */
424
+    protected function groupCreateChecks(\OCP\Share\IShare $share) {
425
+        // Verify group shares are allowed
426
+        if (!$this->allowGroupSharing()) {
427
+            throw new \Exception('Group sharing is now allowed');
428
+        }
429
+
430
+        // Verify if the user can share with this group
431
+        if ($this->shareWithGroupMembersOnly()) {
432
+            $sharedBy = $this->userManager->get($share->getSharedBy());
433
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
434
+            if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
435
+                throw new \Exception('Sharing is only allowed within your own groups');
436
+            }
437
+        }
438
+
439
+        /*
440 440
 		 * TODO: Could be costly, fix
441 441
 		 *
442 442
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
443 443
 		 */
444
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
445
-		$existingShares = $provider->getSharesByPath($share->getNode());
446
-		foreach($existingShares as $existingShare) {
447
-			try {
448
-				if ($existingShare->getFullId() === $share->getFullId()) {
449
-					continue;
450
-				}
451
-			} catch (\UnexpectedValueException $e) {
452
-				//It is a new share so just continue
453
-			}
454
-
455
-			if ($existingShare->getSharedWith() === $share->getSharedWith()) {
456
-				throw new \Exception('Path is already shared with this group');
457
-			}
458
-		}
459
-	}
460
-
461
-	/**
462
-	 * Check for pre share requirements for link shares
463
-	 *
464
-	 * @param \OCP\Share\IShare $share
465
-	 * @throws \Exception
466
-	 */
467
-	protected function linkCreateChecks(\OCP\Share\IShare $share) {
468
-		// Are link shares allowed?
469
-		if (!$this->shareApiAllowLinks()) {
470
-			throw new \Exception('Link sharing is not allowed');
471
-		}
472
-
473
-		// Link shares by definition can't have share permissions
474
-		if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
475
-			throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
476
-		}
477
-
478
-		// Check if public upload is allowed
479
-		if (!$this->shareApiLinkAllowPublicUpload() &&
480
-			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
481
-			throw new \InvalidArgumentException('Public upload is not allowed');
482
-		}
483
-	}
484
-
485
-	/**
486
-	 * To make sure we don't get invisible link shares we set the parent
487
-	 * of a link if it is a reshare. This is a quick word around
488
-	 * until we can properly display multiple link shares in the UI
489
-	 *
490
-	 * See: https://github.com/owncloud/core/issues/22295
491
-	 *
492
-	 * FIXME: Remove once multiple link shares can be properly displayed
493
-	 *
494
-	 * @param \OCP\Share\IShare $share
495
-	 */
496
-	protected function setLinkParent(\OCP\Share\IShare $share) {
497
-
498
-		// No sense in checking if the method is not there.
499
-		if (method_exists($share, 'setParent')) {
500
-			$storage = $share->getNode()->getStorage();
501
-			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
502
-				/** @var \OCA\Files_Sharing\SharedStorage $storage */
503
-				$share->setParent($storage->getShareId());
504
-			}
505
-		};
506
-	}
507
-
508
-	/**
509
-	 * @param File|Folder $path
510
-	 */
511
-	protected function pathCreateChecks($path) {
512
-		// Make sure that we do not share a path that contains a shared mountpoint
513
-		if ($path instanceof \OCP\Files\Folder) {
514
-			$mounts = $this->mountManager->findIn($path->getPath());
515
-			foreach($mounts as $mount) {
516
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
517
-					throw new \InvalidArgumentException('Path contains files shared with you');
518
-				}
519
-			}
520
-		}
521
-	}
522
-
523
-	/**
524
-	 * Check if the user that is sharing can actually share
525
-	 *
526
-	 * @param \OCP\Share\IShare $share
527
-	 * @throws \Exception
528
-	 */
529
-	protected function canShare(\OCP\Share\IShare $share) {
530
-		if (!$this->shareApiEnabled()) {
531
-			throw new \Exception('Sharing is disabled');
532
-		}
533
-
534
-		if ($this->sharingDisabledForUser($share->getSharedBy())) {
535
-			throw new \Exception('Sharing is disabled for you');
536
-		}
537
-	}
538
-
539
-	/**
540
-	 * Share a path
541
-	 *
542
-	 * @param \OCP\Share\IShare $share
543
-	 * @return Share The share object
544
-	 * @throws \Exception
545
-	 *
546
-	 * TODO: handle link share permissions or check them
547
-	 */
548
-	public function createShare(\OCP\Share\IShare $share) {
549
-		$this->canShare($share);
550
-
551
-		$this->generalCreateChecks($share);
552
-
553
-		// Verify if there are any issues with the path
554
-		$this->pathCreateChecks($share->getNode());
555
-
556
-		/*
444
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
445
+        $existingShares = $provider->getSharesByPath($share->getNode());
446
+        foreach($existingShares as $existingShare) {
447
+            try {
448
+                if ($existingShare->getFullId() === $share->getFullId()) {
449
+                    continue;
450
+                }
451
+            } catch (\UnexpectedValueException $e) {
452
+                //It is a new share so just continue
453
+            }
454
+
455
+            if ($existingShare->getSharedWith() === $share->getSharedWith()) {
456
+                throw new \Exception('Path is already shared with this group');
457
+            }
458
+        }
459
+    }
460
+
461
+    /**
462
+     * Check for pre share requirements for link shares
463
+     *
464
+     * @param \OCP\Share\IShare $share
465
+     * @throws \Exception
466
+     */
467
+    protected function linkCreateChecks(\OCP\Share\IShare $share) {
468
+        // Are link shares allowed?
469
+        if (!$this->shareApiAllowLinks()) {
470
+            throw new \Exception('Link sharing is not allowed');
471
+        }
472
+
473
+        // Link shares by definition can't have share permissions
474
+        if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
475
+            throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
476
+        }
477
+
478
+        // Check if public upload is allowed
479
+        if (!$this->shareApiLinkAllowPublicUpload() &&
480
+            ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
481
+            throw new \InvalidArgumentException('Public upload is not allowed');
482
+        }
483
+    }
484
+
485
+    /**
486
+     * To make sure we don't get invisible link shares we set the parent
487
+     * of a link if it is a reshare. This is a quick word around
488
+     * until we can properly display multiple link shares in the UI
489
+     *
490
+     * See: https://github.com/owncloud/core/issues/22295
491
+     *
492
+     * FIXME: Remove once multiple link shares can be properly displayed
493
+     *
494
+     * @param \OCP\Share\IShare $share
495
+     */
496
+    protected function setLinkParent(\OCP\Share\IShare $share) {
497
+
498
+        // No sense in checking if the method is not there.
499
+        if (method_exists($share, 'setParent')) {
500
+            $storage = $share->getNode()->getStorage();
501
+            if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
502
+                /** @var \OCA\Files_Sharing\SharedStorage $storage */
503
+                $share->setParent($storage->getShareId());
504
+            }
505
+        };
506
+    }
507
+
508
+    /**
509
+     * @param File|Folder $path
510
+     */
511
+    protected function pathCreateChecks($path) {
512
+        // Make sure that we do not share a path that contains a shared mountpoint
513
+        if ($path instanceof \OCP\Files\Folder) {
514
+            $mounts = $this->mountManager->findIn($path->getPath());
515
+            foreach($mounts as $mount) {
516
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
517
+                    throw new \InvalidArgumentException('Path contains files shared with you');
518
+                }
519
+            }
520
+        }
521
+    }
522
+
523
+    /**
524
+     * Check if the user that is sharing can actually share
525
+     *
526
+     * @param \OCP\Share\IShare $share
527
+     * @throws \Exception
528
+     */
529
+    protected function canShare(\OCP\Share\IShare $share) {
530
+        if (!$this->shareApiEnabled()) {
531
+            throw new \Exception('Sharing is disabled');
532
+        }
533
+
534
+        if ($this->sharingDisabledForUser($share->getSharedBy())) {
535
+            throw new \Exception('Sharing is disabled for you');
536
+        }
537
+    }
538
+
539
+    /**
540
+     * Share a path
541
+     *
542
+     * @param \OCP\Share\IShare $share
543
+     * @return Share The share object
544
+     * @throws \Exception
545
+     *
546
+     * TODO: handle link share permissions or check them
547
+     */
548
+    public function createShare(\OCP\Share\IShare $share) {
549
+        $this->canShare($share);
550
+
551
+        $this->generalCreateChecks($share);
552
+
553
+        // Verify if there are any issues with the path
554
+        $this->pathCreateChecks($share->getNode());
555
+
556
+        /*
557 557
 		 * On creation of a share the owner is always the owner of the path
558 558
 		 * Except for mounted federated shares.
559 559
 		 */
560
-		$storage = $share->getNode()->getStorage();
561
-		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
562
-			$parent = $share->getNode()->getParent();
563
-			while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
564
-				$parent = $parent->getParent();
565
-			}
566
-			$share->setShareOwner($parent->getOwner()->getUID());
567
-		} else {
568
-			$share->setShareOwner($share->getNode()->getOwner()->getUID());
569
-		}
570
-
571
-		//Verify share type
572
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
573
-			$this->userCreateChecks($share);
574
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
575
-			$this->groupCreateChecks($share);
576
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
577
-			$this->linkCreateChecks($share);
578
-			$this->setLinkParent($share);
579
-
580
-			/*
560
+        $storage = $share->getNode()->getStorage();
561
+        if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
562
+            $parent = $share->getNode()->getParent();
563
+            while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
564
+                $parent = $parent->getParent();
565
+            }
566
+            $share->setShareOwner($parent->getOwner()->getUID());
567
+        } else {
568
+            $share->setShareOwner($share->getNode()->getOwner()->getUID());
569
+        }
570
+
571
+        //Verify share type
572
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
573
+            $this->userCreateChecks($share);
574
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
575
+            $this->groupCreateChecks($share);
576
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
577
+            $this->linkCreateChecks($share);
578
+            $this->setLinkParent($share);
579
+
580
+            /*
581 581
 			 * For now ignore a set token.
582 582
 			 */
583
-			$share->setToken(
584
-				$this->secureRandom->generate(
585
-					\OC\Share\Constants::TOKEN_LENGTH,
586
-					\OCP\Security\ISecureRandom::CHAR_LOWER.
587
-					\OCP\Security\ISecureRandom::CHAR_UPPER.
588
-					\OCP\Security\ISecureRandom::CHAR_DIGITS
589
-				)
590
-			);
591
-
592
-			//Verify the expiration date
593
-			$this->validateExpirationDate($share);
594
-
595
-			//Verify the password
596
-			$this->verifyPassword($share->getPassword());
597
-
598
-			// If a password is set. Hash it!
599
-			if ($share->getPassword() !== null) {
600
-				$share->setPassword($this->hasher->hash($share->getPassword()));
601
-			}
602
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
603
-			$share->setToken(
604
-				$this->secureRandom->generate(
605
-					\OC\Share\Constants::TOKEN_LENGTH,
606
-					\OCP\Security\ISecureRandom::CHAR_LOWER.
607
-					\OCP\Security\ISecureRandom::CHAR_UPPER.
608
-					\OCP\Security\ISecureRandom::CHAR_DIGITS
609
-				)
610
-			);
611
-		}
612
-
613
-		// Cannot share with the owner
614
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
615
-			$share->getSharedWith() === $share->getShareOwner()) {
616
-			throw new \InvalidArgumentException('Can’t share with the share owner');
617
-		}
618
-
619
-		// Generate the target
620
-		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
621
-		$target = \OC\Files\Filesystem::normalizePath($target);
622
-		$share->setTarget($target);
623
-
624
-		// Pre share hook
625
-		$run = true;
626
-		$error = '';
627
-		$preHookData = [
628
-			'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
629
-			'itemSource' => $share->getNode()->getId(),
630
-			'shareType' => $share->getShareType(),
631
-			'uidOwner' => $share->getSharedBy(),
632
-			'permissions' => $share->getPermissions(),
633
-			'fileSource' => $share->getNode()->getId(),
634
-			'expiration' => $share->getExpirationDate(),
635
-			'token' => $share->getToken(),
636
-			'itemTarget' => $share->getTarget(),
637
-			'shareWith' => $share->getSharedWith(),
638
-			'run' => &$run,
639
-			'error' => &$error,
640
-		];
641
-		\OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
642
-
643
-		if ($run === false) {
644
-			throw new \Exception($error);
645
-		}
646
-
647
-		$oldShare = $share;
648
-		$provider = $this->factory->getProviderForType($share->getShareType());
649
-		$share = $provider->create($share);
650
-		//reuse the node we already have
651
-		$share->setNode($oldShare->getNode());
652
-
653
-		// Post share hook
654
-		$postHookData = [
655
-			'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
656
-			'itemSource' => $share->getNode()->getId(),
657
-			'shareType' => $share->getShareType(),
658
-			'uidOwner' => $share->getSharedBy(),
659
-			'permissions' => $share->getPermissions(),
660
-			'fileSource' => $share->getNode()->getId(),
661
-			'expiration' => $share->getExpirationDate(),
662
-			'token' => $share->getToken(),
663
-			'id' => $share->getId(),
664
-			'shareWith' => $share->getSharedWith(),
665
-			'itemTarget' => $share->getTarget(),
666
-			'fileTarget' => $share->getTarget(),
667
-		];
668
-
669
-		\OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
670
-
671
-		return $share;
672
-	}
673
-
674
-	/**
675
-	 * Update a share
676
-	 *
677
-	 * @param \OCP\Share\IShare $share
678
-	 * @return \OCP\Share\IShare The share object
679
-	 * @throws \InvalidArgumentException
680
-	 */
681
-	public function updateShare(\OCP\Share\IShare $share) {
682
-		$expirationDateUpdated = false;
683
-
684
-		$this->canShare($share);
685
-
686
-		try {
687
-			$originalShare = $this->getShareById($share->getFullId());
688
-		} catch (\UnexpectedValueException $e) {
689
-			throw new \InvalidArgumentException('Share does not have a full id');
690
-		}
691
-
692
-		// We can't change the share type!
693
-		if ($share->getShareType() !== $originalShare->getShareType()) {
694
-			throw new \InvalidArgumentException('Can’t change share type');
695
-		}
696
-
697
-		// We can only change the recipient on user shares
698
-		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
699
-		    $share->getShareType() !== \OCP\Share::SHARE_TYPE_USER) {
700
-			throw new \InvalidArgumentException('Can only update recipient on user shares');
701
-		}
702
-
703
-		// Cannot share with the owner
704
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
705
-			$share->getSharedWith() === $share->getShareOwner()) {
706
-			throw new \InvalidArgumentException('Can’t share with the share owner');
707
-		}
708
-
709
-		$this->generalCreateChecks($share);
710
-
711
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
712
-			$this->userCreateChecks($share);
713
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
714
-			$this->groupCreateChecks($share);
715
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
716
-			$this->linkCreateChecks($share);
717
-
718
-			$this->updateSharePasswordIfNeeded($share, $originalShare);
719
-
720
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
721
-				//Verify the expiration date
722
-				$this->validateExpirationDate($share);
723
-				$expirationDateUpdated = true;
724
-			}
725
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
726
-			$plainTextPassword = $share->getPassword();
727
-			if (!$this->updateSharePasswordIfNeeded($share, $originalShare)) {
728
-				$plainTextPassword = null;
729
-			}
730
-		}
731
-
732
-		$this->pathCreateChecks($share->getNode());
733
-
734
-		// Now update the share!
735
-		$provider = $this->factory->getProviderForType($share->getShareType());
736
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
737
-			$share = $provider->update($share, $plainTextPassword);
738
-		} else {
739
-			$share = $provider->update($share);
740
-		}
741
-
742
-		if ($expirationDateUpdated === true) {
743
-			\OC_Hook::emit('OCP\Share', 'post_set_expiration_date', [
744
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
745
-				'itemSource' => $share->getNode()->getId(),
746
-				'date' => $share->getExpirationDate(),
747
-				'uidOwner' => $share->getSharedBy(),
748
-			]);
749
-		}
750
-
751
-		if ($share->getPassword() !== $originalShare->getPassword()) {
752
-			\OC_Hook::emit('OCP\Share', 'post_update_password', [
753
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
754
-				'itemSource' => $share->getNode()->getId(),
755
-				'uidOwner' => $share->getSharedBy(),
756
-				'token' => $share->getToken(),
757
-				'disabled' => is_null($share->getPassword()),
758
-			]);
759
-		}
760
-
761
-		if ($share->getPermissions() !== $originalShare->getPermissions()) {
762
-			if ($this->userManager->userExists($share->getShareOwner())) {
763
-				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
764
-			} else {
765
-				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
766
-			}
767
-			\OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
768
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
769
-				'itemSource' => $share->getNode()->getId(),
770
-				'shareType' => $share->getShareType(),
771
-				'shareWith' => $share->getSharedWith(),
772
-				'uidOwner' => $share->getSharedBy(),
773
-				'permissions' => $share->getPermissions(),
774
-				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
775
-			));
776
-		}
777
-
778
-		return $share;
779
-	}
780
-
781
-	/**
782
-	 * Updates the password of the given share if it is not the same as the
783
-	 * password of the original share.
784
-	 *
785
-	 * @param \OCP\Share\IShare $share the share to update its password.
786
-	 * @param \OCP\Share\IShare $originalShare the original share to compare its
787
-	 *        password with.
788
-	 * @return boolean whether the password was updated or not.
789
-	 */
790
-	private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
791
-		// Password updated.
792
-		if ($share->getPassword() !== $originalShare->getPassword()) {
793
-			//Verify the password
794
-			$this->verifyPassword($share->getPassword());
795
-
796
-			// If a password is set. Hash it!
797
-			if ($share->getPassword() !== null) {
798
-				$share->setPassword($this->hasher->hash($share->getPassword()));
799
-
800
-				return true;
801
-			}
802
-		}
803
-
804
-		return false;
805
-	}
806
-
807
-	/**
808
-	 * Delete all the children of this share
809
-	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
810
-	 *
811
-	 * @param \OCP\Share\IShare $share
812
-	 * @return \OCP\Share\IShare[] List of deleted shares
813
-	 */
814
-	protected function deleteChildren(\OCP\Share\IShare $share) {
815
-		$deletedShares = [];
816
-
817
-		$provider = $this->factory->getProviderForType($share->getShareType());
818
-
819
-		foreach ($provider->getChildren($share) as $child) {
820
-			$deletedChildren = $this->deleteChildren($child);
821
-			$deletedShares = array_merge($deletedShares, $deletedChildren);
822
-
823
-			$provider->delete($child);
824
-			$deletedShares[] = $child;
825
-		}
826
-
827
-		return $deletedShares;
828
-	}
829
-
830
-	/**
831
-	 * Delete a share
832
-	 *
833
-	 * @param \OCP\Share\IShare $share
834
-	 * @throws ShareNotFound
835
-	 * @throws \InvalidArgumentException
836
-	 */
837
-	public function deleteShare(\OCP\Share\IShare $share) {
838
-
839
-		try {
840
-			$share->getFullId();
841
-		} catch (\UnexpectedValueException $e) {
842
-			throw new \InvalidArgumentException('Share does not have a full id');
843
-		}
844
-
845
-		$event = new GenericEvent($share);
846
-		$this->eventDispatcher->dispatch('OCP\Share::preUnshare', $event);
847
-
848
-		// Get all children and delete them as well
849
-		$deletedShares = $this->deleteChildren($share);
850
-
851
-		// Do the actual delete
852
-		$provider = $this->factory->getProviderForType($share->getShareType());
853
-		$provider->delete($share);
854
-
855
-		// All the deleted shares caused by this delete
856
-		$deletedShares[] = $share;
857
-
858
-		// Emit post hook
859
-		$event->setArgument('deletedShares', $deletedShares);
860
-		$this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
861
-	}
862
-
863
-
864
-	/**
865
-	 * Unshare a file as the recipient.
866
-	 * This can be different from a regular delete for example when one of
867
-	 * the users in a groups deletes that share. But the provider should
868
-	 * handle this.
869
-	 *
870
-	 * @param \OCP\Share\IShare $share
871
-	 * @param string $recipientId
872
-	 */
873
-	public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
874
-		list($providerId, ) = $this->splitFullId($share->getFullId());
875
-		$provider = $this->factory->getProvider($providerId);
876
-
877
-		$provider->deleteFromSelf($share, $recipientId);
878
-	}
879
-
880
-	/**
881
-	 * @inheritdoc
882
-	 */
883
-	public function moveShare(\OCP\Share\IShare $share, $recipientId) {
884
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
885
-			throw new \InvalidArgumentException('Can’t change target of link share');
886
-		}
887
-
888
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
889
-			throw new \InvalidArgumentException('Invalid recipient');
890
-		}
891
-
892
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
893
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
894
-			if (is_null($sharedWith)) {
895
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
896
-			}
897
-			$recipient = $this->userManager->get($recipientId);
898
-			if (!$sharedWith->inGroup($recipient)) {
899
-				throw new \InvalidArgumentException('Invalid recipient');
900
-			}
901
-		}
902
-
903
-		list($providerId, ) = $this->splitFullId($share->getFullId());
904
-		$provider = $this->factory->getProvider($providerId);
905
-
906
-		$provider->move($share, $recipientId);
907
-	}
908
-
909
-	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
910
-		$providers = $this->factory->getAllProviders();
911
-
912
-		return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
913
-			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
914
-			foreach ($newShares as $fid => $data) {
915
-				if (!isset($shares[$fid])) {
916
-					$shares[$fid] = [];
917
-				}
918
-
919
-				$shares[$fid] = array_merge($shares[$fid], $data);
920
-			}
921
-			return $shares;
922
-		}, []);
923
-	}
924
-
925
-	/**
926
-	 * @inheritdoc
927
-	 */
928
-	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
929
-		if ($path !== null &&
930
-				!($path instanceof \OCP\Files\File) &&
931
-				!($path instanceof \OCP\Files\Folder)) {
932
-			throw new \InvalidArgumentException('invalid path');
933
-		}
934
-
935
-		try {
936
-			$provider = $this->factory->getProviderForType($shareType);
937
-		} catch (ProviderException $e) {
938
-			return [];
939
-		}
940
-
941
-		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
942
-
943
-		/*
583
+            $share->setToken(
584
+                $this->secureRandom->generate(
585
+                    \OC\Share\Constants::TOKEN_LENGTH,
586
+                    \OCP\Security\ISecureRandom::CHAR_LOWER.
587
+                    \OCP\Security\ISecureRandom::CHAR_UPPER.
588
+                    \OCP\Security\ISecureRandom::CHAR_DIGITS
589
+                )
590
+            );
591
+
592
+            //Verify the expiration date
593
+            $this->validateExpirationDate($share);
594
+
595
+            //Verify the password
596
+            $this->verifyPassword($share->getPassword());
597
+
598
+            // If a password is set. Hash it!
599
+            if ($share->getPassword() !== null) {
600
+                $share->setPassword($this->hasher->hash($share->getPassword()));
601
+            }
602
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
603
+            $share->setToken(
604
+                $this->secureRandom->generate(
605
+                    \OC\Share\Constants::TOKEN_LENGTH,
606
+                    \OCP\Security\ISecureRandom::CHAR_LOWER.
607
+                    \OCP\Security\ISecureRandom::CHAR_UPPER.
608
+                    \OCP\Security\ISecureRandom::CHAR_DIGITS
609
+                )
610
+            );
611
+        }
612
+
613
+        // Cannot share with the owner
614
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
615
+            $share->getSharedWith() === $share->getShareOwner()) {
616
+            throw new \InvalidArgumentException('Can’t share with the share owner');
617
+        }
618
+
619
+        // Generate the target
620
+        $target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
621
+        $target = \OC\Files\Filesystem::normalizePath($target);
622
+        $share->setTarget($target);
623
+
624
+        // Pre share hook
625
+        $run = true;
626
+        $error = '';
627
+        $preHookData = [
628
+            'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
629
+            'itemSource' => $share->getNode()->getId(),
630
+            'shareType' => $share->getShareType(),
631
+            'uidOwner' => $share->getSharedBy(),
632
+            'permissions' => $share->getPermissions(),
633
+            'fileSource' => $share->getNode()->getId(),
634
+            'expiration' => $share->getExpirationDate(),
635
+            'token' => $share->getToken(),
636
+            'itemTarget' => $share->getTarget(),
637
+            'shareWith' => $share->getSharedWith(),
638
+            'run' => &$run,
639
+            'error' => &$error,
640
+        ];
641
+        \OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
642
+
643
+        if ($run === false) {
644
+            throw new \Exception($error);
645
+        }
646
+
647
+        $oldShare = $share;
648
+        $provider = $this->factory->getProviderForType($share->getShareType());
649
+        $share = $provider->create($share);
650
+        //reuse the node we already have
651
+        $share->setNode($oldShare->getNode());
652
+
653
+        // Post share hook
654
+        $postHookData = [
655
+            'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
656
+            'itemSource' => $share->getNode()->getId(),
657
+            'shareType' => $share->getShareType(),
658
+            'uidOwner' => $share->getSharedBy(),
659
+            'permissions' => $share->getPermissions(),
660
+            'fileSource' => $share->getNode()->getId(),
661
+            'expiration' => $share->getExpirationDate(),
662
+            'token' => $share->getToken(),
663
+            'id' => $share->getId(),
664
+            'shareWith' => $share->getSharedWith(),
665
+            'itemTarget' => $share->getTarget(),
666
+            'fileTarget' => $share->getTarget(),
667
+        ];
668
+
669
+        \OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
670
+
671
+        return $share;
672
+    }
673
+
674
+    /**
675
+     * Update a share
676
+     *
677
+     * @param \OCP\Share\IShare $share
678
+     * @return \OCP\Share\IShare The share object
679
+     * @throws \InvalidArgumentException
680
+     */
681
+    public function updateShare(\OCP\Share\IShare $share) {
682
+        $expirationDateUpdated = false;
683
+
684
+        $this->canShare($share);
685
+
686
+        try {
687
+            $originalShare = $this->getShareById($share->getFullId());
688
+        } catch (\UnexpectedValueException $e) {
689
+            throw new \InvalidArgumentException('Share does not have a full id');
690
+        }
691
+
692
+        // We can't change the share type!
693
+        if ($share->getShareType() !== $originalShare->getShareType()) {
694
+            throw new \InvalidArgumentException('Can’t change share type');
695
+        }
696
+
697
+        // We can only change the recipient on user shares
698
+        if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
699
+            $share->getShareType() !== \OCP\Share::SHARE_TYPE_USER) {
700
+            throw new \InvalidArgumentException('Can only update recipient on user shares');
701
+        }
702
+
703
+        // Cannot share with the owner
704
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
705
+            $share->getSharedWith() === $share->getShareOwner()) {
706
+            throw new \InvalidArgumentException('Can’t share with the share owner');
707
+        }
708
+
709
+        $this->generalCreateChecks($share);
710
+
711
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
712
+            $this->userCreateChecks($share);
713
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
714
+            $this->groupCreateChecks($share);
715
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
716
+            $this->linkCreateChecks($share);
717
+
718
+            $this->updateSharePasswordIfNeeded($share, $originalShare);
719
+
720
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
721
+                //Verify the expiration date
722
+                $this->validateExpirationDate($share);
723
+                $expirationDateUpdated = true;
724
+            }
725
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
726
+            $plainTextPassword = $share->getPassword();
727
+            if (!$this->updateSharePasswordIfNeeded($share, $originalShare)) {
728
+                $plainTextPassword = null;
729
+            }
730
+        }
731
+
732
+        $this->pathCreateChecks($share->getNode());
733
+
734
+        // Now update the share!
735
+        $provider = $this->factory->getProviderForType($share->getShareType());
736
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
737
+            $share = $provider->update($share, $plainTextPassword);
738
+        } else {
739
+            $share = $provider->update($share);
740
+        }
741
+
742
+        if ($expirationDateUpdated === true) {
743
+            \OC_Hook::emit('OCP\Share', 'post_set_expiration_date', [
744
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
745
+                'itemSource' => $share->getNode()->getId(),
746
+                'date' => $share->getExpirationDate(),
747
+                'uidOwner' => $share->getSharedBy(),
748
+            ]);
749
+        }
750
+
751
+        if ($share->getPassword() !== $originalShare->getPassword()) {
752
+            \OC_Hook::emit('OCP\Share', 'post_update_password', [
753
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
754
+                'itemSource' => $share->getNode()->getId(),
755
+                'uidOwner' => $share->getSharedBy(),
756
+                'token' => $share->getToken(),
757
+                'disabled' => is_null($share->getPassword()),
758
+            ]);
759
+        }
760
+
761
+        if ($share->getPermissions() !== $originalShare->getPermissions()) {
762
+            if ($this->userManager->userExists($share->getShareOwner())) {
763
+                $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
764
+            } else {
765
+                $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
766
+            }
767
+            \OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
768
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
769
+                'itemSource' => $share->getNode()->getId(),
770
+                'shareType' => $share->getShareType(),
771
+                'shareWith' => $share->getSharedWith(),
772
+                'uidOwner' => $share->getSharedBy(),
773
+                'permissions' => $share->getPermissions(),
774
+                'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
775
+            ));
776
+        }
777
+
778
+        return $share;
779
+    }
780
+
781
+    /**
782
+     * Updates the password of the given share if it is not the same as the
783
+     * password of the original share.
784
+     *
785
+     * @param \OCP\Share\IShare $share the share to update its password.
786
+     * @param \OCP\Share\IShare $originalShare the original share to compare its
787
+     *        password with.
788
+     * @return boolean whether the password was updated or not.
789
+     */
790
+    private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
791
+        // Password updated.
792
+        if ($share->getPassword() !== $originalShare->getPassword()) {
793
+            //Verify the password
794
+            $this->verifyPassword($share->getPassword());
795
+
796
+            // If a password is set. Hash it!
797
+            if ($share->getPassword() !== null) {
798
+                $share->setPassword($this->hasher->hash($share->getPassword()));
799
+
800
+                return true;
801
+            }
802
+        }
803
+
804
+        return false;
805
+    }
806
+
807
+    /**
808
+     * Delete all the children of this share
809
+     * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
810
+     *
811
+     * @param \OCP\Share\IShare $share
812
+     * @return \OCP\Share\IShare[] List of deleted shares
813
+     */
814
+    protected function deleteChildren(\OCP\Share\IShare $share) {
815
+        $deletedShares = [];
816
+
817
+        $provider = $this->factory->getProviderForType($share->getShareType());
818
+
819
+        foreach ($provider->getChildren($share) as $child) {
820
+            $deletedChildren = $this->deleteChildren($child);
821
+            $deletedShares = array_merge($deletedShares, $deletedChildren);
822
+
823
+            $provider->delete($child);
824
+            $deletedShares[] = $child;
825
+        }
826
+
827
+        return $deletedShares;
828
+    }
829
+
830
+    /**
831
+     * Delete a share
832
+     *
833
+     * @param \OCP\Share\IShare $share
834
+     * @throws ShareNotFound
835
+     * @throws \InvalidArgumentException
836
+     */
837
+    public function deleteShare(\OCP\Share\IShare $share) {
838
+
839
+        try {
840
+            $share->getFullId();
841
+        } catch (\UnexpectedValueException $e) {
842
+            throw new \InvalidArgumentException('Share does not have a full id');
843
+        }
844
+
845
+        $event = new GenericEvent($share);
846
+        $this->eventDispatcher->dispatch('OCP\Share::preUnshare', $event);
847
+
848
+        // Get all children and delete them as well
849
+        $deletedShares = $this->deleteChildren($share);
850
+
851
+        // Do the actual delete
852
+        $provider = $this->factory->getProviderForType($share->getShareType());
853
+        $provider->delete($share);
854
+
855
+        // All the deleted shares caused by this delete
856
+        $deletedShares[] = $share;
857
+
858
+        // Emit post hook
859
+        $event->setArgument('deletedShares', $deletedShares);
860
+        $this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
861
+    }
862
+
863
+
864
+    /**
865
+     * Unshare a file as the recipient.
866
+     * This can be different from a regular delete for example when one of
867
+     * the users in a groups deletes that share. But the provider should
868
+     * handle this.
869
+     *
870
+     * @param \OCP\Share\IShare $share
871
+     * @param string $recipientId
872
+     */
873
+    public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
874
+        list($providerId, ) = $this->splitFullId($share->getFullId());
875
+        $provider = $this->factory->getProvider($providerId);
876
+
877
+        $provider->deleteFromSelf($share, $recipientId);
878
+    }
879
+
880
+    /**
881
+     * @inheritdoc
882
+     */
883
+    public function moveShare(\OCP\Share\IShare $share, $recipientId) {
884
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
885
+            throw new \InvalidArgumentException('Can’t change target of link share');
886
+        }
887
+
888
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
889
+            throw new \InvalidArgumentException('Invalid recipient');
890
+        }
891
+
892
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
893
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
894
+            if (is_null($sharedWith)) {
895
+                throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
896
+            }
897
+            $recipient = $this->userManager->get($recipientId);
898
+            if (!$sharedWith->inGroup($recipient)) {
899
+                throw new \InvalidArgumentException('Invalid recipient');
900
+            }
901
+        }
902
+
903
+        list($providerId, ) = $this->splitFullId($share->getFullId());
904
+        $provider = $this->factory->getProvider($providerId);
905
+
906
+        $provider->move($share, $recipientId);
907
+    }
908
+
909
+    public function getSharesInFolder($userId, Folder $node, $reshares = false) {
910
+        $providers = $this->factory->getAllProviders();
911
+
912
+        return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
913
+            $newShares = $provider->getSharesInFolder($userId, $node, $reshares);
914
+            foreach ($newShares as $fid => $data) {
915
+                if (!isset($shares[$fid])) {
916
+                    $shares[$fid] = [];
917
+                }
918
+
919
+                $shares[$fid] = array_merge($shares[$fid], $data);
920
+            }
921
+            return $shares;
922
+        }, []);
923
+    }
924
+
925
+    /**
926
+     * @inheritdoc
927
+     */
928
+    public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
929
+        if ($path !== null &&
930
+                !($path instanceof \OCP\Files\File) &&
931
+                !($path instanceof \OCP\Files\Folder)) {
932
+            throw new \InvalidArgumentException('invalid path');
933
+        }
934
+
935
+        try {
936
+            $provider = $this->factory->getProviderForType($shareType);
937
+        } catch (ProviderException $e) {
938
+            return [];
939
+        }
940
+
941
+        $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
942
+
943
+        /*
944 944
 		 * Work around so we don't return expired shares but still follow
945 945
 		 * proper pagination.
946 946
 		 */
947 947
 
948
-		$shares2 = [];
949
-
950
-		while(true) {
951
-			$added = 0;
952
-			foreach ($shares as $share) {
953
-
954
-				try {
955
-					$this->checkExpireDate($share);
956
-				} catch (ShareNotFound $e) {
957
-					//Ignore since this basically means the share is deleted
958
-					continue;
959
-				}
960
-
961
-				$added++;
962
-				$shares2[] = $share;
963
-
964
-				if (count($shares2) === $limit) {
965
-					break;
966
-				}
967
-			}
968
-
969
-			if (count($shares2) === $limit) {
970
-				break;
971
-			}
972
-
973
-			// If there was no limit on the select we are done
974
-			if ($limit === -1) {
975
-				break;
976
-			}
977
-
978
-			$offset += $added;
979
-
980
-			// Fetch again $limit shares
981
-			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
982
-
983
-			// No more shares means we are done
984
-			if (empty($shares)) {
985
-				break;
986
-			}
987
-		}
988
-
989
-		$shares = $shares2;
990
-
991
-		return $shares;
992
-	}
993
-
994
-	/**
995
-	 * @inheritdoc
996
-	 */
997
-	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
998
-		try {
999
-			$provider = $this->factory->getProviderForType($shareType);
1000
-		} catch (ProviderException $e) {
1001
-			return [];
1002
-		}
1003
-
1004
-		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1005
-
1006
-		// remove all shares which are already expired
1007
-		foreach ($shares as $key => $share) {
1008
-			try {
1009
-				$this->checkExpireDate($share);
1010
-			} catch (ShareNotFound $e) {
1011
-				unset($shares[$key]);
1012
-			}
1013
-		}
1014
-
1015
-		return $shares;
1016
-	}
1017
-
1018
-	/**
1019
-	 * @inheritdoc
1020
-	 */
1021
-	public function getShareById($id, $recipient = null) {
1022
-		if ($id === null) {
1023
-			throw new ShareNotFound();
1024
-		}
1025
-
1026
-		list($providerId, $id) = $this->splitFullId($id);
1027
-
1028
-		try {
1029
-			$provider = $this->factory->getProvider($providerId);
1030
-		} catch (ProviderException $e) {
1031
-			throw new ShareNotFound();
1032
-		}
1033
-
1034
-		$share = $provider->getShareById($id, $recipient);
1035
-
1036
-		$this->checkExpireDate($share);
1037
-
1038
-		return $share;
1039
-	}
1040
-
1041
-	/**
1042
-	 * Get all the shares for a given path
1043
-	 *
1044
-	 * @param \OCP\Files\Node $path
1045
-	 * @param int $page
1046
-	 * @param int $perPage
1047
-	 *
1048
-	 * @return Share[]
1049
-	 */
1050
-	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1051
-		return [];
1052
-	}
1053
-
1054
-	/**
1055
-	 * Get the share by token possible with password
1056
-	 *
1057
-	 * @param string $token
1058
-	 * @return Share
1059
-	 *
1060
-	 * @throws ShareNotFound
1061
-	 */
1062
-	public function getShareByToken($token) {
1063
-		$share = null;
1064
-		try {
1065
-			if($this->shareApiAllowLinks()) {
1066
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
1067
-				$share = $provider->getShareByToken($token);
1068
-			}
1069
-		} catch (ProviderException $e) {
1070
-		} catch (ShareNotFound $e) {
1071
-		}
1072
-
1073
-
1074
-		// If it is not a link share try to fetch a federated share by token
1075
-		if ($share === null) {
1076
-			try {
1077
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_REMOTE);
1078
-				$share = $provider->getShareByToken($token);
1079
-			} catch (ProviderException $e) {
1080
-			} catch (ShareNotFound $e) {
1081
-			}
1082
-		}
1083
-
1084
-		// If it is not a link share try to fetch a mail share by token
1085
-		if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
1086
-			try {
1087
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_EMAIL);
1088
-				$share = $provider->getShareByToken($token);
1089
-			} catch (ProviderException $e) {
1090
-			} catch (ShareNotFound $e) {
1091
-			}
1092
-		}
1093
-
1094
-		if ($share === null) {
1095
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1096
-		}
1097
-
1098
-		$this->checkExpireDate($share);
1099
-
1100
-		/*
948
+        $shares2 = [];
949
+
950
+        while(true) {
951
+            $added = 0;
952
+            foreach ($shares as $share) {
953
+
954
+                try {
955
+                    $this->checkExpireDate($share);
956
+                } catch (ShareNotFound $e) {
957
+                    //Ignore since this basically means the share is deleted
958
+                    continue;
959
+                }
960
+
961
+                $added++;
962
+                $shares2[] = $share;
963
+
964
+                if (count($shares2) === $limit) {
965
+                    break;
966
+                }
967
+            }
968
+
969
+            if (count($shares2) === $limit) {
970
+                break;
971
+            }
972
+
973
+            // If there was no limit on the select we are done
974
+            if ($limit === -1) {
975
+                break;
976
+            }
977
+
978
+            $offset += $added;
979
+
980
+            // Fetch again $limit shares
981
+            $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
982
+
983
+            // No more shares means we are done
984
+            if (empty($shares)) {
985
+                break;
986
+            }
987
+        }
988
+
989
+        $shares = $shares2;
990
+
991
+        return $shares;
992
+    }
993
+
994
+    /**
995
+     * @inheritdoc
996
+     */
997
+    public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
998
+        try {
999
+            $provider = $this->factory->getProviderForType($shareType);
1000
+        } catch (ProviderException $e) {
1001
+            return [];
1002
+        }
1003
+
1004
+        $shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1005
+
1006
+        // remove all shares which are already expired
1007
+        foreach ($shares as $key => $share) {
1008
+            try {
1009
+                $this->checkExpireDate($share);
1010
+            } catch (ShareNotFound $e) {
1011
+                unset($shares[$key]);
1012
+            }
1013
+        }
1014
+
1015
+        return $shares;
1016
+    }
1017
+
1018
+    /**
1019
+     * @inheritdoc
1020
+     */
1021
+    public function getShareById($id, $recipient = null) {
1022
+        if ($id === null) {
1023
+            throw new ShareNotFound();
1024
+        }
1025
+
1026
+        list($providerId, $id) = $this->splitFullId($id);
1027
+
1028
+        try {
1029
+            $provider = $this->factory->getProvider($providerId);
1030
+        } catch (ProviderException $e) {
1031
+            throw new ShareNotFound();
1032
+        }
1033
+
1034
+        $share = $provider->getShareById($id, $recipient);
1035
+
1036
+        $this->checkExpireDate($share);
1037
+
1038
+        return $share;
1039
+    }
1040
+
1041
+    /**
1042
+     * Get all the shares for a given path
1043
+     *
1044
+     * @param \OCP\Files\Node $path
1045
+     * @param int $page
1046
+     * @param int $perPage
1047
+     *
1048
+     * @return Share[]
1049
+     */
1050
+    public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1051
+        return [];
1052
+    }
1053
+
1054
+    /**
1055
+     * Get the share by token possible with password
1056
+     *
1057
+     * @param string $token
1058
+     * @return Share
1059
+     *
1060
+     * @throws ShareNotFound
1061
+     */
1062
+    public function getShareByToken($token) {
1063
+        $share = null;
1064
+        try {
1065
+            if($this->shareApiAllowLinks()) {
1066
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
1067
+                $share = $provider->getShareByToken($token);
1068
+            }
1069
+        } catch (ProviderException $e) {
1070
+        } catch (ShareNotFound $e) {
1071
+        }
1072
+
1073
+
1074
+        // If it is not a link share try to fetch a federated share by token
1075
+        if ($share === null) {
1076
+            try {
1077
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_REMOTE);
1078
+                $share = $provider->getShareByToken($token);
1079
+            } catch (ProviderException $e) {
1080
+            } catch (ShareNotFound $e) {
1081
+            }
1082
+        }
1083
+
1084
+        // If it is not a link share try to fetch a mail share by token
1085
+        if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
1086
+            try {
1087
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_EMAIL);
1088
+                $share = $provider->getShareByToken($token);
1089
+            } catch (ProviderException $e) {
1090
+            } catch (ShareNotFound $e) {
1091
+            }
1092
+        }
1093
+
1094
+        if ($share === null) {
1095
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1096
+        }
1097
+
1098
+        $this->checkExpireDate($share);
1099
+
1100
+        /*
1101 1101
 		 * Reduce the permissions for link shares if public upload is not enabled
1102 1102
 		 */
1103
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
1104
-			!$this->shareApiLinkAllowPublicUpload()) {
1105
-			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1106
-		}
1107
-
1108
-		return $share;
1109
-	}
1110
-
1111
-	protected function checkExpireDate($share) {
1112
-		if ($share->getExpirationDate() !== null &&
1113
-			$share->getExpirationDate() <= new \DateTime()) {
1114
-			$this->deleteShare($share);
1115
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1116
-		}
1117
-
1118
-	}
1119
-
1120
-	/**
1121
-	 * Verify the password of a public share
1122
-	 *
1123
-	 * @param \OCP\Share\IShare $share
1124
-	 * @param string $password
1125
-	 * @return bool
1126
-	 */
1127
-	public function checkPassword(\OCP\Share\IShare $share, $password) {
1128
-		$passwordProtected = $share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK
1129
-			|| $share->getShareType() !== \OCP\Share::SHARE_TYPE_EMAIL;
1130
-		if (!$passwordProtected) {
1131
-			//TODO maybe exception?
1132
-			return false;
1133
-		}
1134
-
1135
-		if ($password === null || $share->getPassword() === null) {
1136
-			return false;
1137
-		}
1138
-
1139
-		$newHash = '';
1140
-		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1141
-			return false;
1142
-		}
1143
-
1144
-		if (!empty($newHash)) {
1145
-			$share->setPassword($newHash);
1146
-			$provider = $this->factory->getProviderForType($share->getShareType());
1147
-			$provider->update($share);
1148
-		}
1149
-
1150
-		return true;
1151
-	}
1152
-
1153
-	/**
1154
-	 * @inheritdoc
1155
-	 */
1156
-	public function userDeleted($uid) {
1157
-		$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];
1158
-
1159
-		foreach ($types as $type) {
1160
-			try {
1161
-				$provider = $this->factory->getProviderForType($type);
1162
-			} catch (ProviderException $e) {
1163
-				continue;
1164
-			}
1165
-			$provider->userDeleted($uid, $type);
1166
-		}
1167
-	}
1168
-
1169
-	/**
1170
-	 * @inheritdoc
1171
-	 */
1172
-	public function groupDeleted($gid) {
1173
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1174
-		$provider->groupDeleted($gid);
1175
-	}
1176
-
1177
-	/**
1178
-	 * @inheritdoc
1179
-	 */
1180
-	public function userDeletedFromGroup($uid, $gid) {
1181
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1182
-		$provider->userDeletedFromGroup($uid, $gid);
1183
-	}
1184
-
1185
-	/**
1186
-	 * Get access list to a path. This means
1187
-	 * all the users that can access a given path.
1188
-	 *
1189
-	 * Consider:
1190
-	 * -root
1191
-	 * |-folder1 (23)
1192
-	 *  |-folder2 (32)
1193
-	 *   |-fileA (42)
1194
-	 *
1195
-	 * fileA is shared with user1 and user1@server1
1196
-	 * folder2 is shared with group2 (user4 is a member of group2)
1197
-	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1198
-	 *
1199
-	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1200
-	 * [
1201
-	 *  users  => [
1202
-	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1203
-	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1204
-	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1205
-	 *  ],
1206
-	 *  remote => [
1207
-	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1208
-	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1209
-	 *  ],
1210
-	 *  public => bool
1211
-	 *  mail => bool
1212
-	 * ]
1213
-	 *
1214
-	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1215
-	 * [
1216
-	 *  users  => ['user1', 'user2', 'user4'],
1217
-	 *  remote => bool,
1218
-	 *  public => bool
1219
-	 *  mail => bool
1220
-	 * ]
1221
-	 *
1222
-	 * This is required for encryption/activity
1223
-	 *
1224
-	 * @param \OCP\Files\Node $path
1225
-	 * @param bool $recursive Should we check all parent folders as well
1226
-	 * @param bool $currentAccess Should the user have currently access to the file
1227
-	 * @return array
1228
-	 */
1229
-	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1230
-		$owner = $path->getOwner()->getUID();
1231
-
1232
-		if ($currentAccess) {
1233
-			$al = ['users' => [], 'remote' => [], 'public' => false];
1234
-		} else {
1235
-			$al = ['users' => [], 'remote' => false, 'public' => false];
1236
-		}
1237
-		if (!$this->userManager->userExists($owner)) {
1238
-			return $al;
1239
-		}
1240
-
1241
-		//Get node for the owner
1242
-		$userFolder = $this->rootFolder->getUserFolder($owner);
1243
-		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1244
-			$path = $userFolder->getById($path->getId())[0];
1245
-		}
1246
-
1247
-		$providers = $this->factory->getAllProviders();
1248
-
1249
-		/** @var Node[] $nodes */
1250
-		$nodes = [];
1251
-
1252
-
1253
-		if ($currentAccess) {
1254
-			$ownerPath = $path->getPath();
1255
-			$ownerPath = explode('/', $ownerPath, 4);
1256
-			if (count($ownerPath) < 4) {
1257
-				$ownerPath = '';
1258
-			} else {
1259
-				$ownerPath = $ownerPath[3];
1260
-			}
1261
-			$al['users'][$owner] = [
1262
-				'node_id' => $path->getId(),
1263
-				'node_path' => '/' . $ownerPath,
1264
-			];
1265
-		} else {
1266
-			$al['users'][] = $owner;
1267
-		}
1268
-
1269
-		// Collect all the shares
1270
-		while ($path->getPath() !== $userFolder->getPath()) {
1271
-			$nodes[] = $path;
1272
-			if (!$recursive) {
1273
-				break;
1274
-			}
1275
-			$path = $path->getParent();
1276
-		}
1277
-
1278
-		foreach ($providers as $provider) {
1279
-			$tmp = $provider->getAccessList($nodes, $currentAccess);
1280
-
1281
-			foreach ($tmp as $k => $v) {
1282
-				if (isset($al[$k])) {
1283
-					if (is_array($al[$k])) {
1284
-						$al[$k] = array_merge($al[$k], $v);
1285
-					} else {
1286
-						$al[$k] = $al[$k] || $v;
1287
-					}
1288
-				} else {
1289
-					$al[$k] = $v;
1290
-				}
1291
-			}
1292
-		}
1293
-
1294
-		return $al;
1295
-	}
1296
-
1297
-	/**
1298
-	 * Create a new share
1299
-	 * @return \OCP\Share\IShare;
1300
-	 */
1301
-	public function newShare() {
1302
-		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1303
-	}
1304
-
1305
-	/**
1306
-	 * Is the share API enabled
1307
-	 *
1308
-	 * @return bool
1309
-	 */
1310
-	public function shareApiEnabled() {
1311
-		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1312
-	}
1313
-
1314
-	/**
1315
-	 * Is public link sharing enabled
1316
-	 *
1317
-	 * @return bool
1318
-	 */
1319
-	public function shareApiAllowLinks() {
1320
-		return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1321
-	}
1322
-
1323
-	/**
1324
-	 * Is password on public link requires
1325
-	 *
1326
-	 * @return bool
1327
-	 */
1328
-	public function shareApiLinkEnforcePassword() {
1329
-		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1330
-	}
1331
-
1332
-	/**
1333
-	 * Is default expire date enabled
1334
-	 *
1335
-	 * @return bool
1336
-	 */
1337
-	public function shareApiLinkDefaultExpireDate() {
1338
-		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1339
-	}
1340
-
1341
-	/**
1342
-	 * Is default expire date enforced
1343
-	 *`
1344
-	 * @return bool
1345
-	 */
1346
-	public function shareApiLinkDefaultExpireDateEnforced() {
1347
-		return $this->shareApiLinkDefaultExpireDate() &&
1348
-			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1349
-	}
1350
-
1351
-	/**
1352
-	 * Number of default expire days
1353
-	 *shareApiLinkAllowPublicUpload
1354
-	 * @return int
1355
-	 */
1356
-	public function shareApiLinkDefaultExpireDays() {
1357
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1358
-	}
1359
-
1360
-	/**
1361
-	 * Allow public upload on link shares
1362
-	 *
1363
-	 * @return bool
1364
-	 */
1365
-	public function shareApiLinkAllowPublicUpload() {
1366
-		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1367
-	}
1368
-
1369
-	/**
1370
-	 * check if user can only share with group members
1371
-	 * @return bool
1372
-	 */
1373
-	public function shareWithGroupMembersOnly() {
1374
-		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1375
-	}
1376
-
1377
-	/**
1378
-	 * Check if users can share with groups
1379
-	 * @return bool
1380
-	 */
1381
-	public function allowGroupSharing() {
1382
-		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1383
-	}
1384
-
1385
-	/**
1386
-	 * Copied from \OC_Util::isSharingDisabledForUser
1387
-	 *
1388
-	 * TODO: Deprecate fuction from OC_Util
1389
-	 *
1390
-	 * @param string $userId
1391
-	 * @return bool
1392
-	 */
1393
-	public function sharingDisabledForUser($userId) {
1394
-		if ($userId === null) {
1395
-			return false;
1396
-		}
1397
-
1398
-		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1399
-			return $this->sharingDisabledForUsersCache[$userId];
1400
-		}
1401
-
1402
-		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1403
-			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1404
-			$excludedGroups = json_decode($groupsList);
1405
-			if (is_null($excludedGroups)) {
1406
-				$excludedGroups = explode(',', $groupsList);
1407
-				$newValue = json_encode($excludedGroups);
1408
-				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1409
-			}
1410
-			$user = $this->userManager->get($userId);
1411
-			$usersGroups = $this->groupManager->getUserGroupIds($user);
1412
-			if (!empty($usersGroups)) {
1413
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1414
-				// if the user is only in groups which are disabled for sharing then
1415
-				// sharing is also disabled for the user
1416
-				if (empty($remainingGroups)) {
1417
-					$this->sharingDisabledForUsersCache[$userId] = true;
1418
-					return true;
1419
-				}
1420
-			}
1421
-		}
1422
-
1423
-		$this->sharingDisabledForUsersCache[$userId] = false;
1424
-		return false;
1425
-	}
1426
-
1427
-	/**
1428
-	 * @inheritdoc
1429
-	 */
1430
-	public function outgoingServer2ServerSharesAllowed() {
1431
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1432
-	}
1433
-
1434
-	/**
1435
-	 * @inheritdoc
1436
-	 */
1437
-	public function shareProviderExists($shareType) {
1438
-		try {
1439
-			$this->factory->getProviderForType($shareType);
1440
-		} catch (ProviderException $e) {
1441
-			return false;
1442
-		}
1443
-
1444
-		return true;
1445
-	}
1103
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
1104
+            !$this->shareApiLinkAllowPublicUpload()) {
1105
+            $share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1106
+        }
1107
+
1108
+        return $share;
1109
+    }
1110
+
1111
+    protected function checkExpireDate($share) {
1112
+        if ($share->getExpirationDate() !== null &&
1113
+            $share->getExpirationDate() <= new \DateTime()) {
1114
+            $this->deleteShare($share);
1115
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1116
+        }
1117
+
1118
+    }
1119
+
1120
+    /**
1121
+     * Verify the password of a public share
1122
+     *
1123
+     * @param \OCP\Share\IShare $share
1124
+     * @param string $password
1125
+     * @return bool
1126
+     */
1127
+    public function checkPassword(\OCP\Share\IShare $share, $password) {
1128
+        $passwordProtected = $share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK
1129
+            || $share->getShareType() !== \OCP\Share::SHARE_TYPE_EMAIL;
1130
+        if (!$passwordProtected) {
1131
+            //TODO maybe exception?
1132
+            return false;
1133
+        }
1134
+
1135
+        if ($password === null || $share->getPassword() === null) {
1136
+            return false;
1137
+        }
1138
+
1139
+        $newHash = '';
1140
+        if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1141
+            return false;
1142
+        }
1143
+
1144
+        if (!empty($newHash)) {
1145
+            $share->setPassword($newHash);
1146
+            $provider = $this->factory->getProviderForType($share->getShareType());
1147
+            $provider->update($share);
1148
+        }
1149
+
1150
+        return true;
1151
+    }
1152
+
1153
+    /**
1154
+     * @inheritdoc
1155
+     */
1156
+    public function userDeleted($uid) {
1157
+        $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];
1158
+
1159
+        foreach ($types as $type) {
1160
+            try {
1161
+                $provider = $this->factory->getProviderForType($type);
1162
+            } catch (ProviderException $e) {
1163
+                continue;
1164
+            }
1165
+            $provider->userDeleted($uid, $type);
1166
+        }
1167
+    }
1168
+
1169
+    /**
1170
+     * @inheritdoc
1171
+     */
1172
+    public function groupDeleted($gid) {
1173
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1174
+        $provider->groupDeleted($gid);
1175
+    }
1176
+
1177
+    /**
1178
+     * @inheritdoc
1179
+     */
1180
+    public function userDeletedFromGroup($uid, $gid) {
1181
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1182
+        $provider->userDeletedFromGroup($uid, $gid);
1183
+    }
1184
+
1185
+    /**
1186
+     * Get access list to a path. This means
1187
+     * all the users that can access a given path.
1188
+     *
1189
+     * Consider:
1190
+     * -root
1191
+     * |-folder1 (23)
1192
+     *  |-folder2 (32)
1193
+     *   |-fileA (42)
1194
+     *
1195
+     * fileA is shared with user1 and user1@server1
1196
+     * folder2 is shared with group2 (user4 is a member of group2)
1197
+     * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1198
+     *
1199
+     * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1200
+     * [
1201
+     *  users  => [
1202
+     *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1203
+     *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1204
+     *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1205
+     *  ],
1206
+     *  remote => [
1207
+     *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1208
+     *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1209
+     *  ],
1210
+     *  public => bool
1211
+     *  mail => bool
1212
+     * ]
1213
+     *
1214
+     * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1215
+     * [
1216
+     *  users  => ['user1', 'user2', 'user4'],
1217
+     *  remote => bool,
1218
+     *  public => bool
1219
+     *  mail => bool
1220
+     * ]
1221
+     *
1222
+     * This is required for encryption/activity
1223
+     *
1224
+     * @param \OCP\Files\Node $path
1225
+     * @param bool $recursive Should we check all parent folders as well
1226
+     * @param bool $currentAccess Should the user have currently access to the file
1227
+     * @return array
1228
+     */
1229
+    public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1230
+        $owner = $path->getOwner()->getUID();
1231
+
1232
+        if ($currentAccess) {
1233
+            $al = ['users' => [], 'remote' => [], 'public' => false];
1234
+        } else {
1235
+            $al = ['users' => [], 'remote' => false, 'public' => false];
1236
+        }
1237
+        if (!$this->userManager->userExists($owner)) {
1238
+            return $al;
1239
+        }
1240
+
1241
+        //Get node for the owner
1242
+        $userFolder = $this->rootFolder->getUserFolder($owner);
1243
+        if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1244
+            $path = $userFolder->getById($path->getId())[0];
1245
+        }
1246
+
1247
+        $providers = $this->factory->getAllProviders();
1248
+
1249
+        /** @var Node[] $nodes */
1250
+        $nodes = [];
1251
+
1252
+
1253
+        if ($currentAccess) {
1254
+            $ownerPath = $path->getPath();
1255
+            $ownerPath = explode('/', $ownerPath, 4);
1256
+            if (count($ownerPath) < 4) {
1257
+                $ownerPath = '';
1258
+            } else {
1259
+                $ownerPath = $ownerPath[3];
1260
+            }
1261
+            $al['users'][$owner] = [
1262
+                'node_id' => $path->getId(),
1263
+                'node_path' => '/' . $ownerPath,
1264
+            ];
1265
+        } else {
1266
+            $al['users'][] = $owner;
1267
+        }
1268
+
1269
+        // Collect all the shares
1270
+        while ($path->getPath() !== $userFolder->getPath()) {
1271
+            $nodes[] = $path;
1272
+            if (!$recursive) {
1273
+                break;
1274
+            }
1275
+            $path = $path->getParent();
1276
+        }
1277
+
1278
+        foreach ($providers as $provider) {
1279
+            $tmp = $provider->getAccessList($nodes, $currentAccess);
1280
+
1281
+            foreach ($tmp as $k => $v) {
1282
+                if (isset($al[$k])) {
1283
+                    if (is_array($al[$k])) {
1284
+                        $al[$k] = array_merge($al[$k], $v);
1285
+                    } else {
1286
+                        $al[$k] = $al[$k] || $v;
1287
+                    }
1288
+                } else {
1289
+                    $al[$k] = $v;
1290
+                }
1291
+            }
1292
+        }
1293
+
1294
+        return $al;
1295
+    }
1296
+
1297
+    /**
1298
+     * Create a new share
1299
+     * @return \OCP\Share\IShare;
1300
+     */
1301
+    public function newShare() {
1302
+        return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1303
+    }
1304
+
1305
+    /**
1306
+     * Is the share API enabled
1307
+     *
1308
+     * @return bool
1309
+     */
1310
+    public function shareApiEnabled() {
1311
+        return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1312
+    }
1313
+
1314
+    /**
1315
+     * Is public link sharing enabled
1316
+     *
1317
+     * @return bool
1318
+     */
1319
+    public function shareApiAllowLinks() {
1320
+        return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1321
+    }
1322
+
1323
+    /**
1324
+     * Is password on public link requires
1325
+     *
1326
+     * @return bool
1327
+     */
1328
+    public function shareApiLinkEnforcePassword() {
1329
+        return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1330
+    }
1331
+
1332
+    /**
1333
+     * Is default expire date enabled
1334
+     *
1335
+     * @return bool
1336
+     */
1337
+    public function shareApiLinkDefaultExpireDate() {
1338
+        return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1339
+    }
1340
+
1341
+    /**
1342
+     * Is default expire date enforced
1343
+     *`
1344
+     * @return bool
1345
+     */
1346
+    public function shareApiLinkDefaultExpireDateEnforced() {
1347
+        return $this->shareApiLinkDefaultExpireDate() &&
1348
+            $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1349
+    }
1350
+
1351
+    /**
1352
+     * Number of default expire days
1353
+     *shareApiLinkAllowPublicUpload
1354
+     * @return int
1355
+     */
1356
+    public function shareApiLinkDefaultExpireDays() {
1357
+        return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1358
+    }
1359
+
1360
+    /**
1361
+     * Allow public upload on link shares
1362
+     *
1363
+     * @return bool
1364
+     */
1365
+    public function shareApiLinkAllowPublicUpload() {
1366
+        return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1367
+    }
1368
+
1369
+    /**
1370
+     * check if user can only share with group members
1371
+     * @return bool
1372
+     */
1373
+    public function shareWithGroupMembersOnly() {
1374
+        return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1375
+    }
1376
+
1377
+    /**
1378
+     * Check if users can share with groups
1379
+     * @return bool
1380
+     */
1381
+    public function allowGroupSharing() {
1382
+        return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1383
+    }
1384
+
1385
+    /**
1386
+     * Copied from \OC_Util::isSharingDisabledForUser
1387
+     *
1388
+     * TODO: Deprecate fuction from OC_Util
1389
+     *
1390
+     * @param string $userId
1391
+     * @return bool
1392
+     */
1393
+    public function sharingDisabledForUser($userId) {
1394
+        if ($userId === null) {
1395
+            return false;
1396
+        }
1397
+
1398
+        if (isset($this->sharingDisabledForUsersCache[$userId])) {
1399
+            return $this->sharingDisabledForUsersCache[$userId];
1400
+        }
1401
+
1402
+        if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1403
+            $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1404
+            $excludedGroups = json_decode($groupsList);
1405
+            if (is_null($excludedGroups)) {
1406
+                $excludedGroups = explode(',', $groupsList);
1407
+                $newValue = json_encode($excludedGroups);
1408
+                $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1409
+            }
1410
+            $user = $this->userManager->get($userId);
1411
+            $usersGroups = $this->groupManager->getUserGroupIds($user);
1412
+            if (!empty($usersGroups)) {
1413
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
1414
+                // if the user is only in groups which are disabled for sharing then
1415
+                // sharing is also disabled for the user
1416
+                if (empty($remainingGroups)) {
1417
+                    $this->sharingDisabledForUsersCache[$userId] = true;
1418
+                    return true;
1419
+                }
1420
+            }
1421
+        }
1422
+
1423
+        $this->sharingDisabledForUsersCache[$userId] = false;
1424
+        return false;
1425
+    }
1426
+
1427
+    /**
1428
+     * @inheritdoc
1429
+     */
1430
+    public function outgoingServer2ServerSharesAllowed() {
1431
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1432
+    }
1433
+
1434
+    /**
1435
+     * @inheritdoc
1436
+     */
1437
+    public function shareProviderExists($shareType) {
1438
+        try {
1439
+            $this->factory->getProviderForType($shareType);
1440
+        } catch (ProviderException $e) {
1441
+            return false;
1442
+        }
1443
+
1444
+        return true;
1445
+    }
1446 1446
 
1447 1447
 }
Please login to merge, or discard this patch.
lib/private/Diagnostics/QueryLogger.php 1 patch
Indentation   +55 added lines, -55 removed lines patch added patch discarded remove patch
@@ -29,68 +29,68 @@
 block discarded – undo
29 29
 use OCP\Diagnostics\IQueryLogger;
30 30
 
31 31
 class QueryLogger implements IQueryLogger {
32
-	/**
33
-	 * @var \OC\Diagnostics\Query
34
-	 */
35
-	protected $activeQuery;
32
+    /**
33
+     * @var \OC\Diagnostics\Query
34
+     */
35
+    protected $activeQuery;
36 36
 
37
-	/**
38
-	 * @var CappedMemoryCache
39
-	 */
40
-	protected $queries;
37
+    /**
38
+     * @var CappedMemoryCache
39
+     */
40
+    protected $queries;
41 41
 
42
-	/**
43
-	 * QueryLogger constructor.
44
-	 */
45
-	public function __construct() {
46
-		$this->queries = new CappedMemoryCache(1024);
47
-	}
42
+    /**
43
+     * QueryLogger constructor.
44
+     */
45
+    public function __construct() {
46
+        $this->queries = new CappedMemoryCache(1024);
47
+    }
48 48
 
49 49
 
50
-	/**
51
-	 * @var bool - Module needs to be activated by some app
52
-	 */
53
-	private $activated = false;
50
+    /**
51
+     * @var bool - Module needs to be activated by some app
52
+     */
53
+    private $activated = false;
54 54
 
55
-	/**
56
-	 * @inheritdoc
57
-	 */
58
-	public function startQuery($sql, array $params = null, array $types = null) {
59
-		if ($this->activated) {
60
-			$this->activeQuery = new Query($sql, $params, microtime(true), $this->getStack());
61
-		}
62
-	}
55
+    /**
56
+     * @inheritdoc
57
+     */
58
+    public function startQuery($sql, array $params = null, array $types = null) {
59
+        if ($this->activated) {
60
+            $this->activeQuery = new Query($sql, $params, microtime(true), $this->getStack());
61
+        }
62
+    }
63 63
 
64
-	private function getStack() {
65
-		$stack = debug_backtrace();
66
-		array_shift($stack);
67
-		array_shift($stack);
68
-		array_shift($stack);
69
-		return $stack;
70
-	}
64
+    private function getStack() {
65
+        $stack = debug_backtrace();
66
+        array_shift($stack);
67
+        array_shift($stack);
68
+        array_shift($stack);
69
+        return $stack;
70
+    }
71 71
 
72
-	/**
73
-	 * @inheritdoc
74
-	 */
75
-	public function stopQuery() {
76
-		if ($this->activated && $this->activeQuery) {
77
-			$this->activeQuery->end(microtime(true));
78
-			$this->queries[] = $this->activeQuery;
79
-			$this->activeQuery = null;
80
-		}
81
-	}
72
+    /**
73
+     * @inheritdoc
74
+     */
75
+    public function stopQuery() {
76
+        if ($this->activated && $this->activeQuery) {
77
+            $this->activeQuery->end(microtime(true));
78
+            $this->queries[] = $this->activeQuery;
79
+            $this->activeQuery = null;
80
+        }
81
+    }
82 82
 
83
-	/**
84
-	 * @inheritdoc
85
-	 */
86
-	public function getQueries() {
87
-		return $this->queries->getData();
88
-	}
83
+    /**
84
+     * @inheritdoc
85
+     */
86
+    public function getQueries() {
87
+        return $this->queries->getData();
88
+    }
89 89
 
90
-	/**
91
-	 * @inheritdoc
92
-	 */
93
-	public function activate() {
94
-		$this->activated = true;
95
-	}
90
+    /**
91
+     * @inheritdoc
92
+     */
93
+    public function activate() {
94
+        $this->activated = true;
95
+    }
96 96
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/Swift.php 2 patches
Indentation   +601 added lines, -601 removed lines patch added patch discarded remove patch
@@ -48,606 +48,606 @@
 block discarded – undo
48 48
 
49 49
 class Swift extends \OC\Files\Storage\Common {
50 50
 
51
-	/**
52
-	 * @var \OpenCloud\ObjectStore\Service
53
-	 */
54
-	private $connection;
55
-	/**
56
-	 * @var \OpenCloud\ObjectStore\Resource\Container
57
-	 */
58
-	private $container;
59
-	/**
60
-	 * @var \OpenCloud\OpenStack
61
-	 */
62
-	private $anchor;
63
-	/**
64
-	 * @var string
65
-	 */
66
-	private $bucket;
67
-	/**
68
-	 * Connection parameters
69
-	 *
70
-	 * @var array
71
-	 */
72
-	private $params;
73
-
74
-	/** @var string  */
75
-	private $id;
76
-
77
-	/**
78
-	 * @var array
79
-	 */
80
-	private static $tmpFiles = array();
81
-
82
-	/**
83
-	 * Key value cache mapping path to data object. Maps path to
84
-	 * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
85
-	 * paths and path to false for not existing paths.
86
-	 * @var \OCP\ICache
87
-	 */
88
-	private $objectCache;
89
-
90
-	/**
91
-	 * @param string $path
92
-	 */
93
-	private function normalizePath($path) {
94
-		$path = trim($path, '/');
95
-
96
-		if (!$path) {
97
-			$path = '.';
98
-		}
99
-
100
-		$path = str_replace('#', '%23', $path);
101
-
102
-		return $path;
103
-	}
104
-
105
-	const SUBCONTAINER_FILE = '.subcontainers';
106
-
107
-	/**
108
-	 * translate directory path to container name
109
-	 *
110
-	 * @param string $path
111
-	 * @return string
112
-	 */
113
-
114
-	/**
115
-	 * Fetches an object from the API.
116
-	 * If the object is cached already or a
117
-	 * failed "doesn't exist" response was cached,
118
-	 * that one will be returned.
119
-	 *
120
-	 * @param string $path
121
-	 * @return \OpenCloud\ObjectStore\Resource\DataObject|bool object
122
-	 * or false if the object did not exist
123
-	 */
124
-	private function fetchObject($path) {
125
-		if ($this->objectCache->hasKey($path)) {
126
-			// might be "false" if object did not exist from last check
127
-			return $this->objectCache->get($path);
128
-		}
129
-		try {
130
-			$object = $this->getContainer()->getPartialObject($path);
131
-			$this->objectCache->set($path, $object);
132
-			return $object;
133
-		} catch (ClientErrorResponseException $e) {
134
-			// this exception happens when the object does not exist, which
135
-			// is expected in most cases
136
-			$this->objectCache->set($path, false);
137
-			return false;
138
-		} catch (ClientErrorResponseException $e) {
139
-			// Expected response is "404 Not Found", so only log if it isn't
140
-			if ($e->getResponse()->getStatusCode() !== 404) {
141
-				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
142
-			}
143
-			return false;
144
-		}
145
-	}
146
-
147
-	/**
148
-	 * Returns whether the given path exists.
149
-	 *
150
-	 * @param string $path
151
-	 *
152
-	 * @return bool true if the object exist, false otherwise
153
-	 */
154
-	private function doesObjectExist($path) {
155
-		return $this->fetchObject($path) !== false;
156
-	}
157
-
158
-	public function __construct($params) {
159
-		if ((empty($params['key']) and empty($params['password']))
160
-			or empty($params['user']) or empty($params['bucket'])
161
-			or empty($params['region'])
162
-		) {
163
-			throw new \Exception("API Key or password, Username, Bucket and Region have to be configured.");
164
-		}
165
-
166
-		$this->id = 'swift::' . $params['user'] . md5($params['bucket']);
167
-
168
-		$bucketUrl = Url::factory($params['bucket']);
169
-		if ($bucketUrl->isAbsolute()) {
170
-			$this->bucket = end(($bucketUrl->getPathSegments()));
171
-			$params['endpoint_url'] = $bucketUrl->addPath('..')->normalizePath();
172
-		} else {
173
-			$this->bucket = $params['bucket'];
174
-		}
175
-
176
-		if (empty($params['url'])) {
177
-			$params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
178
-		}
179
-
180
-		if (empty($params['service_name'])) {
181
-			$params['service_name'] = 'cloudFiles';
182
-		}
183
-
184
-		$this->params = $params;
185
-		// FIXME: private class...
186
-		$this->objectCache = new \OC\Cache\CappedMemoryCache();
187
-	}
188
-
189
-	public function mkdir($path) {
190
-		$path = $this->normalizePath($path);
191
-
192
-		if ($this->is_dir($path)) {
193
-			return false;
194
-		}
195
-
196
-		if ($path !== '.') {
197
-			$path .= '/';
198
-		}
199
-
200
-		try {
201
-			$customHeaders = array('content-type' => 'httpd/unix-directory');
202
-			$metadataHeaders = DataObject::stockHeaders(array());
203
-			$allHeaders = $customHeaders + $metadataHeaders;
204
-			$this->getContainer()->uploadObject($path, '', $allHeaders);
205
-			// invalidate so that the next access gets the real object
206
-			// with all properties
207
-			$this->objectCache->remove($path);
208
-		} catch (Exceptions\CreateUpdateError $e) {
209
-			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
210
-			return false;
211
-		}
212
-
213
-		return true;
214
-	}
215
-
216
-	public function file_exists($path) {
217
-		$path = $this->normalizePath($path);
218
-
219
-		if ($path !== '.' && $this->is_dir($path)) {
220
-			$path .= '/';
221
-		}
222
-
223
-		return $this->doesObjectExist($path);
224
-	}
225
-
226
-	public function rmdir($path) {
227
-		$path = $this->normalizePath($path);
228
-
229
-		if (!$this->is_dir($path) || !$this->isDeletable($path)) {
230
-			return false;
231
-		}
232
-
233
-		$dh = $this->opendir($path);
234
-		while ($file = readdir($dh)) {
235
-			if (\OC\Files\Filesystem::isIgnoredDir($file)) {
236
-				continue;
237
-			}
238
-
239
-			if ($this->is_dir($path . '/' . $file)) {
240
-				$this->rmdir($path . '/' . $file);
241
-			} else {
242
-				$this->unlink($path . '/' . $file);
243
-			}
244
-		}
245
-
246
-		try {
247
-			$this->getContainer()->dataObject()->setName($path . '/')->delete();
248
-			$this->objectCache->remove($path . '/');
249
-		} catch (Exceptions\DeleteError $e) {
250
-			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
251
-			return false;
252
-		}
253
-
254
-		return true;
255
-	}
256
-
257
-	public function opendir($path) {
258
-		$path = $this->normalizePath($path);
259
-
260
-		if ($path === '.') {
261
-			$path = '';
262
-		} else {
263
-			$path .= '/';
264
-		}
265
-
266
-		$path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of #
267
-
268
-		try {
269
-			$files = array();
270
-			/** @var OpenCloud\Common\Collection $objects */
271
-			$objects = $this->getContainer()->objectList(array(
272
-				'prefix' => $path,
273
-				'delimiter' => '/'
274
-			));
275
-
276
-			/** @var OpenCloud\ObjectStore\Resource\DataObject $object */
277
-			foreach ($objects as $object) {
278
-				$file = basename($object->getName());
279
-				if ($file !== basename($path)) {
280
-					$files[] = $file;
281
-				}
282
-			}
283
-
284
-			return IteratorDirectory::wrap($files);
285
-		} catch (\Exception $e) {
286
-			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
287
-			return false;
288
-		}
289
-
290
-	}
291
-
292
-	public function stat($path) {
293
-		$path = $this->normalizePath($path);
294
-
295
-		if ($path === '.') {
296
-			$path = '';
297
-		} else if ($this->is_dir($path)) {
298
-			$path .= '/';
299
-		}
300
-
301
-		try {
302
-			/** @var DataObject $object */
303
-			$object = $this->fetchObject($path);
304
-			if (!$object) {
305
-				return false;
306
-			}
307
-		} catch (ClientErrorResponseException $e) {
308
-			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
309
-			return false;
310
-		}
311
-
312
-		$dateTime = \DateTime::createFromFormat(\DateTime::RFC1123, $object->getLastModified());
313
-		if ($dateTime !== false) {
314
-			$mtime = $dateTime->getTimestamp();
315
-		} else {
316
-			$mtime = null;
317
-		}
318
-		$objectMetadata = $object->getMetadata();
319
-		$metaTimestamp = $objectMetadata->getProperty('timestamp');
320
-		if (isset($metaTimestamp)) {
321
-			$mtime = $metaTimestamp;
322
-		}
323
-
324
-		if (!empty($mtime)) {
325
-			$mtime = floor($mtime);
326
-		}
327
-
328
-		$stat = array();
329
-		$stat['size'] = (int)$object->getContentLength();
330
-		$stat['mtime'] = $mtime;
331
-		$stat['atime'] = time();
332
-		return $stat;
333
-	}
334
-
335
-	public function filetype($path) {
336
-		$path = $this->normalizePath($path);
337
-
338
-		if ($path !== '.' && $this->doesObjectExist($path)) {
339
-			return 'file';
340
-		}
341
-
342
-		if ($path !== '.') {
343
-			$path .= '/';
344
-		}
345
-
346
-		if ($this->doesObjectExist($path)) {
347
-			return 'dir';
348
-		}
349
-	}
350
-
351
-	public function unlink($path) {
352
-		$path = $this->normalizePath($path);
353
-
354
-		if ($this->is_dir($path)) {
355
-			return $this->rmdir($path);
356
-		}
357
-
358
-		try {
359
-			$this->getContainer()->dataObject()->setName($path)->delete();
360
-			$this->objectCache->remove($path);
361
-			$this->objectCache->remove($path . '/');
362
-		} catch (ClientErrorResponseException $e) {
363
-			if ($e->getResponse()->getStatusCode() !== 404) {
364
-				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
365
-			}
366
-			return false;
367
-		}
368
-
369
-		return true;
370
-	}
371
-
372
-	public function fopen($path, $mode) {
373
-		$path = $this->normalizePath($path);
374
-
375
-		switch ($mode) {
376
-			case 'a':
377
-			case 'ab':
378
-			case 'a+':
379
-				return false;
380
-			case 'r':
381
-			case 'rb':
382
-				try {
383
-					$c = $this->getContainer();
384
-					$streamFactory = new \Guzzle\Stream\PhpStreamRequestFactory();
385
-					/** @var \OpenCloud\Common\Http\Client $client */
386
-					$client = $c->getClient();
387
-					$streamInterface = $streamFactory->fromRequest($client->get($c->getUrl($path)));
388
-					$streamInterface->rewind();
389
-					$stream = $streamInterface->getStream();
390
-					stream_context_set_option($stream, 'swift','content', $streamInterface);
391
-					if(!strrpos($streamInterface
392
-						->getMetaData('wrapper_data')[0], '404 Not Found')) {
393
-						return $stream;
394
-					}
395
-					return false;
396
-				} catch (\Guzzle\Http\Exception\BadResponseException $e) {
397
-					\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
398
-					return false;
399
-				}
400
-			case 'w':
401
-			case 'wb':
402
-			case 'r+':
403
-			case 'w+':
404
-			case 'wb+':
405
-			case 'x':
406
-			case 'x+':
407
-			case 'c':
408
-			case 'c+':
409
-				if (strrpos($path, '.') !== false) {
410
-					$ext = substr($path, strrpos($path, '.'));
411
-				} else {
412
-					$ext = '';
413
-				}
414
-				$tmpFile = \OCP\Files::tmpFile($ext);
415
-				// Fetch existing file if required
416
-				if ($mode[0] !== 'w' && $this->file_exists($path)) {
417
-					if ($mode[0] === 'x') {
418
-						// File cannot already exist
419
-						return false;
420
-					}
421
-					$source = $this->fopen($path, 'r');
422
-					file_put_contents($tmpFile, $source);
423
-				}
424
-				$handle = fopen($tmpFile, $mode);
425
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
426
-					$this->writeBack($tmpFile, $path);
427
-				});
428
-		}
429
-	}
430
-
431
-	public function touch($path, $mtime = null) {
432
-		$path = $this->normalizePath($path);
433
-		if (is_null($mtime)) {
434
-			$mtime = time();
435
-		}
436
-		$metadata = array('timestamp' => $mtime);
437
-		if ($this->file_exists($path)) {
438
-			if ($this->is_dir($path) && $path != '.') {
439
-				$path .= '/';
440
-			}
441
-
442
-			$object = $this->fetchObject($path);
443
-			if ($object->saveMetadata($metadata)) {
444
-				// invalidate target object to force repopulation on fetch
445
-				$this->objectCache->remove($path);
446
-			}
447
-			return true;
448
-		} else {
449
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
450
-			$customHeaders = array('content-type' => $mimeType);
451
-			$metadataHeaders = DataObject::stockHeaders($metadata);
452
-			$allHeaders = $customHeaders + $metadataHeaders;
453
-			$this->getContainer()->uploadObject($path, '', $allHeaders);
454
-			// invalidate target object to force repopulation on fetch
455
-			$this->objectCache->remove($path);
456
-			return true;
457
-		}
458
-	}
459
-
460
-	public function copy($path1, $path2) {
461
-		$path1 = $this->normalizePath($path1);
462
-		$path2 = $this->normalizePath($path2);
463
-
464
-		$fileType = $this->filetype($path1);
465
-		if ($fileType === 'file') {
466
-
467
-			// make way
468
-			$this->unlink($path2);
469
-
470
-			try {
471
-				$source = $this->fetchObject($path1);
472
-				$source->copy($this->bucket . '/' . $path2);
473
-				// invalidate target object to force repopulation on fetch
474
-				$this->objectCache->remove($path2);
475
-				$this->objectCache->remove($path2 . '/');
476
-			} catch (ClientErrorResponseException $e) {
477
-				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
478
-				return false;
479
-			}
480
-
481
-		} else if ($fileType === 'dir') {
482
-
483
-			// make way
484
-			$this->unlink($path2);
485
-
486
-			try {
487
-				$source = $this->fetchObject($path1 . '/');
488
-				$source->copy($this->bucket . '/' . $path2 . '/');
489
-				// invalidate target object to force repopulation on fetch
490
-				$this->objectCache->remove($path2);
491
-				$this->objectCache->remove($path2 . '/');
492
-			} catch (ClientErrorResponseException $e) {
493
-				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
494
-				return false;
495
-			}
496
-
497
-			$dh = $this->opendir($path1);
498
-			while ($file = readdir($dh)) {
499
-				if (\OC\Files\Filesystem::isIgnoredDir($file)) {
500
-					continue;
501
-				}
502
-
503
-				$source = $path1 . '/' . $file;
504
-				$target = $path2 . '/' . $file;
505
-				$this->copy($source, $target);
506
-			}
507
-
508
-		} else {
509
-			//file does not exist
510
-			return false;
511
-		}
512
-
513
-		return true;
514
-	}
515
-
516
-	public function rename($path1, $path2) {
517
-		$path1 = $this->normalizePath($path1);
518
-		$path2 = $this->normalizePath($path2);
519
-
520
-		$fileType = $this->filetype($path1);
521
-
522
-		if ($fileType === 'dir' || $fileType === 'file') {
523
-			// copy
524
-			if ($this->copy($path1, $path2) === false) {
525
-				return false;
526
-			}
527
-
528
-			// cleanup
529
-			if ($this->unlink($path1) === false) {
530
-				$this->unlink($path2);
531
-				return false;
532
-			}
533
-
534
-			return true;
535
-		}
536
-
537
-		return false;
538
-	}
539
-
540
-	public function getId() {
541
-		return $this->id;
542
-	}
543
-
544
-	/**
545
-	 * Returns the connection
546
-	 *
547
-	 * @return OpenCloud\ObjectStore\Service connected client
548
-	 * @throws \Exception if connection could not be made
549
-	 */
550
-	public function getConnection() {
551
-		if (!is_null($this->connection)) {
552
-			return $this->connection;
553
-		}
554
-
555
-		$settings = array(
556
-			'username' => $this->params['user'],
557
-		);
558
-
559
-		if (!empty($this->params['password'])) {
560
-			$settings['password'] = $this->params['password'];
561
-		} else if (!empty($this->params['key'])) {
562
-			$settings['apiKey'] = $this->params['key'];
563
-		}
564
-
565
-		if (!empty($this->params['tenant'])) {
566
-			$settings['tenantName'] = $this->params['tenant'];
567
-		}
568
-
569
-		if (!empty($this->params['timeout'])) {
570
-			$settings['timeout'] = $this->params['timeout'];
571
-		}
572
-
573
-		if (isset($settings['apiKey'])) {
574
-			$this->anchor = new Rackspace($this->params['url'], $settings);
575
-		} else {
576
-			$this->anchor = new OpenStack($this->params['url'], $settings);
577
-		}
578
-
579
-		$connection = $this->anchor->objectStoreService($this->params['service_name'], $this->params['region']);
580
-
581
-		if (!empty($this->params['endpoint_url'])) {
582
-			$endpoint = $connection->getEndpoint();
583
-			$endpoint->setPublicUrl($this->params['endpoint_url']);
584
-			$endpoint->setPrivateUrl($this->params['endpoint_url']);
585
-			$connection->setEndpoint($endpoint);
586
-		}
587
-
588
-		$this->connection = $connection;
589
-
590
-		return $this->connection;
591
-	}
592
-
593
-	/**
594
-	 * Returns the initialized object store container.
595
-	 *
596
-	 * @return OpenCloud\ObjectStore\Resource\Container
597
-	 */
598
-	public function getContainer() {
599
-		if (!is_null($this->container)) {
600
-			return $this->container;
601
-		}
602
-
603
-		try {
604
-			$this->container = $this->getConnection()->getContainer($this->bucket);
605
-		} catch (ClientErrorResponseException $e) {
606
-			$this->container = $this->getConnection()->createContainer($this->bucket);
607
-		}
608
-
609
-		if (!$this->file_exists('.')) {
610
-			$this->mkdir('.');
611
-		}
612
-
613
-		return $this->container;
614
-	}
615
-
616
-	public function writeBack($tmpFile, $path) {
617
-		$fileData = fopen($tmpFile, 'r');
618
-		$this->getContainer()->uploadObject($path, $fileData);
619
-		// invalidate target object to force repopulation on fetch
620
-		$this->objectCache->remove(self::$tmpFiles[$tmpFile]);
621
-		unlink($tmpFile);
622
-	}
623
-
624
-	public function hasUpdated($path, $time) {
625
-		if ($this->is_file($path)) {
626
-			return parent::hasUpdated($path, $time);
627
-		}
628
-		$path = $this->normalizePath($path);
629
-		$dh = $this->opendir($path);
630
-		$content = array();
631
-		while (($file = readdir($dh)) !== false) {
632
-			$content[] = $file;
633
-		}
634
-		if ($path === '.') {
635
-			$path = '';
636
-		}
637
-		$cachedContent = $this->getCache()->getFolderContents($path);
638
-		$cachedNames = array_map(function ($content) {
639
-			return $content['name'];
640
-		}, $cachedContent);
641
-		sort($cachedNames);
642
-		sort($content);
643
-		return $cachedNames != $content;
644
-	}
645
-
646
-	/**
647
-	 * check if curl is installed
648
-	 */
649
-	public static function checkDependencies() {
650
-		return true;
651
-	}
51
+    /**
52
+     * @var \OpenCloud\ObjectStore\Service
53
+     */
54
+    private $connection;
55
+    /**
56
+     * @var \OpenCloud\ObjectStore\Resource\Container
57
+     */
58
+    private $container;
59
+    /**
60
+     * @var \OpenCloud\OpenStack
61
+     */
62
+    private $anchor;
63
+    /**
64
+     * @var string
65
+     */
66
+    private $bucket;
67
+    /**
68
+     * Connection parameters
69
+     *
70
+     * @var array
71
+     */
72
+    private $params;
73
+
74
+    /** @var string  */
75
+    private $id;
76
+
77
+    /**
78
+     * @var array
79
+     */
80
+    private static $tmpFiles = array();
81
+
82
+    /**
83
+     * Key value cache mapping path to data object. Maps path to
84
+     * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
85
+     * paths and path to false for not existing paths.
86
+     * @var \OCP\ICache
87
+     */
88
+    private $objectCache;
89
+
90
+    /**
91
+     * @param string $path
92
+     */
93
+    private function normalizePath($path) {
94
+        $path = trim($path, '/');
95
+
96
+        if (!$path) {
97
+            $path = '.';
98
+        }
99
+
100
+        $path = str_replace('#', '%23', $path);
101
+
102
+        return $path;
103
+    }
104
+
105
+    const SUBCONTAINER_FILE = '.subcontainers';
106
+
107
+    /**
108
+     * translate directory path to container name
109
+     *
110
+     * @param string $path
111
+     * @return string
112
+     */
113
+
114
+    /**
115
+     * Fetches an object from the API.
116
+     * If the object is cached already or a
117
+     * failed "doesn't exist" response was cached,
118
+     * that one will be returned.
119
+     *
120
+     * @param string $path
121
+     * @return \OpenCloud\ObjectStore\Resource\DataObject|bool object
122
+     * or false if the object did not exist
123
+     */
124
+    private function fetchObject($path) {
125
+        if ($this->objectCache->hasKey($path)) {
126
+            // might be "false" if object did not exist from last check
127
+            return $this->objectCache->get($path);
128
+        }
129
+        try {
130
+            $object = $this->getContainer()->getPartialObject($path);
131
+            $this->objectCache->set($path, $object);
132
+            return $object;
133
+        } catch (ClientErrorResponseException $e) {
134
+            // this exception happens when the object does not exist, which
135
+            // is expected in most cases
136
+            $this->objectCache->set($path, false);
137
+            return false;
138
+        } catch (ClientErrorResponseException $e) {
139
+            // Expected response is "404 Not Found", so only log if it isn't
140
+            if ($e->getResponse()->getStatusCode() !== 404) {
141
+                \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
142
+            }
143
+            return false;
144
+        }
145
+    }
146
+
147
+    /**
148
+     * Returns whether the given path exists.
149
+     *
150
+     * @param string $path
151
+     *
152
+     * @return bool true if the object exist, false otherwise
153
+     */
154
+    private function doesObjectExist($path) {
155
+        return $this->fetchObject($path) !== false;
156
+    }
157
+
158
+    public function __construct($params) {
159
+        if ((empty($params['key']) and empty($params['password']))
160
+            or empty($params['user']) or empty($params['bucket'])
161
+            or empty($params['region'])
162
+        ) {
163
+            throw new \Exception("API Key or password, Username, Bucket and Region have to be configured.");
164
+        }
165
+
166
+        $this->id = 'swift::' . $params['user'] . md5($params['bucket']);
167
+
168
+        $bucketUrl = Url::factory($params['bucket']);
169
+        if ($bucketUrl->isAbsolute()) {
170
+            $this->bucket = end(($bucketUrl->getPathSegments()));
171
+            $params['endpoint_url'] = $bucketUrl->addPath('..')->normalizePath();
172
+        } else {
173
+            $this->bucket = $params['bucket'];
174
+        }
175
+
176
+        if (empty($params['url'])) {
177
+            $params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
178
+        }
179
+
180
+        if (empty($params['service_name'])) {
181
+            $params['service_name'] = 'cloudFiles';
182
+        }
183
+
184
+        $this->params = $params;
185
+        // FIXME: private class...
186
+        $this->objectCache = new \OC\Cache\CappedMemoryCache();
187
+    }
188
+
189
+    public function mkdir($path) {
190
+        $path = $this->normalizePath($path);
191
+
192
+        if ($this->is_dir($path)) {
193
+            return false;
194
+        }
195
+
196
+        if ($path !== '.') {
197
+            $path .= '/';
198
+        }
199
+
200
+        try {
201
+            $customHeaders = array('content-type' => 'httpd/unix-directory');
202
+            $metadataHeaders = DataObject::stockHeaders(array());
203
+            $allHeaders = $customHeaders + $metadataHeaders;
204
+            $this->getContainer()->uploadObject($path, '', $allHeaders);
205
+            // invalidate so that the next access gets the real object
206
+            // with all properties
207
+            $this->objectCache->remove($path);
208
+        } catch (Exceptions\CreateUpdateError $e) {
209
+            \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
210
+            return false;
211
+        }
212
+
213
+        return true;
214
+    }
215
+
216
+    public function file_exists($path) {
217
+        $path = $this->normalizePath($path);
218
+
219
+        if ($path !== '.' && $this->is_dir($path)) {
220
+            $path .= '/';
221
+        }
222
+
223
+        return $this->doesObjectExist($path);
224
+    }
225
+
226
+    public function rmdir($path) {
227
+        $path = $this->normalizePath($path);
228
+
229
+        if (!$this->is_dir($path) || !$this->isDeletable($path)) {
230
+            return false;
231
+        }
232
+
233
+        $dh = $this->opendir($path);
234
+        while ($file = readdir($dh)) {
235
+            if (\OC\Files\Filesystem::isIgnoredDir($file)) {
236
+                continue;
237
+            }
238
+
239
+            if ($this->is_dir($path . '/' . $file)) {
240
+                $this->rmdir($path . '/' . $file);
241
+            } else {
242
+                $this->unlink($path . '/' . $file);
243
+            }
244
+        }
245
+
246
+        try {
247
+            $this->getContainer()->dataObject()->setName($path . '/')->delete();
248
+            $this->objectCache->remove($path . '/');
249
+        } catch (Exceptions\DeleteError $e) {
250
+            \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
251
+            return false;
252
+        }
253
+
254
+        return true;
255
+    }
256
+
257
+    public function opendir($path) {
258
+        $path = $this->normalizePath($path);
259
+
260
+        if ($path === '.') {
261
+            $path = '';
262
+        } else {
263
+            $path .= '/';
264
+        }
265
+
266
+        $path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of #
267
+
268
+        try {
269
+            $files = array();
270
+            /** @var OpenCloud\Common\Collection $objects */
271
+            $objects = $this->getContainer()->objectList(array(
272
+                'prefix' => $path,
273
+                'delimiter' => '/'
274
+            ));
275
+
276
+            /** @var OpenCloud\ObjectStore\Resource\DataObject $object */
277
+            foreach ($objects as $object) {
278
+                $file = basename($object->getName());
279
+                if ($file !== basename($path)) {
280
+                    $files[] = $file;
281
+                }
282
+            }
283
+
284
+            return IteratorDirectory::wrap($files);
285
+        } catch (\Exception $e) {
286
+            \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
287
+            return false;
288
+        }
289
+
290
+    }
291
+
292
+    public function stat($path) {
293
+        $path = $this->normalizePath($path);
294
+
295
+        if ($path === '.') {
296
+            $path = '';
297
+        } else if ($this->is_dir($path)) {
298
+            $path .= '/';
299
+        }
300
+
301
+        try {
302
+            /** @var DataObject $object */
303
+            $object = $this->fetchObject($path);
304
+            if (!$object) {
305
+                return false;
306
+            }
307
+        } catch (ClientErrorResponseException $e) {
308
+            \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
309
+            return false;
310
+        }
311
+
312
+        $dateTime = \DateTime::createFromFormat(\DateTime::RFC1123, $object->getLastModified());
313
+        if ($dateTime !== false) {
314
+            $mtime = $dateTime->getTimestamp();
315
+        } else {
316
+            $mtime = null;
317
+        }
318
+        $objectMetadata = $object->getMetadata();
319
+        $metaTimestamp = $objectMetadata->getProperty('timestamp');
320
+        if (isset($metaTimestamp)) {
321
+            $mtime = $metaTimestamp;
322
+        }
323
+
324
+        if (!empty($mtime)) {
325
+            $mtime = floor($mtime);
326
+        }
327
+
328
+        $stat = array();
329
+        $stat['size'] = (int)$object->getContentLength();
330
+        $stat['mtime'] = $mtime;
331
+        $stat['atime'] = time();
332
+        return $stat;
333
+    }
334
+
335
+    public function filetype($path) {
336
+        $path = $this->normalizePath($path);
337
+
338
+        if ($path !== '.' && $this->doesObjectExist($path)) {
339
+            return 'file';
340
+        }
341
+
342
+        if ($path !== '.') {
343
+            $path .= '/';
344
+        }
345
+
346
+        if ($this->doesObjectExist($path)) {
347
+            return 'dir';
348
+        }
349
+    }
350
+
351
+    public function unlink($path) {
352
+        $path = $this->normalizePath($path);
353
+
354
+        if ($this->is_dir($path)) {
355
+            return $this->rmdir($path);
356
+        }
357
+
358
+        try {
359
+            $this->getContainer()->dataObject()->setName($path)->delete();
360
+            $this->objectCache->remove($path);
361
+            $this->objectCache->remove($path . '/');
362
+        } catch (ClientErrorResponseException $e) {
363
+            if ($e->getResponse()->getStatusCode() !== 404) {
364
+                \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
365
+            }
366
+            return false;
367
+        }
368
+
369
+        return true;
370
+    }
371
+
372
+    public function fopen($path, $mode) {
373
+        $path = $this->normalizePath($path);
374
+
375
+        switch ($mode) {
376
+            case 'a':
377
+            case 'ab':
378
+            case 'a+':
379
+                return false;
380
+            case 'r':
381
+            case 'rb':
382
+                try {
383
+                    $c = $this->getContainer();
384
+                    $streamFactory = new \Guzzle\Stream\PhpStreamRequestFactory();
385
+                    /** @var \OpenCloud\Common\Http\Client $client */
386
+                    $client = $c->getClient();
387
+                    $streamInterface = $streamFactory->fromRequest($client->get($c->getUrl($path)));
388
+                    $streamInterface->rewind();
389
+                    $stream = $streamInterface->getStream();
390
+                    stream_context_set_option($stream, 'swift','content', $streamInterface);
391
+                    if(!strrpos($streamInterface
392
+                        ->getMetaData('wrapper_data')[0], '404 Not Found')) {
393
+                        return $stream;
394
+                    }
395
+                    return false;
396
+                } catch (\Guzzle\Http\Exception\BadResponseException $e) {
397
+                    \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
398
+                    return false;
399
+                }
400
+            case 'w':
401
+            case 'wb':
402
+            case 'r+':
403
+            case 'w+':
404
+            case 'wb+':
405
+            case 'x':
406
+            case 'x+':
407
+            case 'c':
408
+            case 'c+':
409
+                if (strrpos($path, '.') !== false) {
410
+                    $ext = substr($path, strrpos($path, '.'));
411
+                } else {
412
+                    $ext = '';
413
+                }
414
+                $tmpFile = \OCP\Files::tmpFile($ext);
415
+                // Fetch existing file if required
416
+                if ($mode[0] !== 'w' && $this->file_exists($path)) {
417
+                    if ($mode[0] === 'x') {
418
+                        // File cannot already exist
419
+                        return false;
420
+                    }
421
+                    $source = $this->fopen($path, 'r');
422
+                    file_put_contents($tmpFile, $source);
423
+                }
424
+                $handle = fopen($tmpFile, $mode);
425
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
426
+                    $this->writeBack($tmpFile, $path);
427
+                });
428
+        }
429
+    }
430
+
431
+    public function touch($path, $mtime = null) {
432
+        $path = $this->normalizePath($path);
433
+        if (is_null($mtime)) {
434
+            $mtime = time();
435
+        }
436
+        $metadata = array('timestamp' => $mtime);
437
+        if ($this->file_exists($path)) {
438
+            if ($this->is_dir($path) && $path != '.') {
439
+                $path .= '/';
440
+            }
441
+
442
+            $object = $this->fetchObject($path);
443
+            if ($object->saveMetadata($metadata)) {
444
+                // invalidate target object to force repopulation on fetch
445
+                $this->objectCache->remove($path);
446
+            }
447
+            return true;
448
+        } else {
449
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
450
+            $customHeaders = array('content-type' => $mimeType);
451
+            $metadataHeaders = DataObject::stockHeaders($metadata);
452
+            $allHeaders = $customHeaders + $metadataHeaders;
453
+            $this->getContainer()->uploadObject($path, '', $allHeaders);
454
+            // invalidate target object to force repopulation on fetch
455
+            $this->objectCache->remove($path);
456
+            return true;
457
+        }
458
+    }
459
+
460
+    public function copy($path1, $path2) {
461
+        $path1 = $this->normalizePath($path1);
462
+        $path2 = $this->normalizePath($path2);
463
+
464
+        $fileType = $this->filetype($path1);
465
+        if ($fileType === 'file') {
466
+
467
+            // make way
468
+            $this->unlink($path2);
469
+
470
+            try {
471
+                $source = $this->fetchObject($path1);
472
+                $source->copy($this->bucket . '/' . $path2);
473
+                // invalidate target object to force repopulation on fetch
474
+                $this->objectCache->remove($path2);
475
+                $this->objectCache->remove($path2 . '/');
476
+            } catch (ClientErrorResponseException $e) {
477
+                \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
478
+                return false;
479
+            }
480
+
481
+        } else if ($fileType === 'dir') {
482
+
483
+            // make way
484
+            $this->unlink($path2);
485
+
486
+            try {
487
+                $source = $this->fetchObject($path1 . '/');
488
+                $source->copy($this->bucket . '/' . $path2 . '/');
489
+                // invalidate target object to force repopulation on fetch
490
+                $this->objectCache->remove($path2);
491
+                $this->objectCache->remove($path2 . '/');
492
+            } catch (ClientErrorResponseException $e) {
493
+                \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
494
+                return false;
495
+            }
496
+
497
+            $dh = $this->opendir($path1);
498
+            while ($file = readdir($dh)) {
499
+                if (\OC\Files\Filesystem::isIgnoredDir($file)) {
500
+                    continue;
501
+                }
502
+
503
+                $source = $path1 . '/' . $file;
504
+                $target = $path2 . '/' . $file;
505
+                $this->copy($source, $target);
506
+            }
507
+
508
+        } else {
509
+            //file does not exist
510
+            return false;
511
+        }
512
+
513
+        return true;
514
+    }
515
+
516
+    public function rename($path1, $path2) {
517
+        $path1 = $this->normalizePath($path1);
518
+        $path2 = $this->normalizePath($path2);
519
+
520
+        $fileType = $this->filetype($path1);
521
+
522
+        if ($fileType === 'dir' || $fileType === 'file') {
523
+            // copy
524
+            if ($this->copy($path1, $path2) === false) {
525
+                return false;
526
+            }
527
+
528
+            // cleanup
529
+            if ($this->unlink($path1) === false) {
530
+                $this->unlink($path2);
531
+                return false;
532
+            }
533
+
534
+            return true;
535
+        }
536
+
537
+        return false;
538
+    }
539
+
540
+    public function getId() {
541
+        return $this->id;
542
+    }
543
+
544
+    /**
545
+     * Returns the connection
546
+     *
547
+     * @return OpenCloud\ObjectStore\Service connected client
548
+     * @throws \Exception if connection could not be made
549
+     */
550
+    public function getConnection() {
551
+        if (!is_null($this->connection)) {
552
+            return $this->connection;
553
+        }
554
+
555
+        $settings = array(
556
+            'username' => $this->params['user'],
557
+        );
558
+
559
+        if (!empty($this->params['password'])) {
560
+            $settings['password'] = $this->params['password'];
561
+        } else if (!empty($this->params['key'])) {
562
+            $settings['apiKey'] = $this->params['key'];
563
+        }
564
+
565
+        if (!empty($this->params['tenant'])) {
566
+            $settings['tenantName'] = $this->params['tenant'];
567
+        }
568
+
569
+        if (!empty($this->params['timeout'])) {
570
+            $settings['timeout'] = $this->params['timeout'];
571
+        }
572
+
573
+        if (isset($settings['apiKey'])) {
574
+            $this->anchor = new Rackspace($this->params['url'], $settings);
575
+        } else {
576
+            $this->anchor = new OpenStack($this->params['url'], $settings);
577
+        }
578
+
579
+        $connection = $this->anchor->objectStoreService($this->params['service_name'], $this->params['region']);
580
+
581
+        if (!empty($this->params['endpoint_url'])) {
582
+            $endpoint = $connection->getEndpoint();
583
+            $endpoint->setPublicUrl($this->params['endpoint_url']);
584
+            $endpoint->setPrivateUrl($this->params['endpoint_url']);
585
+            $connection->setEndpoint($endpoint);
586
+        }
587
+
588
+        $this->connection = $connection;
589
+
590
+        return $this->connection;
591
+    }
592
+
593
+    /**
594
+     * Returns the initialized object store container.
595
+     *
596
+     * @return OpenCloud\ObjectStore\Resource\Container
597
+     */
598
+    public function getContainer() {
599
+        if (!is_null($this->container)) {
600
+            return $this->container;
601
+        }
602
+
603
+        try {
604
+            $this->container = $this->getConnection()->getContainer($this->bucket);
605
+        } catch (ClientErrorResponseException $e) {
606
+            $this->container = $this->getConnection()->createContainer($this->bucket);
607
+        }
608
+
609
+        if (!$this->file_exists('.')) {
610
+            $this->mkdir('.');
611
+        }
612
+
613
+        return $this->container;
614
+    }
615
+
616
+    public function writeBack($tmpFile, $path) {
617
+        $fileData = fopen($tmpFile, 'r');
618
+        $this->getContainer()->uploadObject($path, $fileData);
619
+        // invalidate target object to force repopulation on fetch
620
+        $this->objectCache->remove(self::$tmpFiles[$tmpFile]);
621
+        unlink($tmpFile);
622
+    }
623
+
624
+    public function hasUpdated($path, $time) {
625
+        if ($this->is_file($path)) {
626
+            return parent::hasUpdated($path, $time);
627
+        }
628
+        $path = $this->normalizePath($path);
629
+        $dh = $this->opendir($path);
630
+        $content = array();
631
+        while (($file = readdir($dh)) !== false) {
632
+            $content[] = $file;
633
+        }
634
+        if ($path === '.') {
635
+            $path = '';
636
+        }
637
+        $cachedContent = $this->getCache()->getFolderContents($path);
638
+        $cachedNames = array_map(function ($content) {
639
+            return $content['name'];
640
+        }, $cachedContent);
641
+        sort($cachedNames);
642
+        sort($content);
643
+        return $cachedNames != $content;
644
+    }
645
+
646
+    /**
647
+     * check if curl is installed
648
+     */
649
+    public static function checkDependencies() {
650
+        return true;
651
+    }
652 652
 
653 653
 }
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 			throw new \Exception("API Key or password, Username, Bucket and Region have to be configured.");
164 164
 		}
165 165
 
166
-		$this->id = 'swift::' . $params['user'] . md5($params['bucket']);
166
+		$this->id = 'swift::'.$params['user'].md5($params['bucket']);
167 167
 
168 168
 		$bucketUrl = Url::factory($params['bucket']);
169 169
 		if ($bucketUrl->isAbsolute()) {
@@ -236,16 +236,16 @@  discard block
 block discarded – undo
236 236
 				continue;
237 237
 			}
238 238
 
239
-			if ($this->is_dir($path . '/' . $file)) {
240
-				$this->rmdir($path . '/' . $file);
239
+			if ($this->is_dir($path.'/'.$file)) {
240
+				$this->rmdir($path.'/'.$file);
241 241
 			} else {
242
-				$this->unlink($path . '/' . $file);
242
+				$this->unlink($path.'/'.$file);
243 243
 			}
244 244
 		}
245 245
 
246 246
 		try {
247
-			$this->getContainer()->dataObject()->setName($path . '/')->delete();
248
-			$this->objectCache->remove($path . '/');
247
+			$this->getContainer()->dataObject()->setName($path.'/')->delete();
248
+			$this->objectCache->remove($path.'/');
249 249
 		} catch (Exceptions\DeleteError $e) {
250 250
 			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
251 251
 			return false;
@@ -326,7 +326,7 @@  discard block
 block discarded – undo
326 326
 		}
327 327
 
328 328
 		$stat = array();
329
-		$stat['size'] = (int)$object->getContentLength();
329
+		$stat['size'] = (int) $object->getContentLength();
330 330
 		$stat['mtime'] = $mtime;
331 331
 		$stat['atime'] = time();
332 332
 		return $stat;
@@ -358,7 +358,7 @@  discard block
 block discarded – undo
358 358
 		try {
359 359
 			$this->getContainer()->dataObject()->setName($path)->delete();
360 360
 			$this->objectCache->remove($path);
361
-			$this->objectCache->remove($path . '/');
361
+			$this->objectCache->remove($path.'/');
362 362
 		} catch (ClientErrorResponseException $e) {
363 363
 			if ($e->getResponse()->getStatusCode() !== 404) {
364 364
 				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
@@ -387,8 +387,8 @@  discard block
 block discarded – undo
387 387
 					$streamInterface = $streamFactory->fromRequest($client->get($c->getUrl($path)));
388 388
 					$streamInterface->rewind();
389 389
 					$stream = $streamInterface->getStream();
390
-					stream_context_set_option($stream, 'swift','content', $streamInterface);
391
-					if(!strrpos($streamInterface
390
+					stream_context_set_option($stream, 'swift', 'content', $streamInterface);
391
+					if (!strrpos($streamInterface
392 392
 						->getMetaData('wrapper_data')[0], '404 Not Found')) {
393 393
 						return $stream;
394 394
 					}
@@ -422,7 +422,7 @@  discard block
 block discarded – undo
422 422
 					file_put_contents($tmpFile, $source);
423 423
 				}
424 424
 				$handle = fopen($tmpFile, $mode);
425
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
425
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
426 426
 					$this->writeBack($tmpFile, $path);
427 427
 				});
428 428
 		}
@@ -469,10 +469,10 @@  discard block
 block discarded – undo
469 469
 
470 470
 			try {
471 471
 				$source = $this->fetchObject($path1);
472
-				$source->copy($this->bucket . '/' . $path2);
472
+				$source->copy($this->bucket.'/'.$path2);
473 473
 				// invalidate target object to force repopulation on fetch
474 474
 				$this->objectCache->remove($path2);
475
-				$this->objectCache->remove($path2 . '/');
475
+				$this->objectCache->remove($path2.'/');
476 476
 			} catch (ClientErrorResponseException $e) {
477 477
 				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
478 478
 				return false;
@@ -484,11 +484,11 @@  discard block
 block discarded – undo
484 484
 			$this->unlink($path2);
485 485
 
486 486
 			try {
487
-				$source = $this->fetchObject($path1 . '/');
488
-				$source->copy($this->bucket . '/' . $path2 . '/');
487
+				$source = $this->fetchObject($path1.'/');
488
+				$source->copy($this->bucket.'/'.$path2.'/');
489 489
 				// invalidate target object to force repopulation on fetch
490 490
 				$this->objectCache->remove($path2);
491
-				$this->objectCache->remove($path2 . '/');
491
+				$this->objectCache->remove($path2.'/');
492 492
 			} catch (ClientErrorResponseException $e) {
493 493
 				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
494 494
 				return false;
@@ -500,8 +500,8 @@  discard block
 block discarded – undo
500 500
 					continue;
501 501
 				}
502 502
 
503
-				$source = $path1 . '/' . $file;
504
-				$target = $path2 . '/' . $file;
503
+				$source = $path1.'/'.$file;
504
+				$target = $path2.'/'.$file;
505 505
 				$this->copy($source, $target);
506 506
 			}
507 507
 
@@ -635,7 +635,7 @@  discard block
 block discarded – undo
635 635
 			$path = '';
636 636
 		}
637 637
 		$cachedContent = $this->getCache()->getFolderContents($path);
638
-		$cachedNames = array_map(function ($content) {
638
+		$cachedNames = array_map(function($content) {
639 639
 			return $content['name'];
640 640
 		}, $cachedContent);
641 641
 		sort($cachedNames);
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareAPIController.php 1 patch
Indentation   +878 added lines, -878 removed lines patch added patch discarded remove patch
@@ -52,891 +52,891 @@
 block discarded – undo
52 52
  */
53 53
 class ShareAPIController extends OCSController {
54 54
 
55
-	/** @var IManager */
56
-	private $shareManager;
57
-	/** @var IGroupManager */
58
-	private $groupManager;
59
-	/** @var IUserManager */
60
-	private $userManager;
61
-	/** @var IRequest */
62
-	protected $request;
63
-	/** @var IRootFolder */
64
-	private $rootFolder;
65
-	/** @var IURLGenerator */
66
-	private $urlGenerator;
67
-	/** @var string */
68
-	private $currentUser;
69
-	/** @var IL10N */
70
-	private $l;
71
-	/** @var \OCP\Files\Node */
72
-	private $lockedNode;
73
-
74
-	/**
75
-	 * Share20OCS constructor.
76
-	 *
77
-	 * @param string $appName
78
-	 * @param IRequest $request
79
-	 * @param IManager $shareManager
80
-	 * @param IGroupManager $groupManager
81
-	 * @param IUserManager $userManager
82
-	 * @param IRootFolder $rootFolder
83
-	 * @param IURLGenerator $urlGenerator
84
-	 * @param string $userId
85
-	 * @param IL10N $l10n
86
-	 */
87
-	public function __construct(
88
-		$appName,
89
-		IRequest $request,
90
-		IManager $shareManager,
91
-		IGroupManager $groupManager,
92
-		IUserManager $userManager,
93
-		IRootFolder $rootFolder,
94
-		IURLGenerator $urlGenerator,
95
-		$userId,
96
-		IL10N $l10n
97
-	) {
98
-		parent::__construct($appName, $request);
99
-
100
-		$this->shareManager = $shareManager;
101
-		$this->userManager = $userManager;
102
-		$this->groupManager = $groupManager;
103
-		$this->request = $request;
104
-		$this->rootFolder = $rootFolder;
105
-		$this->urlGenerator = $urlGenerator;
106
-		$this->currentUser = $userId;
107
-		$this->l = $l10n;
108
-	}
109
-
110
-	/**
111
-	 * Convert an IShare to an array for OCS output
112
-	 *
113
-	 * @param \OCP\Share\IShare $share
114
-	 * @param Node|null $recipientNode
115
-	 * @return array
116
-	 * @throws NotFoundException In case the node can't be resolved.
117
-	 */
118
-	protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = null) {
119
-		$sharedBy = $this->userManager->get($share->getSharedBy());
120
-		$shareOwner = $this->userManager->get($share->getShareOwner());
121
-
122
-		$result = [
123
-			'id' => $share->getId(),
124
-			'share_type' => $share->getShareType(),
125
-			'uid_owner' => $share->getSharedBy(),
126
-			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
127
-			'permissions' => $share->getPermissions(),
128
-			'stime' => $share->getShareTime()->getTimestamp(),
129
-			'parent' => null,
130
-			'expiration' => null,
131
-			'token' => null,
132
-			'uid_file_owner' => $share->getShareOwner(),
133
-			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
134
-		];
135
-
136
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
137
-		if ($recipientNode) {
138
-			$node = $recipientNode;
139
-		} else {
140
-			$nodes = $userFolder->getById($share->getNodeId());
141
-
142
-			if (empty($nodes)) {
143
-				// fallback to guessing the path
144
-				$node = $userFolder->get($share->getTarget());
145
-				if ($node === null) {
146
-					throw new NotFoundException();
147
-				}
148
-			} else {
149
-				$node = $nodes[0];
150
-			}
151
-		}
152
-
153
-		$result['path'] = $userFolder->getRelativePath($node->getPath());
154
-		if ($node instanceOf \OCP\Files\Folder) {
155
-			$result['item_type'] = 'folder';
156
-		} else {
157
-			$result['item_type'] = 'file';
158
-		}
159
-		$result['mimetype'] = $node->getMimetype();
160
-		$result['storage_id'] = $node->getStorage()->getId();
161
-		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
162
-		$result['item_source'] = $node->getId();
163
-		$result['file_source'] = $node->getId();
164
-		$result['file_parent'] = $node->getParent()->getId();
165
-		$result['file_target'] = $share->getTarget();
166
-
167
-		$expiration = $share->getExpirationDate();
168
-		if ($expiration !== null) {
169
-			$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
170
-		}
171
-
172
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
173
-			$sharedWith = $this->userManager->get($share->getSharedWith());
174
-			$result['share_with'] = $share->getSharedWith();
175
-			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
176
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
177
-			$group = $this->groupManager->get($share->getSharedWith());
178
-			$result['share_with'] = $share->getSharedWith();
179
-			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
180
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
181
-
182
-			$result['share_with'] = $share->getPassword();
183
-			$result['share_with_displayname'] = $share->getPassword();
184
-
185
-			$result['token'] = $share->getToken();
186
-			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
187
-
188
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
189
-			$result['share_with'] = $share->getSharedWith();
190
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
191
-			$result['token'] = $share->getToken();
192
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
193
-			$result['share_with'] = $share->getSharedWith();
194
-			$result['password'] = $share->getPassword();
195
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
196
-			$result['token'] = $share->getToken();
197
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
198
-			$result['share_with_displayname'] = $share->getSharedWith();
199
-			$result['share_with'] = explode(' ', $share->getSharedWith(), 2)[0];
200
-		}
201
-
202
-
203
-		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
204
-
205
-		return $result;
206
-	}
207
-
208
-	/**
209
-	 * Check if one of the users address books knows the exact property, if
210
-	 * yes we return the full name.
211
-	 *
212
-	 * @param string $query
213
-	 * @param string $property
214
-	 * @return string
215
-	 */
216
-	private function getDisplayNameFromAddressBook($query, $property) {
217
-		// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
218
-		$result = \OC::$server->getContactsManager()->search($query, [$property]);
219
-		foreach ($result as $r) {
220
-			foreach($r[$property] as $value) {
221
-				if ($value === $query) {
222
-					return $r['FN'];
223
-				}
224
-			}
225
-		}
226
-
227
-		return $query;
228
-	}
229
-
230
-	/**
231
-	 * Get a specific share by id
232
-	 *
233
-	 * @NoAdminRequired
234
-	 *
235
-	 * @param string $id
236
-	 * @return DataResponse
237
-	 * @throws OCSNotFoundException
238
-	 */
239
-	public function getShare($id) {
240
-		try {
241
-			$share = $this->getShareById($id);
242
-		} catch (ShareNotFound $e) {
243
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
244
-		}
245
-
246
-		if ($this->canAccessShare($share)) {
247
-			try {
248
-				$share = $this->formatShare($share);
249
-				return new DataResponse([$share]);
250
-			} catch (NotFoundException $e) {
251
-				//Fall trough
252
-			}
253
-		}
254
-
255
-		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
256
-	}
257
-
258
-	/**
259
-	 * Delete a share
260
-	 *
261
-	 * @NoAdminRequired
262
-	 *
263
-	 * @param string $id
264
-	 * @return DataResponse
265
-	 * @throws OCSNotFoundException
266
-	 */
267
-	public function deleteShare($id) {
268
-		try {
269
-			$share = $this->getShareById($id);
270
-		} catch (ShareNotFound $e) {
271
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
272
-		}
273
-
274
-		try {
275
-			$this->lock($share->getNode());
276
-		} catch (LockedException $e) {
277
-			throw new OCSNotFoundException($this->l->t('could not delete share'));
278
-		}
279
-
280
-		if (!$this->canAccessShare($share)) {
281
-			throw new OCSNotFoundException($this->l->t('Could not delete share'));
282
-		}
283
-
284
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP &&
285
-			$share->getShareOwner() !== $this->currentUser &&
286
-			$share->getSharedBy() !== $this->currentUser) {
287
-			$this->shareManager->deleteFromSelf($share, $this->currentUser);
288
-		} else {
289
-			$this->shareManager->deleteShare($share);
290
-		}
291
-
292
-		return new DataResponse();
293
-	}
294
-
295
-	/**
296
-	 * @NoAdminRequired
297
-	 *
298
-	 * @param string $path
299
-	 * @param int $permissions
300
-	 * @param int $shareType
301
-	 * @param string $shareWith
302
-	 * @param string $publicUpload
303
-	 * @param string $password
304
-	 * @param string $expireDate
305
-	 *
306
-	 * @return DataResponse
307
-	 * @throws OCSNotFoundException
308
-	 * @throws OCSForbiddenException
309
-	 * @throws OCSBadRequestException
310
-	 * @throws OCSException
311
-	 *
312
-	 * @suppress PhanUndeclaredClassMethod
313
-	 */
314
-	public function createShare(
315
-		$path = null,
316
-		$permissions = \OCP\Constants::PERMISSION_ALL,
317
-		$shareType = -1,
318
-		$shareWith = null,
319
-		$publicUpload = 'false',
320
-		$password = '',
321
-		$expireDate = ''
322
-	) {
323
-		$share = $this->shareManager->newShare();
324
-
325
-		// Verify path
326
-		if ($path === null) {
327
-			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
328
-		}
329
-
330
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
331
-		try {
332
-			$path = $userFolder->get($path);
333
-		} catch (NotFoundException $e) {
334
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
335
-		}
336
-
337
-		$share->setNode($path);
338
-
339
-		try {
340
-			$this->lock($share->getNode());
341
-		} catch (LockedException $e) {
342
-			throw new OCSNotFoundException($this->l->t('Could not create share'));
343
-		}
344
-
345
-		if ($permissions < 0 || $permissions > \OCP\Constants::PERMISSION_ALL) {
346
-			throw new OCSNotFoundException($this->l->t('invalid permissions'));
347
-		}
348
-
349
-		// Shares always require read permissions
350
-		$permissions |= \OCP\Constants::PERMISSION_READ;
351
-
352
-		if ($path instanceof \OCP\Files\File) {
353
-			// Single file shares should never have delete or create permissions
354
-			$permissions &= ~\OCP\Constants::PERMISSION_DELETE;
355
-			$permissions &= ~\OCP\Constants::PERMISSION_CREATE;
356
-		}
357
-
358
-		/*
55
+    /** @var IManager */
56
+    private $shareManager;
57
+    /** @var IGroupManager */
58
+    private $groupManager;
59
+    /** @var IUserManager */
60
+    private $userManager;
61
+    /** @var IRequest */
62
+    protected $request;
63
+    /** @var IRootFolder */
64
+    private $rootFolder;
65
+    /** @var IURLGenerator */
66
+    private $urlGenerator;
67
+    /** @var string */
68
+    private $currentUser;
69
+    /** @var IL10N */
70
+    private $l;
71
+    /** @var \OCP\Files\Node */
72
+    private $lockedNode;
73
+
74
+    /**
75
+     * Share20OCS constructor.
76
+     *
77
+     * @param string $appName
78
+     * @param IRequest $request
79
+     * @param IManager $shareManager
80
+     * @param IGroupManager $groupManager
81
+     * @param IUserManager $userManager
82
+     * @param IRootFolder $rootFolder
83
+     * @param IURLGenerator $urlGenerator
84
+     * @param string $userId
85
+     * @param IL10N $l10n
86
+     */
87
+    public function __construct(
88
+        $appName,
89
+        IRequest $request,
90
+        IManager $shareManager,
91
+        IGroupManager $groupManager,
92
+        IUserManager $userManager,
93
+        IRootFolder $rootFolder,
94
+        IURLGenerator $urlGenerator,
95
+        $userId,
96
+        IL10N $l10n
97
+    ) {
98
+        parent::__construct($appName, $request);
99
+
100
+        $this->shareManager = $shareManager;
101
+        $this->userManager = $userManager;
102
+        $this->groupManager = $groupManager;
103
+        $this->request = $request;
104
+        $this->rootFolder = $rootFolder;
105
+        $this->urlGenerator = $urlGenerator;
106
+        $this->currentUser = $userId;
107
+        $this->l = $l10n;
108
+    }
109
+
110
+    /**
111
+     * Convert an IShare to an array for OCS output
112
+     *
113
+     * @param \OCP\Share\IShare $share
114
+     * @param Node|null $recipientNode
115
+     * @return array
116
+     * @throws NotFoundException In case the node can't be resolved.
117
+     */
118
+    protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = null) {
119
+        $sharedBy = $this->userManager->get($share->getSharedBy());
120
+        $shareOwner = $this->userManager->get($share->getShareOwner());
121
+
122
+        $result = [
123
+            'id' => $share->getId(),
124
+            'share_type' => $share->getShareType(),
125
+            'uid_owner' => $share->getSharedBy(),
126
+            'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
127
+            'permissions' => $share->getPermissions(),
128
+            'stime' => $share->getShareTime()->getTimestamp(),
129
+            'parent' => null,
130
+            'expiration' => null,
131
+            'token' => null,
132
+            'uid_file_owner' => $share->getShareOwner(),
133
+            'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
134
+        ];
135
+
136
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
137
+        if ($recipientNode) {
138
+            $node = $recipientNode;
139
+        } else {
140
+            $nodes = $userFolder->getById($share->getNodeId());
141
+
142
+            if (empty($nodes)) {
143
+                // fallback to guessing the path
144
+                $node = $userFolder->get($share->getTarget());
145
+                if ($node === null) {
146
+                    throw new NotFoundException();
147
+                }
148
+            } else {
149
+                $node = $nodes[0];
150
+            }
151
+        }
152
+
153
+        $result['path'] = $userFolder->getRelativePath($node->getPath());
154
+        if ($node instanceOf \OCP\Files\Folder) {
155
+            $result['item_type'] = 'folder';
156
+        } else {
157
+            $result['item_type'] = 'file';
158
+        }
159
+        $result['mimetype'] = $node->getMimetype();
160
+        $result['storage_id'] = $node->getStorage()->getId();
161
+        $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
162
+        $result['item_source'] = $node->getId();
163
+        $result['file_source'] = $node->getId();
164
+        $result['file_parent'] = $node->getParent()->getId();
165
+        $result['file_target'] = $share->getTarget();
166
+
167
+        $expiration = $share->getExpirationDate();
168
+        if ($expiration !== null) {
169
+            $result['expiration'] = $expiration->format('Y-m-d 00:00:00');
170
+        }
171
+
172
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
173
+            $sharedWith = $this->userManager->get($share->getSharedWith());
174
+            $result['share_with'] = $share->getSharedWith();
175
+            $result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
176
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
177
+            $group = $this->groupManager->get($share->getSharedWith());
178
+            $result['share_with'] = $share->getSharedWith();
179
+            $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
180
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
181
+
182
+            $result['share_with'] = $share->getPassword();
183
+            $result['share_with_displayname'] = $share->getPassword();
184
+
185
+            $result['token'] = $share->getToken();
186
+            $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
187
+
188
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
189
+            $result['share_with'] = $share->getSharedWith();
190
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
191
+            $result['token'] = $share->getToken();
192
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
193
+            $result['share_with'] = $share->getSharedWith();
194
+            $result['password'] = $share->getPassword();
195
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
196
+            $result['token'] = $share->getToken();
197
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
198
+            $result['share_with_displayname'] = $share->getSharedWith();
199
+            $result['share_with'] = explode(' ', $share->getSharedWith(), 2)[0];
200
+        }
201
+
202
+
203
+        $result['mail_send'] = $share->getMailSend() ? 1 : 0;
204
+
205
+        return $result;
206
+    }
207
+
208
+    /**
209
+     * Check if one of the users address books knows the exact property, if
210
+     * yes we return the full name.
211
+     *
212
+     * @param string $query
213
+     * @param string $property
214
+     * @return string
215
+     */
216
+    private function getDisplayNameFromAddressBook($query, $property) {
217
+        // FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
218
+        $result = \OC::$server->getContactsManager()->search($query, [$property]);
219
+        foreach ($result as $r) {
220
+            foreach($r[$property] as $value) {
221
+                if ($value === $query) {
222
+                    return $r['FN'];
223
+                }
224
+            }
225
+        }
226
+
227
+        return $query;
228
+    }
229
+
230
+    /**
231
+     * Get a specific share by id
232
+     *
233
+     * @NoAdminRequired
234
+     *
235
+     * @param string $id
236
+     * @return DataResponse
237
+     * @throws OCSNotFoundException
238
+     */
239
+    public function getShare($id) {
240
+        try {
241
+            $share = $this->getShareById($id);
242
+        } catch (ShareNotFound $e) {
243
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
244
+        }
245
+
246
+        if ($this->canAccessShare($share)) {
247
+            try {
248
+                $share = $this->formatShare($share);
249
+                return new DataResponse([$share]);
250
+            } catch (NotFoundException $e) {
251
+                //Fall trough
252
+            }
253
+        }
254
+
255
+        throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
256
+    }
257
+
258
+    /**
259
+     * Delete a share
260
+     *
261
+     * @NoAdminRequired
262
+     *
263
+     * @param string $id
264
+     * @return DataResponse
265
+     * @throws OCSNotFoundException
266
+     */
267
+    public function deleteShare($id) {
268
+        try {
269
+            $share = $this->getShareById($id);
270
+        } catch (ShareNotFound $e) {
271
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
272
+        }
273
+
274
+        try {
275
+            $this->lock($share->getNode());
276
+        } catch (LockedException $e) {
277
+            throw new OCSNotFoundException($this->l->t('could not delete share'));
278
+        }
279
+
280
+        if (!$this->canAccessShare($share)) {
281
+            throw new OCSNotFoundException($this->l->t('Could not delete share'));
282
+        }
283
+
284
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP &&
285
+            $share->getShareOwner() !== $this->currentUser &&
286
+            $share->getSharedBy() !== $this->currentUser) {
287
+            $this->shareManager->deleteFromSelf($share, $this->currentUser);
288
+        } else {
289
+            $this->shareManager->deleteShare($share);
290
+        }
291
+
292
+        return new DataResponse();
293
+    }
294
+
295
+    /**
296
+     * @NoAdminRequired
297
+     *
298
+     * @param string $path
299
+     * @param int $permissions
300
+     * @param int $shareType
301
+     * @param string $shareWith
302
+     * @param string $publicUpload
303
+     * @param string $password
304
+     * @param string $expireDate
305
+     *
306
+     * @return DataResponse
307
+     * @throws OCSNotFoundException
308
+     * @throws OCSForbiddenException
309
+     * @throws OCSBadRequestException
310
+     * @throws OCSException
311
+     *
312
+     * @suppress PhanUndeclaredClassMethod
313
+     */
314
+    public function createShare(
315
+        $path = null,
316
+        $permissions = \OCP\Constants::PERMISSION_ALL,
317
+        $shareType = -1,
318
+        $shareWith = null,
319
+        $publicUpload = 'false',
320
+        $password = '',
321
+        $expireDate = ''
322
+    ) {
323
+        $share = $this->shareManager->newShare();
324
+
325
+        // Verify path
326
+        if ($path === null) {
327
+            throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
328
+        }
329
+
330
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
331
+        try {
332
+            $path = $userFolder->get($path);
333
+        } catch (NotFoundException $e) {
334
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
335
+        }
336
+
337
+        $share->setNode($path);
338
+
339
+        try {
340
+            $this->lock($share->getNode());
341
+        } catch (LockedException $e) {
342
+            throw new OCSNotFoundException($this->l->t('Could not create share'));
343
+        }
344
+
345
+        if ($permissions < 0 || $permissions > \OCP\Constants::PERMISSION_ALL) {
346
+            throw new OCSNotFoundException($this->l->t('invalid permissions'));
347
+        }
348
+
349
+        // Shares always require read permissions
350
+        $permissions |= \OCP\Constants::PERMISSION_READ;
351
+
352
+        if ($path instanceof \OCP\Files\File) {
353
+            // Single file shares should never have delete or create permissions
354
+            $permissions &= ~\OCP\Constants::PERMISSION_DELETE;
355
+            $permissions &= ~\OCP\Constants::PERMISSION_CREATE;
356
+        }
357
+
358
+        /*
359 359
 		 * Hack for https://github.com/owncloud/core/issues/22587
360 360
 		 * We check the permissions via webdav. But the permissions of the mount point
361 361
 		 * do not equal the share permissions. Here we fix that for federated mounts.
362 362
 		 */
363
-		if ($path->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
364
-			$permissions &= ~($permissions & ~$path->getPermissions());
365
-		}
366
-
367
-		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
368
-			// Valid user is required to share
369
-			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
370
-				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
371
-			}
372
-			$share->setSharedWith($shareWith);
373
-			$share->setPermissions($permissions);
374
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
375
-			if (!$this->shareManager->allowGroupSharing()) {
376
-				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
377
-			}
378
-
379
-			// Valid group is required to share
380
-			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
381
-				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
382
-			}
383
-			$share->setSharedWith($shareWith);
384
-			$share->setPermissions($permissions);
385
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
386
-			//Can we even share links?
387
-			if (!$this->shareManager->shareApiAllowLinks()) {
388
-				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
389
-			}
390
-
391
-			/*
363
+        if ($path->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
364
+            $permissions &= ~($permissions & ~$path->getPermissions());
365
+        }
366
+
367
+        if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
368
+            // Valid user is required to share
369
+            if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
370
+                throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
371
+            }
372
+            $share->setSharedWith($shareWith);
373
+            $share->setPermissions($permissions);
374
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
375
+            if (!$this->shareManager->allowGroupSharing()) {
376
+                throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
377
+            }
378
+
379
+            // Valid group is required to share
380
+            if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
381
+                throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
382
+            }
383
+            $share->setSharedWith($shareWith);
384
+            $share->setPermissions($permissions);
385
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
386
+            //Can we even share links?
387
+            if (!$this->shareManager->shareApiAllowLinks()) {
388
+                throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
389
+            }
390
+
391
+            /*
392 392
 			 * For now we only allow 1 link share.
393 393
 			 * Return the existing link share if this is a duplicate
394 394
 			 */
395
-			$existingShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $path, false, 1, 0);
396
-			if (!empty($existingShares)) {
397
-				return new DataResponse($this->formatShare($existingShares[0]));
398
-			}
399
-
400
-			if ($publicUpload === 'true') {
401
-				// Check if public upload is allowed
402
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
403
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
404
-				}
405
-
406
-				// Public upload can only be set for folders
407
-				if ($path instanceof \OCP\Files\File) {
408
-					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
409
-				}
410
-
411
-				$share->setPermissions(
412
-					\OCP\Constants::PERMISSION_READ |
413
-					\OCP\Constants::PERMISSION_CREATE |
414
-					\OCP\Constants::PERMISSION_UPDATE |
415
-					\OCP\Constants::PERMISSION_DELETE
416
-				);
417
-			} else {
418
-				$share->setPermissions(\OCP\Constants::PERMISSION_READ);
419
-			}
420
-
421
-			// Set password
422
-			if ($password !== '') {
423
-				$share->setPassword($password);
424
-			}
425
-
426
-			//Expire date
427
-			if ($expireDate !== '') {
428
-				try {
429
-					$expireDate = $this->parseDate($expireDate);
430
-					$share->setExpirationDate($expireDate);
431
-				} catch (\Exception $e) {
432
-					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
433
-				}
434
-			}
435
-
436
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
437
-			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
438
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not allow shares from type %s', [$path->getPath(), $shareType]));
439
-			}
440
-
441
-			$share->setSharedWith($shareWith);
442
-			$share->setPermissions($permissions);
443
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_EMAIL) {
444
-			if ($share->getNodeType() === 'file') {
445
-				$share->setPermissions(\OCP\Constants::PERMISSION_READ);
446
-			} else {
447
-				$share->setPermissions(
448
-					\OCP\Constants::PERMISSION_READ |
449
-					\OCP\Constants::PERMISSION_CREATE |
450
-					\OCP\Constants::PERMISSION_UPDATE |
451
-					\OCP\Constants::PERMISSION_DELETE);
452
-			}
453
-			$share->setSharedWith($shareWith);
454
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_CIRCLE) {
455
-			if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
456
-				throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
457
-			}
458
-
459
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
460
-
461
-			// Valid circle is required to share
462
-			if ($circle === null) {
463
-				throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
464
-			}
465
-			$share->setSharedWith($shareWith);
466
-			$share->setPermissions($permissions);
467
-		} else {
468
-			throw new OCSBadRequestException($this->l->t('Unknown share type'));
469
-		}
470
-
471
-		$share->setShareType($shareType);
472
-		$share->setSharedBy($this->currentUser);
473
-
474
-		try {
475
-			$share = $this->shareManager->createShare($share);
476
-		} catch (GenericShareException $e) {
477
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
478
-			throw new OCSException($e->getHint(), $code);
479
-		} catch (\Exception $e) {
480
-			throw new OCSForbiddenException($e->getMessage());
481
-		}
482
-
483
-		$output = $this->formatShare($share);
484
-
485
-		return new DataResponse($output);
486
-	}
487
-
488
-	/**
489
-	 * @param \OCP\Files\File|\OCP\Files\Folder $node
490
-	 * @param boolean $includeTags
491
-	 * @return DataResponse
492
-	 */
493
-	private function getSharedWithMe($node = null, $includeTags) {
494
-
495
-		$userShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
496
-		$groupShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
497
-		$circleShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_CIRCLE, $node, -1, 0);
498
-
499
-		$shares = array_merge($userShares, $groupShares, $circleShares);
500
-
501
-		$shares = array_filter($shares, function (IShare $share) {
502
-			return $share->getShareOwner() !== $this->currentUser;
503
-		});
504
-
505
-		$formatted = [];
506
-		foreach ($shares as $share) {
507
-			if ($this->canAccessShare($share)) {
508
-				try {
509
-					$formatted[] = $this->formatShare($share);
510
-				} catch (NotFoundException $e) {
511
-					// Ignore this share
512
-				}
513
-			}
514
-		}
515
-
516
-		if ($includeTags) {
517
-			$formatted = Helper::populateTags($formatted, 'file_source');
518
-		}
519
-
520
-		return new DataResponse($formatted);
521
-	}
522
-
523
-	/**
524
-	 * @param \OCP\Files\Folder $folder
525
-	 * @return DataResponse
526
-	 * @throws OCSBadRequestException
527
-	 */
528
-	private function getSharesInDir($folder) {
529
-		if (!($folder instanceof \OCP\Files\Folder)) {
530
-			throw new OCSBadRequestException($this->l->t('Not a directory'));
531
-		}
532
-
533
-		$nodes = $folder->getDirectoryListing();
534
-		/** @var \OCP\Share\IShare[] $shares */
535
-		$shares = [];
536
-		foreach ($nodes as $node) {
537
-			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $node, false, -1, 0));
538
-			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
539
-			$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $node, false, -1, 0));
540
-			if($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
541
-				$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_EMAIL, $node, false, -1, 0));
542
-			}
543
-			if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
544
-				$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
545
-			}
546
-		}
547
-
548
-		$formatted = [];
549
-		foreach ($shares as $share) {
550
-			try {
551
-				$formatted[] = $this->formatShare($share);
552
-			} catch (NotFoundException $e) {
553
-				//Ignore this share
554
-			}
555
-		}
556
-
557
-		return new DataResponse($formatted);
558
-	}
559
-
560
-	/**
561
-	 * The getShares function.
562
-	 *
563
-	 * @NoAdminRequired
564
-	 *
565
-	 * @param string $shared_with_me
566
-	 * @param string $reshares
567
-	 * @param string $subfiles
568
-	 * @param string $path
569
-	 *
570
-	 * - Get shares by the current user
571
-	 * - Get shares by the current user and reshares (?reshares=true)
572
-	 * - Get shares with the current user (?shared_with_me=true)
573
-	 * - Get shares for a specific path (?path=...)
574
-	 * - Get all shares in a folder (?subfiles=true&path=..)
575
-	 *
576
-	 * @return DataResponse
577
-	 * @throws OCSNotFoundException
578
-	 */
579
-	public function getShares(
580
-		$shared_with_me = 'false',
581
-		$reshares = 'false',
582
-		$subfiles = 'false',
583
-		$path = null,
584
-		$include_tags = 'false'
585
-	) {
586
-
587
-		if ($path !== null) {
588
-			$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
589
-			try {
590
-				$path = $userFolder->get($path);
591
-				$this->lock($path);
592
-			} catch (\OCP\Files\NotFoundException $e) {
593
-				throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
594
-			} catch (LockedException $e) {
595
-				throw new OCSNotFoundException($this->l->t('Could not lock path'));
596
-			}
597
-		}
598
-
599
-		if ($shared_with_me === 'true') {
600
-			$result = $this->getSharedWithMe($path, $include_tags);
601
-			return $result;
602
-		}
603
-
604
-		if ($subfiles === 'true') {
605
-			$result = $this->getSharesInDir($path);
606
-			return $result;
607
-		}
608
-
609
-		if ($reshares === 'true') {
610
-			$reshares = true;
611
-		} else {
612
-			$reshares = false;
613
-		}
614
-
615
-		// Get all shares
616
-		$userShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
617
-		$groupShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
618
-		$linkShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
619
-		if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
620
-			$mailShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
621
-		} else {
622
-			$mailShares = [];
623
-		}
624
-		if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
625
-			$circleShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);
626
-		} else {
627
-			$circleShares = [];
628
-		}
629
-
630
-		$shares = array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares);
631
-
632
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
633
-			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
634
-			$shares = array_merge($shares, $federatedShares);
635
-		}
636
-
637
-		$formatted = [];
638
-		foreach ($shares as $share) {
639
-			try {
640
-				$formatted[] = $this->formatShare($share, $path);
641
-			} catch (NotFoundException $e) {
642
-				//Ignore share
643
-			}
644
-		}
645
-
646
-		if ($include_tags) {
647
-			$formatted = Helper::populateTags($formatted, 'file_source');
648
-		}
649
-
650
-		return new DataResponse($formatted);
651
-	}
652
-
653
-	/**
654
-	 * @NoAdminRequired
655
-	 *
656
-	 * @param int $id
657
-	 * @param int $permissions
658
-	 * @param string $password
659
-	 * @param string $publicUpload
660
-	 * @param string $expireDate
661
-	 * @return DataResponse
662
-	 * @throws OCSNotFoundException
663
-	 * @throws OCSBadRequestException
664
-	 * @throws OCSForbiddenException
665
-	 */
666
-	public function updateShare(
667
-		$id,
668
-		$permissions = null,
669
-		$password = null,
670
-		$publicUpload = null,
671
-		$expireDate = null
672
-	) {
673
-		try {
674
-			$share = $this->getShareById($id);
675
-		} catch (ShareNotFound $e) {
676
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
677
-		}
678
-
679
-		$this->lock($share->getNode());
680
-
681
-		if (!$this->canAccessShare($share, false)) {
682
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
683
-		}
684
-
685
-		if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null) {
686
-			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
687
-		}
688
-
689
-		/*
395
+            $existingShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $path, false, 1, 0);
396
+            if (!empty($existingShares)) {
397
+                return new DataResponse($this->formatShare($existingShares[0]));
398
+            }
399
+
400
+            if ($publicUpload === 'true') {
401
+                // Check if public upload is allowed
402
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
403
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
404
+                }
405
+
406
+                // Public upload can only be set for folders
407
+                if ($path instanceof \OCP\Files\File) {
408
+                    throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
409
+                }
410
+
411
+                $share->setPermissions(
412
+                    \OCP\Constants::PERMISSION_READ |
413
+                    \OCP\Constants::PERMISSION_CREATE |
414
+                    \OCP\Constants::PERMISSION_UPDATE |
415
+                    \OCP\Constants::PERMISSION_DELETE
416
+                );
417
+            } else {
418
+                $share->setPermissions(\OCP\Constants::PERMISSION_READ);
419
+            }
420
+
421
+            // Set password
422
+            if ($password !== '') {
423
+                $share->setPassword($password);
424
+            }
425
+
426
+            //Expire date
427
+            if ($expireDate !== '') {
428
+                try {
429
+                    $expireDate = $this->parseDate($expireDate);
430
+                    $share->setExpirationDate($expireDate);
431
+                } catch (\Exception $e) {
432
+                    throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
433
+                }
434
+            }
435
+
436
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
437
+            if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
438
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not allow shares from type %s', [$path->getPath(), $shareType]));
439
+            }
440
+
441
+            $share->setSharedWith($shareWith);
442
+            $share->setPermissions($permissions);
443
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_EMAIL) {
444
+            if ($share->getNodeType() === 'file') {
445
+                $share->setPermissions(\OCP\Constants::PERMISSION_READ);
446
+            } else {
447
+                $share->setPermissions(
448
+                    \OCP\Constants::PERMISSION_READ |
449
+                    \OCP\Constants::PERMISSION_CREATE |
450
+                    \OCP\Constants::PERMISSION_UPDATE |
451
+                    \OCP\Constants::PERMISSION_DELETE);
452
+            }
453
+            $share->setSharedWith($shareWith);
454
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_CIRCLE) {
455
+            if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
456
+                throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
457
+            }
458
+
459
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
460
+
461
+            // Valid circle is required to share
462
+            if ($circle === null) {
463
+                throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
464
+            }
465
+            $share->setSharedWith($shareWith);
466
+            $share->setPermissions($permissions);
467
+        } else {
468
+            throw new OCSBadRequestException($this->l->t('Unknown share type'));
469
+        }
470
+
471
+        $share->setShareType($shareType);
472
+        $share->setSharedBy($this->currentUser);
473
+
474
+        try {
475
+            $share = $this->shareManager->createShare($share);
476
+        } catch (GenericShareException $e) {
477
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
478
+            throw new OCSException($e->getHint(), $code);
479
+        } catch (\Exception $e) {
480
+            throw new OCSForbiddenException($e->getMessage());
481
+        }
482
+
483
+        $output = $this->formatShare($share);
484
+
485
+        return new DataResponse($output);
486
+    }
487
+
488
+    /**
489
+     * @param \OCP\Files\File|\OCP\Files\Folder $node
490
+     * @param boolean $includeTags
491
+     * @return DataResponse
492
+     */
493
+    private function getSharedWithMe($node = null, $includeTags) {
494
+
495
+        $userShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
496
+        $groupShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
497
+        $circleShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_CIRCLE, $node, -1, 0);
498
+
499
+        $shares = array_merge($userShares, $groupShares, $circleShares);
500
+
501
+        $shares = array_filter($shares, function (IShare $share) {
502
+            return $share->getShareOwner() !== $this->currentUser;
503
+        });
504
+
505
+        $formatted = [];
506
+        foreach ($shares as $share) {
507
+            if ($this->canAccessShare($share)) {
508
+                try {
509
+                    $formatted[] = $this->formatShare($share);
510
+                } catch (NotFoundException $e) {
511
+                    // Ignore this share
512
+                }
513
+            }
514
+        }
515
+
516
+        if ($includeTags) {
517
+            $formatted = Helper::populateTags($formatted, 'file_source');
518
+        }
519
+
520
+        return new DataResponse($formatted);
521
+    }
522
+
523
+    /**
524
+     * @param \OCP\Files\Folder $folder
525
+     * @return DataResponse
526
+     * @throws OCSBadRequestException
527
+     */
528
+    private function getSharesInDir($folder) {
529
+        if (!($folder instanceof \OCP\Files\Folder)) {
530
+            throw new OCSBadRequestException($this->l->t('Not a directory'));
531
+        }
532
+
533
+        $nodes = $folder->getDirectoryListing();
534
+        /** @var \OCP\Share\IShare[] $shares */
535
+        $shares = [];
536
+        foreach ($nodes as $node) {
537
+            $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $node, false, -1, 0));
538
+            $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
539
+            $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $node, false, -1, 0));
540
+            if($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
541
+                $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_EMAIL, $node, false, -1, 0));
542
+            }
543
+            if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
544
+                $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
545
+            }
546
+        }
547
+
548
+        $formatted = [];
549
+        foreach ($shares as $share) {
550
+            try {
551
+                $formatted[] = $this->formatShare($share);
552
+            } catch (NotFoundException $e) {
553
+                //Ignore this share
554
+            }
555
+        }
556
+
557
+        return new DataResponse($formatted);
558
+    }
559
+
560
+    /**
561
+     * The getShares function.
562
+     *
563
+     * @NoAdminRequired
564
+     *
565
+     * @param string $shared_with_me
566
+     * @param string $reshares
567
+     * @param string $subfiles
568
+     * @param string $path
569
+     *
570
+     * - Get shares by the current user
571
+     * - Get shares by the current user and reshares (?reshares=true)
572
+     * - Get shares with the current user (?shared_with_me=true)
573
+     * - Get shares for a specific path (?path=...)
574
+     * - Get all shares in a folder (?subfiles=true&path=..)
575
+     *
576
+     * @return DataResponse
577
+     * @throws OCSNotFoundException
578
+     */
579
+    public function getShares(
580
+        $shared_with_me = 'false',
581
+        $reshares = 'false',
582
+        $subfiles = 'false',
583
+        $path = null,
584
+        $include_tags = 'false'
585
+    ) {
586
+
587
+        if ($path !== null) {
588
+            $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
589
+            try {
590
+                $path = $userFolder->get($path);
591
+                $this->lock($path);
592
+            } catch (\OCP\Files\NotFoundException $e) {
593
+                throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
594
+            } catch (LockedException $e) {
595
+                throw new OCSNotFoundException($this->l->t('Could not lock path'));
596
+            }
597
+        }
598
+
599
+        if ($shared_with_me === 'true') {
600
+            $result = $this->getSharedWithMe($path, $include_tags);
601
+            return $result;
602
+        }
603
+
604
+        if ($subfiles === 'true') {
605
+            $result = $this->getSharesInDir($path);
606
+            return $result;
607
+        }
608
+
609
+        if ($reshares === 'true') {
610
+            $reshares = true;
611
+        } else {
612
+            $reshares = false;
613
+        }
614
+
615
+        // Get all shares
616
+        $userShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
617
+        $groupShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
618
+        $linkShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
619
+        if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
620
+            $mailShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
621
+        } else {
622
+            $mailShares = [];
623
+        }
624
+        if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
625
+            $circleShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);
626
+        } else {
627
+            $circleShares = [];
628
+        }
629
+
630
+        $shares = array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares);
631
+
632
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
633
+            $federatedShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
634
+            $shares = array_merge($shares, $federatedShares);
635
+        }
636
+
637
+        $formatted = [];
638
+        foreach ($shares as $share) {
639
+            try {
640
+                $formatted[] = $this->formatShare($share, $path);
641
+            } catch (NotFoundException $e) {
642
+                //Ignore share
643
+            }
644
+        }
645
+
646
+        if ($include_tags) {
647
+            $formatted = Helper::populateTags($formatted, 'file_source');
648
+        }
649
+
650
+        return new DataResponse($formatted);
651
+    }
652
+
653
+    /**
654
+     * @NoAdminRequired
655
+     *
656
+     * @param int $id
657
+     * @param int $permissions
658
+     * @param string $password
659
+     * @param string $publicUpload
660
+     * @param string $expireDate
661
+     * @return DataResponse
662
+     * @throws OCSNotFoundException
663
+     * @throws OCSBadRequestException
664
+     * @throws OCSForbiddenException
665
+     */
666
+    public function updateShare(
667
+        $id,
668
+        $permissions = null,
669
+        $password = null,
670
+        $publicUpload = null,
671
+        $expireDate = null
672
+    ) {
673
+        try {
674
+            $share = $this->getShareById($id);
675
+        } catch (ShareNotFound $e) {
676
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
677
+        }
678
+
679
+        $this->lock($share->getNode());
680
+
681
+        if (!$this->canAccessShare($share, false)) {
682
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
683
+        }
684
+
685
+        if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null) {
686
+            throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
687
+        }
688
+
689
+        /*
690 690
 		 * expirationdate, password and publicUpload only make sense for link shares
691 691
 		 */
692
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
693
-
694
-			$newPermissions = null;
695
-			if ($publicUpload === 'true') {
696
-				$newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
697
-			} else if ($publicUpload === 'false') {
698
-				$newPermissions = \OCP\Constants::PERMISSION_READ;
699
-			}
700
-
701
-			if ($permissions !== null) {
702
-				$newPermissions = (int)$permissions;
703
-			}
704
-
705
-			if ($newPermissions !== null &&
706
-				!in_array($newPermissions, [
707
-					\OCP\Constants::PERMISSION_READ,
708
-					\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE, // legacy
709
-					\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE, // correct
710
-					\OCP\Constants::PERMISSION_CREATE, // hidden file list
711
-					\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE, // allow to edit single files
712
-				])
713
-			) {
714
-				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
715
-			}
716
-
717
-			if (
718
-				// legacy
719
-				$newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE) ||
720
-				// correct
721
-				$newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)
722
-			) {
723
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
724
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
725
-				}
726
-
727
-				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
728
-					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
729
-				}
730
-
731
-				// normalize to correct public upload permissions
732
-				$newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
733
-			}
734
-
735
-			if ($newPermissions !== null) {
736
-				$share->setPermissions($newPermissions);
737
-				$permissions = $newPermissions;
738
-			}
739
-
740
-			if ($expireDate === '') {
741
-				$share->setExpirationDate(null);
742
-			} else if ($expireDate !== null) {
743
-				try {
744
-					$expireDate = $this->parseDate($expireDate);
745
-				} catch (\Exception $e) {
746
-					throw new OCSBadRequestException($e->getMessage());
747
-				}
748
-				$share->setExpirationDate($expireDate);
749
-			}
750
-
751
-			if ($password === '') {
752
-				$share->setPassword(null);
753
-			} else if ($password !== null) {
754
-				$share->setPassword($password);
755
-			}
756
-
757
-		} else {
758
-			if ($permissions !== null) {
759
-				$permissions = (int)$permissions;
760
-				$share->setPermissions($permissions);
761
-			}
762
-
763
-			if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
764
-				if ($password === '') {
765
-					$share->setPassword(null);
766
-				} else if ($password !== null) {
767
-					$share->setPassword($password);
768
-				}
769
-			}
770
-
771
-			if ($expireDate === '') {
772
-				$share->setExpirationDate(null);
773
-			} else if ($expireDate !== null) {
774
-				try {
775
-					$expireDate = $this->parseDate($expireDate);
776
-				} catch (\Exception $e) {
777
-					throw new OCSBadRequestException($e->getMessage());
778
-				}
779
-				$share->setExpirationDate($expireDate);
780
-			}
781
-
782
-		}
783
-
784
-		if ($permissions !== null && $share->getShareOwner() !== $this->currentUser) {
785
-			/* Check if this is an incomming share */
786
-			$incomingShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
787
-			$incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
788
-
789
-			/** @var \OCP\Share\IShare[] $incomingShares */
790
-			if (!empty($incomingShares)) {
791
-				$maxPermissions = 0;
792
-				foreach ($incomingShares as $incomingShare) {
793
-					$maxPermissions |= $incomingShare->getPermissions();
794
-				}
795
-
796
-				if ($share->getPermissions() & ~$maxPermissions) {
797
-					throw new OCSNotFoundException($this->l->t('Cannot increase permissions'));
798
-				}
799
-			}
800
-		}
801
-
802
-
803
-		try {
804
-			$share = $this->shareManager->updateShare($share);
805
-		} catch (\Exception $e) {
806
-			throw new OCSBadRequestException($e->getMessage());
807
-		}
808
-
809
-		return new DataResponse($this->formatShare($share));
810
-	}
811
-
812
-	/**
813
-	 * @param \OCP\Share\IShare $share
814
-	 * @return bool
815
-	 */
816
-	protected function canAccessShare(\OCP\Share\IShare $share, $checkGroups = true) {
817
-		// A file with permissions 0 can't be accessed by us. So Don't show it
818
-		if ($share->getPermissions() === 0) {
819
-			return false;
820
-		}
821
-
822
-		// Owner of the file and the sharer of the file can always get share
823
-		if ($share->getShareOwner() === $this->currentUser ||
824
-			$share->getSharedBy() === $this->currentUser
825
-		) {
826
-			return true;
827
-		}
828
-
829
-		// If the share is shared with you (or a group you are a member of)
830
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
831
-			$share->getSharedWith() === $this->currentUser
832
-		) {
833
-			return true;
834
-		}
835
-
836
-		if ($checkGroups && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
837
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
838
-			$user = $this->userManager->get($this->currentUser);
839
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
840
-				return true;
841
-			}
842
-		}
843
-
844
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
845
-			// TODO: have a sanity check like above?
846
-			return true;
847
-		}
848
-
849
-		return false;
850
-	}
851
-
852
-	/**
853
-	 * Make sure that the passed date is valid ISO 8601
854
-	 * So YYYY-MM-DD
855
-	 * If not throw an exception
856
-	 *
857
-	 * @param string $expireDate
858
-	 *
859
-	 * @throws \Exception
860
-	 * @return \DateTime
861
-	 */
862
-	private function parseDate($expireDate) {
863
-		try {
864
-			$date = new \DateTime($expireDate);
865
-		} catch (\Exception $e) {
866
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
867
-		}
868
-
869
-		if ($date === false) {
870
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
871
-		}
872
-
873
-		$date->setTime(0, 0, 0);
874
-
875
-		return $date;
876
-	}
877
-
878
-	/**
879
-	 * Since we have multiple providers but the OCS Share API v1 does
880
-	 * not support this we need to check all backends.
881
-	 *
882
-	 * @param string $id
883
-	 * @return \OCP\Share\IShare
884
-	 * @throws ShareNotFound
885
-	 */
886
-	private function getShareById($id) {
887
-		$share = null;
888
-
889
-		// First check if it is an internal share.
890
-		try {
891
-			$share = $this->shareManager->getShareById('ocinternal:' . $id);
892
-			return $share;
893
-		} catch (ShareNotFound $e) {
894
-			// Do nothing, just try the other share type
895
-		}
896
-
897
-
898
-		try {
899
-			if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
900
-				$share = $this->shareManager->getShareById('ocCircleShare:' . $id);
901
-				return $share;
902
-			}
903
-		} catch (ShareNotFound $e) {
904
-			// Do nothing, just try the other share type
905
-		}
906
-
907
-		try {
908
-			if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
909
-				$share = $this->shareManager->getShareById('ocMailShare:' . $id);
910
-				return $share;
911
-			}
912
-		} catch (ShareNotFound $e) {
913
-			// Do nothing, just try the other share type
914
-		}
915
-
916
-		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
917
-			throw new ShareNotFound();
918
-		}
919
-		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id);
920
-
921
-		return $share;
922
-	}
923
-
924
-	/**
925
-	 * Lock a Node
926
-	 *
927
-	 * @param \OCP\Files\Node $node
928
-	 */
929
-	private function lock(\OCP\Files\Node $node) {
930
-		$node->lock(ILockingProvider::LOCK_SHARED);
931
-		$this->lockedNode = $node;
932
-	}
933
-
934
-	/**
935
-	 * Cleanup the remaining locks
936
-	 */
937
-	public function cleanup() {
938
-		if ($this->lockedNode !== null) {
939
-			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
940
-		}
941
-	}
692
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
693
+
694
+            $newPermissions = null;
695
+            if ($publicUpload === 'true') {
696
+                $newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
697
+            } else if ($publicUpload === 'false') {
698
+                $newPermissions = \OCP\Constants::PERMISSION_READ;
699
+            }
700
+
701
+            if ($permissions !== null) {
702
+                $newPermissions = (int)$permissions;
703
+            }
704
+
705
+            if ($newPermissions !== null &&
706
+                !in_array($newPermissions, [
707
+                    \OCP\Constants::PERMISSION_READ,
708
+                    \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE, // legacy
709
+                    \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE, // correct
710
+                    \OCP\Constants::PERMISSION_CREATE, // hidden file list
711
+                    \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE, // allow to edit single files
712
+                ])
713
+            ) {
714
+                throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
715
+            }
716
+
717
+            if (
718
+                // legacy
719
+                $newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE) ||
720
+                // correct
721
+                $newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)
722
+            ) {
723
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
724
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
725
+                }
726
+
727
+                if (!($share->getNode() instanceof \OCP\Files\Folder)) {
728
+                    throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
729
+                }
730
+
731
+                // normalize to correct public upload permissions
732
+                $newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
733
+            }
734
+
735
+            if ($newPermissions !== null) {
736
+                $share->setPermissions($newPermissions);
737
+                $permissions = $newPermissions;
738
+            }
739
+
740
+            if ($expireDate === '') {
741
+                $share->setExpirationDate(null);
742
+            } else if ($expireDate !== null) {
743
+                try {
744
+                    $expireDate = $this->parseDate($expireDate);
745
+                } catch (\Exception $e) {
746
+                    throw new OCSBadRequestException($e->getMessage());
747
+                }
748
+                $share->setExpirationDate($expireDate);
749
+            }
750
+
751
+            if ($password === '') {
752
+                $share->setPassword(null);
753
+            } else if ($password !== null) {
754
+                $share->setPassword($password);
755
+            }
756
+
757
+        } else {
758
+            if ($permissions !== null) {
759
+                $permissions = (int)$permissions;
760
+                $share->setPermissions($permissions);
761
+            }
762
+
763
+            if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
764
+                if ($password === '') {
765
+                    $share->setPassword(null);
766
+                } else if ($password !== null) {
767
+                    $share->setPassword($password);
768
+                }
769
+            }
770
+
771
+            if ($expireDate === '') {
772
+                $share->setExpirationDate(null);
773
+            } else if ($expireDate !== null) {
774
+                try {
775
+                    $expireDate = $this->parseDate($expireDate);
776
+                } catch (\Exception $e) {
777
+                    throw new OCSBadRequestException($e->getMessage());
778
+                }
779
+                $share->setExpirationDate($expireDate);
780
+            }
781
+
782
+        }
783
+
784
+        if ($permissions !== null && $share->getShareOwner() !== $this->currentUser) {
785
+            /* Check if this is an incomming share */
786
+            $incomingShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
787
+            $incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
788
+
789
+            /** @var \OCP\Share\IShare[] $incomingShares */
790
+            if (!empty($incomingShares)) {
791
+                $maxPermissions = 0;
792
+                foreach ($incomingShares as $incomingShare) {
793
+                    $maxPermissions |= $incomingShare->getPermissions();
794
+                }
795
+
796
+                if ($share->getPermissions() & ~$maxPermissions) {
797
+                    throw new OCSNotFoundException($this->l->t('Cannot increase permissions'));
798
+                }
799
+            }
800
+        }
801
+
802
+
803
+        try {
804
+            $share = $this->shareManager->updateShare($share);
805
+        } catch (\Exception $e) {
806
+            throw new OCSBadRequestException($e->getMessage());
807
+        }
808
+
809
+        return new DataResponse($this->formatShare($share));
810
+    }
811
+
812
+    /**
813
+     * @param \OCP\Share\IShare $share
814
+     * @return bool
815
+     */
816
+    protected function canAccessShare(\OCP\Share\IShare $share, $checkGroups = true) {
817
+        // A file with permissions 0 can't be accessed by us. So Don't show it
818
+        if ($share->getPermissions() === 0) {
819
+            return false;
820
+        }
821
+
822
+        // Owner of the file and the sharer of the file can always get share
823
+        if ($share->getShareOwner() === $this->currentUser ||
824
+            $share->getSharedBy() === $this->currentUser
825
+        ) {
826
+            return true;
827
+        }
828
+
829
+        // If the share is shared with you (or a group you are a member of)
830
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
831
+            $share->getSharedWith() === $this->currentUser
832
+        ) {
833
+            return true;
834
+        }
835
+
836
+        if ($checkGroups && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
837
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
838
+            $user = $this->userManager->get($this->currentUser);
839
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
840
+                return true;
841
+            }
842
+        }
843
+
844
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
845
+            // TODO: have a sanity check like above?
846
+            return true;
847
+        }
848
+
849
+        return false;
850
+    }
851
+
852
+    /**
853
+     * Make sure that the passed date is valid ISO 8601
854
+     * So YYYY-MM-DD
855
+     * If not throw an exception
856
+     *
857
+     * @param string $expireDate
858
+     *
859
+     * @throws \Exception
860
+     * @return \DateTime
861
+     */
862
+    private function parseDate($expireDate) {
863
+        try {
864
+            $date = new \DateTime($expireDate);
865
+        } catch (\Exception $e) {
866
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
867
+        }
868
+
869
+        if ($date === false) {
870
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
871
+        }
872
+
873
+        $date->setTime(0, 0, 0);
874
+
875
+        return $date;
876
+    }
877
+
878
+    /**
879
+     * Since we have multiple providers but the OCS Share API v1 does
880
+     * not support this we need to check all backends.
881
+     *
882
+     * @param string $id
883
+     * @return \OCP\Share\IShare
884
+     * @throws ShareNotFound
885
+     */
886
+    private function getShareById($id) {
887
+        $share = null;
888
+
889
+        // First check if it is an internal share.
890
+        try {
891
+            $share = $this->shareManager->getShareById('ocinternal:' . $id);
892
+            return $share;
893
+        } catch (ShareNotFound $e) {
894
+            // Do nothing, just try the other share type
895
+        }
896
+
897
+
898
+        try {
899
+            if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
900
+                $share = $this->shareManager->getShareById('ocCircleShare:' . $id);
901
+                return $share;
902
+            }
903
+        } catch (ShareNotFound $e) {
904
+            // Do nothing, just try the other share type
905
+        }
906
+
907
+        try {
908
+            if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
909
+                $share = $this->shareManager->getShareById('ocMailShare:' . $id);
910
+                return $share;
911
+            }
912
+        } catch (ShareNotFound $e) {
913
+            // Do nothing, just try the other share type
914
+        }
915
+
916
+        if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
917
+            throw new ShareNotFound();
918
+        }
919
+        $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id);
920
+
921
+        return $share;
922
+    }
923
+
924
+    /**
925
+     * Lock a Node
926
+     *
927
+     * @param \OCP\Files\Node $node
928
+     */
929
+    private function lock(\OCP\Files\Node $node) {
930
+        $node->lock(ILockingProvider::LOCK_SHARED);
931
+        $this->lockedNode = $node;
932
+    }
933
+
934
+    /**
935
+     * Cleanup the remaining locks
936
+     */
937
+    public function cleanup() {
938
+        if ($this->lockedNode !== null) {
939
+            $this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
940
+        }
941
+    }
942 942
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareesAPIController.php 1 patch
Indentation   +721 added lines, -721 removed lines patch added patch discarded remove patch
@@ -43,725 +43,725 @@
 block discarded – undo
43 43
 
44 44
 class ShareesAPIController extends OCSController {
45 45
 
46
-	/** @var IGroupManager */
47
-	protected $groupManager;
48
-
49
-	/** @var IUserManager */
50
-	protected $userManager;
51
-
52
-	/** @var IManager */
53
-	protected $contactsManager;
54
-
55
-	/** @var IConfig */
56
-	protected $config;
57
-
58
-	/** @var IUserSession */
59
-	protected $userSession;
60
-
61
-	/** @var IURLGenerator */
62
-	protected $urlGenerator;
63
-
64
-	/** @var ILogger */
65
-	protected $logger;
66
-
67
-	/** @var \OCP\Share\IManager */
68
-	protected $shareManager;
69
-
70
-	/** @var IClientService */
71
-	protected $clientService;
72
-
73
-	/** @var ICloudIdManager  */
74
-	protected $cloudIdManager;
75
-
76
-	/** @var bool */
77
-	protected $shareWithGroupOnly = false;
78
-
79
-	/** @var bool */
80
-	protected $shareeEnumeration = true;
81
-
82
-	/** @var int */
83
-	protected $offset = 0;
84
-
85
-	/** @var int */
86
-	protected $limit = 10;
87
-
88
-	/** @var array */
89
-	protected $result = [
90
-		'exact' => [
91
-			'users' => [],
92
-			'groups' => [],
93
-			'remotes' => [],
94
-			'emails' => [],
95
-			'circles' => [],
96
-		],
97
-		'users' => [],
98
-		'groups' => [],
99
-		'remotes' => [],
100
-		'emails' => [],
101
-		'lookup' => [],
102
-		'circles' => [],
103
-	];
104
-
105
-	protected $reachedEndFor = [];
106
-
107
-	/**
108
-	 * @param string $appName
109
-	 * @param IRequest $request
110
-	 * @param IGroupManager $groupManager
111
-	 * @param IUserManager $userManager
112
-	 * @param IManager $contactsManager
113
-	 * @param IConfig $config
114
-	 * @param IUserSession $userSession
115
-	 * @param IURLGenerator $urlGenerator
116
-	 * @param ILogger $logger
117
-	 * @param \OCP\Share\IManager $shareManager
118
-	 * @param IClientService $clientService
119
-	 * @param ICloudIdManager $cloudIdManager
120
-	 */
121
-	public function __construct($appName,
122
-								IRequest $request,
123
-								IGroupManager $groupManager,
124
-								IUserManager $userManager,
125
-								IManager $contactsManager,
126
-								IConfig $config,
127
-								IUserSession $userSession,
128
-								IURLGenerator $urlGenerator,
129
-								ILogger $logger,
130
-								\OCP\Share\IManager $shareManager,
131
-								IClientService $clientService,
132
-								ICloudIdManager $cloudIdManager
133
-	) {
134
-		parent::__construct($appName, $request);
135
-
136
-		$this->groupManager = $groupManager;
137
-		$this->userManager = $userManager;
138
-		$this->contactsManager = $contactsManager;
139
-		$this->config = $config;
140
-		$this->userSession = $userSession;
141
-		$this->urlGenerator = $urlGenerator;
142
-		$this->logger = $logger;
143
-		$this->shareManager = $shareManager;
144
-		$this->clientService = $clientService;
145
-		$this->cloudIdManager = $cloudIdManager;
146
-	}
147
-
148
-	/**
149
-	 * @param string $search
150
-	 */
151
-	protected function getUsers($search) {
152
-		$this->result['users'] = $this->result['exact']['users'] = $users = [];
153
-
154
-		$userGroups = [];
155
-		if ($this->shareWithGroupOnly) {
156
-			// Search in all the groups this user is part of
157
-			$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
158
-			foreach ($userGroups as $userGroup) {
159
-				$usersTmp = $this->groupManager->displayNamesInGroup($userGroup, $search, $this->limit, $this->offset);
160
-				foreach ($usersTmp as $uid => $userDisplayName) {
161
-					$users[$uid] = $userDisplayName;
162
-				}
163
-			}
164
-		} else {
165
-			// Search in all users
166
-			$usersTmp = $this->userManager->searchDisplayName($search, $this->limit, $this->offset);
167
-
168
-			foreach ($usersTmp as $user) {
169
-				$users[$user->getUID()] = $user->getDisplayName();
170
-			}
171
-		}
172
-
173
-		if (!$this->shareeEnumeration || sizeof($users) < $this->limit) {
174
-			$this->reachedEndFor[] = 'users';
175
-		}
176
-
177
-		$foundUserById = false;
178
-		$lowerSearch = strtolower($search);
179
-		foreach ($users as $uid => $userDisplayName) {
180
-			if (strtolower($uid) === $lowerSearch || strtolower($userDisplayName) === $lowerSearch) {
181
-				if (strtolower($uid) === $lowerSearch) {
182
-					$foundUserById = true;
183
-				}
184
-				$this->result['exact']['users'][] = [
185
-					'label' => $userDisplayName,
186
-					'value' => [
187
-						'shareType' => Share::SHARE_TYPE_USER,
188
-						'shareWith' => $uid,
189
-					],
190
-				];
191
-			} else {
192
-				$this->result['users'][] = [
193
-					'label' => $userDisplayName,
194
-					'value' => [
195
-						'shareType' => Share::SHARE_TYPE_USER,
196
-						'shareWith' => $uid,
197
-					],
198
-				];
199
-			}
200
-		}
201
-
202
-		if ($this->offset === 0 && !$foundUserById) {
203
-			// On page one we try if the search result has a direct hit on the
204
-			// user id and if so, we add that to the exact match list
205
-			$user = $this->userManager->get($search);
206
-			if ($user instanceof IUser) {
207
-				$addUser = true;
208
-
209
-				if ($this->shareWithGroupOnly) {
210
-					// Only add, if we have a common group
211
-					$commonGroups = array_intersect($userGroups, $this->groupManager->getUserGroupIds($user));
212
-					$addUser = !empty($commonGroups);
213
-				}
214
-
215
-				if ($addUser) {
216
-					array_push($this->result['exact']['users'], [
217
-						'label' => $user->getDisplayName(),
218
-						'value' => [
219
-							'shareType' => Share::SHARE_TYPE_USER,
220
-							'shareWith' => $user->getUID(),
221
-						],
222
-					]);
223
-				}
224
-			}
225
-		}
226
-
227
-		if (!$this->shareeEnumeration) {
228
-			$this->result['users'] = [];
229
-		}
230
-	}
231
-
232
-	/**
233
-	 * @param string $search
234
-	 */
235
-	protected function getGroups($search) {
236
-		$this->result['groups'] = $this->result['exact']['groups'] = [];
237
-
238
-		$groups = $this->groupManager->search($search, $this->limit, $this->offset);
239
-		$groupIds = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
240
-
241
-		if (!$this->shareeEnumeration || sizeof($groups) < $this->limit) {
242
-			$this->reachedEndFor[] = 'groups';
243
-		}
244
-
245
-		$userGroups =  [];
246
-		if (!empty($groups) && $this->shareWithGroupOnly) {
247
-			// Intersect all the groups that match with the groups this user is a member of
248
-			$userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
249
-			$userGroups = array_map(function (IGroup $group) { return $group->getGID(); }, $userGroups);
250
-			$groupIds = array_intersect($groupIds, $userGroups);
251
-		}
252
-
253
-		$lowerSearch = strtolower($search);
254
-		foreach ($groups as $group) {
255
-			// FIXME: use a more efficient approach
256
-			$gid = $group->getGID();
257
-			if (!in_array($gid, $groupIds)) {
258
-				continue;
259
-			}
260
-			if (strtolower($gid) === $lowerSearch || strtolower($group->getDisplayName()) === $lowerSearch) {
261
-				$this->result['exact']['groups'][] = [
262
-					'label' => $group->getDisplayName(),
263
-					'value' => [
264
-						'shareType' => Share::SHARE_TYPE_GROUP,
265
-						'shareWith' => $gid,
266
-					],
267
-				];
268
-			} else {
269
-				$this->result['groups'][] = [
270
-					'label' => $group->getDisplayName(),
271
-					'value' => [
272
-						'shareType' => Share::SHARE_TYPE_GROUP,
273
-						'shareWith' => $gid,
274
-					],
275
-				];
276
-			}
277
-		}
278
-
279
-		if ($this->offset === 0 && empty($this->result['exact']['groups'])) {
280
-			// On page one we try if the search result has a direct hit on the
281
-			// user id and if so, we add that to the exact match list
282
-			$group = $this->groupManager->get($search);
283
-			if ($group instanceof IGroup && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups))) {
284
-				array_push($this->result['exact']['groups'], [
285
-					'label' => $group->getDisplayName(),
286
-					'value' => [
287
-						'shareType' => Share::SHARE_TYPE_GROUP,
288
-						'shareWith' => $group->getGID(),
289
-					],
290
-				]);
291
-			}
292
-		}
293
-
294
-		if (!$this->shareeEnumeration) {
295
-			$this->result['groups'] = [];
296
-		}
297
-	}
298
-
299
-
300
-	/**
301
-	 * @param string $search
302
-	 * @suppress PhanUndeclaredClassMethod
303
-	 */
304
-	protected function getCircles($search) {
305
-		$this->result['circles'] = $this->result['exact']['circles'] = [];
306
-
307
-		$result = \OCA\Circles\Api\Sharees::search($search, $this->limit, $this->offset);
308
-		if (array_key_exists('circles', $result['exact'])) {
309
-			$this->result['exact']['circles'] = $result['exact']['circles'];
310
-		}
311
-		if (array_key_exists('circles', $result)) {
312
-			$this->result['circles'] = $result['circles'];
313
-		}
314
-	}
315
-
316
-
317
-	/**
318
-	 * @param string $search
319
-	 * @return array
320
-	 */
321
-	protected function getRemote($search) {
322
-		$result = ['results' => [], 'exact' => []];
323
-
324
-		// Search in contacts
325
-		//@todo Pagination missing
326
-		$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
327
-		$result['exactIdMatch'] = false;
328
-		foreach ($addressBookContacts as $contact) {
329
-			if (isset($contact['isLocalSystemBook'])) {
330
-				continue;
331
-			}
332
-			if (isset($contact['CLOUD'])) {
333
-				$cloudIds = $contact['CLOUD'];
334
-				if (!is_array($cloudIds)) {
335
-					$cloudIds = [$cloudIds];
336
-				}
337
-				$lowerSearch = strtolower($search);
338
-				foreach ($cloudIds as $cloudId) {
339
-					list(, $serverUrl) = $this->splitUserRemote($cloudId);
340
-					if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
341
-						if (strtolower($cloudId) === $lowerSearch) {
342
-							$result['exactIdMatch'] = true;
343
-						}
344
-						$result['exact'][] = [
345
-							'label' => $contact['FN'] . " ($cloudId)",
346
-							'value' => [
347
-								'shareType' => Share::SHARE_TYPE_REMOTE,
348
-								'shareWith' => $cloudId,
349
-								'server' => $serverUrl,
350
-							],
351
-						];
352
-					} else {
353
-						$result['results'][] = [
354
-							'label' => $contact['FN'] . " ($cloudId)",
355
-							'value' => [
356
-								'shareType' => Share::SHARE_TYPE_REMOTE,
357
-								'shareWith' => $cloudId,
358
-								'server' => $serverUrl,
359
-							],
360
-						];
361
-					}
362
-				}
363
-			}
364
-		}
365
-
366
-		if (!$this->shareeEnumeration) {
367
-			$result['results'] = [];
368
-		}
369
-
370
-		if (!$result['exactIdMatch'] && $this->cloudIdManager->isValidCloudId($search) && $this->offset === 0) {
371
-			$result['exact'][] = [
372
-				'label' => $search,
373
-				'value' => [
374
-					'shareType' => Share::SHARE_TYPE_REMOTE,
375
-					'shareWith' => $search,
376
-				],
377
-			];
378
-		}
379
-
380
-		$this->reachedEndFor[] = 'remotes';
381
-
382
-		return $result;
383
-	}
384
-
385
-	/**
386
-	 * split user and remote from federated cloud id
387
-	 *
388
-	 * @param string $address federated share address
389
-	 * @return array [user, remoteURL]
390
-	 * @throws \Exception
391
-	 */
392
-	public function splitUserRemote($address) {
393
-		try {
394
-			$cloudId = $this->cloudIdManager->resolveCloudId($address);
395
-			return [$cloudId->getUser(), $cloudId->getRemote()];
396
-		} catch (\InvalidArgumentException $e) {
397
-			throw new \Exception('Invalid Federated Cloud ID', 0, $e);
398
-		}
399
-	}
400
-
401
-	/**
402
-	 * Strips away a potential file names and trailing slashes:
403
-	 * - http://localhost
404
-	 * - http://localhost/
405
-	 * - http://localhost/index.php
406
-	 * - http://localhost/index.php/s/{shareToken}
407
-	 *
408
-	 * all return: http://localhost
409
-	 *
410
-	 * @param string $remote
411
-	 * @return string
412
-	 */
413
-	protected function fixRemoteURL($remote) {
414
-		$remote = str_replace('\\', '/', $remote);
415
-		if ($fileNamePosition = strpos($remote, '/index.php')) {
416
-			$remote = substr($remote, 0, $fileNamePosition);
417
-		}
418
-		$remote = rtrim($remote, '/');
419
-
420
-		return $remote;
421
-	}
422
-
423
-	/**
424
-	 * @NoAdminRequired
425
-	 *
426
-	 * @param string $search
427
-	 * @param string $itemType
428
-	 * @param int $page
429
-	 * @param int $perPage
430
-	 * @param int|int[] $shareType
431
-	 * @param bool $lookup
432
-	 * @return DataResponse
433
-	 * @throws OCSBadRequestException
434
-	 */
435
-	public function search($search = '', $itemType = null, $page = 1, $perPage = 200, $shareType = null, $lookup = true) {
436
-
437
-		// only search for string larger than a given threshold
438
-		$threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0);
439
-		if (strlen($search) < $threshold) {
440
-			return new DataResponse($this->result);
441
-		}
442
-
443
-		// never return more than the max. number of results configured in the config.php
444
-		$maxResults = (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0);
445
-		if ($maxResults > 0) {
446
-			$perPage = min($perPage, $maxResults);
447
-		}
448
-		if ($perPage <= 0) {
449
-			throw new OCSBadRequestException('Invalid perPage argument');
450
-		}
451
-		if ($page <= 0) {
452
-			throw new OCSBadRequestException('Invalid page');
453
-		}
454
-
455
-		$shareTypes = [
456
-			Share::SHARE_TYPE_USER,
457
-		];
458
-
459
-		if ($itemType === 'file' || $itemType === 'folder') {
460
-			if ($this->shareManager->allowGroupSharing()) {
461
-				$shareTypes[] = Share::SHARE_TYPE_GROUP;
462
-			}
463
-
464
-			if ($this->isRemoteSharingAllowed($itemType)) {
465
-				$shareTypes[] = Share::SHARE_TYPE_REMOTE;
466
-			}
467
-
468
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
469
-				$shareTypes[] = Share::SHARE_TYPE_EMAIL;
470
-			}
471
-		} else {
472
-			$shareTypes[] = Share::SHARE_TYPE_GROUP;
473
-			$shareTypes[] = Share::SHARE_TYPE_EMAIL;
474
-		}
475
-
476
-		if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
477
-			$shareTypes[] = Share::SHARE_TYPE_CIRCLE;
478
-		}
479
-
480
-		if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
481
-			$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
482
-			sort($shareTypes);
483
-		} else if (is_numeric($shareType)) {
484
-			$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
485
-			sort($shareTypes);
486
-		}
487
-
488
-		$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
489
-		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
490
-		$this->limit = (int) $perPage;
491
-		$this->offset = $perPage * ($page - 1);
492
-
493
-		return $this->searchSharees($search, $itemType, $shareTypes, $page, $perPage, $lookup);
494
-	}
495
-
496
-	/**
497
-	 * Method to get out the static call for better testing
498
-	 *
499
-	 * @param string $itemType
500
-	 * @return bool
501
-	 */
502
-	protected function isRemoteSharingAllowed($itemType) {
503
-		try {
504
-			$backend = Share::getBackend($itemType);
505
-			return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
506
-		} catch (\Exception $e) {
507
-			return false;
508
-		}
509
-	}
510
-
511
-	/**
512
-	 * Testable search function that does not need globals
513
-	 *
514
-	 * @param string $search
515
-	 * @param string $itemType
516
-	 * @param array $shareTypes
517
-	 * @param int $page
518
-	 * @param int $perPage
519
-	 * @param bool $lookup
520
-	 * @return DataResponse
521
-	 * @throws OCSBadRequestException
522
-	 */
523
-	protected function searchSharees($search, $itemType, array $shareTypes, $page, $perPage, $lookup) {
524
-		// Verify arguments
525
-		if ($itemType === null) {
526
-			throw new OCSBadRequestException('Missing itemType');
527
-		}
528
-
529
-		// Get users
530
-		if (in_array(Share::SHARE_TYPE_USER, $shareTypes)) {
531
-			$this->getUsers($search);
532
-		}
533
-
534
-		// Get groups
535
-		if (in_array(Share::SHARE_TYPE_GROUP, $shareTypes)) {
536
-			$this->getGroups($search);
537
-		}
538
-
539
-		// Get circles
540
-		if (in_array(Share::SHARE_TYPE_CIRCLE, $shareTypes)) {
541
-			$this->getCircles($search);
542
-		}
543
-
544
-
545
-		// Get remote
546
-		$remoteResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
547
-		if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes)) {
548
-			$remoteResults = $this->getRemote($search);
549
-		}
550
-
551
-		// Get emails
552
-		$mailResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
553
-		if (in_array(Share::SHARE_TYPE_EMAIL, $shareTypes)) {
554
-			$mailResults = $this->getEmail($search);
555
-		}
556
-
557
-		// Get from lookup server
558
-		if ($lookup) {
559
-			$this->getLookup($search);
560
-		}
561
-
562
-		// if we have a exact match, either for the federated cloud id or for the
563
-		// email address we only return the exact match. It is highly unlikely
564
-		// that the exact same email address and federated cloud id exists
565
-		if ($mailResults['exactIdMatch'] && !$remoteResults['exactIdMatch']) {
566
-			$this->result['emails'] = $mailResults['results'];
567
-			$this->result['exact']['emails'] = $mailResults['exact'];
568
-		} else if (!$mailResults['exactIdMatch'] && $remoteResults['exactIdMatch']) {
569
-			$this->result['remotes'] = $remoteResults['results'];
570
-			$this->result['exact']['remotes'] = $remoteResults['exact'];
571
-		} else {
572
-			$this->result['remotes'] = $remoteResults['results'];
573
-			$this->result['exact']['remotes'] = $remoteResults['exact'];
574
-			$this->result['emails'] = $mailResults['results'];
575
-			$this->result['exact']['emails'] = $mailResults['exact'];
576
-		}
577
-
578
-		$response = new DataResponse($this->result);
579
-
580
-		if (sizeof($this->reachedEndFor) < 3) {
581
-			$response->addHeader('Link', $this->getPaginationLink($page, [
582
-				'search' => $search,
583
-				'itemType' => $itemType,
584
-				'shareType' => $shareTypes,
585
-				'perPage' => $perPage,
586
-			]));
587
-		}
588
-
589
-		return $response;
590
-	}
591
-
592
-	/**
593
-	 * @param string $search
594
-	 * @return array
595
-	 */
596
-	protected function getEmail($search) {
597
-		$result = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
598
-
599
-		// Search in contacts
600
-		//@todo Pagination missing
601
-		$addressBookContacts = $this->contactsManager->search($search, ['EMAIL', 'FN']);
602
-		$lowerSearch = strtolower($search);
603
-		foreach ($addressBookContacts as $contact) {
604
-			if (isset($contact['EMAIL'])) {
605
-				$emailAddresses = $contact['EMAIL'];
606
-				if (!is_array($emailAddresses)) {
607
-					$emailAddresses = [$emailAddresses];
608
-				}
609
-				foreach ($emailAddresses as $emailAddress) {
610
-					$exactEmailMatch = strtolower($emailAddress) === $lowerSearch;
611
-
612
-					if (isset($contact['isLocalSystemBook'])) {
613
-						if ($exactEmailMatch) {
614
-							$cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
615
-							if (!$this->hasUserInResult($cloud->getUser())) {
616
-								$this->result['exact']['users'][] = [
617
-									'label' => $contact['FN'] . " ($emailAddress)",
618
-									'value' => [
619
-										'shareType' => Share::SHARE_TYPE_USER,
620
-										'shareWith' => $cloud->getUser(),
621
-									],
622
-								];
623
-							}
624
-							return ['results' => [], 'exact' => [], 'exactIdMatch' => true];
625
-						}
626
-						if ($this->shareeEnumeration) {
627
-							$cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
628
-							if (!$this->hasUserInResult($cloud->getUser())) {
629
-								$this->result['users'][] = [
630
-									'label' => $contact['FN'] . " ($emailAddress)",
631
-									'value' => [
632
-										'shareType' => Share::SHARE_TYPE_USER,
633
-										'shareWith' => $cloud->getUser(),
634
-									],
635
-								];
636
-							}
637
-						}
638
-						continue;
639
-					}
640
-
641
-					if ($exactEmailMatch || strtolower($contact['FN']) === $lowerSearch) {
642
-						if ($exactEmailMatch) {
643
-							$result['exactIdMatch'] = true;
644
-						}
645
-						$result['exact'][] = [
646
-							'label' => $contact['FN'] . " ($emailAddress)",
647
-							'value' => [
648
-								'shareType' => Share::SHARE_TYPE_EMAIL,
649
-								'shareWith' => $emailAddress,
650
-							],
651
-						];
652
-					} else {
653
-						$result['results'][] = [
654
-							'label' => $contact['FN'] . " ($emailAddress)",
655
-							'value' => [
656
-								'shareType' => Share::SHARE_TYPE_EMAIL,
657
-								'shareWith' => $emailAddress,
658
-							],
659
-						];
660
-					}
661
-				}
662
-			}
663
-		}
664
-
665
-		if (!$this->shareeEnumeration) {
666
-			$result['results'] = [];
667
-		}
668
-
669
-		if (!$result['exactIdMatch'] && filter_var($search, FILTER_VALIDATE_EMAIL)) {
670
-			$result['exact'][] = [
671
-				'label' => $search,
672
-				'value' => [
673
-					'shareType' => Share::SHARE_TYPE_EMAIL,
674
-					'shareWith' => $search,
675
-				],
676
-			];
677
-		}
678
-
679
-		$this->reachedEndFor[] = 'emails';
680
-
681
-		return $result;
682
-	}
683
-
684
-	protected function getLookup($search) {
685
-		$isEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
686
-		$lookupServerUrl = $this->config->getSystemValue('lookup_server', 'https://lookup.nextcloud.com');
687
-		$lookupServerUrl = rtrim($lookupServerUrl, '/');
688
-		$result = [];
689
-
690
-		if($isEnabled === 'yes') {
691
-			try {
692
-				$client = $this->clientService->newClient();
693
-				$response = $client->get(
694
-					$lookupServerUrl . '/users?search=' . urlencode($search),
695
-					[
696
-						'timeout' => 10,
697
-						'connect_timeout' => 3,
698
-					]
699
-				);
700
-
701
-				$body = json_decode($response->getBody(), true);
702
-
703
-				$result = [];
704
-				foreach ($body as $lookup) {
705
-					$result[] = [
706
-						'label' => $lookup['federationId'],
707
-						'value' => [
708
-							'shareType' => Share::SHARE_TYPE_REMOTE,
709
-							'shareWith' => $lookup['federationId'],
710
-						],
711
-						'extra' => $lookup,
712
-					];
713
-				}
714
-			} catch (\Exception $e) {}
715
-		}
716
-
717
-		$this->result['lookup'] = $result;
718
-	}
719
-
720
-	/**
721
-	 * Check if a given user is already part of the result
722
-	 *
723
-	 * @param string $userId
724
-	 * @return bool
725
-	 */
726
-	protected function hasUserInResult($userId) {
727
-		foreach ($this->result['exact']['users'] as $result) {
728
-			if ($result['value']['shareWith'] === $userId) {
729
-				return true;
730
-			}
731
-		}
732
-
733
-		foreach ($this->result['users'] as $result) {
734
-			if ($result['value']['shareWith'] === $userId) {
735
-				return true;
736
-			}
737
-		}
738
-
739
-		return false;
740
-	}
741
-
742
-	/**
743
-	 * Generates a bunch of pagination links for the current page
744
-	 *
745
-	 * @param int $page Current page
746
-	 * @param array $params Parameters for the URL
747
-	 * @return string
748
-	 */
749
-	protected function getPaginationLink($page, array $params) {
750
-		if ($this->isV2()) {
751
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
752
-		} else {
753
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
754
-		}
755
-		$params['page'] = $page + 1;
756
-		$link = '<' . $url . http_build_query($params) . '>; rel="next"';
757
-
758
-		return $link;
759
-	}
760
-
761
-	/**
762
-	 * @return bool
763
-	 */
764
-	protected function isV2() {
765
-		return $this->request->getScriptName() === '/ocs/v2.php';
766
-	}
46
+    /** @var IGroupManager */
47
+    protected $groupManager;
48
+
49
+    /** @var IUserManager */
50
+    protected $userManager;
51
+
52
+    /** @var IManager */
53
+    protected $contactsManager;
54
+
55
+    /** @var IConfig */
56
+    protected $config;
57
+
58
+    /** @var IUserSession */
59
+    protected $userSession;
60
+
61
+    /** @var IURLGenerator */
62
+    protected $urlGenerator;
63
+
64
+    /** @var ILogger */
65
+    protected $logger;
66
+
67
+    /** @var \OCP\Share\IManager */
68
+    protected $shareManager;
69
+
70
+    /** @var IClientService */
71
+    protected $clientService;
72
+
73
+    /** @var ICloudIdManager  */
74
+    protected $cloudIdManager;
75
+
76
+    /** @var bool */
77
+    protected $shareWithGroupOnly = false;
78
+
79
+    /** @var bool */
80
+    protected $shareeEnumeration = true;
81
+
82
+    /** @var int */
83
+    protected $offset = 0;
84
+
85
+    /** @var int */
86
+    protected $limit = 10;
87
+
88
+    /** @var array */
89
+    protected $result = [
90
+        'exact' => [
91
+            'users' => [],
92
+            'groups' => [],
93
+            'remotes' => [],
94
+            'emails' => [],
95
+            'circles' => [],
96
+        ],
97
+        'users' => [],
98
+        'groups' => [],
99
+        'remotes' => [],
100
+        'emails' => [],
101
+        'lookup' => [],
102
+        'circles' => [],
103
+    ];
104
+
105
+    protected $reachedEndFor = [];
106
+
107
+    /**
108
+     * @param string $appName
109
+     * @param IRequest $request
110
+     * @param IGroupManager $groupManager
111
+     * @param IUserManager $userManager
112
+     * @param IManager $contactsManager
113
+     * @param IConfig $config
114
+     * @param IUserSession $userSession
115
+     * @param IURLGenerator $urlGenerator
116
+     * @param ILogger $logger
117
+     * @param \OCP\Share\IManager $shareManager
118
+     * @param IClientService $clientService
119
+     * @param ICloudIdManager $cloudIdManager
120
+     */
121
+    public function __construct($appName,
122
+                                IRequest $request,
123
+                                IGroupManager $groupManager,
124
+                                IUserManager $userManager,
125
+                                IManager $contactsManager,
126
+                                IConfig $config,
127
+                                IUserSession $userSession,
128
+                                IURLGenerator $urlGenerator,
129
+                                ILogger $logger,
130
+                                \OCP\Share\IManager $shareManager,
131
+                                IClientService $clientService,
132
+                                ICloudIdManager $cloudIdManager
133
+    ) {
134
+        parent::__construct($appName, $request);
135
+
136
+        $this->groupManager = $groupManager;
137
+        $this->userManager = $userManager;
138
+        $this->contactsManager = $contactsManager;
139
+        $this->config = $config;
140
+        $this->userSession = $userSession;
141
+        $this->urlGenerator = $urlGenerator;
142
+        $this->logger = $logger;
143
+        $this->shareManager = $shareManager;
144
+        $this->clientService = $clientService;
145
+        $this->cloudIdManager = $cloudIdManager;
146
+    }
147
+
148
+    /**
149
+     * @param string $search
150
+     */
151
+    protected function getUsers($search) {
152
+        $this->result['users'] = $this->result['exact']['users'] = $users = [];
153
+
154
+        $userGroups = [];
155
+        if ($this->shareWithGroupOnly) {
156
+            // Search in all the groups this user is part of
157
+            $userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
158
+            foreach ($userGroups as $userGroup) {
159
+                $usersTmp = $this->groupManager->displayNamesInGroup($userGroup, $search, $this->limit, $this->offset);
160
+                foreach ($usersTmp as $uid => $userDisplayName) {
161
+                    $users[$uid] = $userDisplayName;
162
+                }
163
+            }
164
+        } else {
165
+            // Search in all users
166
+            $usersTmp = $this->userManager->searchDisplayName($search, $this->limit, $this->offset);
167
+
168
+            foreach ($usersTmp as $user) {
169
+                $users[$user->getUID()] = $user->getDisplayName();
170
+            }
171
+        }
172
+
173
+        if (!$this->shareeEnumeration || sizeof($users) < $this->limit) {
174
+            $this->reachedEndFor[] = 'users';
175
+        }
176
+
177
+        $foundUserById = false;
178
+        $lowerSearch = strtolower($search);
179
+        foreach ($users as $uid => $userDisplayName) {
180
+            if (strtolower($uid) === $lowerSearch || strtolower($userDisplayName) === $lowerSearch) {
181
+                if (strtolower($uid) === $lowerSearch) {
182
+                    $foundUserById = true;
183
+                }
184
+                $this->result['exact']['users'][] = [
185
+                    'label' => $userDisplayName,
186
+                    'value' => [
187
+                        'shareType' => Share::SHARE_TYPE_USER,
188
+                        'shareWith' => $uid,
189
+                    ],
190
+                ];
191
+            } else {
192
+                $this->result['users'][] = [
193
+                    'label' => $userDisplayName,
194
+                    'value' => [
195
+                        'shareType' => Share::SHARE_TYPE_USER,
196
+                        'shareWith' => $uid,
197
+                    ],
198
+                ];
199
+            }
200
+        }
201
+
202
+        if ($this->offset === 0 && !$foundUserById) {
203
+            // On page one we try if the search result has a direct hit on the
204
+            // user id and if so, we add that to the exact match list
205
+            $user = $this->userManager->get($search);
206
+            if ($user instanceof IUser) {
207
+                $addUser = true;
208
+
209
+                if ($this->shareWithGroupOnly) {
210
+                    // Only add, if we have a common group
211
+                    $commonGroups = array_intersect($userGroups, $this->groupManager->getUserGroupIds($user));
212
+                    $addUser = !empty($commonGroups);
213
+                }
214
+
215
+                if ($addUser) {
216
+                    array_push($this->result['exact']['users'], [
217
+                        'label' => $user->getDisplayName(),
218
+                        'value' => [
219
+                            'shareType' => Share::SHARE_TYPE_USER,
220
+                            'shareWith' => $user->getUID(),
221
+                        ],
222
+                    ]);
223
+                }
224
+            }
225
+        }
226
+
227
+        if (!$this->shareeEnumeration) {
228
+            $this->result['users'] = [];
229
+        }
230
+    }
231
+
232
+    /**
233
+     * @param string $search
234
+     */
235
+    protected function getGroups($search) {
236
+        $this->result['groups'] = $this->result['exact']['groups'] = [];
237
+
238
+        $groups = $this->groupManager->search($search, $this->limit, $this->offset);
239
+        $groupIds = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
240
+
241
+        if (!$this->shareeEnumeration || sizeof($groups) < $this->limit) {
242
+            $this->reachedEndFor[] = 'groups';
243
+        }
244
+
245
+        $userGroups =  [];
246
+        if (!empty($groups) && $this->shareWithGroupOnly) {
247
+            // Intersect all the groups that match with the groups this user is a member of
248
+            $userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
249
+            $userGroups = array_map(function (IGroup $group) { return $group->getGID(); }, $userGroups);
250
+            $groupIds = array_intersect($groupIds, $userGroups);
251
+        }
252
+
253
+        $lowerSearch = strtolower($search);
254
+        foreach ($groups as $group) {
255
+            // FIXME: use a more efficient approach
256
+            $gid = $group->getGID();
257
+            if (!in_array($gid, $groupIds)) {
258
+                continue;
259
+            }
260
+            if (strtolower($gid) === $lowerSearch || strtolower($group->getDisplayName()) === $lowerSearch) {
261
+                $this->result['exact']['groups'][] = [
262
+                    'label' => $group->getDisplayName(),
263
+                    'value' => [
264
+                        'shareType' => Share::SHARE_TYPE_GROUP,
265
+                        'shareWith' => $gid,
266
+                    ],
267
+                ];
268
+            } else {
269
+                $this->result['groups'][] = [
270
+                    'label' => $group->getDisplayName(),
271
+                    'value' => [
272
+                        'shareType' => Share::SHARE_TYPE_GROUP,
273
+                        'shareWith' => $gid,
274
+                    ],
275
+                ];
276
+            }
277
+        }
278
+
279
+        if ($this->offset === 0 && empty($this->result['exact']['groups'])) {
280
+            // On page one we try if the search result has a direct hit on the
281
+            // user id and if so, we add that to the exact match list
282
+            $group = $this->groupManager->get($search);
283
+            if ($group instanceof IGroup && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups))) {
284
+                array_push($this->result['exact']['groups'], [
285
+                    'label' => $group->getDisplayName(),
286
+                    'value' => [
287
+                        'shareType' => Share::SHARE_TYPE_GROUP,
288
+                        'shareWith' => $group->getGID(),
289
+                    ],
290
+                ]);
291
+            }
292
+        }
293
+
294
+        if (!$this->shareeEnumeration) {
295
+            $this->result['groups'] = [];
296
+        }
297
+    }
298
+
299
+
300
+    /**
301
+     * @param string $search
302
+     * @suppress PhanUndeclaredClassMethod
303
+     */
304
+    protected function getCircles($search) {
305
+        $this->result['circles'] = $this->result['exact']['circles'] = [];
306
+
307
+        $result = \OCA\Circles\Api\Sharees::search($search, $this->limit, $this->offset);
308
+        if (array_key_exists('circles', $result['exact'])) {
309
+            $this->result['exact']['circles'] = $result['exact']['circles'];
310
+        }
311
+        if (array_key_exists('circles', $result)) {
312
+            $this->result['circles'] = $result['circles'];
313
+        }
314
+    }
315
+
316
+
317
+    /**
318
+     * @param string $search
319
+     * @return array
320
+     */
321
+    protected function getRemote($search) {
322
+        $result = ['results' => [], 'exact' => []];
323
+
324
+        // Search in contacts
325
+        //@todo Pagination missing
326
+        $addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
327
+        $result['exactIdMatch'] = false;
328
+        foreach ($addressBookContacts as $contact) {
329
+            if (isset($contact['isLocalSystemBook'])) {
330
+                continue;
331
+            }
332
+            if (isset($contact['CLOUD'])) {
333
+                $cloudIds = $contact['CLOUD'];
334
+                if (!is_array($cloudIds)) {
335
+                    $cloudIds = [$cloudIds];
336
+                }
337
+                $lowerSearch = strtolower($search);
338
+                foreach ($cloudIds as $cloudId) {
339
+                    list(, $serverUrl) = $this->splitUserRemote($cloudId);
340
+                    if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
341
+                        if (strtolower($cloudId) === $lowerSearch) {
342
+                            $result['exactIdMatch'] = true;
343
+                        }
344
+                        $result['exact'][] = [
345
+                            'label' => $contact['FN'] . " ($cloudId)",
346
+                            'value' => [
347
+                                'shareType' => Share::SHARE_TYPE_REMOTE,
348
+                                'shareWith' => $cloudId,
349
+                                'server' => $serverUrl,
350
+                            ],
351
+                        ];
352
+                    } else {
353
+                        $result['results'][] = [
354
+                            'label' => $contact['FN'] . " ($cloudId)",
355
+                            'value' => [
356
+                                'shareType' => Share::SHARE_TYPE_REMOTE,
357
+                                'shareWith' => $cloudId,
358
+                                'server' => $serverUrl,
359
+                            ],
360
+                        ];
361
+                    }
362
+                }
363
+            }
364
+        }
365
+
366
+        if (!$this->shareeEnumeration) {
367
+            $result['results'] = [];
368
+        }
369
+
370
+        if (!$result['exactIdMatch'] && $this->cloudIdManager->isValidCloudId($search) && $this->offset === 0) {
371
+            $result['exact'][] = [
372
+                'label' => $search,
373
+                'value' => [
374
+                    'shareType' => Share::SHARE_TYPE_REMOTE,
375
+                    'shareWith' => $search,
376
+                ],
377
+            ];
378
+        }
379
+
380
+        $this->reachedEndFor[] = 'remotes';
381
+
382
+        return $result;
383
+    }
384
+
385
+    /**
386
+     * split user and remote from federated cloud id
387
+     *
388
+     * @param string $address federated share address
389
+     * @return array [user, remoteURL]
390
+     * @throws \Exception
391
+     */
392
+    public function splitUserRemote($address) {
393
+        try {
394
+            $cloudId = $this->cloudIdManager->resolveCloudId($address);
395
+            return [$cloudId->getUser(), $cloudId->getRemote()];
396
+        } catch (\InvalidArgumentException $e) {
397
+            throw new \Exception('Invalid Federated Cloud ID', 0, $e);
398
+        }
399
+    }
400
+
401
+    /**
402
+     * Strips away a potential file names and trailing slashes:
403
+     * - http://localhost
404
+     * - http://localhost/
405
+     * - http://localhost/index.php
406
+     * - http://localhost/index.php/s/{shareToken}
407
+     *
408
+     * all return: http://localhost
409
+     *
410
+     * @param string $remote
411
+     * @return string
412
+     */
413
+    protected function fixRemoteURL($remote) {
414
+        $remote = str_replace('\\', '/', $remote);
415
+        if ($fileNamePosition = strpos($remote, '/index.php')) {
416
+            $remote = substr($remote, 0, $fileNamePosition);
417
+        }
418
+        $remote = rtrim($remote, '/');
419
+
420
+        return $remote;
421
+    }
422
+
423
+    /**
424
+     * @NoAdminRequired
425
+     *
426
+     * @param string $search
427
+     * @param string $itemType
428
+     * @param int $page
429
+     * @param int $perPage
430
+     * @param int|int[] $shareType
431
+     * @param bool $lookup
432
+     * @return DataResponse
433
+     * @throws OCSBadRequestException
434
+     */
435
+    public function search($search = '', $itemType = null, $page = 1, $perPage = 200, $shareType = null, $lookup = true) {
436
+
437
+        // only search for string larger than a given threshold
438
+        $threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0);
439
+        if (strlen($search) < $threshold) {
440
+            return new DataResponse($this->result);
441
+        }
442
+
443
+        // never return more than the max. number of results configured in the config.php
444
+        $maxResults = (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0);
445
+        if ($maxResults > 0) {
446
+            $perPage = min($perPage, $maxResults);
447
+        }
448
+        if ($perPage <= 0) {
449
+            throw new OCSBadRequestException('Invalid perPage argument');
450
+        }
451
+        if ($page <= 0) {
452
+            throw new OCSBadRequestException('Invalid page');
453
+        }
454
+
455
+        $shareTypes = [
456
+            Share::SHARE_TYPE_USER,
457
+        ];
458
+
459
+        if ($itemType === 'file' || $itemType === 'folder') {
460
+            if ($this->shareManager->allowGroupSharing()) {
461
+                $shareTypes[] = Share::SHARE_TYPE_GROUP;
462
+            }
463
+
464
+            if ($this->isRemoteSharingAllowed($itemType)) {
465
+                $shareTypes[] = Share::SHARE_TYPE_REMOTE;
466
+            }
467
+
468
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
469
+                $shareTypes[] = Share::SHARE_TYPE_EMAIL;
470
+            }
471
+        } else {
472
+            $shareTypes[] = Share::SHARE_TYPE_GROUP;
473
+            $shareTypes[] = Share::SHARE_TYPE_EMAIL;
474
+        }
475
+
476
+        if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
477
+            $shareTypes[] = Share::SHARE_TYPE_CIRCLE;
478
+        }
479
+
480
+        if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
481
+            $shareTypes = array_intersect($shareTypes, $_GET['shareType']);
482
+            sort($shareTypes);
483
+        } else if (is_numeric($shareType)) {
484
+            $shareTypes = array_intersect($shareTypes, [(int) $shareType]);
485
+            sort($shareTypes);
486
+        }
487
+
488
+        $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
489
+        $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
490
+        $this->limit = (int) $perPage;
491
+        $this->offset = $perPage * ($page - 1);
492
+
493
+        return $this->searchSharees($search, $itemType, $shareTypes, $page, $perPage, $lookup);
494
+    }
495
+
496
+    /**
497
+     * Method to get out the static call for better testing
498
+     *
499
+     * @param string $itemType
500
+     * @return bool
501
+     */
502
+    protected function isRemoteSharingAllowed($itemType) {
503
+        try {
504
+            $backend = Share::getBackend($itemType);
505
+            return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
506
+        } catch (\Exception $e) {
507
+            return false;
508
+        }
509
+    }
510
+
511
+    /**
512
+     * Testable search function that does not need globals
513
+     *
514
+     * @param string $search
515
+     * @param string $itemType
516
+     * @param array $shareTypes
517
+     * @param int $page
518
+     * @param int $perPage
519
+     * @param bool $lookup
520
+     * @return DataResponse
521
+     * @throws OCSBadRequestException
522
+     */
523
+    protected function searchSharees($search, $itemType, array $shareTypes, $page, $perPage, $lookup) {
524
+        // Verify arguments
525
+        if ($itemType === null) {
526
+            throw new OCSBadRequestException('Missing itemType');
527
+        }
528
+
529
+        // Get users
530
+        if (in_array(Share::SHARE_TYPE_USER, $shareTypes)) {
531
+            $this->getUsers($search);
532
+        }
533
+
534
+        // Get groups
535
+        if (in_array(Share::SHARE_TYPE_GROUP, $shareTypes)) {
536
+            $this->getGroups($search);
537
+        }
538
+
539
+        // Get circles
540
+        if (in_array(Share::SHARE_TYPE_CIRCLE, $shareTypes)) {
541
+            $this->getCircles($search);
542
+        }
543
+
544
+
545
+        // Get remote
546
+        $remoteResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
547
+        if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes)) {
548
+            $remoteResults = $this->getRemote($search);
549
+        }
550
+
551
+        // Get emails
552
+        $mailResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
553
+        if (in_array(Share::SHARE_TYPE_EMAIL, $shareTypes)) {
554
+            $mailResults = $this->getEmail($search);
555
+        }
556
+
557
+        // Get from lookup server
558
+        if ($lookup) {
559
+            $this->getLookup($search);
560
+        }
561
+
562
+        // if we have a exact match, either for the federated cloud id or for the
563
+        // email address we only return the exact match. It is highly unlikely
564
+        // that the exact same email address and federated cloud id exists
565
+        if ($mailResults['exactIdMatch'] && !$remoteResults['exactIdMatch']) {
566
+            $this->result['emails'] = $mailResults['results'];
567
+            $this->result['exact']['emails'] = $mailResults['exact'];
568
+        } else if (!$mailResults['exactIdMatch'] && $remoteResults['exactIdMatch']) {
569
+            $this->result['remotes'] = $remoteResults['results'];
570
+            $this->result['exact']['remotes'] = $remoteResults['exact'];
571
+        } else {
572
+            $this->result['remotes'] = $remoteResults['results'];
573
+            $this->result['exact']['remotes'] = $remoteResults['exact'];
574
+            $this->result['emails'] = $mailResults['results'];
575
+            $this->result['exact']['emails'] = $mailResults['exact'];
576
+        }
577
+
578
+        $response = new DataResponse($this->result);
579
+
580
+        if (sizeof($this->reachedEndFor) < 3) {
581
+            $response->addHeader('Link', $this->getPaginationLink($page, [
582
+                'search' => $search,
583
+                'itemType' => $itemType,
584
+                'shareType' => $shareTypes,
585
+                'perPage' => $perPage,
586
+            ]));
587
+        }
588
+
589
+        return $response;
590
+    }
591
+
592
+    /**
593
+     * @param string $search
594
+     * @return array
595
+     */
596
+    protected function getEmail($search) {
597
+        $result = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
598
+
599
+        // Search in contacts
600
+        //@todo Pagination missing
601
+        $addressBookContacts = $this->contactsManager->search($search, ['EMAIL', 'FN']);
602
+        $lowerSearch = strtolower($search);
603
+        foreach ($addressBookContacts as $contact) {
604
+            if (isset($contact['EMAIL'])) {
605
+                $emailAddresses = $contact['EMAIL'];
606
+                if (!is_array($emailAddresses)) {
607
+                    $emailAddresses = [$emailAddresses];
608
+                }
609
+                foreach ($emailAddresses as $emailAddress) {
610
+                    $exactEmailMatch = strtolower($emailAddress) === $lowerSearch;
611
+
612
+                    if (isset($contact['isLocalSystemBook'])) {
613
+                        if ($exactEmailMatch) {
614
+                            $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
615
+                            if (!$this->hasUserInResult($cloud->getUser())) {
616
+                                $this->result['exact']['users'][] = [
617
+                                    'label' => $contact['FN'] . " ($emailAddress)",
618
+                                    'value' => [
619
+                                        'shareType' => Share::SHARE_TYPE_USER,
620
+                                        'shareWith' => $cloud->getUser(),
621
+                                    ],
622
+                                ];
623
+                            }
624
+                            return ['results' => [], 'exact' => [], 'exactIdMatch' => true];
625
+                        }
626
+                        if ($this->shareeEnumeration) {
627
+                            $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
628
+                            if (!$this->hasUserInResult($cloud->getUser())) {
629
+                                $this->result['users'][] = [
630
+                                    'label' => $contact['FN'] . " ($emailAddress)",
631
+                                    'value' => [
632
+                                        'shareType' => Share::SHARE_TYPE_USER,
633
+                                        'shareWith' => $cloud->getUser(),
634
+                                    ],
635
+                                ];
636
+                            }
637
+                        }
638
+                        continue;
639
+                    }
640
+
641
+                    if ($exactEmailMatch || strtolower($contact['FN']) === $lowerSearch) {
642
+                        if ($exactEmailMatch) {
643
+                            $result['exactIdMatch'] = true;
644
+                        }
645
+                        $result['exact'][] = [
646
+                            'label' => $contact['FN'] . " ($emailAddress)",
647
+                            'value' => [
648
+                                'shareType' => Share::SHARE_TYPE_EMAIL,
649
+                                'shareWith' => $emailAddress,
650
+                            ],
651
+                        ];
652
+                    } else {
653
+                        $result['results'][] = [
654
+                            'label' => $contact['FN'] . " ($emailAddress)",
655
+                            'value' => [
656
+                                'shareType' => Share::SHARE_TYPE_EMAIL,
657
+                                'shareWith' => $emailAddress,
658
+                            ],
659
+                        ];
660
+                    }
661
+                }
662
+            }
663
+        }
664
+
665
+        if (!$this->shareeEnumeration) {
666
+            $result['results'] = [];
667
+        }
668
+
669
+        if (!$result['exactIdMatch'] && filter_var($search, FILTER_VALIDATE_EMAIL)) {
670
+            $result['exact'][] = [
671
+                'label' => $search,
672
+                'value' => [
673
+                    'shareType' => Share::SHARE_TYPE_EMAIL,
674
+                    'shareWith' => $search,
675
+                ],
676
+            ];
677
+        }
678
+
679
+        $this->reachedEndFor[] = 'emails';
680
+
681
+        return $result;
682
+    }
683
+
684
+    protected function getLookup($search) {
685
+        $isEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
686
+        $lookupServerUrl = $this->config->getSystemValue('lookup_server', 'https://lookup.nextcloud.com');
687
+        $lookupServerUrl = rtrim($lookupServerUrl, '/');
688
+        $result = [];
689
+
690
+        if($isEnabled === 'yes') {
691
+            try {
692
+                $client = $this->clientService->newClient();
693
+                $response = $client->get(
694
+                    $lookupServerUrl . '/users?search=' . urlencode($search),
695
+                    [
696
+                        'timeout' => 10,
697
+                        'connect_timeout' => 3,
698
+                    ]
699
+                );
700
+
701
+                $body = json_decode($response->getBody(), true);
702
+
703
+                $result = [];
704
+                foreach ($body as $lookup) {
705
+                    $result[] = [
706
+                        'label' => $lookup['federationId'],
707
+                        'value' => [
708
+                            'shareType' => Share::SHARE_TYPE_REMOTE,
709
+                            'shareWith' => $lookup['federationId'],
710
+                        ],
711
+                        'extra' => $lookup,
712
+                    ];
713
+                }
714
+            } catch (\Exception $e) {}
715
+        }
716
+
717
+        $this->result['lookup'] = $result;
718
+    }
719
+
720
+    /**
721
+     * Check if a given user is already part of the result
722
+     *
723
+     * @param string $userId
724
+     * @return bool
725
+     */
726
+    protected function hasUserInResult($userId) {
727
+        foreach ($this->result['exact']['users'] as $result) {
728
+            if ($result['value']['shareWith'] === $userId) {
729
+                return true;
730
+            }
731
+        }
732
+
733
+        foreach ($this->result['users'] as $result) {
734
+            if ($result['value']['shareWith'] === $userId) {
735
+                return true;
736
+            }
737
+        }
738
+
739
+        return false;
740
+    }
741
+
742
+    /**
743
+     * Generates a bunch of pagination links for the current page
744
+     *
745
+     * @param int $page Current page
746
+     * @param array $params Parameters for the URL
747
+     * @return string
748
+     */
749
+    protected function getPaginationLink($page, array $params) {
750
+        if ($this->isV2()) {
751
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
752
+        } else {
753
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
754
+        }
755
+        $params['page'] = $page + 1;
756
+        $link = '<' . $url . http_build_query($params) . '>; rel="next"';
757
+
758
+        return $link;
759
+    }
760
+
761
+    /**
762
+     * @return bool
763
+     */
764
+    protected function isV2() {
765
+        return $this->request->getScriptName() === '/ocs/v2.php';
766
+    }
767 767
 }
Please login to merge, or discard this patch.
apps/sharebymail/lib/ShareByMailProvider.php 1 patch
Indentation   +999 added lines, -999 removed lines patch added patch discarded remove patch
@@ -53,1017 +53,1017 @@
 block discarded – undo
53 53
  */
54 54
 class ShareByMailProvider implements IShareProvider {
55 55
 
56
-	/** @var  IDBConnection */
57
-	private $dbConnection;
58
-
59
-	/** @var ILogger */
60
-	private $logger;
61
-
62
-	/** @var ISecureRandom */
63
-	private $secureRandom;
64
-
65
-	/** @var IUserManager */
66
-	private $userManager;
67
-
68
-	/** @var IRootFolder */
69
-	private $rootFolder;
70
-
71
-	/** @var IL10N */
72
-	private $l;
73
-
74
-	/** @var IMailer */
75
-	private $mailer;
76
-
77
-	/** @var IURLGenerator */
78
-	private $urlGenerator;
79
-
80
-	/** @var IManager  */
81
-	private $activityManager;
82
-
83
-	/** @var SettingsManager */
84
-	private $settingsManager;
85
-
86
-	/** @var Defaults */
87
-	private $defaults;
88
-
89
-	/** @var IHasher */
90
-	private $hasher;
91
-
92
-	/** @var  CapabilitiesManager */
93
-	private $capabilitiesManager;
94
-
95
-	/**
96
-	 * Return the identifier of this provider.
97
-	 *
98
-	 * @return string Containing only [a-zA-Z0-9]
99
-	 */
100
-	public function identifier() {
101
-		return 'ocMailShare';
102
-	}
103
-
104
-	/**
105
-	 * DefaultShareProvider constructor.
106
-	 *
107
-	 * @param IDBConnection $connection
108
-	 * @param ISecureRandom $secureRandom
109
-	 * @param IUserManager $userManager
110
-	 * @param IRootFolder $rootFolder
111
-	 * @param IL10N $l
112
-	 * @param ILogger $logger
113
-	 * @param IMailer $mailer
114
-	 * @param IURLGenerator $urlGenerator
115
-	 * @param IManager $activityManager
116
-	 * @param SettingsManager $settingsManager
117
-	 * @param Defaults $defaults
118
-	 * @param IHasher $hasher
119
-	 * @param CapabilitiesManager $capabilitiesManager
120
-	 */
121
-	public function __construct(
122
-		IDBConnection $connection,
123
-		ISecureRandom $secureRandom,
124
-		IUserManager $userManager,
125
-		IRootFolder $rootFolder,
126
-		IL10N $l,
127
-		ILogger $logger,
128
-		IMailer $mailer,
129
-		IURLGenerator $urlGenerator,
130
-		IManager $activityManager,
131
-		SettingsManager $settingsManager,
132
-		Defaults $defaults,
133
-		IHasher $hasher,
134
-		CapabilitiesManager $capabilitiesManager
135
-	) {
136
-		$this->dbConnection = $connection;
137
-		$this->secureRandom = $secureRandom;
138
-		$this->userManager = $userManager;
139
-		$this->rootFolder = $rootFolder;
140
-		$this->l = $l;
141
-		$this->logger = $logger;
142
-		$this->mailer = $mailer;
143
-		$this->urlGenerator = $urlGenerator;
144
-		$this->activityManager = $activityManager;
145
-		$this->settingsManager = $settingsManager;
146
-		$this->defaults = $defaults;
147
-		$this->hasher = $hasher;
148
-		$this->capabilitiesManager = $capabilitiesManager;
149
-	}
150
-
151
-	/**
152
-	 * Share a path
153
-	 *
154
-	 * @param IShare $share
155
-	 * @return IShare The share object
156
-	 * @throws ShareNotFound
157
-	 * @throws \Exception
158
-	 */
159
-	public function create(IShare $share) {
160
-
161
-		$shareWith = $share->getSharedWith();
162
-		/*
56
+    /** @var  IDBConnection */
57
+    private $dbConnection;
58
+
59
+    /** @var ILogger */
60
+    private $logger;
61
+
62
+    /** @var ISecureRandom */
63
+    private $secureRandom;
64
+
65
+    /** @var IUserManager */
66
+    private $userManager;
67
+
68
+    /** @var IRootFolder */
69
+    private $rootFolder;
70
+
71
+    /** @var IL10N */
72
+    private $l;
73
+
74
+    /** @var IMailer */
75
+    private $mailer;
76
+
77
+    /** @var IURLGenerator */
78
+    private $urlGenerator;
79
+
80
+    /** @var IManager  */
81
+    private $activityManager;
82
+
83
+    /** @var SettingsManager */
84
+    private $settingsManager;
85
+
86
+    /** @var Defaults */
87
+    private $defaults;
88
+
89
+    /** @var IHasher */
90
+    private $hasher;
91
+
92
+    /** @var  CapabilitiesManager */
93
+    private $capabilitiesManager;
94
+
95
+    /**
96
+     * Return the identifier of this provider.
97
+     *
98
+     * @return string Containing only [a-zA-Z0-9]
99
+     */
100
+    public function identifier() {
101
+        return 'ocMailShare';
102
+    }
103
+
104
+    /**
105
+     * DefaultShareProvider constructor.
106
+     *
107
+     * @param IDBConnection $connection
108
+     * @param ISecureRandom $secureRandom
109
+     * @param IUserManager $userManager
110
+     * @param IRootFolder $rootFolder
111
+     * @param IL10N $l
112
+     * @param ILogger $logger
113
+     * @param IMailer $mailer
114
+     * @param IURLGenerator $urlGenerator
115
+     * @param IManager $activityManager
116
+     * @param SettingsManager $settingsManager
117
+     * @param Defaults $defaults
118
+     * @param IHasher $hasher
119
+     * @param CapabilitiesManager $capabilitiesManager
120
+     */
121
+    public function __construct(
122
+        IDBConnection $connection,
123
+        ISecureRandom $secureRandom,
124
+        IUserManager $userManager,
125
+        IRootFolder $rootFolder,
126
+        IL10N $l,
127
+        ILogger $logger,
128
+        IMailer $mailer,
129
+        IURLGenerator $urlGenerator,
130
+        IManager $activityManager,
131
+        SettingsManager $settingsManager,
132
+        Defaults $defaults,
133
+        IHasher $hasher,
134
+        CapabilitiesManager $capabilitiesManager
135
+    ) {
136
+        $this->dbConnection = $connection;
137
+        $this->secureRandom = $secureRandom;
138
+        $this->userManager = $userManager;
139
+        $this->rootFolder = $rootFolder;
140
+        $this->l = $l;
141
+        $this->logger = $logger;
142
+        $this->mailer = $mailer;
143
+        $this->urlGenerator = $urlGenerator;
144
+        $this->activityManager = $activityManager;
145
+        $this->settingsManager = $settingsManager;
146
+        $this->defaults = $defaults;
147
+        $this->hasher = $hasher;
148
+        $this->capabilitiesManager = $capabilitiesManager;
149
+    }
150
+
151
+    /**
152
+     * Share a path
153
+     *
154
+     * @param IShare $share
155
+     * @return IShare The share object
156
+     * @throws ShareNotFound
157
+     * @throws \Exception
158
+     */
159
+    public function create(IShare $share) {
160
+
161
+        $shareWith = $share->getSharedWith();
162
+        /*
163 163
 		 * Check if file is not already shared with the remote user
164 164
 		 */
165
-		$alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_EMAIL, $share->getNode(), 1, 0);
166
-		if (!empty($alreadyShared)) {
167
-			$message = 'Sharing %s failed, this item is already shared with %s';
168
-			$message_t = $this->l->t('Sharing %s failed, this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
169
-			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
170
-			throw new \Exception($message_t);
171
-		}
172
-
173
-		// if the admin enforces a password for all mail shares we create a
174
-		// random password and send it to the recipient
175
-		$password = '';
176
-		$passwordEnforced = $this->settingsManager->enforcePasswordProtection();
177
-		if ($passwordEnforced) {
178
-			$password = $this->autoGeneratePassword($share);
179
-		}
180
-
181
-		$shareId = $this->createMailShare($share);
182
-		$send = $this->sendPassword($share, $password);
183
-		if ($passwordEnforced && $send === false) {
184
-			$this->sendPasswordToOwner($share, $password);
185
-		}
186
-
187
-		$this->createShareActivity($share);
188
-		$data = $this->getRawShare($shareId);
189
-
190
-		return $this->createShareObject($data);
191
-
192
-	}
193
-
194
-	/**
195
-	 * auto generate password in case of password enforcement on mail shares
196
-	 *
197
-	 * @param IShare $share
198
-	 * @return string
199
-	 * @throws \Exception
200
-	 */
201
-	protected function autoGeneratePassword($share) {
202
-		$initiatorUser = $this->userManager->get($share->getSharedBy());
203
-		$initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
204
-		$allowPasswordByMail = $this->settingsManager->sendPasswordByMail();
205
-
206
-		if ($initiatorEMailAddress === null && !$allowPasswordByMail) {
207
-			throw new \Exception(
208
-				$this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
209
-			);
210
-		}
211
-
212
-		$passwordPolicy = $this->getPasswordPolicy();
213
-		$passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS;
214
-		$passwordLength = 8;
215
-		if (!empty($passwordPolicy)) {
216
-			$passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength;
217
-			$passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : '';
218
-		}
219
-
220
-		$password = $this->secureRandom->generate($passwordLength, $passwordCharset);
221
-
222
-		$share->setPassword($this->hasher->hash($password));
223
-
224
-		return $password;
225
-	}
226
-
227
-	/**
228
-	 * get password policy
229
-	 *
230
-	 * @return array
231
-	 */
232
-	protected function getPasswordPolicy() {
233
-		$capabilities = $this->capabilitiesManager->getCapabilities();
234
-		if (isset($capabilities['password_policy'])) {
235
-			return $capabilities['password_policy'];
236
-		}
237
-
238
-		return [];
239
-	}
240
-
241
-	/**
242
-	 * create activity if a file/folder was shared by mail
243
-	 *
244
-	 * @param IShare $share
245
-	 */
246
-	protected function createShareActivity(IShare $share) {
247
-
248
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
249
-
250
-		$this->publishActivity(
251
-			Activity::SUBJECT_SHARED_EMAIL_SELF,
252
-			[$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()],
253
-			$share->getSharedBy(),
254
-			$share->getNode()->getId(),
255
-			$userFolder->getRelativePath($share->getNode()->getPath())
256
-		);
257
-
258
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
259
-			$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
260
-			$fileId = $share->getNode()->getId();
261
-			$nodes = $ownerFolder->getById($fileId);
262
-			$ownerPath = $nodes[0]->getPath();
263
-			$this->publishActivity(
264
-				Activity::SUBJECT_SHARED_EMAIL_BY,
265
-				[$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()],
266
-				$share->getShareOwner(),
267
-				$fileId,
268
-				$ownerFolder->getRelativePath($ownerPath)
269
-			);
270
-		}
271
-
272
-	}
273
-
274
-	/**
275
-	 * create activity if a file/folder was shared by mail
276
-	 *
277
-	 * @param IShare $share
278
-	 * @param string $sharedWith
279
-	 * @param bool $sendToSelf
280
-	 */
281
-	protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) {
282
-
283
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
284
-
285
-		if ($sendToSelf) {
286
-			$this->publishActivity(
287
-				Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF,
288
-				[$userFolder->getRelativePath($share->getNode()->getPath())],
289
-				$share->getSharedBy(),
290
-				$share->getNode()->getId(),
291
-				$userFolder->getRelativePath($share->getNode()->getPath())
292
-			);
293
-		} else {
294
-			$this->publishActivity(
295
-				Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND,
296
-				[$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith],
297
-				$share->getSharedBy(),
298
-				$share->getNode()->getId(),
299
-				$userFolder->getRelativePath($share->getNode()->getPath())
300
-			);
301
-		}
302
-	}
303
-
304
-
305
-	/**
306
-	 * publish activity if a file/folder was shared by mail
307
-	 *
308
-	 * @param $subject
309
-	 * @param $parameters
310
-	 * @param $affectedUser
311
-	 * @param $fileId
312
-	 * @param $filePath
313
-	 */
314
-	protected function publishActivity($subject, $parameters, $affectedUser, $fileId, $filePath) {
315
-		$event = $this->activityManager->generateEvent();
316
-		$event->setApp('sharebymail')
317
-			->setType('shared')
318
-			->setSubject($subject, $parameters)
319
-			->setAffectedUser($affectedUser)
320
-			->setObject('files', $fileId, $filePath);
321
-		$this->activityManager->publish($event);
322
-
323
-	}
324
-
325
-	/**
326
-	 * @param IShare $share
327
-	 * @return int
328
-	 * @throws \Exception
329
-	 */
330
-	protected function createMailShare(IShare $share) {
331
-		$share->setToken($this->generateToken());
332
-		$shareId = $this->addShareToDB(
333
-			$share->getNodeId(),
334
-			$share->getNodeType(),
335
-			$share->getSharedWith(),
336
-			$share->getSharedBy(),
337
-			$share->getShareOwner(),
338
-			$share->getPermissions(),
339
-			$share->getToken(),
340
-			$share->getPassword()
341
-		);
342
-
343
-		try {
344
-			$link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
345
-				['token' => $share->getToken()]);
346
-			$this->sendMailNotification(
347
-				$share->getNode()->getName(),
348
-				$link,
349
-				$share->getSharedBy(),
350
-				$share->getSharedWith()
351
-			);
352
-		} catch (HintException $hintException) {
353
-			$this->logger->error('Failed to send share by mail: ' . $hintException->getMessage());
354
-			$this->removeShareFromTable($shareId);
355
-			throw $hintException;
356
-		} catch (\Exception $e) {
357
-			$this->logger->error('Failed to send share by email: ' . $e->getMessage());
358
-			$this->removeShareFromTable($shareId);
359
-			throw new HintException('Failed to send share by mail',
360
-				$this->l->t('Failed to send share by email'));
361
-		}
362
-
363
-		return $shareId;
364
-
365
-	}
366
-
367
-	/**
368
-	 * @param string $filename
369
-	 * @param string $link
370
-	 * @param string $initiator
371
-	 * @param string $shareWith
372
-	 * @throws \Exception If mail couldn't be sent
373
-	 */
374
-	protected function sendMailNotification($filename,
375
-											$link,
376
-											$initiator,
377
-											$shareWith) {
378
-		$initiatorUser = $this->userManager->get($initiator);
379
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
380
-		$subject = (string)$this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename));
381
-
382
-		$message = $this->mailer->createMessage();
383
-
384
-		$emailTemplate = $this->mailer->createEMailTemplate();
385
-
386
-		$emailTemplate->addHeader();
387
-		$emailTemplate->addHeading($this->l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false);
388
-		$text = $this->l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
389
-
390
-		$emailTemplate->addBodyText(
391
-			$text . ' ' . $this->l->t('Click the button below to open it.'),
392
-			$text
393
-		);
394
-		$emailTemplate->addBodyButton(
395
-			$this->l->t('Open »%s«', [$filename]),
396
-			$link
397
-		);
398
-
399
-		$message->setTo([$shareWith]);
400
-
401
-		// The "From" contains the sharers name
402
-		$instanceName = $this->defaults->getName();
403
-		$senderName = $this->l->t(
404
-			'%s via %s',
405
-			[
406
-				$initiatorDisplayName,
407
-				$instanceName
408
-			]
409
-		);
410
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
411
-
412
-		// The "Reply-To" is set to the sharer if an mail address is configured
413
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
414
-		$initiatorEmail = $initiatorUser->getEMailAddress();
415
-		if($initiatorEmail !== null) {
416
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
417
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
418
-		} else {
419
-			$emailTemplate->addFooter();
420
-		}
421
-
422
-		$message->setSubject($subject);
423
-		$message->setPlainBody($emailTemplate->renderText());
424
-		$message->setHtmlBody($emailTemplate->renderHtml());
425
-		$this->mailer->send($message);
426
-	}
427
-
428
-	/**
429
-	 * send password to recipient of a mail share
430
-	 *
431
-	 * @param IShare $share
432
-	 * @param string $password
433
-	 * @return bool
434
-	 */
435
-	protected function sendPassword(IShare $share, $password) {
436
-
437
-		$filename = $share->getNode()->getName();
438
-		$initiator = $share->getSharedBy();
439
-		$shareWith = $share->getSharedWith();
440
-
441
-		if ($password === '' || $this->settingsManager->sendPasswordByMail() === false) {
442
-			return false;
443
-		}
444
-
445
-		$initiatorUser = $this->userManager->get($initiator);
446
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
447
-		$initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
448
-
449
-		$subject = (string)$this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]);
450
-		$plainBodyPart = $this->l->t("%s shared »%s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]);
451
-		$htmlBodyPart = $this->l->t('%s shared »%s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]);
452
-
453
-		$message = $this->mailer->createMessage();
454
-
455
-		$emailTemplate = $this->mailer->createEMailTemplate();
456
-		$emailTemplate->addHeader();
457
-		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
458
-		$emailTemplate->addBodyText($htmlBodyPart, $plainBodyPart);
459
-		$emailTemplate->addBodyText($this->l->t('It is protected with the following password: %s', [$password]));
460
-
461
-		// The "From" contains the sharers name
462
-		$instanceName = $this->defaults->getName();
463
-		$senderName = $this->l->t(
464
-			'%s via %s',
465
-			[
466
-				$initiatorDisplayName,
467
-				$instanceName
468
-			]
469
-		);
470
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
471
-		if ($initiatorEmailAddress !== null) {
472
-			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
473
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
474
-		} else {
475
-			$emailTemplate->addFooter();
476
-		}
477
-
478
-		$message->setTo([$shareWith]);
479
-		$message->setSubject($subject);
480
-		$message->setBody($emailTemplate->renderText(), 'text/plain');
481
-		$message->setHtmlBody($emailTemplate->renderHtml());
482
-		$this->mailer->send($message);
483
-
484
-		$this->createPasswordSendActivity($share, $shareWith, false);
485
-
486
-		return true;
487
-	}
488
-
489
-	/**
490
-	 * send auto generated password to the owner. This happens if the admin enforces
491
-	 * a password for mail shares and forbid to send the password by mail to the recipient
492
-	 *
493
-	 * @param IShare $share
494
-	 * @param string $password
495
-	 * @return bool
496
-	 * @throws \Exception
497
-	 */
498
-	protected function sendPasswordToOwner(IShare $share, $password) {
499
-
500
-		$filename = $share->getNode()->getName();
501
-		$initiator = $this->userManager->get($share->getSharedBy());
502
-		$initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
503
-		$initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
504
-		$shareWith = $share->getSharedWith();
505
-
506
-		if ($initiatorEMailAddress === null) {
507
-			throw new \Exception(
508
-				$this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
509
-			);
510
-		}
511
-
512
-		$subject = (string)$this->l->t('Password to access »%s« shared with %s', [$filename, $shareWith]);
513
-		$bodyPart = $this->l->t("You just shared »%s« with %s. The share was already send to the recipient. Due to the security policies defined by the administrator of %s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.", [$filename, $shareWith, $this->defaults->getName()]);
514
-
515
-		$message = $this->mailer->createMessage();
516
-		$emailTemplate = $this->mailer->createEMailTemplate();
517
-
518
-		$emailTemplate->addHeader();
519
-		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
520
-		$emailTemplate->addBodyText($bodyPart);
521
-		$emailTemplate->addBodyText($this->l->t('This is the password: %s', [$password]));
522
-		$emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
523
-		$emailTemplate->addFooter();
524
-
525
-		if ($initiatorEMailAddress) {
526
-			$message->setFrom([$initiatorEMailAddress => $initiatorDisplayName]);
527
-		}
528
-		$message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
529
-		$message->setSubject($subject);
530
-		$message->setBody($emailTemplate->renderText(), 'text/plain');
531
-		$message->setHtmlBody($emailTemplate->renderHtml());
532
-		$this->mailer->send($message);
533
-
534
-		$this->createPasswordSendActivity($share, $shareWith, true);
535
-
536
-		return true;
537
-	}
538
-
539
-	/**
540
-	 * generate share token
541
-	 *
542
-	 * @return string
543
-	 */
544
-	protected function generateToken($size = 15) {
545
-		$token = $this->secureRandom->generate(
546
-			$size, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
547
-		return $token;
548
-	}
549
-
550
-	/**
551
-	 * Get all children of this share
552
-	 *
553
-	 * @param IShare $parent
554
-	 * @return IShare[]
555
-	 */
556
-	public function getChildren(IShare $parent) {
557
-		$children = [];
558
-
559
-		$qb = $this->dbConnection->getQueryBuilder();
560
-		$qb->select('*')
561
-			->from('share')
562
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
563
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
564
-			->orderBy('id');
565
-
566
-		$cursor = $qb->execute();
567
-		while($data = $cursor->fetch()) {
568
-			$children[] = $this->createShareObject($data);
569
-		}
570
-		$cursor->closeCursor();
571
-
572
-		return $children;
573
-	}
574
-
575
-	/**
576
-	 * add share to the database and return the ID
577
-	 *
578
-	 * @param int $itemSource
579
-	 * @param string $itemType
580
-	 * @param string $shareWith
581
-	 * @param string $sharedBy
582
-	 * @param string $uidOwner
583
-	 * @param int $permissions
584
-	 * @param string $token
585
-	 * @return int
586
-	 */
587
-	protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password) {
588
-		$qb = $this->dbConnection->getQueryBuilder();
589
-		$qb->insert('share')
590
-			->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
591
-			->setValue('item_type', $qb->createNamedParameter($itemType))
592
-			->setValue('item_source', $qb->createNamedParameter($itemSource))
593
-			->setValue('file_source', $qb->createNamedParameter($itemSource))
594
-			->setValue('share_with', $qb->createNamedParameter($shareWith))
595
-			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
596
-			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
597
-			->setValue('permissions', $qb->createNamedParameter($permissions))
598
-			->setValue('token', $qb->createNamedParameter($token))
599
-			->setValue('password', $qb->createNamedParameter($password))
600
-			->setValue('stime', $qb->createNamedParameter(time()));
601
-
602
-		/*
165
+        $alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_EMAIL, $share->getNode(), 1, 0);
166
+        if (!empty($alreadyShared)) {
167
+            $message = 'Sharing %s failed, this item is already shared with %s';
168
+            $message_t = $this->l->t('Sharing %s failed, this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
169
+            $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
170
+            throw new \Exception($message_t);
171
+        }
172
+
173
+        // if the admin enforces a password for all mail shares we create a
174
+        // random password and send it to the recipient
175
+        $password = '';
176
+        $passwordEnforced = $this->settingsManager->enforcePasswordProtection();
177
+        if ($passwordEnforced) {
178
+            $password = $this->autoGeneratePassword($share);
179
+        }
180
+
181
+        $shareId = $this->createMailShare($share);
182
+        $send = $this->sendPassword($share, $password);
183
+        if ($passwordEnforced && $send === false) {
184
+            $this->sendPasswordToOwner($share, $password);
185
+        }
186
+
187
+        $this->createShareActivity($share);
188
+        $data = $this->getRawShare($shareId);
189
+
190
+        return $this->createShareObject($data);
191
+
192
+    }
193
+
194
+    /**
195
+     * auto generate password in case of password enforcement on mail shares
196
+     *
197
+     * @param IShare $share
198
+     * @return string
199
+     * @throws \Exception
200
+     */
201
+    protected function autoGeneratePassword($share) {
202
+        $initiatorUser = $this->userManager->get($share->getSharedBy());
203
+        $initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
204
+        $allowPasswordByMail = $this->settingsManager->sendPasswordByMail();
205
+
206
+        if ($initiatorEMailAddress === null && !$allowPasswordByMail) {
207
+            throw new \Exception(
208
+                $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
209
+            );
210
+        }
211
+
212
+        $passwordPolicy = $this->getPasswordPolicy();
213
+        $passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS;
214
+        $passwordLength = 8;
215
+        if (!empty($passwordPolicy)) {
216
+            $passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength;
217
+            $passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : '';
218
+        }
219
+
220
+        $password = $this->secureRandom->generate($passwordLength, $passwordCharset);
221
+
222
+        $share->setPassword($this->hasher->hash($password));
223
+
224
+        return $password;
225
+    }
226
+
227
+    /**
228
+     * get password policy
229
+     *
230
+     * @return array
231
+     */
232
+    protected function getPasswordPolicy() {
233
+        $capabilities = $this->capabilitiesManager->getCapabilities();
234
+        if (isset($capabilities['password_policy'])) {
235
+            return $capabilities['password_policy'];
236
+        }
237
+
238
+        return [];
239
+    }
240
+
241
+    /**
242
+     * create activity if a file/folder was shared by mail
243
+     *
244
+     * @param IShare $share
245
+     */
246
+    protected function createShareActivity(IShare $share) {
247
+
248
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
249
+
250
+        $this->publishActivity(
251
+            Activity::SUBJECT_SHARED_EMAIL_SELF,
252
+            [$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()],
253
+            $share->getSharedBy(),
254
+            $share->getNode()->getId(),
255
+            $userFolder->getRelativePath($share->getNode()->getPath())
256
+        );
257
+
258
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
259
+            $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
260
+            $fileId = $share->getNode()->getId();
261
+            $nodes = $ownerFolder->getById($fileId);
262
+            $ownerPath = $nodes[0]->getPath();
263
+            $this->publishActivity(
264
+                Activity::SUBJECT_SHARED_EMAIL_BY,
265
+                [$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()],
266
+                $share->getShareOwner(),
267
+                $fileId,
268
+                $ownerFolder->getRelativePath($ownerPath)
269
+            );
270
+        }
271
+
272
+    }
273
+
274
+    /**
275
+     * create activity if a file/folder was shared by mail
276
+     *
277
+     * @param IShare $share
278
+     * @param string $sharedWith
279
+     * @param bool $sendToSelf
280
+     */
281
+    protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) {
282
+
283
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
284
+
285
+        if ($sendToSelf) {
286
+            $this->publishActivity(
287
+                Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF,
288
+                [$userFolder->getRelativePath($share->getNode()->getPath())],
289
+                $share->getSharedBy(),
290
+                $share->getNode()->getId(),
291
+                $userFolder->getRelativePath($share->getNode()->getPath())
292
+            );
293
+        } else {
294
+            $this->publishActivity(
295
+                Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND,
296
+                [$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith],
297
+                $share->getSharedBy(),
298
+                $share->getNode()->getId(),
299
+                $userFolder->getRelativePath($share->getNode()->getPath())
300
+            );
301
+        }
302
+    }
303
+
304
+
305
+    /**
306
+     * publish activity if a file/folder was shared by mail
307
+     *
308
+     * @param $subject
309
+     * @param $parameters
310
+     * @param $affectedUser
311
+     * @param $fileId
312
+     * @param $filePath
313
+     */
314
+    protected function publishActivity($subject, $parameters, $affectedUser, $fileId, $filePath) {
315
+        $event = $this->activityManager->generateEvent();
316
+        $event->setApp('sharebymail')
317
+            ->setType('shared')
318
+            ->setSubject($subject, $parameters)
319
+            ->setAffectedUser($affectedUser)
320
+            ->setObject('files', $fileId, $filePath);
321
+        $this->activityManager->publish($event);
322
+
323
+    }
324
+
325
+    /**
326
+     * @param IShare $share
327
+     * @return int
328
+     * @throws \Exception
329
+     */
330
+    protected function createMailShare(IShare $share) {
331
+        $share->setToken($this->generateToken());
332
+        $shareId = $this->addShareToDB(
333
+            $share->getNodeId(),
334
+            $share->getNodeType(),
335
+            $share->getSharedWith(),
336
+            $share->getSharedBy(),
337
+            $share->getShareOwner(),
338
+            $share->getPermissions(),
339
+            $share->getToken(),
340
+            $share->getPassword()
341
+        );
342
+
343
+        try {
344
+            $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
345
+                ['token' => $share->getToken()]);
346
+            $this->sendMailNotification(
347
+                $share->getNode()->getName(),
348
+                $link,
349
+                $share->getSharedBy(),
350
+                $share->getSharedWith()
351
+            );
352
+        } catch (HintException $hintException) {
353
+            $this->logger->error('Failed to send share by mail: ' . $hintException->getMessage());
354
+            $this->removeShareFromTable($shareId);
355
+            throw $hintException;
356
+        } catch (\Exception $e) {
357
+            $this->logger->error('Failed to send share by email: ' . $e->getMessage());
358
+            $this->removeShareFromTable($shareId);
359
+            throw new HintException('Failed to send share by mail',
360
+                $this->l->t('Failed to send share by email'));
361
+        }
362
+
363
+        return $shareId;
364
+
365
+    }
366
+
367
+    /**
368
+     * @param string $filename
369
+     * @param string $link
370
+     * @param string $initiator
371
+     * @param string $shareWith
372
+     * @throws \Exception If mail couldn't be sent
373
+     */
374
+    protected function sendMailNotification($filename,
375
+                                            $link,
376
+                                            $initiator,
377
+                                            $shareWith) {
378
+        $initiatorUser = $this->userManager->get($initiator);
379
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
380
+        $subject = (string)$this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename));
381
+
382
+        $message = $this->mailer->createMessage();
383
+
384
+        $emailTemplate = $this->mailer->createEMailTemplate();
385
+
386
+        $emailTemplate->addHeader();
387
+        $emailTemplate->addHeading($this->l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false);
388
+        $text = $this->l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
389
+
390
+        $emailTemplate->addBodyText(
391
+            $text . ' ' . $this->l->t('Click the button below to open it.'),
392
+            $text
393
+        );
394
+        $emailTemplate->addBodyButton(
395
+            $this->l->t('Open »%s«', [$filename]),
396
+            $link
397
+        );
398
+
399
+        $message->setTo([$shareWith]);
400
+
401
+        // The "From" contains the sharers name
402
+        $instanceName = $this->defaults->getName();
403
+        $senderName = $this->l->t(
404
+            '%s via %s',
405
+            [
406
+                $initiatorDisplayName,
407
+                $instanceName
408
+            ]
409
+        );
410
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
411
+
412
+        // The "Reply-To" is set to the sharer if an mail address is configured
413
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
414
+        $initiatorEmail = $initiatorUser->getEMailAddress();
415
+        if($initiatorEmail !== null) {
416
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
417
+            $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
418
+        } else {
419
+            $emailTemplate->addFooter();
420
+        }
421
+
422
+        $message->setSubject($subject);
423
+        $message->setPlainBody($emailTemplate->renderText());
424
+        $message->setHtmlBody($emailTemplate->renderHtml());
425
+        $this->mailer->send($message);
426
+    }
427
+
428
+    /**
429
+     * send password to recipient of a mail share
430
+     *
431
+     * @param IShare $share
432
+     * @param string $password
433
+     * @return bool
434
+     */
435
+    protected function sendPassword(IShare $share, $password) {
436
+
437
+        $filename = $share->getNode()->getName();
438
+        $initiator = $share->getSharedBy();
439
+        $shareWith = $share->getSharedWith();
440
+
441
+        if ($password === '' || $this->settingsManager->sendPasswordByMail() === false) {
442
+            return false;
443
+        }
444
+
445
+        $initiatorUser = $this->userManager->get($initiator);
446
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
447
+        $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
448
+
449
+        $subject = (string)$this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]);
450
+        $plainBodyPart = $this->l->t("%s shared »%s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]);
451
+        $htmlBodyPart = $this->l->t('%s shared »%s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]);
452
+
453
+        $message = $this->mailer->createMessage();
454
+
455
+        $emailTemplate = $this->mailer->createEMailTemplate();
456
+        $emailTemplate->addHeader();
457
+        $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
458
+        $emailTemplate->addBodyText($htmlBodyPart, $plainBodyPart);
459
+        $emailTemplate->addBodyText($this->l->t('It is protected with the following password: %s', [$password]));
460
+
461
+        // The "From" contains the sharers name
462
+        $instanceName = $this->defaults->getName();
463
+        $senderName = $this->l->t(
464
+            '%s via %s',
465
+            [
466
+                $initiatorDisplayName,
467
+                $instanceName
468
+            ]
469
+        );
470
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
471
+        if ($initiatorEmailAddress !== null) {
472
+            $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
473
+            $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
474
+        } else {
475
+            $emailTemplate->addFooter();
476
+        }
477
+
478
+        $message->setTo([$shareWith]);
479
+        $message->setSubject($subject);
480
+        $message->setBody($emailTemplate->renderText(), 'text/plain');
481
+        $message->setHtmlBody($emailTemplate->renderHtml());
482
+        $this->mailer->send($message);
483
+
484
+        $this->createPasswordSendActivity($share, $shareWith, false);
485
+
486
+        return true;
487
+    }
488
+
489
+    /**
490
+     * send auto generated password to the owner. This happens if the admin enforces
491
+     * a password for mail shares and forbid to send the password by mail to the recipient
492
+     *
493
+     * @param IShare $share
494
+     * @param string $password
495
+     * @return bool
496
+     * @throws \Exception
497
+     */
498
+    protected function sendPasswordToOwner(IShare $share, $password) {
499
+
500
+        $filename = $share->getNode()->getName();
501
+        $initiator = $this->userManager->get($share->getSharedBy());
502
+        $initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
503
+        $initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
504
+        $shareWith = $share->getSharedWith();
505
+
506
+        if ($initiatorEMailAddress === null) {
507
+            throw new \Exception(
508
+                $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
509
+            );
510
+        }
511
+
512
+        $subject = (string)$this->l->t('Password to access »%s« shared with %s', [$filename, $shareWith]);
513
+        $bodyPart = $this->l->t("You just shared »%s« with %s. The share was already send to the recipient. Due to the security policies defined by the administrator of %s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.", [$filename, $shareWith, $this->defaults->getName()]);
514
+
515
+        $message = $this->mailer->createMessage();
516
+        $emailTemplate = $this->mailer->createEMailTemplate();
517
+
518
+        $emailTemplate->addHeader();
519
+        $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
520
+        $emailTemplate->addBodyText($bodyPart);
521
+        $emailTemplate->addBodyText($this->l->t('This is the password: %s', [$password]));
522
+        $emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
523
+        $emailTemplate->addFooter();
524
+
525
+        if ($initiatorEMailAddress) {
526
+            $message->setFrom([$initiatorEMailAddress => $initiatorDisplayName]);
527
+        }
528
+        $message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
529
+        $message->setSubject($subject);
530
+        $message->setBody($emailTemplate->renderText(), 'text/plain');
531
+        $message->setHtmlBody($emailTemplate->renderHtml());
532
+        $this->mailer->send($message);
533
+
534
+        $this->createPasswordSendActivity($share, $shareWith, true);
535
+
536
+        return true;
537
+    }
538
+
539
+    /**
540
+     * generate share token
541
+     *
542
+     * @return string
543
+     */
544
+    protected function generateToken($size = 15) {
545
+        $token = $this->secureRandom->generate(
546
+            $size, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
547
+        return $token;
548
+    }
549
+
550
+    /**
551
+     * Get all children of this share
552
+     *
553
+     * @param IShare $parent
554
+     * @return IShare[]
555
+     */
556
+    public function getChildren(IShare $parent) {
557
+        $children = [];
558
+
559
+        $qb = $this->dbConnection->getQueryBuilder();
560
+        $qb->select('*')
561
+            ->from('share')
562
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
563
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
564
+            ->orderBy('id');
565
+
566
+        $cursor = $qb->execute();
567
+        while($data = $cursor->fetch()) {
568
+            $children[] = $this->createShareObject($data);
569
+        }
570
+        $cursor->closeCursor();
571
+
572
+        return $children;
573
+    }
574
+
575
+    /**
576
+     * add share to the database and return the ID
577
+     *
578
+     * @param int $itemSource
579
+     * @param string $itemType
580
+     * @param string $shareWith
581
+     * @param string $sharedBy
582
+     * @param string $uidOwner
583
+     * @param int $permissions
584
+     * @param string $token
585
+     * @return int
586
+     */
587
+    protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password) {
588
+        $qb = $this->dbConnection->getQueryBuilder();
589
+        $qb->insert('share')
590
+            ->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
591
+            ->setValue('item_type', $qb->createNamedParameter($itemType))
592
+            ->setValue('item_source', $qb->createNamedParameter($itemSource))
593
+            ->setValue('file_source', $qb->createNamedParameter($itemSource))
594
+            ->setValue('share_with', $qb->createNamedParameter($shareWith))
595
+            ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
596
+            ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
597
+            ->setValue('permissions', $qb->createNamedParameter($permissions))
598
+            ->setValue('token', $qb->createNamedParameter($token))
599
+            ->setValue('password', $qb->createNamedParameter($password))
600
+            ->setValue('stime', $qb->createNamedParameter(time()));
601
+
602
+        /*
603 603
 		 * Added to fix https://github.com/owncloud/core/issues/22215
604 604
 		 * Can be removed once we get rid of ajax/share.php
605 605
 		 */
606
-		$qb->setValue('file_target', $qb->createNamedParameter(''));
606
+        $qb->setValue('file_target', $qb->createNamedParameter(''));
607 607
 
608
-		$qb->execute();
609
-		$id = $qb->getLastInsertId();
608
+        $qb->execute();
609
+        $id = $qb->getLastInsertId();
610 610
 
611
-		return (int)$id;
612
-	}
611
+        return (int)$id;
612
+    }
613 613
 
614
-	/**
615
-	 * Update a share
616
-	 *
617
-	 * @param IShare $share
618
-	 * @param string|null $plainTextPassword
619
-	 * @return IShare The share object
620
-	 */
621
-	public function update(IShare $share, $plainTextPassword = null) {
614
+    /**
615
+     * Update a share
616
+     *
617
+     * @param IShare $share
618
+     * @param string|null $plainTextPassword
619
+     * @return IShare The share object
620
+     */
621
+    public function update(IShare $share, $plainTextPassword = null) {
622 622
 
623
-		$originalShare = $this->getShareById($share->getId());
623
+        $originalShare = $this->getShareById($share->getId());
624 624
 
625
-		// a real password was given
626
-		$validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
625
+        // a real password was given
626
+        $validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
627 627
 
628
-		if($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
629
-			$this->sendPassword($share, $plainTextPassword);
630
-		}
631
-		/*
628
+        if($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
629
+            $this->sendPassword($share, $plainTextPassword);
630
+        }
631
+        /*
632 632
 		 * We allow updating the permissions and password of mail shares
633 633
 		 */
634
-		$qb = $this->dbConnection->getQueryBuilder();
635
-		$qb->update('share')
636
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
637
-			->set('permissions', $qb->createNamedParameter($share->getPermissions()))
638
-			->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
639
-			->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
640
-			->set('password', $qb->createNamedParameter($share->getPassword()))
641
-			->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
642
-			->execute();
643
-
644
-		return $share;
645
-	}
646
-
647
-	/**
648
-	 * @inheritdoc
649
-	 */
650
-	public function move(IShare $share, $recipient) {
651
-		/**
652
-		 * nothing to do here, mail shares are only outgoing shares
653
-		 */
654
-		return $share;
655
-	}
656
-
657
-	/**
658
-	 * Delete a share (owner unShares the file)
659
-	 *
660
-	 * @param IShare $share
661
-	 */
662
-	public function delete(IShare $share) {
663
-		$this->removeShareFromTable($share->getId());
664
-	}
665
-
666
-	/**
667
-	 * @inheritdoc
668
-	 */
669
-	public function deleteFromSelf(IShare $share, $recipient) {
670
-		// nothing to do here, mail shares are only outgoing shares
671
-		return;
672
-	}
673
-
674
-	/**
675
-	 * @inheritdoc
676
-	 */
677
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
678
-		$qb = $this->dbConnection->getQueryBuilder();
679
-		$qb->select('*')
680
-			->from('share');
681
-
682
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
683
-
684
-		/**
685
-		 * Reshares for this user are shares where they are the owner.
686
-		 */
687
-		if ($reshares === false) {
688
-			//Special case for old shares created via the web UI
689
-			$or1 = $qb->expr()->andX(
690
-				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
691
-				$qb->expr()->isNull('uid_initiator')
692
-			);
693
-
694
-			$qb->andWhere(
695
-				$qb->expr()->orX(
696
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
697
-					$or1
698
-				)
699
-			);
700
-		} else {
701
-			$qb->andWhere(
702
-				$qb->expr()->orX(
703
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
704
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
705
-				)
706
-			);
707
-		}
708
-
709
-		if ($node !== null) {
710
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
711
-		}
712
-
713
-		if ($limit !== -1) {
714
-			$qb->setMaxResults($limit);
715
-		}
716
-
717
-		$qb->setFirstResult($offset);
718
-		$qb->orderBy('id');
719
-
720
-		$cursor = $qb->execute();
721
-		$shares = [];
722
-		while($data = $cursor->fetch()) {
723
-			$shares[] = $this->createShareObject($data);
724
-		}
725
-		$cursor->closeCursor();
726
-
727
-		return $shares;
728
-	}
729
-
730
-	/**
731
-	 * @inheritdoc
732
-	 */
733
-	public function getShareById($id, $recipientId = null) {
734
-		$qb = $this->dbConnection->getQueryBuilder();
735
-
736
-		$qb->select('*')
737
-			->from('share')
738
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
739
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
740
-
741
-		$cursor = $qb->execute();
742
-		$data = $cursor->fetch();
743
-		$cursor->closeCursor();
744
-
745
-		if ($data === false) {
746
-			throw new ShareNotFound();
747
-		}
748
-
749
-		try {
750
-			$share = $this->createShareObject($data);
751
-		} catch (InvalidShare $e) {
752
-			throw new ShareNotFound();
753
-		}
754
-
755
-		return $share;
756
-	}
757
-
758
-	/**
759
-	 * Get shares for a given path
760
-	 *
761
-	 * @param \OCP\Files\Node $path
762
-	 * @return IShare[]
763
-	 */
764
-	public function getSharesByPath(Node $path) {
765
-		$qb = $this->dbConnection->getQueryBuilder();
766
-
767
-		$cursor = $qb->select('*')
768
-			->from('share')
769
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
770
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
771
-			->execute();
772
-
773
-		$shares = [];
774
-		while($data = $cursor->fetch()) {
775
-			$shares[] = $this->createShareObject($data);
776
-		}
777
-		$cursor->closeCursor();
778
-
779
-		return $shares;
780
-	}
781
-
782
-	/**
783
-	 * @inheritdoc
784
-	 */
785
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
786
-		/** @var IShare[] $shares */
787
-		$shares = [];
788
-
789
-		//Get shares directly with this user
790
-		$qb = $this->dbConnection->getQueryBuilder();
791
-		$qb->select('*')
792
-			->from('share');
793
-
794
-		// Order by id
795
-		$qb->orderBy('id');
796
-
797
-		// Set limit and offset
798
-		if ($limit !== -1) {
799
-			$qb->setMaxResults($limit);
800
-		}
801
-		$qb->setFirstResult($offset);
802
-
803
-		$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
804
-		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
805
-
806
-		// Filter by node if provided
807
-		if ($node !== null) {
808
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
809
-		}
810
-
811
-		$cursor = $qb->execute();
812
-
813
-		while($data = $cursor->fetch()) {
814
-			$shares[] = $this->createShareObject($data);
815
-		}
816
-		$cursor->closeCursor();
817
-
818
-
819
-		return $shares;
820
-	}
821
-
822
-	/**
823
-	 * Get a share by token
824
-	 *
825
-	 * @param string $token
826
-	 * @return IShare
827
-	 * @throws ShareNotFound
828
-	 */
829
-	public function getShareByToken($token) {
830
-		$qb = $this->dbConnection->getQueryBuilder();
831
-
832
-		$cursor = $qb->select('*')
833
-			->from('share')
834
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
835
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
836
-			->execute();
837
-
838
-		$data = $cursor->fetch();
839
-
840
-		if ($data === false) {
841
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
842
-		}
843
-
844
-		try {
845
-			$share = $this->createShareObject($data);
846
-		} catch (InvalidShare $e) {
847
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
848
-		}
849
-
850
-		return $share;
851
-	}
852
-
853
-	/**
854
-	 * remove share from table
855
-	 *
856
-	 * @param string $shareId
857
-	 */
858
-	protected function removeShareFromTable($shareId) {
859
-		$qb = $this->dbConnection->getQueryBuilder();
860
-		$qb->delete('share')
861
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
862
-		$qb->execute();
863
-	}
864
-
865
-	/**
866
-	 * Create a share object from an database row
867
-	 *
868
-	 * @param array $data
869
-	 * @return IShare
870
-	 * @throws InvalidShare
871
-	 * @throws ShareNotFound
872
-	 */
873
-	protected function createShareObject($data) {
874
-
875
-		$share = new Share($this->rootFolder, $this->userManager);
876
-		$share->setId((int)$data['id'])
877
-			->setShareType((int)$data['share_type'])
878
-			->setPermissions((int)$data['permissions'])
879
-			->setTarget($data['file_target'])
880
-			->setMailSend((bool)$data['mail_send'])
881
-			->setToken($data['token']);
882
-
883
-		$shareTime = new \DateTime();
884
-		$shareTime->setTimestamp((int)$data['stime']);
885
-		$share->setShareTime($shareTime);
886
-		$share->setSharedWith($data['share_with']);
887
-		$share->setPassword($data['password']);
888
-
889
-		if ($data['uid_initiator'] !== null) {
890
-			$share->setShareOwner($data['uid_owner']);
891
-			$share->setSharedBy($data['uid_initiator']);
892
-		} else {
893
-			//OLD SHARE
894
-			$share->setSharedBy($data['uid_owner']);
895
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
896
-
897
-			$owner = $path->getOwner();
898
-			$share->setShareOwner($owner->getUID());
899
-		}
900
-
901
-		if ($data['expiration'] !== null) {
902
-			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
903
-			if ($expiration !== false) {
904
-				$share->setExpirationDate($expiration);
905
-			}
906
-		}
907
-
908
-		$share->setNodeId((int)$data['file_source']);
909
-		$share->setNodeType($data['item_type']);
910
-
911
-		$share->setProviderId($this->identifier());
912
-
913
-		return $share;
914
-	}
915
-
916
-	/**
917
-	 * Get the node with file $id for $user
918
-	 *
919
-	 * @param string $userId
920
-	 * @param int $id
921
-	 * @return \OCP\Files\File|\OCP\Files\Folder
922
-	 * @throws InvalidShare
923
-	 */
924
-	private function getNode($userId, $id) {
925
-		try {
926
-			$userFolder = $this->rootFolder->getUserFolder($userId);
927
-		} catch (NoUserException $e) {
928
-			throw new InvalidShare();
929
-		}
930
-
931
-		$nodes = $userFolder->getById($id);
932
-
933
-		if (empty($nodes)) {
934
-			throw new InvalidShare();
935
-		}
936
-
937
-		return $nodes[0];
938
-	}
939
-
940
-	/**
941
-	 * A user is deleted from the system
942
-	 * So clean up the relevant shares.
943
-	 *
944
-	 * @param string $uid
945
-	 * @param int $shareType
946
-	 */
947
-	public function userDeleted($uid, $shareType) {
948
-		$qb = $this->dbConnection->getQueryBuilder();
949
-
950
-		$qb->delete('share')
951
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
952
-			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
953
-			->execute();
954
-	}
955
-
956
-	/**
957
-	 * This provider does not support group shares
958
-	 *
959
-	 * @param string $gid
960
-	 */
961
-	public function groupDeleted($gid) {
962
-		return;
963
-	}
964
-
965
-	/**
966
-	 * This provider does not support group shares
967
-	 *
968
-	 * @param string $uid
969
-	 * @param string $gid
970
-	 */
971
-	public function userDeletedFromGroup($uid, $gid) {
972
-		return;
973
-	}
974
-
975
-	/**
976
-	 * get database row of a give share
977
-	 *
978
-	 * @param $id
979
-	 * @return array
980
-	 * @throws ShareNotFound
981
-	 */
982
-	protected function getRawShare($id) {
983
-
984
-		// Now fetch the inserted share and create a complete share object
985
-		$qb = $this->dbConnection->getQueryBuilder();
986
-		$qb->select('*')
987
-			->from('share')
988
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
989
-
990
-		$cursor = $qb->execute();
991
-		$data = $cursor->fetch();
992
-		$cursor->closeCursor();
993
-
994
-		if ($data === false) {
995
-			throw new ShareNotFound;
996
-		}
997
-
998
-		return $data;
999
-	}
1000
-
1001
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
1002
-		$qb = $this->dbConnection->getQueryBuilder();
1003
-		$qb->select('*')
1004
-			->from('share', 's')
1005
-			->andWhere($qb->expr()->orX(
1006
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1007
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1008
-			))
1009
-			->andWhere(
1010
-				$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
1011
-			);
1012
-
1013
-		/**
1014
-		 * Reshares for this user are shares where they are the owner.
1015
-		 */
1016
-		if ($reshares === false) {
1017
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
1018
-		} else {
1019
-			$qb->andWhere(
1020
-				$qb->expr()->orX(
1021
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
1022
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
1023
-				)
1024
-			);
1025
-		}
1026
-
1027
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1028
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1029
-
1030
-		$qb->orderBy('id');
1031
-
1032
-		$cursor = $qb->execute();
1033
-		$shares = [];
1034
-		while ($data = $cursor->fetch()) {
1035
-			$shares[$data['fileid']][] = $this->createShareObject($data);
1036
-		}
1037
-		$cursor->closeCursor();
1038
-
1039
-		return $shares;
1040
-	}
1041
-
1042
-	/**
1043
-	 * @inheritdoc
1044
-	 */
1045
-	public function getAccessList($nodes, $currentAccess) {
1046
-		$ids = [];
1047
-		foreach ($nodes as $node) {
1048
-			$ids[] = $node->getId();
1049
-		}
1050
-
1051
-		$qb = $this->dbConnection->getQueryBuilder();
1052
-		$qb->select('share_with')
1053
-			->from('share')
1054
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
1055
-			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1056
-			->andWhere($qb->expr()->orX(
1057
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1058
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1059
-			))
1060
-			->setMaxResults(1);
1061
-		$cursor = $qb->execute();
1062
-
1063
-		$mail = $cursor->fetch() !== false;
1064
-		$cursor->closeCursor();
1065
-
1066
-		return ['public' => $mail];
1067
-	}
634
+        $qb = $this->dbConnection->getQueryBuilder();
635
+        $qb->update('share')
636
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
637
+            ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
638
+            ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
639
+            ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
640
+            ->set('password', $qb->createNamedParameter($share->getPassword()))
641
+            ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
642
+            ->execute();
643
+
644
+        return $share;
645
+    }
646
+
647
+    /**
648
+     * @inheritdoc
649
+     */
650
+    public function move(IShare $share, $recipient) {
651
+        /**
652
+         * nothing to do here, mail shares are only outgoing shares
653
+         */
654
+        return $share;
655
+    }
656
+
657
+    /**
658
+     * Delete a share (owner unShares the file)
659
+     *
660
+     * @param IShare $share
661
+     */
662
+    public function delete(IShare $share) {
663
+        $this->removeShareFromTable($share->getId());
664
+    }
665
+
666
+    /**
667
+     * @inheritdoc
668
+     */
669
+    public function deleteFromSelf(IShare $share, $recipient) {
670
+        // nothing to do here, mail shares are only outgoing shares
671
+        return;
672
+    }
673
+
674
+    /**
675
+     * @inheritdoc
676
+     */
677
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
678
+        $qb = $this->dbConnection->getQueryBuilder();
679
+        $qb->select('*')
680
+            ->from('share');
681
+
682
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
683
+
684
+        /**
685
+         * Reshares for this user are shares where they are the owner.
686
+         */
687
+        if ($reshares === false) {
688
+            //Special case for old shares created via the web UI
689
+            $or1 = $qb->expr()->andX(
690
+                $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
691
+                $qb->expr()->isNull('uid_initiator')
692
+            );
693
+
694
+            $qb->andWhere(
695
+                $qb->expr()->orX(
696
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
697
+                    $or1
698
+                )
699
+            );
700
+        } else {
701
+            $qb->andWhere(
702
+                $qb->expr()->orX(
703
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
704
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
705
+                )
706
+            );
707
+        }
708
+
709
+        if ($node !== null) {
710
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
711
+        }
712
+
713
+        if ($limit !== -1) {
714
+            $qb->setMaxResults($limit);
715
+        }
716
+
717
+        $qb->setFirstResult($offset);
718
+        $qb->orderBy('id');
719
+
720
+        $cursor = $qb->execute();
721
+        $shares = [];
722
+        while($data = $cursor->fetch()) {
723
+            $shares[] = $this->createShareObject($data);
724
+        }
725
+        $cursor->closeCursor();
726
+
727
+        return $shares;
728
+    }
729
+
730
+    /**
731
+     * @inheritdoc
732
+     */
733
+    public function getShareById($id, $recipientId = null) {
734
+        $qb = $this->dbConnection->getQueryBuilder();
735
+
736
+        $qb->select('*')
737
+            ->from('share')
738
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
739
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
740
+
741
+        $cursor = $qb->execute();
742
+        $data = $cursor->fetch();
743
+        $cursor->closeCursor();
744
+
745
+        if ($data === false) {
746
+            throw new ShareNotFound();
747
+        }
748
+
749
+        try {
750
+            $share = $this->createShareObject($data);
751
+        } catch (InvalidShare $e) {
752
+            throw new ShareNotFound();
753
+        }
754
+
755
+        return $share;
756
+    }
757
+
758
+    /**
759
+     * Get shares for a given path
760
+     *
761
+     * @param \OCP\Files\Node $path
762
+     * @return IShare[]
763
+     */
764
+    public function getSharesByPath(Node $path) {
765
+        $qb = $this->dbConnection->getQueryBuilder();
766
+
767
+        $cursor = $qb->select('*')
768
+            ->from('share')
769
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
770
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
771
+            ->execute();
772
+
773
+        $shares = [];
774
+        while($data = $cursor->fetch()) {
775
+            $shares[] = $this->createShareObject($data);
776
+        }
777
+        $cursor->closeCursor();
778
+
779
+        return $shares;
780
+    }
781
+
782
+    /**
783
+     * @inheritdoc
784
+     */
785
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
786
+        /** @var IShare[] $shares */
787
+        $shares = [];
788
+
789
+        //Get shares directly with this user
790
+        $qb = $this->dbConnection->getQueryBuilder();
791
+        $qb->select('*')
792
+            ->from('share');
793
+
794
+        // Order by id
795
+        $qb->orderBy('id');
796
+
797
+        // Set limit and offset
798
+        if ($limit !== -1) {
799
+            $qb->setMaxResults($limit);
800
+        }
801
+        $qb->setFirstResult($offset);
802
+
803
+        $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
804
+        $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
805
+
806
+        // Filter by node if provided
807
+        if ($node !== null) {
808
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
809
+        }
810
+
811
+        $cursor = $qb->execute();
812
+
813
+        while($data = $cursor->fetch()) {
814
+            $shares[] = $this->createShareObject($data);
815
+        }
816
+        $cursor->closeCursor();
817
+
818
+
819
+        return $shares;
820
+    }
821
+
822
+    /**
823
+     * Get a share by token
824
+     *
825
+     * @param string $token
826
+     * @return IShare
827
+     * @throws ShareNotFound
828
+     */
829
+    public function getShareByToken($token) {
830
+        $qb = $this->dbConnection->getQueryBuilder();
831
+
832
+        $cursor = $qb->select('*')
833
+            ->from('share')
834
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
835
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
836
+            ->execute();
837
+
838
+        $data = $cursor->fetch();
839
+
840
+        if ($data === false) {
841
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
842
+        }
843
+
844
+        try {
845
+            $share = $this->createShareObject($data);
846
+        } catch (InvalidShare $e) {
847
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
848
+        }
849
+
850
+        return $share;
851
+    }
852
+
853
+    /**
854
+     * remove share from table
855
+     *
856
+     * @param string $shareId
857
+     */
858
+    protected function removeShareFromTable($shareId) {
859
+        $qb = $this->dbConnection->getQueryBuilder();
860
+        $qb->delete('share')
861
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
862
+        $qb->execute();
863
+    }
864
+
865
+    /**
866
+     * Create a share object from an database row
867
+     *
868
+     * @param array $data
869
+     * @return IShare
870
+     * @throws InvalidShare
871
+     * @throws ShareNotFound
872
+     */
873
+    protected function createShareObject($data) {
874
+
875
+        $share = new Share($this->rootFolder, $this->userManager);
876
+        $share->setId((int)$data['id'])
877
+            ->setShareType((int)$data['share_type'])
878
+            ->setPermissions((int)$data['permissions'])
879
+            ->setTarget($data['file_target'])
880
+            ->setMailSend((bool)$data['mail_send'])
881
+            ->setToken($data['token']);
882
+
883
+        $shareTime = new \DateTime();
884
+        $shareTime->setTimestamp((int)$data['stime']);
885
+        $share->setShareTime($shareTime);
886
+        $share->setSharedWith($data['share_with']);
887
+        $share->setPassword($data['password']);
888
+
889
+        if ($data['uid_initiator'] !== null) {
890
+            $share->setShareOwner($data['uid_owner']);
891
+            $share->setSharedBy($data['uid_initiator']);
892
+        } else {
893
+            //OLD SHARE
894
+            $share->setSharedBy($data['uid_owner']);
895
+            $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
896
+
897
+            $owner = $path->getOwner();
898
+            $share->setShareOwner($owner->getUID());
899
+        }
900
+
901
+        if ($data['expiration'] !== null) {
902
+            $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
903
+            if ($expiration !== false) {
904
+                $share->setExpirationDate($expiration);
905
+            }
906
+        }
907
+
908
+        $share->setNodeId((int)$data['file_source']);
909
+        $share->setNodeType($data['item_type']);
910
+
911
+        $share->setProviderId($this->identifier());
912
+
913
+        return $share;
914
+    }
915
+
916
+    /**
917
+     * Get the node with file $id for $user
918
+     *
919
+     * @param string $userId
920
+     * @param int $id
921
+     * @return \OCP\Files\File|\OCP\Files\Folder
922
+     * @throws InvalidShare
923
+     */
924
+    private function getNode($userId, $id) {
925
+        try {
926
+            $userFolder = $this->rootFolder->getUserFolder($userId);
927
+        } catch (NoUserException $e) {
928
+            throw new InvalidShare();
929
+        }
930
+
931
+        $nodes = $userFolder->getById($id);
932
+
933
+        if (empty($nodes)) {
934
+            throw new InvalidShare();
935
+        }
936
+
937
+        return $nodes[0];
938
+    }
939
+
940
+    /**
941
+     * A user is deleted from the system
942
+     * So clean up the relevant shares.
943
+     *
944
+     * @param string $uid
945
+     * @param int $shareType
946
+     */
947
+    public function userDeleted($uid, $shareType) {
948
+        $qb = $this->dbConnection->getQueryBuilder();
949
+
950
+        $qb->delete('share')
951
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
952
+            ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
953
+            ->execute();
954
+    }
955
+
956
+    /**
957
+     * This provider does not support group shares
958
+     *
959
+     * @param string $gid
960
+     */
961
+    public function groupDeleted($gid) {
962
+        return;
963
+    }
964
+
965
+    /**
966
+     * This provider does not support group shares
967
+     *
968
+     * @param string $uid
969
+     * @param string $gid
970
+     */
971
+    public function userDeletedFromGroup($uid, $gid) {
972
+        return;
973
+    }
974
+
975
+    /**
976
+     * get database row of a give share
977
+     *
978
+     * @param $id
979
+     * @return array
980
+     * @throws ShareNotFound
981
+     */
982
+    protected function getRawShare($id) {
983
+
984
+        // Now fetch the inserted share and create a complete share object
985
+        $qb = $this->dbConnection->getQueryBuilder();
986
+        $qb->select('*')
987
+            ->from('share')
988
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
989
+
990
+        $cursor = $qb->execute();
991
+        $data = $cursor->fetch();
992
+        $cursor->closeCursor();
993
+
994
+        if ($data === false) {
995
+            throw new ShareNotFound;
996
+        }
997
+
998
+        return $data;
999
+    }
1000
+
1001
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
1002
+        $qb = $this->dbConnection->getQueryBuilder();
1003
+        $qb->select('*')
1004
+            ->from('share', 's')
1005
+            ->andWhere($qb->expr()->orX(
1006
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1007
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1008
+            ))
1009
+            ->andWhere(
1010
+                $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
1011
+            );
1012
+
1013
+        /**
1014
+         * Reshares for this user are shares where they are the owner.
1015
+         */
1016
+        if ($reshares === false) {
1017
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
1018
+        } else {
1019
+            $qb->andWhere(
1020
+                $qb->expr()->orX(
1021
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
1022
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
1023
+                )
1024
+            );
1025
+        }
1026
+
1027
+        $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1028
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1029
+
1030
+        $qb->orderBy('id');
1031
+
1032
+        $cursor = $qb->execute();
1033
+        $shares = [];
1034
+        while ($data = $cursor->fetch()) {
1035
+            $shares[$data['fileid']][] = $this->createShareObject($data);
1036
+        }
1037
+        $cursor->closeCursor();
1038
+
1039
+        return $shares;
1040
+    }
1041
+
1042
+    /**
1043
+     * @inheritdoc
1044
+     */
1045
+    public function getAccessList($nodes, $currentAccess) {
1046
+        $ids = [];
1047
+        foreach ($nodes as $node) {
1048
+            $ids[] = $node->getId();
1049
+        }
1050
+
1051
+        $qb = $this->dbConnection->getQueryBuilder();
1052
+        $qb->select('share_with')
1053
+            ->from('share')
1054
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
1055
+            ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1056
+            ->andWhere($qb->expr()->orX(
1057
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1058
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1059
+            ))
1060
+            ->setMaxResults(1);
1061
+        $cursor = $qb->execute();
1062
+
1063
+        $mail = $cursor->fetch() !== false;
1064
+        $cursor->closeCursor();
1065
+
1066
+        return ['public' => $mail];
1067
+    }
1068 1068
 
1069 1069
 }
Please login to merge, or discard this patch.
core/routes.php 1 patch
Indentation   +69 added lines, -69 removed lines patch added patch discarded remove patch
@@ -35,40 +35,40 @@  discard block
 block discarded – undo
35 35
 
36 36
 $application = new Application();
37 37
 $application->registerRoutes($this, [
38
-	'routes' => [
39
-		['name' => 'lost#email', 'url' => '/lostpassword/email', 'verb' => 'POST'],
40
-		['name' => 'lost#resetform', 'url' => '/lostpassword/reset/form/{token}/{userId}', 'verb' => 'GET'],
41
-		['name' => 'lost#setPassword', 'url' => '/lostpassword/set/{token}/{userId}', 'verb' => 'POST'],
42
-		['name' => 'user#getDisplayNames', 'url' => '/displaynames', 'verb' => 'POST'],
43
-		['name' => 'avatar#getAvatar', 'url' => '/avatar/{userId}/{size}', 'verb' => 'GET'],
44
-		['name' => 'avatar#deleteAvatar', 'url' => '/avatar/', 'verb' => 'DELETE'],
45
-		['name' => 'avatar#postCroppedAvatar', 'url' => '/avatar/cropped', 'verb' => 'POST'],
46
-		['name' => 'avatar#getTmpAvatar', 'url' => '/avatar/tmp', 'verb' => 'GET'],
47
-		['name' => 'avatar#postAvatar', 'url' => '/avatar/', 'verb' => 'POST'],
48
-		['name' => 'login#tryLogin', 'url' => '/login', 'verb' => 'POST'],
49
-		['name' => 'login#confirmPassword', 'url' => '/login/confirm', 'verb' => 'POST'],
50
-		['name' => 'login#showLoginForm', 'url' => '/login', 'verb' => 'GET'],
51
-		['name' => 'login#logout', 'url' => '/logout', 'verb' => 'GET'],
52
-		['name' => 'ClientFlowLogin#showAuthPickerPage', 'url' => '/login/flow', 'verb' => 'GET'],
53
-		['name' => 'ClientFlowLogin#redirectPage', 'url' => '/login/flow/redirect', 'verb' => 'GET'],
54
-		['name' => 'ClientFlowLogin#generateAppPassword', 'url' => '/login/flow', 'verb' => 'POST'],
55
-		['name' => 'TwoFactorChallenge#selectChallenge', 'url' => '/login/selectchallenge', 'verb' => 'GET'],
56
-		['name' => 'TwoFactorChallenge#showChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'GET'],
57
-		['name' => 'TwoFactorChallenge#solveChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'POST'],
58
-		['name' => 'OCJS#getConfig', 'url' => '/core/js/oc.js', 'verb' => 'GET'],
59
-		['name' => 'Preview#getPreview', 'url' => '/core/preview', 'verb' => 'GET'],
60
-		['name' => 'Preview#getPreview', 'url' => '/core/preview.png', 'verb' => 'GET'],
61
-		['name' => 'Css#getCss', 'url' => '/css/{appName}/{fileName}', 'verb' => 'GET'],
62
-		['name' => 'Js#getJs', 'url' => '/js/{appName}/{fileName}', 'verb' => 'GET'],
63
-		['name' => 'contactsMenu#index', 'url' => '/contactsmenu/contacts', 'verb' => 'POST'],
64
-		['name' => 'contactsMenu#findOne', 'url' => '/contactsmenu/findOne', 'verb' => 'POST'],
65
-	],
66
-	'ocs' => [
67
-		['root' => '/cloud', 'name' => 'OCS#getCapabilities', 'url' => '/capabilities', 'verb' => 'GET'],
68
-		['root' => '', 'name' => 'OCS#getConfig', 'url' => '/config', 'verb' => 'GET'],
69
-		['root' => '/person', 'name' => 'OCS#personCheck', 'url' => '/check', 'verb' => 'POST'],
70
-		['root' => '/identityproof', 'name' => 'OCS#getIdentityProof', 'url' => '/key/{cloudId}', 'verb' => 'GET'],
71
-	],
38
+    'routes' => [
39
+        ['name' => 'lost#email', 'url' => '/lostpassword/email', 'verb' => 'POST'],
40
+        ['name' => 'lost#resetform', 'url' => '/lostpassword/reset/form/{token}/{userId}', 'verb' => 'GET'],
41
+        ['name' => 'lost#setPassword', 'url' => '/lostpassword/set/{token}/{userId}', 'verb' => 'POST'],
42
+        ['name' => 'user#getDisplayNames', 'url' => '/displaynames', 'verb' => 'POST'],
43
+        ['name' => 'avatar#getAvatar', 'url' => '/avatar/{userId}/{size}', 'verb' => 'GET'],
44
+        ['name' => 'avatar#deleteAvatar', 'url' => '/avatar/', 'verb' => 'DELETE'],
45
+        ['name' => 'avatar#postCroppedAvatar', 'url' => '/avatar/cropped', 'verb' => 'POST'],
46
+        ['name' => 'avatar#getTmpAvatar', 'url' => '/avatar/tmp', 'verb' => 'GET'],
47
+        ['name' => 'avatar#postAvatar', 'url' => '/avatar/', 'verb' => 'POST'],
48
+        ['name' => 'login#tryLogin', 'url' => '/login', 'verb' => 'POST'],
49
+        ['name' => 'login#confirmPassword', 'url' => '/login/confirm', 'verb' => 'POST'],
50
+        ['name' => 'login#showLoginForm', 'url' => '/login', 'verb' => 'GET'],
51
+        ['name' => 'login#logout', 'url' => '/logout', 'verb' => 'GET'],
52
+        ['name' => 'ClientFlowLogin#showAuthPickerPage', 'url' => '/login/flow', 'verb' => 'GET'],
53
+        ['name' => 'ClientFlowLogin#redirectPage', 'url' => '/login/flow/redirect', 'verb' => 'GET'],
54
+        ['name' => 'ClientFlowLogin#generateAppPassword', 'url' => '/login/flow', 'verb' => 'POST'],
55
+        ['name' => 'TwoFactorChallenge#selectChallenge', 'url' => '/login/selectchallenge', 'verb' => 'GET'],
56
+        ['name' => 'TwoFactorChallenge#showChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'GET'],
57
+        ['name' => 'TwoFactorChallenge#solveChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'POST'],
58
+        ['name' => 'OCJS#getConfig', 'url' => '/core/js/oc.js', 'verb' => 'GET'],
59
+        ['name' => 'Preview#getPreview', 'url' => '/core/preview', 'verb' => 'GET'],
60
+        ['name' => 'Preview#getPreview', 'url' => '/core/preview.png', 'verb' => 'GET'],
61
+        ['name' => 'Css#getCss', 'url' => '/css/{appName}/{fileName}', 'verb' => 'GET'],
62
+        ['name' => 'Js#getJs', 'url' => '/js/{appName}/{fileName}', 'verb' => 'GET'],
63
+        ['name' => 'contactsMenu#index', 'url' => '/contactsmenu/contacts', 'verb' => 'POST'],
64
+        ['name' => 'contactsMenu#findOne', 'url' => '/contactsmenu/findOne', 'verb' => 'POST'],
65
+    ],
66
+    'ocs' => [
67
+        ['root' => '/cloud', 'name' => 'OCS#getCapabilities', 'url' => '/capabilities', 'verb' => 'GET'],
68
+        ['root' => '', 'name' => 'OCS#getConfig', 'url' => '/config', 'verb' => 'GET'],
69
+        ['root' => '/person', 'name' => 'OCS#personCheck', 'url' => '/check', 'verb' => 'POST'],
70
+        ['root' => '/identityproof', 'name' => 'OCS#getIdentityProof', 'url' => '/key/{cloudId}', 'verb' => 'GET'],
71
+    ],
72 72
 ]);
73 73
 
74 74
 // Post installation check
@@ -77,15 +77,15 @@  discard block
 block discarded – undo
77 77
 // Core ajax actions
78 78
 // Search
79 79
 $this->create('search_ajax_search', '/core/search')
80
-	->actionInclude('core/search/ajax/search.php');
80
+    ->actionInclude('core/search/ajax/search.php');
81 81
 // Routing
82 82
 $this->create('core_ajax_update', '/core/ajax/update.php')
83
-	->actionInclude('core/ajax/update.php');
83
+    ->actionInclude('core/ajax/update.php');
84 84
 
85 85
 // File routes
86 86
 $this->create('files.viewcontroller.showFile', '/f/{fileid}')->action(function($urlParams) {
87
-	$app = new \OCA\Files\AppInfo\Application($urlParams);
88
-	$app->dispatch('ViewController', 'index');
87
+    $app = new \OCA\Files\AppInfo\Application($urlParams);
88
+    $app->dispatch('ViewController', 'index');
89 89
 });
90 90
 
91 91
 // Call routes
@@ -94,49 +94,49 @@  discard block
 block discarded – undo
94 94
  * @suppress PhanUndeclaredClassMethod
95 95
  */
96 96
 $this->create('spreed.pagecontroller.showCall', '/call/{token}')->action(function($urlParams) {
97
-	if (class_exists(\OCA\Spreed\AppInfo\Application::class, false)) {
98
-		$app = new \OCA\Spreed\AppInfo\Application($urlParams);
99
-		$app->dispatch('PageController', 'index');
100
-	} else {
101
-		throw new \OC\HintException('App spreed is not enabled');
102
-	}
97
+    if (class_exists(\OCA\Spreed\AppInfo\Application::class, false)) {
98
+        $app = new \OCA\Spreed\AppInfo\Application($urlParams);
99
+        $app->dispatch('PageController', 'index');
100
+    } else {
101
+        throw new \OC\HintException('App spreed is not enabled');
102
+    }
103 103
 });
104 104
 
105 105
 // Sharing routes
106 106
 $this->create('files_sharing.sharecontroller.showShare', '/s/{token}')->action(function($urlParams) {
107
-	if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) {
108
-		$app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);
109
-		$app->dispatch('ShareController', 'showShare');
110
-	} else {
111
-		throw new \OC\HintException('App file sharing is not enabled');
112
-	}
107
+    if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) {
108
+        $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);
109
+        $app->dispatch('ShareController', 'showShare');
110
+    } else {
111
+        throw new \OC\HintException('App file sharing is not enabled');
112
+    }
113 113
 });
114 114
 $this->create('files_sharing.sharecontroller.authenticate', '/s/{token}/authenticate')->post()->action(function($urlParams) {
115
-	if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) {
116
-		$app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);
117
-		$app->dispatch('ShareController', 'authenticate');
118
-	} else {
119
-		throw new \OC\HintException('App file sharing is not enabled');
120
-	}
115
+    if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) {
116
+        $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);
117
+        $app->dispatch('ShareController', 'authenticate');
118
+    } else {
119
+        throw new \OC\HintException('App file sharing is not enabled');
120
+    }
121 121
 });
122 122
 $this->create('files_sharing.sharecontroller.showAuthenticate', '/s/{token}/authenticate')->get()->action(function($urlParams) {
123
-	if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) {
124
-		$app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);
125
-		$app->dispatch('ShareController', 'showAuthenticate');
126
-	} else {
127
-		throw new \OC\HintException('App file sharing is not enabled');
128
-	}
123
+    if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) {
124
+        $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);
125
+        $app->dispatch('ShareController', 'showAuthenticate');
126
+    } else {
127
+        throw new \OC\HintException('App file sharing is not enabled');
128
+    }
129 129
 });
130 130
 $this->create('files_sharing.sharecontroller.downloadShare', '/s/{token}/download')->get()->action(function($urlParams) {
131
-	if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) {
132
-		$app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);
133
-		$app->dispatch('ShareController', 'downloadShare');
134
-	} else {
135
-		throw new \OC\HintException('App file sharing is not enabled');
136
-	}
131
+    if (class_exists(\OCA\Files_Sharing\AppInfo\Application::class, false)) {
132
+        $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);
133
+        $app->dispatch('ShareController', 'downloadShare');
134
+    } else {
135
+        throw new \OC\HintException('App file sharing is not enabled');
136
+    }
137 137
 });
138 138
 
139 139
 // used for heartbeat
140 140
 $this->create('heartbeat', '/heartbeat')->action(function(){
141
-	// do nothing
141
+    // do nothing
142 142
 });
Please login to merge, or discard this patch.
lib/private/Files/Filesystem.php 1 patch
Indentation   +853 added lines, -853 removed lines patch added patch discarded remove patch
@@ -69,857 +69,857 @@
 block discarded – undo
69 69
 
70 70
 class Filesystem {
71 71
 
72
-	/**
73
-	 * @var Mount\Manager $mounts
74
-	 */
75
-	private static $mounts;
76
-
77
-	public static $loaded = false;
78
-	/**
79
-	 * @var \OC\Files\View $defaultInstance
80
-	 */
81
-	static private $defaultInstance;
82
-
83
-	static private $usersSetup = array();
84
-
85
-	static private $normalizedPathCache = null;
86
-
87
-	static private $listeningForProviders = false;
88
-
89
-	/**
90
-	 * classname which used for hooks handling
91
-	 * used as signalclass in OC_Hooks::emit()
92
-	 */
93
-	const CLASSNAME = 'OC_Filesystem';
94
-
95
-	/**
96
-	 * signalname emitted before file renaming
97
-	 *
98
-	 * @param string $oldpath
99
-	 * @param string $newpath
100
-	 */
101
-	const signal_rename = 'rename';
102
-
103
-	/**
104
-	 * signal emitted after file renaming
105
-	 *
106
-	 * @param string $oldpath
107
-	 * @param string $newpath
108
-	 */
109
-	const signal_post_rename = 'post_rename';
110
-
111
-	/**
112
-	 * signal emitted before file/dir creation
113
-	 *
114
-	 * @param string $path
115
-	 * @param bool $run changing this flag to false in hook handler will cancel event
116
-	 */
117
-	const signal_create = 'create';
118
-
119
-	/**
120
-	 * signal emitted after file/dir creation
121
-	 *
122
-	 * @param string $path
123
-	 * @param bool $run changing this flag to false in hook handler will cancel event
124
-	 */
125
-	const signal_post_create = 'post_create';
126
-
127
-	/**
128
-	 * signal emits before file/dir copy
129
-	 *
130
-	 * @param string $oldpath
131
-	 * @param string $newpath
132
-	 * @param bool $run changing this flag to false in hook handler will cancel event
133
-	 */
134
-	const signal_copy = 'copy';
135
-
136
-	/**
137
-	 * signal emits after file/dir copy
138
-	 *
139
-	 * @param string $oldpath
140
-	 * @param string $newpath
141
-	 */
142
-	const signal_post_copy = 'post_copy';
143
-
144
-	/**
145
-	 * signal emits before file/dir save
146
-	 *
147
-	 * @param string $path
148
-	 * @param bool $run changing this flag to false in hook handler will cancel event
149
-	 */
150
-	const signal_write = 'write';
151
-
152
-	/**
153
-	 * signal emits after file/dir save
154
-	 *
155
-	 * @param string $path
156
-	 */
157
-	const signal_post_write = 'post_write';
158
-
159
-	/**
160
-	 * signal emitted before file/dir update
161
-	 *
162
-	 * @param string $path
163
-	 * @param bool $run changing this flag to false in hook handler will cancel event
164
-	 */
165
-	const signal_update = 'update';
166
-
167
-	/**
168
-	 * signal emitted after file/dir update
169
-	 *
170
-	 * @param string $path
171
-	 * @param bool $run changing this flag to false in hook handler will cancel event
172
-	 */
173
-	const signal_post_update = 'post_update';
174
-
175
-	/**
176
-	 * signal emits when reading file/dir
177
-	 *
178
-	 * @param string $path
179
-	 */
180
-	const signal_read = 'read';
181
-
182
-	/**
183
-	 * signal emits when removing file/dir
184
-	 *
185
-	 * @param string $path
186
-	 */
187
-	const signal_delete = 'delete';
188
-
189
-	/**
190
-	 * parameters definitions for signals
191
-	 */
192
-	const signal_param_path = 'path';
193
-	const signal_param_oldpath = 'oldpath';
194
-	const signal_param_newpath = 'newpath';
195
-
196
-	/**
197
-	 * run - changing this flag to false in hook handler will cancel event
198
-	 */
199
-	const signal_param_run = 'run';
200
-
201
-	const signal_create_mount = 'create_mount';
202
-	const signal_delete_mount = 'delete_mount';
203
-	const signal_param_mount_type = 'mounttype';
204
-	const signal_param_users = 'users';
205
-
206
-	/**
207
-	 * @var \OC\Files\Storage\StorageFactory $loader
208
-	 */
209
-	private static $loader;
210
-
211
-	/** @var bool */
212
-	private static $logWarningWhenAddingStorageWrapper = true;
213
-
214
-	/**
215
-	 * @param bool $shouldLog
216
-	 * @return bool previous value
217
-	 * @internal
218
-	 */
219
-	public static function logWarningWhenAddingStorageWrapper($shouldLog) {
220
-		$previousValue = self::$logWarningWhenAddingStorageWrapper;
221
-		self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
222
-		return $previousValue;
223
-	}
224
-
225
-	/**
226
-	 * @param string $wrapperName
227
-	 * @param callable $wrapper
228
-	 * @param int $priority
229
-	 */
230
-	public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
231
-		if (self::$logWarningWhenAddingStorageWrapper) {
232
-			\OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
233
-				'wrapper' => $wrapperName,
234
-				'app' => 'filesystem',
235
-			]);
236
-		}
237
-
238
-		$mounts = self::getMountManager()->getAll();
239
-		if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
240
-			// do not re-wrap if storage with this name already existed
241
-			return;
242
-		}
243
-	}
244
-
245
-	/**
246
-	 * Returns the storage factory
247
-	 *
248
-	 * @return \OCP\Files\Storage\IStorageFactory
249
-	 */
250
-	public static function getLoader() {
251
-		if (!self::$loader) {
252
-			self::$loader = new StorageFactory();
253
-		}
254
-		return self::$loader;
255
-	}
256
-
257
-	/**
258
-	 * Returns the mount manager
259
-	 *
260
-	 * @return \OC\Files\Mount\Manager
261
-	 */
262
-	public static function getMountManager($user = '') {
263
-		if (!self::$mounts) {
264
-			\OC_Util::setupFS($user);
265
-		}
266
-		return self::$mounts;
267
-	}
268
-
269
-	/**
270
-	 * get the mountpoint of the storage object for a path
271
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
272
-	 * returned mountpoint is relative to the absolute root of the filesystem
273
-	 * and doesn't take the chroot into account )
274
-	 *
275
-	 * @param string $path
276
-	 * @return string
277
-	 */
278
-	static public function getMountPoint($path) {
279
-		if (!self::$mounts) {
280
-			\OC_Util::setupFS();
281
-		}
282
-		$mount = self::$mounts->find($path);
283
-		if ($mount) {
284
-			return $mount->getMountPoint();
285
-		} else {
286
-			return '';
287
-		}
288
-	}
289
-
290
-	/**
291
-	 * get a list of all mount points in a directory
292
-	 *
293
-	 * @param string $path
294
-	 * @return string[]
295
-	 */
296
-	static public function getMountPoints($path) {
297
-		if (!self::$mounts) {
298
-			\OC_Util::setupFS();
299
-		}
300
-		$result = array();
301
-		$mounts = self::$mounts->findIn($path);
302
-		foreach ($mounts as $mount) {
303
-			$result[] = $mount->getMountPoint();
304
-		}
305
-		return $result;
306
-	}
307
-
308
-	/**
309
-	 * get the storage mounted at $mountPoint
310
-	 *
311
-	 * @param string $mountPoint
312
-	 * @return \OC\Files\Storage\Storage
313
-	 */
314
-	public static function getStorage($mountPoint) {
315
-		if (!self::$mounts) {
316
-			\OC_Util::setupFS();
317
-		}
318
-		$mount = self::$mounts->find($mountPoint);
319
-		return $mount->getStorage();
320
-	}
321
-
322
-	/**
323
-	 * @param string $id
324
-	 * @return Mount\MountPoint[]
325
-	 */
326
-	public static function getMountByStorageId($id) {
327
-		if (!self::$mounts) {
328
-			\OC_Util::setupFS();
329
-		}
330
-		return self::$mounts->findByStorageId($id);
331
-	}
332
-
333
-	/**
334
-	 * @param int $id
335
-	 * @return Mount\MountPoint[]
336
-	 */
337
-	public static function getMountByNumericId($id) {
338
-		if (!self::$mounts) {
339
-			\OC_Util::setupFS();
340
-		}
341
-		return self::$mounts->findByNumericId($id);
342
-	}
343
-
344
-	/**
345
-	 * resolve a path to a storage and internal path
346
-	 *
347
-	 * @param string $path
348
-	 * @return array an array consisting of the storage and the internal path
349
-	 */
350
-	static public function resolvePath($path) {
351
-		if (!self::$mounts) {
352
-			\OC_Util::setupFS();
353
-		}
354
-		$mount = self::$mounts->find($path);
355
-		if ($mount) {
356
-			return array($mount->getStorage(), rtrim($mount->getInternalPath($path), '/'));
357
-		} else {
358
-			return array(null, null);
359
-		}
360
-	}
361
-
362
-	static public function init($user, $root) {
363
-		if (self::$defaultInstance) {
364
-			return false;
365
-		}
366
-		self::getLoader();
367
-		self::$defaultInstance = new View($root);
368
-
369
-		if (!self::$mounts) {
370
-			self::$mounts = \OC::$server->getMountManager();
371
-		}
372
-
373
-		//load custom mount config
374
-		self::initMountPoints($user);
375
-
376
-		self::$loaded = true;
377
-
378
-		return true;
379
-	}
380
-
381
-	static public function initMountManager() {
382
-		if (!self::$mounts) {
383
-			self::$mounts = \OC::$server->getMountManager();
384
-		}
385
-	}
386
-
387
-	/**
388
-	 * Initialize system and personal mount points for a user
389
-	 *
390
-	 * @param string $user
391
-	 * @throws \OC\User\NoUserException if the user is not available
392
-	 */
393
-	public static function initMountPoints($user = '') {
394
-		if ($user == '') {
395
-			$user = \OC_User::getUser();
396
-		}
397
-		if ($user === null || $user === false || $user === '') {
398
-			throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
399
-		}
400
-
401
-		if (isset(self::$usersSetup[$user])) {
402
-			return;
403
-		}
404
-
405
-		self::$usersSetup[$user] = true;
406
-
407
-		$userManager = \OC::$server->getUserManager();
408
-		$userObject = $userManager->get($user);
409
-
410
-		if (is_null($userObject)) {
411
-			\OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, \OCP\Util::ERROR);
412
-			// reset flag, this will make it possible to rethrow the exception if called again
413
-			unset(self::$usersSetup[$user]);
414
-			throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
415
-		}
416
-
417
-		$realUid = $userObject->getUID();
418
-		// workaround in case of different casings
419
-		if ($user !== $realUid) {
420
-			$stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50));
421
-			\OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, \OCP\Util::WARN);
422
-			$user = $realUid;
423
-
424
-			// again with the correct casing
425
-			if (isset(self::$usersSetup[$user])) {
426
-				return;
427
-			}
428
-
429
-			self::$usersSetup[$user] = true;
430
-		}
431
-
432
-		if (\OC::$server->getLockdownManager()->canAccessFilesystem()) {
433
-			/** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
434
-			$mountConfigManager = \OC::$server->getMountProviderCollection();
435
-
436
-			// home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
437
-			$homeMount = $mountConfigManager->getHomeMountForUser($userObject);
438
-
439
-			self::getMountManager()->addMount($homeMount);
440
-
441
-			\OC\Files\Filesystem::getStorage($user);
442
-
443
-			// Chance to mount for other storages
444
-			if ($userObject) {
445
-				$mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager());
446
-				$mounts[] = $homeMount;
447
-				$mountConfigManager->registerMounts($userObject, $mounts);
448
-			}
449
-
450
-			self::listenForNewMountProviders($mountConfigManager, $userManager);
451
-		} else {
452
-			self::getMountManager()->addMount(new MountPoint(
453
-				new NullStorage([]),
454
-				'/' . $user
455
-			));
456
-			self::getMountManager()->addMount(new MountPoint(
457
-				new NullStorage([]),
458
-				'/' . $user . '/files'
459
-			));
460
-		}
461
-		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user));
462
-	}
463
-
464
-	/**
465
-	 * Get mounts from mount providers that are registered after setup
466
-	 *
467
-	 * @param MountProviderCollection $mountConfigManager
468
-	 * @param IUserManager $userManager
469
-	 */
470
-	private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
471
-		if (!self::$listeningForProviders) {
472
-			self::$listeningForProviders = true;
473
-			$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
474
-				foreach (Filesystem::$usersSetup as $user => $setup) {
475
-					$userObject = $userManager->get($user);
476
-					if ($userObject) {
477
-						$mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
478
-						array_walk($mounts, array(self::$mounts, 'addMount'));
479
-					}
480
-				}
481
-			});
482
-		}
483
-	}
484
-
485
-	/**
486
-	 * get the default filesystem view
487
-	 *
488
-	 * @return View
489
-	 */
490
-	static public function getView() {
491
-		return self::$defaultInstance;
492
-	}
493
-
494
-	/**
495
-	 * tear down the filesystem, removing all storage providers
496
-	 */
497
-	static public function tearDown() {
498
-		self::clearMounts();
499
-		self::$defaultInstance = null;
500
-	}
501
-
502
-	/**
503
-	 * get the relative path of the root data directory for the current user
504
-	 *
505
-	 * @return string
506
-	 *
507
-	 * Returns path like /admin/files
508
-	 */
509
-	static public function getRoot() {
510
-		if (!self::$defaultInstance) {
511
-			return null;
512
-		}
513
-		return self::$defaultInstance->getRoot();
514
-	}
515
-
516
-	/**
517
-	 * clear all mounts and storage backends
518
-	 */
519
-	public static function clearMounts() {
520
-		if (self::$mounts) {
521
-			self::$usersSetup = array();
522
-			self::$mounts->clear();
523
-		}
524
-	}
525
-
526
-	/**
527
-	 * mount an \OC\Files\Storage\Storage in our virtual filesystem
528
-	 *
529
-	 * @param \OC\Files\Storage\Storage|string $class
530
-	 * @param array $arguments
531
-	 * @param string $mountpoint
532
-	 */
533
-	static public function mount($class, $arguments, $mountpoint) {
534
-		if (!self::$mounts) {
535
-			\OC_Util::setupFS();
536
-		}
537
-		$mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
538
-		self::$mounts->addMount($mount);
539
-	}
540
-
541
-	/**
542
-	 * return the path to a local version of the file
543
-	 * we need this because we can't know if a file is stored local or not from
544
-	 * outside the filestorage and for some purposes a local file is needed
545
-	 *
546
-	 * @param string $path
547
-	 * @return string
548
-	 */
549
-	static public function getLocalFile($path) {
550
-		return self::$defaultInstance->getLocalFile($path);
551
-	}
552
-
553
-	/**
554
-	 * @param string $path
555
-	 * @return string
556
-	 */
557
-	static public function getLocalFolder($path) {
558
-		return self::$defaultInstance->getLocalFolder($path);
559
-	}
560
-
561
-	/**
562
-	 * return path to file which reflects one visible in browser
563
-	 *
564
-	 * @param string $path
565
-	 * @return string
566
-	 */
567
-	static public function getLocalPath($path) {
568
-		$datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
569
-		$newpath = $path;
570
-		if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
571
-			$newpath = substr($path, strlen($datadir));
572
-		}
573
-		return $newpath;
574
-	}
575
-
576
-	/**
577
-	 * check if the requested path is valid
578
-	 *
579
-	 * @param string $path
580
-	 * @return bool
581
-	 */
582
-	static public function isValidPath($path) {
583
-		$path = self::normalizePath($path);
584
-		if (!$path || $path[0] !== '/') {
585
-			$path = '/' . $path;
586
-		}
587
-		if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
588
-			return false;
589
-		}
590
-		return true;
591
-	}
592
-
593
-	/**
594
-	 * checks if a file is blacklisted for storage in the filesystem
595
-	 * Listens to write and rename hooks
596
-	 *
597
-	 * @param array $data from hook
598
-	 */
599
-	static public function isBlacklisted($data) {
600
-		if (isset($data['path'])) {
601
-			$path = $data['path'];
602
-		} else if (isset($data['newpath'])) {
603
-			$path = $data['newpath'];
604
-		}
605
-		if (isset($path)) {
606
-			if (self::isFileBlacklisted($path)) {
607
-				$data['run'] = false;
608
-			}
609
-		}
610
-	}
611
-
612
-	/**
613
-	 * @param string $filename
614
-	 * @return bool
615
-	 */
616
-	static public function isFileBlacklisted($filename) {
617
-		$filename = self::normalizePath($filename);
618
-
619
-		$blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', array('.htaccess'));
620
-		$filename = strtolower(basename($filename));
621
-		return in_array($filename, $blacklist);
622
-	}
623
-
624
-	/**
625
-	 * check if the directory should be ignored when scanning
626
-	 * NOTE: the special directories . and .. would cause never ending recursion
627
-	 *
628
-	 * @param String $dir
629
-	 * @return boolean
630
-	 */
631
-	static public function isIgnoredDir($dir) {
632
-		if ($dir === '.' || $dir === '..') {
633
-			return true;
634
-		}
635
-		return false;
636
-	}
637
-
638
-	/**
639
-	 * following functions are equivalent to their php builtin equivalents for arguments/return values.
640
-	 */
641
-	static public function mkdir($path) {
642
-		return self::$defaultInstance->mkdir($path);
643
-	}
644
-
645
-	static public function rmdir($path) {
646
-		return self::$defaultInstance->rmdir($path);
647
-	}
648
-
649
-	static public function is_dir($path) {
650
-		return self::$defaultInstance->is_dir($path);
651
-	}
652
-
653
-	static public function is_file($path) {
654
-		return self::$defaultInstance->is_file($path);
655
-	}
656
-
657
-	static public function stat($path) {
658
-		return self::$defaultInstance->stat($path);
659
-	}
660
-
661
-	static public function filetype($path) {
662
-		return self::$defaultInstance->filetype($path);
663
-	}
664
-
665
-	static public function filesize($path) {
666
-		return self::$defaultInstance->filesize($path);
667
-	}
668
-
669
-	static public function readfile($path) {
670
-		return self::$defaultInstance->readfile($path);
671
-	}
672
-
673
-	static public function isCreatable($path) {
674
-		return self::$defaultInstance->isCreatable($path);
675
-	}
676
-
677
-	static public function isReadable($path) {
678
-		return self::$defaultInstance->isReadable($path);
679
-	}
680
-
681
-	static public function isUpdatable($path) {
682
-		return self::$defaultInstance->isUpdatable($path);
683
-	}
684
-
685
-	static public function isDeletable($path) {
686
-		return self::$defaultInstance->isDeletable($path);
687
-	}
688
-
689
-	static public function isSharable($path) {
690
-		return self::$defaultInstance->isSharable($path);
691
-	}
692
-
693
-	static public function file_exists($path) {
694
-		return self::$defaultInstance->file_exists($path);
695
-	}
696
-
697
-	static public function filemtime($path) {
698
-		return self::$defaultInstance->filemtime($path);
699
-	}
700
-
701
-	static public function touch($path, $mtime = null) {
702
-		return self::$defaultInstance->touch($path, $mtime);
703
-	}
704
-
705
-	/**
706
-	 * @return string
707
-	 */
708
-	static public function file_get_contents($path) {
709
-		return self::$defaultInstance->file_get_contents($path);
710
-	}
711
-
712
-	static public function file_put_contents($path, $data) {
713
-		return self::$defaultInstance->file_put_contents($path, $data);
714
-	}
715
-
716
-	static public function unlink($path) {
717
-		return self::$defaultInstance->unlink($path);
718
-	}
719
-
720
-	static public function rename($path1, $path2) {
721
-		return self::$defaultInstance->rename($path1, $path2);
722
-	}
723
-
724
-	static public function copy($path1, $path2) {
725
-		return self::$defaultInstance->copy($path1, $path2);
726
-	}
727
-
728
-	static public function fopen($path, $mode) {
729
-		return self::$defaultInstance->fopen($path, $mode);
730
-	}
731
-
732
-	/**
733
-	 * @return string
734
-	 */
735
-	static public function toTmpFile($path) {
736
-		return self::$defaultInstance->toTmpFile($path);
737
-	}
738
-
739
-	static public function fromTmpFile($tmpFile, $path) {
740
-		return self::$defaultInstance->fromTmpFile($tmpFile, $path);
741
-	}
742
-
743
-	static public function getMimeType($path) {
744
-		return self::$defaultInstance->getMimeType($path);
745
-	}
746
-
747
-	static public function hash($type, $path, $raw = false) {
748
-		return self::$defaultInstance->hash($type, $path, $raw);
749
-	}
750
-
751
-	static public function free_space($path = '/') {
752
-		return self::$defaultInstance->free_space($path);
753
-	}
754
-
755
-	static public function search($query) {
756
-		return self::$defaultInstance->search($query);
757
-	}
758
-
759
-	/**
760
-	 * @param string $query
761
-	 */
762
-	static public function searchByMime($query) {
763
-		return self::$defaultInstance->searchByMime($query);
764
-	}
765
-
766
-	/**
767
-	 * @param string|int $tag name or tag id
768
-	 * @param string $userId owner of the tags
769
-	 * @return FileInfo[] array or file info
770
-	 */
771
-	static public function searchByTag($tag, $userId) {
772
-		return self::$defaultInstance->searchByTag($tag, $userId);
773
-	}
774
-
775
-	/**
776
-	 * check if a file or folder has been updated since $time
777
-	 *
778
-	 * @param string $path
779
-	 * @param int $time
780
-	 * @return bool
781
-	 */
782
-	static public function hasUpdated($path, $time) {
783
-		return self::$defaultInstance->hasUpdated($path, $time);
784
-	}
785
-
786
-	/**
787
-	 * Fix common problems with a file path
788
-	 *
789
-	 * @param string $path
790
-	 * @param bool $stripTrailingSlash whether to strip the trailing slash
791
-	 * @param bool $isAbsolutePath whether the given path is absolute
792
-	 * @param bool $keepUnicode true to disable unicode normalization
793
-	 * @return string
794
-	 */
795
-	public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
796
-		if (is_null(self::$normalizedPathCache)) {
797
-			self::$normalizedPathCache = new CappedMemoryCache();
798
-		}
799
-
800
-		/**
801
-		 * FIXME: This is a workaround for existing classes and files which call
802
-		 *        this function with another type than a valid string. This
803
-		 *        conversion should get removed as soon as all existing
804
-		 *        function calls have been fixed.
805
-		 */
806
-		$path = (string)$path;
807
-
808
-		$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
809
-
810
-		if (isset(self::$normalizedPathCache[$cacheKey])) {
811
-			return self::$normalizedPathCache[$cacheKey];
812
-		}
813
-
814
-		if ($path == '') {
815
-			return '/';
816
-		}
817
-
818
-		//normalize unicode if possible
819
-		if (!$keepUnicode) {
820
-			$path = \OC_Util::normalizeUnicode($path);
821
-		}
822
-
823
-		//no windows style slashes
824
-		$path = str_replace('\\', '/', $path);
825
-
826
-		//add leading slash
827
-		if ($path[0] !== '/') {
828
-			$path = '/' . $path;
829
-		}
830
-
831
-		// remove '/./'
832
-		// ugly, but str_replace() can't replace them all in one go
833
-		// as the replacement itself is part of the search string
834
-		// which will only be found during the next iteration
835
-		while (strpos($path, '/./') !== false) {
836
-			$path = str_replace('/./', '/', $path);
837
-		}
838
-		// remove sequences of slashes
839
-		$path = preg_replace('#/{2,}#', '/', $path);
840
-
841
-		//remove trailing slash
842
-		if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') {
843
-			$path = substr($path, 0, -1);
844
-		}
845
-
846
-		// remove trailing '/.'
847
-		if (substr($path, -2) == '/.') {
848
-			$path = substr($path, 0, -2);
849
-		}
850
-
851
-		$normalizedPath = $path;
852
-		self::$normalizedPathCache[$cacheKey] = $normalizedPath;
853
-
854
-		return $normalizedPath;
855
-	}
856
-
857
-	/**
858
-	 * get the filesystem info
859
-	 *
860
-	 * @param string $path
861
-	 * @param boolean $includeMountPoints whether to add mountpoint sizes,
862
-	 * defaults to true
863
-	 * @return \OC\Files\FileInfo|bool False if file does not exist
864
-	 */
865
-	public static function getFileInfo($path, $includeMountPoints = true) {
866
-		return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
867
-	}
868
-
869
-	/**
870
-	 * change file metadata
871
-	 *
872
-	 * @param string $path
873
-	 * @param array $data
874
-	 * @return int
875
-	 *
876
-	 * returns the fileid of the updated file
877
-	 */
878
-	public static function putFileInfo($path, $data) {
879
-		return self::$defaultInstance->putFileInfo($path, $data);
880
-	}
881
-
882
-	/**
883
-	 * get the content of a directory
884
-	 *
885
-	 * @param string $directory path under datadirectory
886
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
887
-	 * @return \OC\Files\FileInfo[]
888
-	 */
889
-	public static function getDirectoryContent($directory, $mimetype_filter = '') {
890
-		return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
891
-	}
892
-
893
-	/**
894
-	 * Get the path of a file by id
895
-	 *
896
-	 * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
897
-	 *
898
-	 * @param int $id
899
-	 * @throws NotFoundException
900
-	 * @return string
901
-	 */
902
-	public static function getPath($id) {
903
-		return self::$defaultInstance->getPath($id);
904
-	}
905
-
906
-	/**
907
-	 * Get the owner for a file or folder
908
-	 *
909
-	 * @param string $path
910
-	 * @return string
911
-	 */
912
-	public static function getOwner($path) {
913
-		return self::$defaultInstance->getOwner($path);
914
-	}
915
-
916
-	/**
917
-	 * get the ETag for a file or folder
918
-	 *
919
-	 * @param string $path
920
-	 * @return string
921
-	 */
922
-	static public function getETag($path) {
923
-		return self::$defaultInstance->getETag($path);
924
-	}
72
+    /**
73
+     * @var Mount\Manager $mounts
74
+     */
75
+    private static $mounts;
76
+
77
+    public static $loaded = false;
78
+    /**
79
+     * @var \OC\Files\View $defaultInstance
80
+     */
81
+    static private $defaultInstance;
82
+
83
+    static private $usersSetup = array();
84
+
85
+    static private $normalizedPathCache = null;
86
+
87
+    static private $listeningForProviders = false;
88
+
89
+    /**
90
+     * classname which used for hooks handling
91
+     * used as signalclass in OC_Hooks::emit()
92
+     */
93
+    const CLASSNAME = 'OC_Filesystem';
94
+
95
+    /**
96
+     * signalname emitted before file renaming
97
+     *
98
+     * @param string $oldpath
99
+     * @param string $newpath
100
+     */
101
+    const signal_rename = 'rename';
102
+
103
+    /**
104
+     * signal emitted after file renaming
105
+     *
106
+     * @param string $oldpath
107
+     * @param string $newpath
108
+     */
109
+    const signal_post_rename = 'post_rename';
110
+
111
+    /**
112
+     * signal emitted before file/dir creation
113
+     *
114
+     * @param string $path
115
+     * @param bool $run changing this flag to false in hook handler will cancel event
116
+     */
117
+    const signal_create = 'create';
118
+
119
+    /**
120
+     * signal emitted after file/dir creation
121
+     *
122
+     * @param string $path
123
+     * @param bool $run changing this flag to false in hook handler will cancel event
124
+     */
125
+    const signal_post_create = 'post_create';
126
+
127
+    /**
128
+     * signal emits before file/dir copy
129
+     *
130
+     * @param string $oldpath
131
+     * @param string $newpath
132
+     * @param bool $run changing this flag to false in hook handler will cancel event
133
+     */
134
+    const signal_copy = 'copy';
135
+
136
+    /**
137
+     * signal emits after file/dir copy
138
+     *
139
+     * @param string $oldpath
140
+     * @param string $newpath
141
+     */
142
+    const signal_post_copy = 'post_copy';
143
+
144
+    /**
145
+     * signal emits before file/dir save
146
+     *
147
+     * @param string $path
148
+     * @param bool $run changing this flag to false in hook handler will cancel event
149
+     */
150
+    const signal_write = 'write';
151
+
152
+    /**
153
+     * signal emits after file/dir save
154
+     *
155
+     * @param string $path
156
+     */
157
+    const signal_post_write = 'post_write';
158
+
159
+    /**
160
+     * signal emitted before file/dir update
161
+     *
162
+     * @param string $path
163
+     * @param bool $run changing this flag to false in hook handler will cancel event
164
+     */
165
+    const signal_update = 'update';
166
+
167
+    /**
168
+     * signal emitted after file/dir update
169
+     *
170
+     * @param string $path
171
+     * @param bool $run changing this flag to false in hook handler will cancel event
172
+     */
173
+    const signal_post_update = 'post_update';
174
+
175
+    /**
176
+     * signal emits when reading file/dir
177
+     *
178
+     * @param string $path
179
+     */
180
+    const signal_read = 'read';
181
+
182
+    /**
183
+     * signal emits when removing file/dir
184
+     *
185
+     * @param string $path
186
+     */
187
+    const signal_delete = 'delete';
188
+
189
+    /**
190
+     * parameters definitions for signals
191
+     */
192
+    const signal_param_path = 'path';
193
+    const signal_param_oldpath = 'oldpath';
194
+    const signal_param_newpath = 'newpath';
195
+
196
+    /**
197
+     * run - changing this flag to false in hook handler will cancel event
198
+     */
199
+    const signal_param_run = 'run';
200
+
201
+    const signal_create_mount = 'create_mount';
202
+    const signal_delete_mount = 'delete_mount';
203
+    const signal_param_mount_type = 'mounttype';
204
+    const signal_param_users = 'users';
205
+
206
+    /**
207
+     * @var \OC\Files\Storage\StorageFactory $loader
208
+     */
209
+    private static $loader;
210
+
211
+    /** @var bool */
212
+    private static $logWarningWhenAddingStorageWrapper = true;
213
+
214
+    /**
215
+     * @param bool $shouldLog
216
+     * @return bool previous value
217
+     * @internal
218
+     */
219
+    public static function logWarningWhenAddingStorageWrapper($shouldLog) {
220
+        $previousValue = self::$logWarningWhenAddingStorageWrapper;
221
+        self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
222
+        return $previousValue;
223
+    }
224
+
225
+    /**
226
+     * @param string $wrapperName
227
+     * @param callable $wrapper
228
+     * @param int $priority
229
+     */
230
+    public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
231
+        if (self::$logWarningWhenAddingStorageWrapper) {
232
+            \OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
233
+                'wrapper' => $wrapperName,
234
+                'app' => 'filesystem',
235
+            ]);
236
+        }
237
+
238
+        $mounts = self::getMountManager()->getAll();
239
+        if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
240
+            // do not re-wrap if storage with this name already existed
241
+            return;
242
+        }
243
+    }
244
+
245
+    /**
246
+     * Returns the storage factory
247
+     *
248
+     * @return \OCP\Files\Storage\IStorageFactory
249
+     */
250
+    public static function getLoader() {
251
+        if (!self::$loader) {
252
+            self::$loader = new StorageFactory();
253
+        }
254
+        return self::$loader;
255
+    }
256
+
257
+    /**
258
+     * Returns the mount manager
259
+     *
260
+     * @return \OC\Files\Mount\Manager
261
+     */
262
+    public static function getMountManager($user = '') {
263
+        if (!self::$mounts) {
264
+            \OC_Util::setupFS($user);
265
+        }
266
+        return self::$mounts;
267
+    }
268
+
269
+    /**
270
+     * get the mountpoint of the storage object for a path
271
+     * ( note: because a storage is not always mounted inside the fakeroot, the
272
+     * returned mountpoint is relative to the absolute root of the filesystem
273
+     * and doesn't take the chroot into account )
274
+     *
275
+     * @param string $path
276
+     * @return string
277
+     */
278
+    static public function getMountPoint($path) {
279
+        if (!self::$mounts) {
280
+            \OC_Util::setupFS();
281
+        }
282
+        $mount = self::$mounts->find($path);
283
+        if ($mount) {
284
+            return $mount->getMountPoint();
285
+        } else {
286
+            return '';
287
+        }
288
+    }
289
+
290
+    /**
291
+     * get a list of all mount points in a directory
292
+     *
293
+     * @param string $path
294
+     * @return string[]
295
+     */
296
+    static public function getMountPoints($path) {
297
+        if (!self::$mounts) {
298
+            \OC_Util::setupFS();
299
+        }
300
+        $result = array();
301
+        $mounts = self::$mounts->findIn($path);
302
+        foreach ($mounts as $mount) {
303
+            $result[] = $mount->getMountPoint();
304
+        }
305
+        return $result;
306
+    }
307
+
308
+    /**
309
+     * get the storage mounted at $mountPoint
310
+     *
311
+     * @param string $mountPoint
312
+     * @return \OC\Files\Storage\Storage
313
+     */
314
+    public static function getStorage($mountPoint) {
315
+        if (!self::$mounts) {
316
+            \OC_Util::setupFS();
317
+        }
318
+        $mount = self::$mounts->find($mountPoint);
319
+        return $mount->getStorage();
320
+    }
321
+
322
+    /**
323
+     * @param string $id
324
+     * @return Mount\MountPoint[]
325
+     */
326
+    public static function getMountByStorageId($id) {
327
+        if (!self::$mounts) {
328
+            \OC_Util::setupFS();
329
+        }
330
+        return self::$mounts->findByStorageId($id);
331
+    }
332
+
333
+    /**
334
+     * @param int $id
335
+     * @return Mount\MountPoint[]
336
+     */
337
+    public static function getMountByNumericId($id) {
338
+        if (!self::$mounts) {
339
+            \OC_Util::setupFS();
340
+        }
341
+        return self::$mounts->findByNumericId($id);
342
+    }
343
+
344
+    /**
345
+     * resolve a path to a storage and internal path
346
+     *
347
+     * @param string $path
348
+     * @return array an array consisting of the storage and the internal path
349
+     */
350
+    static public function resolvePath($path) {
351
+        if (!self::$mounts) {
352
+            \OC_Util::setupFS();
353
+        }
354
+        $mount = self::$mounts->find($path);
355
+        if ($mount) {
356
+            return array($mount->getStorage(), rtrim($mount->getInternalPath($path), '/'));
357
+        } else {
358
+            return array(null, null);
359
+        }
360
+    }
361
+
362
+    static public function init($user, $root) {
363
+        if (self::$defaultInstance) {
364
+            return false;
365
+        }
366
+        self::getLoader();
367
+        self::$defaultInstance = new View($root);
368
+
369
+        if (!self::$mounts) {
370
+            self::$mounts = \OC::$server->getMountManager();
371
+        }
372
+
373
+        //load custom mount config
374
+        self::initMountPoints($user);
375
+
376
+        self::$loaded = true;
377
+
378
+        return true;
379
+    }
380
+
381
+    static public function initMountManager() {
382
+        if (!self::$mounts) {
383
+            self::$mounts = \OC::$server->getMountManager();
384
+        }
385
+    }
386
+
387
+    /**
388
+     * Initialize system and personal mount points for a user
389
+     *
390
+     * @param string $user
391
+     * @throws \OC\User\NoUserException if the user is not available
392
+     */
393
+    public static function initMountPoints($user = '') {
394
+        if ($user == '') {
395
+            $user = \OC_User::getUser();
396
+        }
397
+        if ($user === null || $user === false || $user === '') {
398
+            throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
399
+        }
400
+
401
+        if (isset(self::$usersSetup[$user])) {
402
+            return;
403
+        }
404
+
405
+        self::$usersSetup[$user] = true;
406
+
407
+        $userManager = \OC::$server->getUserManager();
408
+        $userObject = $userManager->get($user);
409
+
410
+        if (is_null($userObject)) {
411
+            \OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, \OCP\Util::ERROR);
412
+            // reset flag, this will make it possible to rethrow the exception if called again
413
+            unset(self::$usersSetup[$user]);
414
+            throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
415
+        }
416
+
417
+        $realUid = $userObject->getUID();
418
+        // workaround in case of different casings
419
+        if ($user !== $realUid) {
420
+            $stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50));
421
+            \OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, \OCP\Util::WARN);
422
+            $user = $realUid;
423
+
424
+            // again with the correct casing
425
+            if (isset(self::$usersSetup[$user])) {
426
+                return;
427
+            }
428
+
429
+            self::$usersSetup[$user] = true;
430
+        }
431
+
432
+        if (\OC::$server->getLockdownManager()->canAccessFilesystem()) {
433
+            /** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
434
+            $mountConfigManager = \OC::$server->getMountProviderCollection();
435
+
436
+            // home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
437
+            $homeMount = $mountConfigManager->getHomeMountForUser($userObject);
438
+
439
+            self::getMountManager()->addMount($homeMount);
440
+
441
+            \OC\Files\Filesystem::getStorage($user);
442
+
443
+            // Chance to mount for other storages
444
+            if ($userObject) {
445
+                $mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager());
446
+                $mounts[] = $homeMount;
447
+                $mountConfigManager->registerMounts($userObject, $mounts);
448
+            }
449
+
450
+            self::listenForNewMountProviders($mountConfigManager, $userManager);
451
+        } else {
452
+            self::getMountManager()->addMount(new MountPoint(
453
+                new NullStorage([]),
454
+                '/' . $user
455
+            ));
456
+            self::getMountManager()->addMount(new MountPoint(
457
+                new NullStorage([]),
458
+                '/' . $user . '/files'
459
+            ));
460
+        }
461
+        \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user));
462
+    }
463
+
464
+    /**
465
+     * Get mounts from mount providers that are registered after setup
466
+     *
467
+     * @param MountProviderCollection $mountConfigManager
468
+     * @param IUserManager $userManager
469
+     */
470
+    private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
471
+        if (!self::$listeningForProviders) {
472
+            self::$listeningForProviders = true;
473
+            $mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
474
+                foreach (Filesystem::$usersSetup as $user => $setup) {
475
+                    $userObject = $userManager->get($user);
476
+                    if ($userObject) {
477
+                        $mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
478
+                        array_walk($mounts, array(self::$mounts, 'addMount'));
479
+                    }
480
+                }
481
+            });
482
+        }
483
+    }
484
+
485
+    /**
486
+     * get the default filesystem view
487
+     *
488
+     * @return View
489
+     */
490
+    static public function getView() {
491
+        return self::$defaultInstance;
492
+    }
493
+
494
+    /**
495
+     * tear down the filesystem, removing all storage providers
496
+     */
497
+    static public function tearDown() {
498
+        self::clearMounts();
499
+        self::$defaultInstance = null;
500
+    }
501
+
502
+    /**
503
+     * get the relative path of the root data directory for the current user
504
+     *
505
+     * @return string
506
+     *
507
+     * Returns path like /admin/files
508
+     */
509
+    static public function getRoot() {
510
+        if (!self::$defaultInstance) {
511
+            return null;
512
+        }
513
+        return self::$defaultInstance->getRoot();
514
+    }
515
+
516
+    /**
517
+     * clear all mounts and storage backends
518
+     */
519
+    public static function clearMounts() {
520
+        if (self::$mounts) {
521
+            self::$usersSetup = array();
522
+            self::$mounts->clear();
523
+        }
524
+    }
525
+
526
+    /**
527
+     * mount an \OC\Files\Storage\Storage in our virtual filesystem
528
+     *
529
+     * @param \OC\Files\Storage\Storage|string $class
530
+     * @param array $arguments
531
+     * @param string $mountpoint
532
+     */
533
+    static public function mount($class, $arguments, $mountpoint) {
534
+        if (!self::$mounts) {
535
+            \OC_Util::setupFS();
536
+        }
537
+        $mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
538
+        self::$mounts->addMount($mount);
539
+    }
540
+
541
+    /**
542
+     * return the path to a local version of the file
543
+     * we need this because we can't know if a file is stored local or not from
544
+     * outside the filestorage and for some purposes a local file is needed
545
+     *
546
+     * @param string $path
547
+     * @return string
548
+     */
549
+    static public function getLocalFile($path) {
550
+        return self::$defaultInstance->getLocalFile($path);
551
+    }
552
+
553
+    /**
554
+     * @param string $path
555
+     * @return string
556
+     */
557
+    static public function getLocalFolder($path) {
558
+        return self::$defaultInstance->getLocalFolder($path);
559
+    }
560
+
561
+    /**
562
+     * return path to file which reflects one visible in browser
563
+     *
564
+     * @param string $path
565
+     * @return string
566
+     */
567
+    static public function getLocalPath($path) {
568
+        $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
569
+        $newpath = $path;
570
+        if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
571
+            $newpath = substr($path, strlen($datadir));
572
+        }
573
+        return $newpath;
574
+    }
575
+
576
+    /**
577
+     * check if the requested path is valid
578
+     *
579
+     * @param string $path
580
+     * @return bool
581
+     */
582
+    static public function isValidPath($path) {
583
+        $path = self::normalizePath($path);
584
+        if (!$path || $path[0] !== '/') {
585
+            $path = '/' . $path;
586
+        }
587
+        if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
588
+            return false;
589
+        }
590
+        return true;
591
+    }
592
+
593
+    /**
594
+     * checks if a file is blacklisted for storage in the filesystem
595
+     * Listens to write and rename hooks
596
+     *
597
+     * @param array $data from hook
598
+     */
599
+    static public function isBlacklisted($data) {
600
+        if (isset($data['path'])) {
601
+            $path = $data['path'];
602
+        } else if (isset($data['newpath'])) {
603
+            $path = $data['newpath'];
604
+        }
605
+        if (isset($path)) {
606
+            if (self::isFileBlacklisted($path)) {
607
+                $data['run'] = false;
608
+            }
609
+        }
610
+    }
611
+
612
+    /**
613
+     * @param string $filename
614
+     * @return bool
615
+     */
616
+    static public function isFileBlacklisted($filename) {
617
+        $filename = self::normalizePath($filename);
618
+
619
+        $blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', array('.htaccess'));
620
+        $filename = strtolower(basename($filename));
621
+        return in_array($filename, $blacklist);
622
+    }
623
+
624
+    /**
625
+     * check if the directory should be ignored when scanning
626
+     * NOTE: the special directories . and .. would cause never ending recursion
627
+     *
628
+     * @param String $dir
629
+     * @return boolean
630
+     */
631
+    static public function isIgnoredDir($dir) {
632
+        if ($dir === '.' || $dir === '..') {
633
+            return true;
634
+        }
635
+        return false;
636
+    }
637
+
638
+    /**
639
+     * following functions are equivalent to their php builtin equivalents for arguments/return values.
640
+     */
641
+    static public function mkdir($path) {
642
+        return self::$defaultInstance->mkdir($path);
643
+    }
644
+
645
+    static public function rmdir($path) {
646
+        return self::$defaultInstance->rmdir($path);
647
+    }
648
+
649
+    static public function is_dir($path) {
650
+        return self::$defaultInstance->is_dir($path);
651
+    }
652
+
653
+    static public function is_file($path) {
654
+        return self::$defaultInstance->is_file($path);
655
+    }
656
+
657
+    static public function stat($path) {
658
+        return self::$defaultInstance->stat($path);
659
+    }
660
+
661
+    static public function filetype($path) {
662
+        return self::$defaultInstance->filetype($path);
663
+    }
664
+
665
+    static public function filesize($path) {
666
+        return self::$defaultInstance->filesize($path);
667
+    }
668
+
669
+    static public function readfile($path) {
670
+        return self::$defaultInstance->readfile($path);
671
+    }
672
+
673
+    static public function isCreatable($path) {
674
+        return self::$defaultInstance->isCreatable($path);
675
+    }
676
+
677
+    static public function isReadable($path) {
678
+        return self::$defaultInstance->isReadable($path);
679
+    }
680
+
681
+    static public function isUpdatable($path) {
682
+        return self::$defaultInstance->isUpdatable($path);
683
+    }
684
+
685
+    static public function isDeletable($path) {
686
+        return self::$defaultInstance->isDeletable($path);
687
+    }
688
+
689
+    static public function isSharable($path) {
690
+        return self::$defaultInstance->isSharable($path);
691
+    }
692
+
693
+    static public function file_exists($path) {
694
+        return self::$defaultInstance->file_exists($path);
695
+    }
696
+
697
+    static public function filemtime($path) {
698
+        return self::$defaultInstance->filemtime($path);
699
+    }
700
+
701
+    static public function touch($path, $mtime = null) {
702
+        return self::$defaultInstance->touch($path, $mtime);
703
+    }
704
+
705
+    /**
706
+     * @return string
707
+     */
708
+    static public function file_get_contents($path) {
709
+        return self::$defaultInstance->file_get_contents($path);
710
+    }
711
+
712
+    static public function file_put_contents($path, $data) {
713
+        return self::$defaultInstance->file_put_contents($path, $data);
714
+    }
715
+
716
+    static public function unlink($path) {
717
+        return self::$defaultInstance->unlink($path);
718
+    }
719
+
720
+    static public function rename($path1, $path2) {
721
+        return self::$defaultInstance->rename($path1, $path2);
722
+    }
723
+
724
+    static public function copy($path1, $path2) {
725
+        return self::$defaultInstance->copy($path1, $path2);
726
+    }
727
+
728
+    static public function fopen($path, $mode) {
729
+        return self::$defaultInstance->fopen($path, $mode);
730
+    }
731
+
732
+    /**
733
+     * @return string
734
+     */
735
+    static public function toTmpFile($path) {
736
+        return self::$defaultInstance->toTmpFile($path);
737
+    }
738
+
739
+    static public function fromTmpFile($tmpFile, $path) {
740
+        return self::$defaultInstance->fromTmpFile($tmpFile, $path);
741
+    }
742
+
743
+    static public function getMimeType($path) {
744
+        return self::$defaultInstance->getMimeType($path);
745
+    }
746
+
747
+    static public function hash($type, $path, $raw = false) {
748
+        return self::$defaultInstance->hash($type, $path, $raw);
749
+    }
750
+
751
+    static public function free_space($path = '/') {
752
+        return self::$defaultInstance->free_space($path);
753
+    }
754
+
755
+    static public function search($query) {
756
+        return self::$defaultInstance->search($query);
757
+    }
758
+
759
+    /**
760
+     * @param string $query
761
+     */
762
+    static public function searchByMime($query) {
763
+        return self::$defaultInstance->searchByMime($query);
764
+    }
765
+
766
+    /**
767
+     * @param string|int $tag name or tag id
768
+     * @param string $userId owner of the tags
769
+     * @return FileInfo[] array or file info
770
+     */
771
+    static public function searchByTag($tag, $userId) {
772
+        return self::$defaultInstance->searchByTag($tag, $userId);
773
+    }
774
+
775
+    /**
776
+     * check if a file or folder has been updated since $time
777
+     *
778
+     * @param string $path
779
+     * @param int $time
780
+     * @return bool
781
+     */
782
+    static public function hasUpdated($path, $time) {
783
+        return self::$defaultInstance->hasUpdated($path, $time);
784
+    }
785
+
786
+    /**
787
+     * Fix common problems with a file path
788
+     *
789
+     * @param string $path
790
+     * @param bool $stripTrailingSlash whether to strip the trailing slash
791
+     * @param bool $isAbsolutePath whether the given path is absolute
792
+     * @param bool $keepUnicode true to disable unicode normalization
793
+     * @return string
794
+     */
795
+    public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
796
+        if (is_null(self::$normalizedPathCache)) {
797
+            self::$normalizedPathCache = new CappedMemoryCache();
798
+        }
799
+
800
+        /**
801
+         * FIXME: This is a workaround for existing classes and files which call
802
+         *        this function with another type than a valid string. This
803
+         *        conversion should get removed as soon as all existing
804
+         *        function calls have been fixed.
805
+         */
806
+        $path = (string)$path;
807
+
808
+        $cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
809
+
810
+        if (isset(self::$normalizedPathCache[$cacheKey])) {
811
+            return self::$normalizedPathCache[$cacheKey];
812
+        }
813
+
814
+        if ($path == '') {
815
+            return '/';
816
+        }
817
+
818
+        //normalize unicode if possible
819
+        if (!$keepUnicode) {
820
+            $path = \OC_Util::normalizeUnicode($path);
821
+        }
822
+
823
+        //no windows style slashes
824
+        $path = str_replace('\\', '/', $path);
825
+
826
+        //add leading slash
827
+        if ($path[0] !== '/') {
828
+            $path = '/' . $path;
829
+        }
830
+
831
+        // remove '/./'
832
+        // ugly, but str_replace() can't replace them all in one go
833
+        // as the replacement itself is part of the search string
834
+        // which will only be found during the next iteration
835
+        while (strpos($path, '/./') !== false) {
836
+            $path = str_replace('/./', '/', $path);
837
+        }
838
+        // remove sequences of slashes
839
+        $path = preg_replace('#/{2,}#', '/', $path);
840
+
841
+        //remove trailing slash
842
+        if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') {
843
+            $path = substr($path, 0, -1);
844
+        }
845
+
846
+        // remove trailing '/.'
847
+        if (substr($path, -2) == '/.') {
848
+            $path = substr($path, 0, -2);
849
+        }
850
+
851
+        $normalizedPath = $path;
852
+        self::$normalizedPathCache[$cacheKey] = $normalizedPath;
853
+
854
+        return $normalizedPath;
855
+    }
856
+
857
+    /**
858
+     * get the filesystem info
859
+     *
860
+     * @param string $path
861
+     * @param boolean $includeMountPoints whether to add mountpoint sizes,
862
+     * defaults to true
863
+     * @return \OC\Files\FileInfo|bool False if file does not exist
864
+     */
865
+    public static function getFileInfo($path, $includeMountPoints = true) {
866
+        return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
867
+    }
868
+
869
+    /**
870
+     * change file metadata
871
+     *
872
+     * @param string $path
873
+     * @param array $data
874
+     * @return int
875
+     *
876
+     * returns the fileid of the updated file
877
+     */
878
+    public static function putFileInfo($path, $data) {
879
+        return self::$defaultInstance->putFileInfo($path, $data);
880
+    }
881
+
882
+    /**
883
+     * get the content of a directory
884
+     *
885
+     * @param string $directory path under datadirectory
886
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
887
+     * @return \OC\Files\FileInfo[]
888
+     */
889
+    public static function getDirectoryContent($directory, $mimetype_filter = '') {
890
+        return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
891
+    }
892
+
893
+    /**
894
+     * Get the path of a file by id
895
+     *
896
+     * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
897
+     *
898
+     * @param int $id
899
+     * @throws NotFoundException
900
+     * @return string
901
+     */
902
+    public static function getPath($id) {
903
+        return self::$defaultInstance->getPath($id);
904
+    }
905
+
906
+    /**
907
+     * Get the owner for a file or folder
908
+     *
909
+     * @param string $path
910
+     * @return string
911
+     */
912
+    public static function getOwner($path) {
913
+        return self::$defaultInstance->getOwner($path);
914
+    }
915
+
916
+    /**
917
+     * get the ETag for a file or folder
918
+     *
919
+     * @param string $path
920
+     * @return string
921
+     */
922
+    static public function getETag($path) {
923
+        return self::$defaultInstance->getETag($path);
924
+    }
925 925
 }
Please login to merge, or discard this patch.