Completed
Pull Request — master (#9293)
by Blizzz
20:13
created
apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php 1 patch
Indentation   +76 added lines, -76 removed lines patch added patch discarded remove patch
@@ -40,87 +40,87 @@
 block discarded – undo
40 40
 use Sabre\DAV\Exception\ServiceUnavailable;
41 41
 
42 42
 class ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin {
43
-	protected $nonFatalExceptions = [
44
-		NotAuthenticated::class => true,
45
-		// If tokenauth can throw this exception (which is basically as
46
-		// NotAuthenticated. So not fatal.
47
-		PasswordLoginForbidden::class => true,
48
-		// basically a NotAuthenticated
49
-		InvalidSyncToken::class => true,
50
-		// the sync client uses this to find out whether files exist,
51
-		// so it is not always an error, log it as debug
52
-		NotFound::class => true,
53
-		// this one mostly happens when the same file is uploaded at
54
-		// exactly the same time from two clients, only one client
55
-		// wins, the second one gets "Precondition failed"
56
-		PreconditionFailed::class => true,
57
-		// forbidden can be expected when trying to upload to
58
-		// read-only folders for example
59
-		Forbidden::class => true,
60
-		// Happens when an external storage or federated share is temporarily
61
-		// not available
62
-		StorageNotAvailableException::class => true,
63
-		// happens if some a client uses the wrong method for a given URL
64
-		// the error message itself is visible on the client side anyways
65
-		NotImplemented::class => true,
66
-		// happens when the parent directory is not present (for example when a
67
-		// move is done to a non-existent directory)
68
-		Conflict::class => true,
69
-		// happens when a certain method is not allowed to be called
70
-		// for example creating a folder that already exists
71
-		MethodNotAllowed::class => true,
72
-	];
43
+    protected $nonFatalExceptions = [
44
+        NotAuthenticated::class => true,
45
+        // If tokenauth can throw this exception (which is basically as
46
+        // NotAuthenticated. So not fatal.
47
+        PasswordLoginForbidden::class => true,
48
+        // basically a NotAuthenticated
49
+        InvalidSyncToken::class => true,
50
+        // the sync client uses this to find out whether files exist,
51
+        // so it is not always an error, log it as debug
52
+        NotFound::class => true,
53
+        // this one mostly happens when the same file is uploaded at
54
+        // exactly the same time from two clients, only one client
55
+        // wins, the second one gets "Precondition failed"
56
+        PreconditionFailed::class => true,
57
+        // forbidden can be expected when trying to upload to
58
+        // read-only folders for example
59
+        Forbidden::class => true,
60
+        // Happens when an external storage or federated share is temporarily
61
+        // not available
62
+        StorageNotAvailableException::class => true,
63
+        // happens if some a client uses the wrong method for a given URL
64
+        // the error message itself is visible on the client side anyways
65
+        NotImplemented::class => true,
66
+        // happens when the parent directory is not present (for example when a
67
+        // move is done to a non-existent directory)
68
+        Conflict::class => true,
69
+        // happens when a certain method is not allowed to be called
70
+        // for example creating a folder that already exists
71
+        MethodNotAllowed::class => true,
72
+    ];
73 73
 
74
-	/** @var string */
75
-	private $appName;
74
+    /** @var string */
75
+    private $appName;
76 76
 
77
-	/** @var ILogger */
78
-	private $logger;
77
+    /** @var ILogger */
78
+    private $logger;
79 79
 
80
-	/**
81
-	 * @param string $loggerAppName app name to use when logging
82
-	 * @param ILogger $logger
83
-	 */
84
-	public function __construct($loggerAppName, $logger) {
85
-		$this->appName = $loggerAppName;
86
-		$this->logger = $logger;
87
-	}
80
+    /**
81
+     * @param string $loggerAppName app name to use when logging
82
+     * @param ILogger $logger
83
+     */
84
+    public function __construct($loggerAppName, $logger) {
85
+        $this->appName = $loggerAppName;
86
+        $this->logger = $logger;
87
+    }
88 88
 
89
-	/**
90
-	 * This initializes the plugin.
91
-	 *
92
-	 * This function is called by \Sabre\DAV\Server, after
93
-	 * addPlugin is called.
94
-	 *
95
-	 * This method should set up the required event subscriptions.
96
-	 *
97
-	 * @param \Sabre\DAV\Server $server
98
-	 * @return void
99
-	 */
100
-	public function initialize(\Sabre\DAV\Server $server) {
89
+    /**
90
+     * This initializes the plugin.
91
+     *
92
+     * This function is called by \Sabre\DAV\Server, after
93
+     * addPlugin is called.
94
+     *
95
+     * This method should set up the required event subscriptions.
96
+     *
97
+     * @param \Sabre\DAV\Server $server
98
+     * @return void
99
+     */
100
+    public function initialize(\Sabre\DAV\Server $server) {
101 101
 
102
-		$server->on('exception', array($this, 'logException'), 10);
103
-	}
102
+        $server->on('exception', array($this, 'logException'), 10);
103
+    }
104 104
 
105
-	/**
106
-	 * Log exception
107
-	 *
108
-	 */
109
-	public function logException(\Exception $ex) {
110
-		$exceptionClass = get_class($ex);
111
-		$level = ILogger::FATAL;
112
-		if (isset($this->nonFatalExceptions[$exceptionClass]) ||
113
-			(
114
-				$exceptionClass === ServiceUnavailable::class &&
115
-				$ex->getMessage() === 'System in maintenance mode.'
116
-			)
117
-		) {
118
-			$level = ILogger::DEBUG;
119
-		}
105
+    /**
106
+     * Log exception
107
+     *
108
+     */
109
+    public function logException(\Exception $ex) {
110
+        $exceptionClass = get_class($ex);
111
+        $level = ILogger::FATAL;
112
+        if (isset($this->nonFatalExceptions[$exceptionClass]) ||
113
+            (
114
+                $exceptionClass === ServiceUnavailable::class &&
115
+                $ex->getMessage() === 'System in maintenance mode.'
116
+            )
117
+        ) {
118
+            $level = ILogger::DEBUG;
119
+        }
120 120
 
121
-		$this->logger->logException($ex, [
122
-			'app' => $this->appName,
123
-			'level' => $level,
124
-		]);
125
-	}
121
+        $this->logger->logException($ex, [
122
+            'app' => $this->appName,
123
+            'level' => $level,
124
+        ]);
125
+    }
126 126
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/lib/FederatedShareProvider.php 1 patch
Indentation   +975 added lines, -975 removed lines patch added patch discarded remove patch
@@ -53,989 +53,989 @@
 block discarded – undo
53 53
  */
54 54
 class FederatedShareProvider implements IShareProvider {
55 55
 
56
-	const SHARE_TYPE_REMOTE = 6;
57
-
58
-	/** @var IDBConnection */
59
-	private $dbConnection;
60
-
61
-	/** @var AddressHandler */
62
-	private $addressHandler;
63
-
64
-	/** @var Notifications */
65
-	private $notifications;
66
-
67
-	/** @var TokenHandler */
68
-	private $tokenHandler;
69
-
70
-	/** @var IL10N */
71
-	private $l;
72
-
73
-	/** @var ILogger */
74
-	private $logger;
75
-
76
-	/** @var IRootFolder */
77
-	private $rootFolder;
78
-
79
-	/** @var IConfig */
80
-	private $config;
81
-
82
-	/** @var string */
83
-	private $externalShareTable = 'share_external';
84
-
85
-	/** @var IUserManager */
86
-	private $userManager;
87
-
88
-	/** @var ICloudIdManager */
89
-	private $cloudIdManager;
90
-
91
-	/** @var \OCP\GlobalScale\IConfig */
92
-	private $gsConfig;
93
-
94
-	/**
95
-	 * DefaultShareProvider constructor.
96
-	 *
97
-	 * @param IDBConnection $connection
98
-	 * @param AddressHandler $addressHandler
99
-	 * @param Notifications $notifications
100
-	 * @param TokenHandler $tokenHandler
101
-	 * @param IL10N $l10n
102
-	 * @param ILogger $logger
103
-	 * @param IRootFolder $rootFolder
104
-	 * @param IConfig $config
105
-	 * @param IUserManager $userManager
106
-	 * @param ICloudIdManager $cloudIdManager
107
-	 * @param \OCP\GlobalScale\IConfig $globalScaleConfig
108
-	 */
109
-	public function __construct(
110
-			IDBConnection $connection,
111
-			AddressHandler $addressHandler,
112
-			Notifications $notifications,
113
-			TokenHandler $tokenHandler,
114
-			IL10N $l10n,
115
-			ILogger $logger,
116
-			IRootFolder $rootFolder,
117
-			IConfig $config,
118
-			IUserManager $userManager,
119
-			ICloudIdManager $cloudIdManager,
120
-			\OCP\GlobalScale\IConfig $globalScaleConfig
121
-	) {
122
-		$this->dbConnection = $connection;
123
-		$this->addressHandler = $addressHandler;
124
-		$this->notifications = $notifications;
125
-		$this->tokenHandler = $tokenHandler;
126
-		$this->l = $l10n;
127
-		$this->logger = $logger;
128
-		$this->rootFolder = $rootFolder;
129
-		$this->config = $config;
130
-		$this->userManager = $userManager;
131
-		$this->cloudIdManager = $cloudIdManager;
132
-		$this->gsConfig = $globalScaleConfig;
133
-	}
134
-
135
-	/**
136
-	 * Return the identifier of this provider.
137
-	 *
138
-	 * @return string Containing only [a-zA-Z0-9]
139
-	 */
140
-	public function identifier() {
141
-		return 'ocFederatedSharing';
142
-	}
143
-
144
-	/**
145
-	 * Share a path
146
-	 *
147
-	 * @param IShare $share
148
-	 * @return IShare The share object
149
-	 * @throws ShareNotFound
150
-	 * @throws \Exception
151
-	 */
152
-	public function create(IShare $share) {
153
-
154
-		$shareWith = $share->getSharedWith();
155
-		$itemSource = $share->getNodeId();
156
-		$itemType = $share->getNodeType();
157
-		$permissions = $share->getPermissions();
158
-		$sharedBy = $share->getSharedBy();
159
-
160
-		/*
56
+    const SHARE_TYPE_REMOTE = 6;
57
+
58
+    /** @var IDBConnection */
59
+    private $dbConnection;
60
+
61
+    /** @var AddressHandler */
62
+    private $addressHandler;
63
+
64
+    /** @var Notifications */
65
+    private $notifications;
66
+
67
+    /** @var TokenHandler */
68
+    private $tokenHandler;
69
+
70
+    /** @var IL10N */
71
+    private $l;
72
+
73
+    /** @var ILogger */
74
+    private $logger;
75
+
76
+    /** @var IRootFolder */
77
+    private $rootFolder;
78
+
79
+    /** @var IConfig */
80
+    private $config;
81
+
82
+    /** @var string */
83
+    private $externalShareTable = 'share_external';
84
+
85
+    /** @var IUserManager */
86
+    private $userManager;
87
+
88
+    /** @var ICloudIdManager */
89
+    private $cloudIdManager;
90
+
91
+    /** @var \OCP\GlobalScale\IConfig */
92
+    private $gsConfig;
93
+
94
+    /**
95
+     * DefaultShareProvider constructor.
96
+     *
97
+     * @param IDBConnection $connection
98
+     * @param AddressHandler $addressHandler
99
+     * @param Notifications $notifications
100
+     * @param TokenHandler $tokenHandler
101
+     * @param IL10N $l10n
102
+     * @param ILogger $logger
103
+     * @param IRootFolder $rootFolder
104
+     * @param IConfig $config
105
+     * @param IUserManager $userManager
106
+     * @param ICloudIdManager $cloudIdManager
107
+     * @param \OCP\GlobalScale\IConfig $globalScaleConfig
108
+     */
109
+    public function __construct(
110
+            IDBConnection $connection,
111
+            AddressHandler $addressHandler,
112
+            Notifications $notifications,
113
+            TokenHandler $tokenHandler,
114
+            IL10N $l10n,
115
+            ILogger $logger,
116
+            IRootFolder $rootFolder,
117
+            IConfig $config,
118
+            IUserManager $userManager,
119
+            ICloudIdManager $cloudIdManager,
120
+            \OCP\GlobalScale\IConfig $globalScaleConfig
121
+    ) {
122
+        $this->dbConnection = $connection;
123
+        $this->addressHandler = $addressHandler;
124
+        $this->notifications = $notifications;
125
+        $this->tokenHandler = $tokenHandler;
126
+        $this->l = $l10n;
127
+        $this->logger = $logger;
128
+        $this->rootFolder = $rootFolder;
129
+        $this->config = $config;
130
+        $this->userManager = $userManager;
131
+        $this->cloudIdManager = $cloudIdManager;
132
+        $this->gsConfig = $globalScaleConfig;
133
+    }
134
+
135
+    /**
136
+     * Return the identifier of this provider.
137
+     *
138
+     * @return string Containing only [a-zA-Z0-9]
139
+     */
140
+    public function identifier() {
141
+        return 'ocFederatedSharing';
142
+    }
143
+
144
+    /**
145
+     * Share a path
146
+     *
147
+     * @param IShare $share
148
+     * @return IShare The share object
149
+     * @throws ShareNotFound
150
+     * @throws \Exception
151
+     */
152
+    public function create(IShare $share) {
153
+
154
+        $shareWith = $share->getSharedWith();
155
+        $itemSource = $share->getNodeId();
156
+        $itemType = $share->getNodeType();
157
+        $permissions = $share->getPermissions();
158
+        $sharedBy = $share->getSharedBy();
159
+
160
+        /*
161 161
 		 * Check if file is not already shared with the remote user
162 162
 		 */
163
-		$alreadyShared = $this->getSharedWith($shareWith, self::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0);
164
-		if (!empty($alreadyShared)) {
165
-			$message = 'Sharing %s failed, because this item is already shared with %s';
166
-			$message_t = $this->l->t('Sharing %s failed, because this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
167
-			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
168
-			throw new \Exception($message_t);
169
-		}
170
-
171
-
172
-		// don't allow federated shares if source and target server are the same
173
-		$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
174
-		$currentServer = $this->addressHandler->generateRemoteURL();
175
-		$currentUser = $sharedBy;
176
-		if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
177
-			$message = 'Not allowed to create a federated share with the same user.';
178
-			$message_t = $this->l->t('Not allowed to create a federated share with the same user');
179
-			$this->logger->debug($message, ['app' => 'Federated File Sharing']);
180
-			throw new \Exception($message_t);
181
-		}
182
-
183
-
184
-		$share->setSharedWith($cloudId->getId());
185
-
186
-		try {
187
-			$remoteShare = $this->getShareFromExternalShareTable($share);
188
-		} catch (ShareNotFound $e) {
189
-			$remoteShare = null;
190
-		}
191
-
192
-		if ($remoteShare) {
193
-			try {
194
-				$ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
195
-				$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time());
196
-				$share->setId($shareId);
197
-				list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
198
-				// remote share was create successfully if we get a valid token as return
199
-				$send = is_string($token) && $token !== '';
200
-			} catch (\Exception $e) {
201
-				// fall back to old re-share behavior if the remote server
202
-				// doesn't support flat re-shares (was introduced with Nextcloud 9.1)
203
-				$this->removeShareFromTable($share);
204
-				$shareId = $this->createFederatedShare($share);
205
-			}
206
-			if ($send) {
207
-				$this->updateSuccessfulReshare($shareId, $token);
208
-				$this->storeRemoteId($shareId, $remoteId);
209
-			} else {
210
-				$this->removeShareFromTable($share);
211
-				$message_t = $this->l->t('File is already shared with %s', [$shareWith]);
212
-				throw new \Exception($message_t);
213
-			}
214
-
215
-		} else {
216
-			$shareId = $this->createFederatedShare($share);
217
-		}
218
-
219
-		$data = $this->getRawShare($shareId);
220
-		return $this->createShareObject($data);
221
-	}
222
-
223
-	/**
224
-	 * create federated share and inform the recipient
225
-	 *
226
-	 * @param IShare $share
227
-	 * @return int
228
-	 * @throws ShareNotFound
229
-	 * @throws \Exception
230
-	 */
231
-	protected function createFederatedShare(IShare $share) {
232
-		$token = $this->tokenHandler->generateToken();
233
-		$shareId = $this->addShareToDB(
234
-			$share->getNodeId(),
235
-			$share->getNodeType(),
236
-			$share->getSharedWith(),
237
-			$share->getSharedBy(),
238
-			$share->getShareOwner(),
239
-			$share->getPermissions(),
240
-			$token
241
-		);
242
-
243
-		$failure = false;
244
-
245
-		try {
246
-			$sharedByFederatedId = $share->getSharedBy();
247
-			if ($this->userManager->userExists($sharedByFederatedId)) {
248
-				$cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
249
-				$sharedByFederatedId = $cloudId->getId();
250
-			}
251
-			$ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
252
-			$send = $this->notifications->sendRemoteShare(
253
-				$token,
254
-				$share->getSharedWith(),
255
-				$share->getNode()->getName(),
256
-				$shareId,
257
-				$share->getShareOwner(),
258
-				$ownerCloudId->getId(),
259
-				$share->getSharedBy(),
260
-				$sharedByFederatedId
261
-			);
262
-
263
-			if ($send === false) {
264
-				$failure = true;
265
-			}
266
-		} catch (\Exception $e) {
267
-			$this->logger->logException($e, [
268
-				'message' => 'Failed to notify remote server of federated share, removing share.',
269
-				'level' => ILogger::ERROR,
270
-				'app' => 'federatedfilesharing',
271
-			]);
272
-			$failure = true;
273
-		}
274
-
275
-		if($failure) {
276
-			$this->removeShareFromTableById($shareId);
277
-			$message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable or uses a self-signed certificate.',
278
-				[$share->getNode()->getName(), $share->getSharedWith()]);
279
-			throw new \Exception($message_t);
280
-		}
281
-
282
-		return $shareId;
283
-
284
-	}
285
-
286
-	/**
287
-	 * @param string $shareWith
288
-	 * @param IShare $share
289
-	 * @param string $shareId internal share Id
290
-	 * @return array
291
-	 * @throws \Exception
292
-	 */
293
-	protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
294
-
295
-		$remoteShare = $this->getShareFromExternalShareTable($share);
296
-		$token = $remoteShare['share_token'];
297
-		$remoteId = $remoteShare['remote_id'];
298
-		$remote = $remoteShare['remote'];
299
-
300
-		list($token, $remoteId) = $this->notifications->requestReShare(
301
-			$token,
302
-			$remoteId,
303
-			$shareId,
304
-			$remote,
305
-			$shareWith,
306
-			$share->getPermissions()
307
-		);
308
-
309
-		return [$token, $remoteId];
310
-	}
311
-
312
-	/**
313
-	 * get federated share from the share_external table but exclude mounted link shares
314
-	 *
315
-	 * @param IShare $share
316
-	 * @return array
317
-	 * @throws ShareNotFound
318
-	 */
319
-	protected function getShareFromExternalShareTable(IShare $share) {
320
-		$query = $this->dbConnection->getQueryBuilder();
321
-		$query->select('*')->from($this->externalShareTable)
322
-			->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
323
-			->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
324
-		$result = $query->execute()->fetchAll();
325
-
326
-		if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
327
-			return $result[0];
328
-		}
329
-
330
-		throw new ShareNotFound('share not found in share_external table');
331
-	}
332
-
333
-	/**
334
-	 * add share to the database and return the ID
335
-	 *
336
-	 * @param int $itemSource
337
-	 * @param string $itemType
338
-	 * @param string $shareWith
339
-	 * @param string $sharedBy
340
-	 * @param string $uidOwner
341
-	 * @param int $permissions
342
-	 * @param string $token
343
-	 * @return int
344
-	 */
345
-	private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token) {
346
-		$qb = $this->dbConnection->getQueryBuilder();
347
-		$qb->insert('share')
348
-			->setValue('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))
349
-			->setValue('item_type', $qb->createNamedParameter($itemType))
350
-			->setValue('item_source', $qb->createNamedParameter($itemSource))
351
-			->setValue('file_source', $qb->createNamedParameter($itemSource))
352
-			->setValue('share_with', $qb->createNamedParameter($shareWith))
353
-			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
354
-			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
355
-			->setValue('permissions', $qb->createNamedParameter($permissions))
356
-			->setValue('token', $qb->createNamedParameter($token))
357
-			->setValue('stime', $qb->createNamedParameter(time()));
358
-
359
-		/*
163
+        $alreadyShared = $this->getSharedWith($shareWith, self::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0);
164
+        if (!empty($alreadyShared)) {
165
+            $message = 'Sharing %s failed, because this item is already shared with %s';
166
+            $message_t = $this->l->t('Sharing %s failed, because this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
167
+            $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
168
+            throw new \Exception($message_t);
169
+        }
170
+
171
+
172
+        // don't allow federated shares if source and target server are the same
173
+        $cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
174
+        $currentServer = $this->addressHandler->generateRemoteURL();
175
+        $currentUser = $sharedBy;
176
+        if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
177
+            $message = 'Not allowed to create a federated share with the same user.';
178
+            $message_t = $this->l->t('Not allowed to create a federated share with the same user');
179
+            $this->logger->debug($message, ['app' => 'Federated File Sharing']);
180
+            throw new \Exception($message_t);
181
+        }
182
+
183
+
184
+        $share->setSharedWith($cloudId->getId());
185
+
186
+        try {
187
+            $remoteShare = $this->getShareFromExternalShareTable($share);
188
+        } catch (ShareNotFound $e) {
189
+            $remoteShare = null;
190
+        }
191
+
192
+        if ($remoteShare) {
193
+            try {
194
+                $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
195
+                $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time());
196
+                $share->setId($shareId);
197
+                list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
198
+                // remote share was create successfully if we get a valid token as return
199
+                $send = is_string($token) && $token !== '';
200
+            } catch (\Exception $e) {
201
+                // fall back to old re-share behavior if the remote server
202
+                // doesn't support flat re-shares (was introduced with Nextcloud 9.1)
203
+                $this->removeShareFromTable($share);
204
+                $shareId = $this->createFederatedShare($share);
205
+            }
206
+            if ($send) {
207
+                $this->updateSuccessfulReshare($shareId, $token);
208
+                $this->storeRemoteId($shareId, $remoteId);
209
+            } else {
210
+                $this->removeShareFromTable($share);
211
+                $message_t = $this->l->t('File is already shared with %s', [$shareWith]);
212
+                throw new \Exception($message_t);
213
+            }
214
+
215
+        } else {
216
+            $shareId = $this->createFederatedShare($share);
217
+        }
218
+
219
+        $data = $this->getRawShare($shareId);
220
+        return $this->createShareObject($data);
221
+    }
222
+
223
+    /**
224
+     * create federated share and inform the recipient
225
+     *
226
+     * @param IShare $share
227
+     * @return int
228
+     * @throws ShareNotFound
229
+     * @throws \Exception
230
+     */
231
+    protected function createFederatedShare(IShare $share) {
232
+        $token = $this->tokenHandler->generateToken();
233
+        $shareId = $this->addShareToDB(
234
+            $share->getNodeId(),
235
+            $share->getNodeType(),
236
+            $share->getSharedWith(),
237
+            $share->getSharedBy(),
238
+            $share->getShareOwner(),
239
+            $share->getPermissions(),
240
+            $token
241
+        );
242
+
243
+        $failure = false;
244
+
245
+        try {
246
+            $sharedByFederatedId = $share->getSharedBy();
247
+            if ($this->userManager->userExists($sharedByFederatedId)) {
248
+                $cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
249
+                $sharedByFederatedId = $cloudId->getId();
250
+            }
251
+            $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
252
+            $send = $this->notifications->sendRemoteShare(
253
+                $token,
254
+                $share->getSharedWith(),
255
+                $share->getNode()->getName(),
256
+                $shareId,
257
+                $share->getShareOwner(),
258
+                $ownerCloudId->getId(),
259
+                $share->getSharedBy(),
260
+                $sharedByFederatedId
261
+            );
262
+
263
+            if ($send === false) {
264
+                $failure = true;
265
+            }
266
+        } catch (\Exception $e) {
267
+            $this->logger->logException($e, [
268
+                'message' => 'Failed to notify remote server of federated share, removing share.',
269
+                'level' => ILogger::ERROR,
270
+                'app' => 'federatedfilesharing',
271
+            ]);
272
+            $failure = true;
273
+        }
274
+
275
+        if($failure) {
276
+            $this->removeShareFromTableById($shareId);
277
+            $message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable or uses a self-signed certificate.',
278
+                [$share->getNode()->getName(), $share->getSharedWith()]);
279
+            throw new \Exception($message_t);
280
+        }
281
+
282
+        return $shareId;
283
+
284
+    }
285
+
286
+    /**
287
+     * @param string $shareWith
288
+     * @param IShare $share
289
+     * @param string $shareId internal share Id
290
+     * @return array
291
+     * @throws \Exception
292
+     */
293
+    protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
294
+
295
+        $remoteShare = $this->getShareFromExternalShareTable($share);
296
+        $token = $remoteShare['share_token'];
297
+        $remoteId = $remoteShare['remote_id'];
298
+        $remote = $remoteShare['remote'];
299
+
300
+        list($token, $remoteId) = $this->notifications->requestReShare(
301
+            $token,
302
+            $remoteId,
303
+            $shareId,
304
+            $remote,
305
+            $shareWith,
306
+            $share->getPermissions()
307
+        );
308
+
309
+        return [$token, $remoteId];
310
+    }
311
+
312
+    /**
313
+     * get federated share from the share_external table but exclude mounted link shares
314
+     *
315
+     * @param IShare $share
316
+     * @return array
317
+     * @throws ShareNotFound
318
+     */
319
+    protected function getShareFromExternalShareTable(IShare $share) {
320
+        $query = $this->dbConnection->getQueryBuilder();
321
+        $query->select('*')->from($this->externalShareTable)
322
+            ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
323
+            ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
324
+        $result = $query->execute()->fetchAll();
325
+
326
+        if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
327
+            return $result[0];
328
+        }
329
+
330
+        throw new ShareNotFound('share not found in share_external table');
331
+    }
332
+
333
+    /**
334
+     * add share to the database and return the ID
335
+     *
336
+     * @param int $itemSource
337
+     * @param string $itemType
338
+     * @param string $shareWith
339
+     * @param string $sharedBy
340
+     * @param string $uidOwner
341
+     * @param int $permissions
342
+     * @param string $token
343
+     * @return int
344
+     */
345
+    private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token) {
346
+        $qb = $this->dbConnection->getQueryBuilder();
347
+        $qb->insert('share')
348
+            ->setValue('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE))
349
+            ->setValue('item_type', $qb->createNamedParameter($itemType))
350
+            ->setValue('item_source', $qb->createNamedParameter($itemSource))
351
+            ->setValue('file_source', $qb->createNamedParameter($itemSource))
352
+            ->setValue('share_with', $qb->createNamedParameter($shareWith))
353
+            ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
354
+            ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
355
+            ->setValue('permissions', $qb->createNamedParameter($permissions))
356
+            ->setValue('token', $qb->createNamedParameter($token))
357
+            ->setValue('stime', $qb->createNamedParameter(time()));
358
+
359
+        /*
360 360
 		 * Added to fix https://github.com/owncloud/core/issues/22215
361 361
 		 * Can be removed once we get rid of ajax/share.php
362 362
 		 */
363
-		$qb->setValue('file_target', $qb->createNamedParameter(''));
364
-
365
-		$qb->execute();
366
-		$id = $qb->getLastInsertId();
367
-
368
-		return (int)$id;
369
-	}
370
-
371
-	/**
372
-	 * Update a share
373
-	 *
374
-	 * @param IShare $share
375
-	 * @return IShare The share object
376
-	 */
377
-	public function update(IShare $share) {
378
-		/*
363
+        $qb->setValue('file_target', $qb->createNamedParameter(''));
364
+
365
+        $qb->execute();
366
+        $id = $qb->getLastInsertId();
367
+
368
+        return (int)$id;
369
+    }
370
+
371
+    /**
372
+     * Update a share
373
+     *
374
+     * @param IShare $share
375
+     * @return IShare The share object
376
+     */
377
+    public function update(IShare $share) {
378
+        /*
379 379
 		 * We allow updating the permissions of federated shares
380 380
 		 */
381
-		$qb = $this->dbConnection->getQueryBuilder();
382
-			$qb->update('share')
383
-				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
384
-				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
385
-				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
386
-				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
387
-				->execute();
388
-
389
-		// send the updated permission to the owner/initiator, if they are not the same
390
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
391
-			$this->sendPermissionUpdate($share);
392
-		}
393
-
394
-		return $share;
395
-	}
396
-
397
-	/**
398
-	 * send the updated permission to the owner/initiator, if they are not the same
399
-	 *
400
-	 * @param IShare $share
401
-	 * @throws ShareNotFound
402
-	 * @throws \OC\HintException
403
-	 */
404
-	protected function sendPermissionUpdate(IShare $share) {
405
-		$remoteId = $this->getRemoteId($share);
406
-		// if the local user is the owner we send the permission change to the initiator
407
-		if ($this->userManager->userExists($share->getShareOwner())) {
408
-			list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
409
-		} else { // ... if not we send the permission change to the owner
410
-			list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
411
-		}
412
-		$this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
413
-	}
414
-
415
-
416
-	/**
417
-	 * update successful reShare with the correct token
418
-	 *
419
-	 * @param int $shareId
420
-	 * @param string $token
421
-	 */
422
-	protected function updateSuccessfulReShare($shareId, $token) {
423
-		$query = $this->dbConnection->getQueryBuilder();
424
-		$query->update('share')
425
-			->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
426
-			->set('token', $query->createNamedParameter($token))
427
-			->execute();
428
-	}
429
-
430
-	/**
431
-	 * store remote ID in federated reShare table
432
-	 *
433
-	 * @param $shareId
434
-	 * @param $remoteId
435
-	 */
436
-	public function storeRemoteId($shareId, $remoteId) {
437
-		$query = $this->dbConnection->getQueryBuilder();
438
-		$query->insert('federated_reshares')
439
-			->values(
440
-				[
441
-					'share_id' =>  $query->createNamedParameter($shareId),
442
-					'remote_id' => $query->createNamedParameter($remoteId),
443
-				]
444
-			);
445
-		$query->execute();
446
-	}
447
-
448
-	/**
449
-	 * get share ID on remote server for federated re-shares
450
-	 *
451
-	 * @param IShare $share
452
-	 * @return int
453
-	 * @throws ShareNotFound
454
-	 */
455
-	public function getRemoteId(IShare $share) {
456
-		$query = $this->dbConnection->getQueryBuilder();
457
-		$query->select('remote_id')->from('federated_reshares')
458
-			->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
459
-		$data = $query->execute()->fetch();
460
-
461
-		if (!is_array($data) || !isset($data['remote_id'])) {
462
-			throw new ShareNotFound();
463
-		}
464
-
465
-		return (int)$data['remote_id'];
466
-	}
467
-
468
-	/**
469
-	 * @inheritdoc
470
-	 */
471
-	public function move(IShare $share, $recipient) {
472
-		/*
381
+        $qb = $this->dbConnection->getQueryBuilder();
382
+            $qb->update('share')
383
+                ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
384
+                ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
385
+                ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
386
+                ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
387
+                ->execute();
388
+
389
+        // send the updated permission to the owner/initiator, if they are not the same
390
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
391
+            $this->sendPermissionUpdate($share);
392
+        }
393
+
394
+        return $share;
395
+    }
396
+
397
+    /**
398
+     * send the updated permission to the owner/initiator, if they are not the same
399
+     *
400
+     * @param IShare $share
401
+     * @throws ShareNotFound
402
+     * @throws \OC\HintException
403
+     */
404
+    protected function sendPermissionUpdate(IShare $share) {
405
+        $remoteId = $this->getRemoteId($share);
406
+        // if the local user is the owner we send the permission change to the initiator
407
+        if ($this->userManager->userExists($share->getShareOwner())) {
408
+            list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
409
+        } else { // ... if not we send the permission change to the owner
410
+            list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
411
+        }
412
+        $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions());
413
+    }
414
+
415
+
416
+    /**
417
+     * update successful reShare with the correct token
418
+     *
419
+     * @param int $shareId
420
+     * @param string $token
421
+     */
422
+    protected function updateSuccessfulReShare($shareId, $token) {
423
+        $query = $this->dbConnection->getQueryBuilder();
424
+        $query->update('share')
425
+            ->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
426
+            ->set('token', $query->createNamedParameter($token))
427
+            ->execute();
428
+    }
429
+
430
+    /**
431
+     * store remote ID in federated reShare table
432
+     *
433
+     * @param $shareId
434
+     * @param $remoteId
435
+     */
436
+    public function storeRemoteId($shareId, $remoteId) {
437
+        $query = $this->dbConnection->getQueryBuilder();
438
+        $query->insert('federated_reshares')
439
+            ->values(
440
+                [
441
+                    'share_id' =>  $query->createNamedParameter($shareId),
442
+                    'remote_id' => $query->createNamedParameter($remoteId),
443
+                ]
444
+            );
445
+        $query->execute();
446
+    }
447
+
448
+    /**
449
+     * get share ID on remote server for federated re-shares
450
+     *
451
+     * @param IShare $share
452
+     * @return int
453
+     * @throws ShareNotFound
454
+     */
455
+    public function getRemoteId(IShare $share) {
456
+        $query = $this->dbConnection->getQueryBuilder();
457
+        $query->select('remote_id')->from('federated_reshares')
458
+            ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
459
+        $data = $query->execute()->fetch();
460
+
461
+        if (!is_array($data) || !isset($data['remote_id'])) {
462
+            throw new ShareNotFound();
463
+        }
464
+
465
+        return (int)$data['remote_id'];
466
+    }
467
+
468
+    /**
469
+     * @inheritdoc
470
+     */
471
+    public function move(IShare $share, $recipient) {
472
+        /*
473 473
 		 * This function does nothing yet as it is just for outgoing
474 474
 		 * federated shares.
475 475
 		 */
476
-		return $share;
477
-	}
478
-
479
-	/**
480
-	 * Get all children of this share
481
-	 *
482
-	 * @param IShare $parent
483
-	 * @return IShare[]
484
-	 */
485
-	public function getChildren(IShare $parent) {
486
-		$children = [];
487
-
488
-		$qb = $this->dbConnection->getQueryBuilder();
489
-		$qb->select('*')
490
-			->from('share')
491
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
492
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
493
-			->orderBy('id');
494
-
495
-		$cursor = $qb->execute();
496
-		while($data = $cursor->fetch()) {
497
-			$children[] = $this->createShareObject($data);
498
-		}
499
-		$cursor->closeCursor();
500
-
501
-		return $children;
502
-	}
503
-
504
-	/**
505
-	 * Delete a share (owner unShares the file)
506
-	 *
507
-	 * @param IShare $share
508
-	 */
509
-	public function delete(IShare $share) {
510
-
511
-		list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith());
512
-
513
-		$isOwner = false;
514
-
515
-		$this->removeShareFromTable($share);
516
-
517
-		// if the local user is the owner we can send the unShare request directly...
518
-		if ($this->userManager->userExists($share->getShareOwner())) {
519
-			$this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
520
-			$this->revokeShare($share, true);
521
-			$isOwner = true;
522
-		} else { // ... if not we need to correct ID for the unShare request
523
-			$remoteId = $this->getRemoteId($share);
524
-			$this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
525
-			$this->revokeShare($share, false);
526
-		}
527
-
528
-		// send revoke notification to the other user, if initiator and owner are not the same user
529
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
530
-			$remoteId = $this->getRemoteId($share);
531
-			if ($isOwner) {
532
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
533
-			} else {
534
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
535
-			}
536
-			$this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
537
-		}
538
-	}
539
-
540
-	/**
541
-	 * in case of a re-share we need to send the other use (initiator or owner)
542
-	 * a message that the file was unshared
543
-	 *
544
-	 * @param IShare $share
545
-	 * @param bool $isOwner the user can either be the owner or the user who re-sahred it
546
-	 * @throws ShareNotFound
547
-	 * @throws \OC\HintException
548
-	 */
549
-	protected function revokeShare($share, $isOwner) {
550
-		// also send a unShare request to the initiator, if this is a different user than the owner
551
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
552
-			if ($isOwner) {
553
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
554
-			} else {
555
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
556
-			}
557
-			$remoteId = $this->getRemoteId($share);
558
-			$this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
559
-		}
560
-	}
561
-
562
-	/**
563
-	 * remove share from table
564
-	 *
565
-	 * @param IShare $share
566
-	 */
567
-	public function removeShareFromTable(IShare $share) {
568
-		$this->removeShareFromTableById($share->getId());
569
-	}
570
-
571
-	/**
572
-	 * remove share from table
573
-	 *
574
-	 * @param string $shareId
575
-	 */
576
-	private function removeShareFromTableById($shareId) {
577
-		$qb = $this->dbConnection->getQueryBuilder();
578
-		$qb->delete('share')
579
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
580
-		$qb->execute();
581
-
582
-		$qb->delete('federated_reshares')
583
-			->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
584
-		$qb->execute();
585
-	}
586
-
587
-	/**
588
-	 * @inheritdoc
589
-	 */
590
-	public function deleteFromSelf(IShare $share, $recipient) {
591
-		// nothing to do here. Technically deleteFromSelf in the context of federated
592
-		// shares is a umount of a external storage. This is handled here
593
-		// apps/files_sharing/lib/external/manager.php
594
-		// TODO move this code over to this app
595
-	}
596
-
597
-
598
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
599
-		$qb = $this->dbConnection->getQueryBuilder();
600
-		$qb->select('*')
601
-			->from('share', 's')
602
-			->andWhere($qb->expr()->orX(
603
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
604
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
605
-			))
606
-			->andWhere(
607
-				$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))
608
-			);
609
-
610
-		/**
611
-		 * Reshares for this user are shares where they are the owner.
612
-		 */
613
-		if ($reshares === false) {
614
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
615
-		} else {
616
-			$qb->andWhere(
617
-				$qb->expr()->orX(
618
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
619
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
620
-				)
621
-			);
622
-		}
623
-
624
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
625
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
626
-
627
-		$qb->orderBy('id');
628
-
629
-		$cursor = $qb->execute();
630
-		$shares = [];
631
-		while ($data = $cursor->fetch()) {
632
-			$shares[$data['fileid']][] = $this->createShareObject($data);
633
-		}
634
-		$cursor->closeCursor();
635
-
636
-		return $shares;
637
-	}
638
-
639
-	/**
640
-	 * @inheritdoc
641
-	 */
642
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
643
-		$qb = $this->dbConnection->getQueryBuilder();
644
-		$qb->select('*')
645
-			->from('share');
646
-
647
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
648
-
649
-		/**
650
-		 * Reshares for this user are shares where they are the owner.
651
-		 */
652
-		if ($reshares === false) {
653
-			//Special case for old shares created via the web UI
654
-			$or1 = $qb->expr()->andX(
655
-				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
656
-				$qb->expr()->isNull('uid_initiator')
657
-			);
658
-
659
-			$qb->andWhere(
660
-				$qb->expr()->orX(
661
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
662
-					$or1
663
-				)
664
-			);
665
-		} else {
666
-			$qb->andWhere(
667
-				$qb->expr()->orX(
668
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
669
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
670
-				)
671
-			);
672
-		}
673
-
674
-		if ($node !== null) {
675
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
676
-		}
677
-
678
-		if ($limit !== -1) {
679
-			$qb->setMaxResults($limit);
680
-		}
681
-
682
-		$qb->setFirstResult($offset);
683
-		$qb->orderBy('id');
684
-
685
-		$cursor = $qb->execute();
686
-		$shares = [];
687
-		while($data = $cursor->fetch()) {
688
-			$shares[] = $this->createShareObject($data);
689
-		}
690
-		$cursor->closeCursor();
691
-
692
-		return $shares;
693
-	}
694
-
695
-	/**
696
-	 * @inheritdoc
697
-	 */
698
-	public function getShareById($id, $recipientId = null) {
699
-		$qb = $this->dbConnection->getQueryBuilder();
700
-
701
-		$qb->select('*')
702
-			->from('share')
703
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
704
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
705
-
706
-		$cursor = $qb->execute();
707
-		$data = $cursor->fetch();
708
-		$cursor->closeCursor();
709
-
710
-		if ($data === false) {
711
-			throw new ShareNotFound();
712
-		}
713
-
714
-		try {
715
-			$share = $this->createShareObject($data);
716
-		} catch (InvalidShare $e) {
717
-			throw new ShareNotFound();
718
-		}
719
-
720
-		return $share;
721
-	}
722
-
723
-	/**
724
-	 * Get shares for a given path
725
-	 *
726
-	 * @param \OCP\Files\Node $path
727
-	 * @return IShare[]
728
-	 */
729
-	public function getSharesByPath(Node $path) {
730
-		$qb = $this->dbConnection->getQueryBuilder();
731
-
732
-		$cursor = $qb->select('*')
733
-			->from('share')
734
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
735
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
736
-			->execute();
737
-
738
-		$shares = [];
739
-		while($data = $cursor->fetch()) {
740
-			$shares[] = $this->createShareObject($data);
741
-		}
742
-		$cursor->closeCursor();
743
-
744
-		return $shares;
745
-	}
746
-
747
-	/**
748
-	 * @inheritdoc
749
-	 */
750
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
751
-		/** @var IShare[] $shares */
752
-		$shares = [];
753
-
754
-		//Get shares directly with this user
755
-		$qb = $this->dbConnection->getQueryBuilder();
756
-		$qb->select('*')
757
-			->from('share');
758
-
759
-		// Order by id
760
-		$qb->orderBy('id');
761
-
762
-		// Set limit and offset
763
-		if ($limit !== -1) {
764
-			$qb->setMaxResults($limit);
765
-		}
766
-		$qb->setFirstResult($offset);
767
-
768
-		$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
769
-		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
770
-
771
-		// Filter by node if provided
772
-		if ($node !== null) {
773
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
774
-		}
775
-
776
-		$cursor = $qb->execute();
777
-
778
-		while($data = $cursor->fetch()) {
779
-			$shares[] = $this->createShareObject($data);
780
-		}
781
-		$cursor->closeCursor();
782
-
783
-
784
-		return $shares;
785
-	}
786
-
787
-	/**
788
-	 * Get a share by token
789
-	 *
790
-	 * @param string $token
791
-	 * @return IShare
792
-	 * @throws ShareNotFound
793
-	 */
794
-	public function getShareByToken($token) {
795
-		$qb = $this->dbConnection->getQueryBuilder();
796
-
797
-		$cursor = $qb->select('*')
798
-			->from('share')
799
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
800
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
801
-			->execute();
802
-
803
-		$data = $cursor->fetch();
804
-
805
-		if ($data === false) {
806
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
807
-		}
808
-
809
-		try {
810
-			$share = $this->createShareObject($data);
811
-		} catch (InvalidShare $e) {
812
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
813
-		}
814
-
815
-		return $share;
816
-	}
817
-
818
-	/**
819
-	 * get database row of a give share
820
-	 *
821
-	 * @param $id
822
-	 * @return array
823
-	 * @throws ShareNotFound
824
-	 */
825
-	private function getRawShare($id) {
826
-
827
-		// Now fetch the inserted share and create a complete share object
828
-		$qb = $this->dbConnection->getQueryBuilder();
829
-		$qb->select('*')
830
-			->from('share')
831
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
832
-
833
-		$cursor = $qb->execute();
834
-		$data = $cursor->fetch();
835
-		$cursor->closeCursor();
836
-
837
-		if ($data === false) {
838
-			throw new ShareNotFound;
839
-		}
840
-
841
-		return $data;
842
-	}
843
-
844
-	/**
845
-	 * Create a share object from an database row
846
-	 *
847
-	 * @param array $data
848
-	 * @return IShare
849
-	 * @throws InvalidShare
850
-	 * @throws ShareNotFound
851
-	 */
852
-	private function createShareObject($data) {
853
-
854
-		$share = new Share($this->rootFolder, $this->userManager);
855
-		$share->setId((int)$data['id'])
856
-			->setShareType((int)$data['share_type'])
857
-			->setPermissions((int)$data['permissions'])
858
-			->setTarget($data['file_target'])
859
-			->setMailSend((bool)$data['mail_send'])
860
-			->setToken($data['token']);
861
-
862
-		$shareTime = new \DateTime();
863
-		$shareTime->setTimestamp((int)$data['stime']);
864
-		$share->setShareTime($shareTime);
865
-		$share->setSharedWith($data['share_with']);
866
-
867
-		if ($data['uid_initiator'] !== null) {
868
-			$share->setShareOwner($data['uid_owner']);
869
-			$share->setSharedBy($data['uid_initiator']);
870
-		} else {
871
-			//OLD SHARE
872
-			$share->setSharedBy($data['uid_owner']);
873
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
874
-
875
-			$owner = $path->getOwner();
876
-			$share->setShareOwner($owner->getUID());
877
-		}
878
-
879
-		$share->setNodeId((int)$data['file_source']);
880
-		$share->setNodeType($data['item_type']);
881
-
882
-		$share->setProviderId($this->identifier());
883
-
884
-		return $share;
885
-	}
886
-
887
-	/**
888
-	 * Get the node with file $id for $user
889
-	 *
890
-	 * @param string $userId
891
-	 * @param int $id
892
-	 * @return \OCP\Files\File|\OCP\Files\Folder
893
-	 * @throws InvalidShare
894
-	 */
895
-	private function getNode($userId, $id) {
896
-		try {
897
-			$userFolder = $this->rootFolder->getUserFolder($userId);
898
-		} catch (NotFoundException $e) {
899
-			throw new InvalidShare();
900
-		}
901
-
902
-		$nodes = $userFolder->getById($id);
903
-
904
-		if (empty($nodes)) {
905
-			throw new InvalidShare();
906
-		}
907
-
908
-		return $nodes[0];
909
-	}
910
-
911
-	/**
912
-	 * A user is deleted from the system
913
-	 * So clean up the relevant shares.
914
-	 *
915
-	 * @param string $uid
916
-	 * @param int $shareType
917
-	 */
918
-	public function userDeleted($uid, $shareType) {
919
-		//TODO: probabaly a good idea to send unshare info to remote servers
920
-
921
-		$qb = $this->dbConnection->getQueryBuilder();
922
-
923
-		$qb->delete('share')
924
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
925
-			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
926
-			->execute();
927
-	}
928
-
929
-	/**
930
-	 * This provider does not handle groups
931
-	 *
932
-	 * @param string $gid
933
-	 */
934
-	public function groupDeleted($gid) {
935
-		// We don't handle groups here
936
-	}
937
-
938
-	/**
939
-	 * This provider does not handle groups
940
-	 *
941
-	 * @param string $uid
942
-	 * @param string $gid
943
-	 */
944
-	public function userDeletedFromGroup($uid, $gid) {
945
-		// We don't handle groups here
946
-	}
947
-
948
-	/**
949
-	 * check if users from other Nextcloud instances are allowed to mount public links share by this instance
950
-	 *
951
-	 * @return bool
952
-	 */
953
-	public function isOutgoingServer2serverShareEnabled() {
954
-		if ($this->gsConfig->onlyInternalFederation()) {
955
-			return false;
956
-		}
957
-		$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
958
-		return ($result === 'yes');
959
-	}
960
-
961
-	/**
962
-	 * check if users are allowed to mount public links from other Nextclouds
963
-	 *
964
-	 * @return bool
965
-	 */
966
-	public function isIncomingServer2serverShareEnabled() {
967
-		if ($this->gsConfig->onlyInternalFederation()) {
968
-			return false;
969
-		}
970
-		$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
971
-		return ($result === 'yes');
972
-	}
973
-
974
-	/**
975
-	 * Check if querying sharees on the lookup server is enabled
976
-	 *
977
-	 * @return bool
978
-	 */
979
-	public function isLookupServerQueriesEnabled() {
980
-		// in a global scale setup we should always query the lookup server
981
-		if ($this->gsConfig->isGlobalScaleEnabled()) {
982
-			return true;
983
-		}
984
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
985
-		return ($result === 'yes');
986
-	}
987
-
988
-
989
-	/**
990
-	 * Check if it is allowed to publish user specific data to the lookup server
991
-	 *
992
-	 * @return bool
993
-	 */
994
-	public function isLookupServerUploadEnabled() {
995
-		// in a global scale setup the admin is responsible to keep the lookup server up-to-date
996
-		if ($this->gsConfig->isGlobalScaleEnabled()) {
997
-			return false;
998
-		}
999
-		$result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
1000
-		return ($result === 'yes');
1001
-	}
1002
-
1003
-	/**
1004
-	 * @inheritdoc
1005
-	 */
1006
-	public function getAccessList($nodes, $currentAccess) {
1007
-		$ids = [];
1008
-		foreach ($nodes as $node) {
1009
-			$ids[] = $node->getId();
1010
-		}
1011
-
1012
-		$qb = $this->dbConnection->getQueryBuilder();
1013
-		$qb->select('share_with', 'token', 'file_source')
1014
-			->from('share')
1015
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
1016
-			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1017
-			->andWhere($qb->expr()->orX(
1018
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1019
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1020
-			));
1021
-		$cursor = $qb->execute();
1022
-
1023
-		if ($currentAccess === false) {
1024
-			$remote = $cursor->fetch() !== false;
1025
-			$cursor->closeCursor();
1026
-
1027
-			return ['remote' => $remote];
1028
-		}
1029
-
1030
-		$remote = [];
1031
-		while ($row = $cursor->fetch()) {
1032
-			$remote[$row['share_with']] = [
1033
-				'node_id' => $row['file_source'],
1034
-				'token' => $row['token'],
1035
-			];
1036
-		}
1037
-		$cursor->closeCursor();
1038
-
1039
-		return ['remote' => $remote];
1040
-	}
476
+        return $share;
477
+    }
478
+
479
+    /**
480
+     * Get all children of this share
481
+     *
482
+     * @param IShare $parent
483
+     * @return IShare[]
484
+     */
485
+    public function getChildren(IShare $parent) {
486
+        $children = [];
487
+
488
+        $qb = $this->dbConnection->getQueryBuilder();
489
+        $qb->select('*')
490
+            ->from('share')
491
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
492
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
493
+            ->orderBy('id');
494
+
495
+        $cursor = $qb->execute();
496
+        while($data = $cursor->fetch()) {
497
+            $children[] = $this->createShareObject($data);
498
+        }
499
+        $cursor->closeCursor();
500
+
501
+        return $children;
502
+    }
503
+
504
+    /**
505
+     * Delete a share (owner unShares the file)
506
+     *
507
+     * @param IShare $share
508
+     */
509
+    public function delete(IShare $share) {
510
+
511
+        list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith());
512
+
513
+        $isOwner = false;
514
+
515
+        $this->removeShareFromTable($share);
516
+
517
+        // if the local user is the owner we can send the unShare request directly...
518
+        if ($this->userManager->userExists($share->getShareOwner())) {
519
+            $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
520
+            $this->revokeShare($share, true);
521
+            $isOwner = true;
522
+        } else { // ... if not we need to correct ID for the unShare request
523
+            $remoteId = $this->getRemoteId($share);
524
+            $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
525
+            $this->revokeShare($share, false);
526
+        }
527
+
528
+        // send revoke notification to the other user, if initiator and owner are not the same user
529
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
530
+            $remoteId = $this->getRemoteId($share);
531
+            if ($isOwner) {
532
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
533
+            } else {
534
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
535
+            }
536
+            $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
537
+        }
538
+    }
539
+
540
+    /**
541
+     * in case of a re-share we need to send the other use (initiator or owner)
542
+     * a message that the file was unshared
543
+     *
544
+     * @param IShare $share
545
+     * @param bool $isOwner the user can either be the owner or the user who re-sahred it
546
+     * @throws ShareNotFound
547
+     * @throws \OC\HintException
548
+     */
549
+    protected function revokeShare($share, $isOwner) {
550
+        // also send a unShare request to the initiator, if this is a different user than the owner
551
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
552
+            if ($isOwner) {
553
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
554
+            } else {
555
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
556
+            }
557
+            $remoteId = $this->getRemoteId($share);
558
+            $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
559
+        }
560
+    }
561
+
562
+    /**
563
+     * remove share from table
564
+     *
565
+     * @param IShare $share
566
+     */
567
+    public function removeShareFromTable(IShare $share) {
568
+        $this->removeShareFromTableById($share->getId());
569
+    }
570
+
571
+    /**
572
+     * remove share from table
573
+     *
574
+     * @param string $shareId
575
+     */
576
+    private function removeShareFromTableById($shareId) {
577
+        $qb = $this->dbConnection->getQueryBuilder();
578
+        $qb->delete('share')
579
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
580
+        $qb->execute();
581
+
582
+        $qb->delete('federated_reshares')
583
+            ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId)));
584
+        $qb->execute();
585
+    }
586
+
587
+    /**
588
+     * @inheritdoc
589
+     */
590
+    public function deleteFromSelf(IShare $share, $recipient) {
591
+        // nothing to do here. Technically deleteFromSelf in the context of federated
592
+        // shares is a umount of a external storage. This is handled here
593
+        // apps/files_sharing/lib/external/manager.php
594
+        // TODO move this code over to this app
595
+    }
596
+
597
+
598
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
599
+        $qb = $this->dbConnection->getQueryBuilder();
600
+        $qb->select('*')
601
+            ->from('share', 's')
602
+            ->andWhere($qb->expr()->orX(
603
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
604
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
605
+            ))
606
+            ->andWhere(
607
+                $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))
608
+            );
609
+
610
+        /**
611
+         * Reshares for this user are shares where they are the owner.
612
+         */
613
+        if ($reshares === false) {
614
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
615
+        } else {
616
+            $qb->andWhere(
617
+                $qb->expr()->orX(
618
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
619
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
620
+                )
621
+            );
622
+        }
623
+
624
+        $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
625
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
626
+
627
+        $qb->orderBy('id');
628
+
629
+        $cursor = $qb->execute();
630
+        $shares = [];
631
+        while ($data = $cursor->fetch()) {
632
+            $shares[$data['fileid']][] = $this->createShareObject($data);
633
+        }
634
+        $cursor->closeCursor();
635
+
636
+        return $shares;
637
+    }
638
+
639
+    /**
640
+     * @inheritdoc
641
+     */
642
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
643
+        $qb = $this->dbConnection->getQueryBuilder();
644
+        $qb->select('*')
645
+            ->from('share');
646
+
647
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
648
+
649
+        /**
650
+         * Reshares for this user are shares where they are the owner.
651
+         */
652
+        if ($reshares === false) {
653
+            //Special case for old shares created via the web UI
654
+            $or1 = $qb->expr()->andX(
655
+                $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
656
+                $qb->expr()->isNull('uid_initiator')
657
+            );
658
+
659
+            $qb->andWhere(
660
+                $qb->expr()->orX(
661
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
662
+                    $or1
663
+                )
664
+            );
665
+        } else {
666
+            $qb->andWhere(
667
+                $qb->expr()->orX(
668
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
669
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
670
+                )
671
+            );
672
+        }
673
+
674
+        if ($node !== null) {
675
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
676
+        }
677
+
678
+        if ($limit !== -1) {
679
+            $qb->setMaxResults($limit);
680
+        }
681
+
682
+        $qb->setFirstResult($offset);
683
+        $qb->orderBy('id');
684
+
685
+        $cursor = $qb->execute();
686
+        $shares = [];
687
+        while($data = $cursor->fetch()) {
688
+            $shares[] = $this->createShareObject($data);
689
+        }
690
+        $cursor->closeCursor();
691
+
692
+        return $shares;
693
+    }
694
+
695
+    /**
696
+     * @inheritdoc
697
+     */
698
+    public function getShareById($id, $recipientId = null) {
699
+        $qb = $this->dbConnection->getQueryBuilder();
700
+
701
+        $qb->select('*')
702
+            ->from('share')
703
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
704
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
705
+
706
+        $cursor = $qb->execute();
707
+        $data = $cursor->fetch();
708
+        $cursor->closeCursor();
709
+
710
+        if ($data === false) {
711
+            throw new ShareNotFound();
712
+        }
713
+
714
+        try {
715
+            $share = $this->createShareObject($data);
716
+        } catch (InvalidShare $e) {
717
+            throw new ShareNotFound();
718
+        }
719
+
720
+        return $share;
721
+    }
722
+
723
+    /**
724
+     * Get shares for a given path
725
+     *
726
+     * @param \OCP\Files\Node $path
727
+     * @return IShare[]
728
+     */
729
+    public function getSharesByPath(Node $path) {
730
+        $qb = $this->dbConnection->getQueryBuilder();
731
+
732
+        $cursor = $qb->select('*')
733
+            ->from('share')
734
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
735
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
736
+            ->execute();
737
+
738
+        $shares = [];
739
+        while($data = $cursor->fetch()) {
740
+            $shares[] = $this->createShareObject($data);
741
+        }
742
+        $cursor->closeCursor();
743
+
744
+        return $shares;
745
+    }
746
+
747
+    /**
748
+     * @inheritdoc
749
+     */
750
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
751
+        /** @var IShare[] $shares */
752
+        $shares = [];
753
+
754
+        //Get shares directly with this user
755
+        $qb = $this->dbConnection->getQueryBuilder();
756
+        $qb->select('*')
757
+            ->from('share');
758
+
759
+        // Order by id
760
+        $qb->orderBy('id');
761
+
762
+        // Set limit and offset
763
+        if ($limit !== -1) {
764
+            $qb->setMaxResults($limit);
765
+        }
766
+        $qb->setFirstResult($offset);
767
+
768
+        $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
769
+        $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
770
+
771
+        // Filter by node if provided
772
+        if ($node !== null) {
773
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
774
+        }
775
+
776
+        $cursor = $qb->execute();
777
+
778
+        while($data = $cursor->fetch()) {
779
+            $shares[] = $this->createShareObject($data);
780
+        }
781
+        $cursor->closeCursor();
782
+
783
+
784
+        return $shares;
785
+    }
786
+
787
+    /**
788
+     * Get a share by token
789
+     *
790
+     * @param string $token
791
+     * @return IShare
792
+     * @throws ShareNotFound
793
+     */
794
+    public function getShareByToken($token) {
795
+        $qb = $this->dbConnection->getQueryBuilder();
796
+
797
+        $cursor = $qb->select('*')
798
+            ->from('share')
799
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)))
800
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
801
+            ->execute();
802
+
803
+        $data = $cursor->fetch();
804
+
805
+        if ($data === false) {
806
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
807
+        }
808
+
809
+        try {
810
+            $share = $this->createShareObject($data);
811
+        } catch (InvalidShare $e) {
812
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
813
+        }
814
+
815
+        return $share;
816
+    }
817
+
818
+    /**
819
+     * get database row of a give share
820
+     *
821
+     * @param $id
822
+     * @return array
823
+     * @throws ShareNotFound
824
+     */
825
+    private function getRawShare($id) {
826
+
827
+        // Now fetch the inserted share and create a complete share object
828
+        $qb = $this->dbConnection->getQueryBuilder();
829
+        $qb->select('*')
830
+            ->from('share')
831
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
832
+
833
+        $cursor = $qb->execute();
834
+        $data = $cursor->fetch();
835
+        $cursor->closeCursor();
836
+
837
+        if ($data === false) {
838
+            throw new ShareNotFound;
839
+        }
840
+
841
+        return $data;
842
+    }
843
+
844
+    /**
845
+     * Create a share object from an database row
846
+     *
847
+     * @param array $data
848
+     * @return IShare
849
+     * @throws InvalidShare
850
+     * @throws ShareNotFound
851
+     */
852
+    private function createShareObject($data) {
853
+
854
+        $share = new Share($this->rootFolder, $this->userManager);
855
+        $share->setId((int)$data['id'])
856
+            ->setShareType((int)$data['share_type'])
857
+            ->setPermissions((int)$data['permissions'])
858
+            ->setTarget($data['file_target'])
859
+            ->setMailSend((bool)$data['mail_send'])
860
+            ->setToken($data['token']);
861
+
862
+        $shareTime = new \DateTime();
863
+        $shareTime->setTimestamp((int)$data['stime']);
864
+        $share->setShareTime($shareTime);
865
+        $share->setSharedWith($data['share_with']);
866
+
867
+        if ($data['uid_initiator'] !== null) {
868
+            $share->setShareOwner($data['uid_owner']);
869
+            $share->setSharedBy($data['uid_initiator']);
870
+        } else {
871
+            //OLD SHARE
872
+            $share->setSharedBy($data['uid_owner']);
873
+            $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
874
+
875
+            $owner = $path->getOwner();
876
+            $share->setShareOwner($owner->getUID());
877
+        }
878
+
879
+        $share->setNodeId((int)$data['file_source']);
880
+        $share->setNodeType($data['item_type']);
881
+
882
+        $share->setProviderId($this->identifier());
883
+
884
+        return $share;
885
+    }
886
+
887
+    /**
888
+     * Get the node with file $id for $user
889
+     *
890
+     * @param string $userId
891
+     * @param int $id
892
+     * @return \OCP\Files\File|\OCP\Files\Folder
893
+     * @throws InvalidShare
894
+     */
895
+    private function getNode($userId, $id) {
896
+        try {
897
+            $userFolder = $this->rootFolder->getUserFolder($userId);
898
+        } catch (NotFoundException $e) {
899
+            throw new InvalidShare();
900
+        }
901
+
902
+        $nodes = $userFolder->getById($id);
903
+
904
+        if (empty($nodes)) {
905
+            throw new InvalidShare();
906
+        }
907
+
908
+        return $nodes[0];
909
+    }
910
+
911
+    /**
912
+     * A user is deleted from the system
913
+     * So clean up the relevant shares.
914
+     *
915
+     * @param string $uid
916
+     * @param int $shareType
917
+     */
918
+    public function userDeleted($uid, $shareType) {
919
+        //TODO: probabaly a good idea to send unshare info to remote servers
920
+
921
+        $qb = $this->dbConnection->getQueryBuilder();
922
+
923
+        $qb->delete('share')
924
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
925
+            ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
926
+            ->execute();
927
+    }
928
+
929
+    /**
930
+     * This provider does not handle groups
931
+     *
932
+     * @param string $gid
933
+     */
934
+    public function groupDeleted($gid) {
935
+        // We don't handle groups here
936
+    }
937
+
938
+    /**
939
+     * This provider does not handle groups
940
+     *
941
+     * @param string $uid
942
+     * @param string $gid
943
+     */
944
+    public function userDeletedFromGroup($uid, $gid) {
945
+        // We don't handle groups here
946
+    }
947
+
948
+    /**
949
+     * check if users from other Nextcloud instances are allowed to mount public links share by this instance
950
+     *
951
+     * @return bool
952
+     */
953
+    public function isOutgoingServer2serverShareEnabled() {
954
+        if ($this->gsConfig->onlyInternalFederation()) {
955
+            return false;
956
+        }
957
+        $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
958
+        return ($result === 'yes');
959
+    }
960
+
961
+    /**
962
+     * check if users are allowed to mount public links from other Nextclouds
963
+     *
964
+     * @return bool
965
+     */
966
+    public function isIncomingServer2serverShareEnabled() {
967
+        if ($this->gsConfig->onlyInternalFederation()) {
968
+            return false;
969
+        }
970
+        $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
971
+        return ($result === 'yes');
972
+    }
973
+
974
+    /**
975
+     * Check if querying sharees on the lookup server is enabled
976
+     *
977
+     * @return bool
978
+     */
979
+    public function isLookupServerQueriesEnabled() {
980
+        // in a global scale setup we should always query the lookup server
981
+        if ($this->gsConfig->isGlobalScaleEnabled()) {
982
+            return true;
983
+        }
984
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
985
+        return ($result === 'yes');
986
+    }
987
+
988
+
989
+    /**
990
+     * Check if it is allowed to publish user specific data to the lookup server
991
+     *
992
+     * @return bool
993
+     */
994
+    public function isLookupServerUploadEnabled() {
995
+        // in a global scale setup the admin is responsible to keep the lookup server up-to-date
996
+        if ($this->gsConfig->isGlobalScaleEnabled()) {
997
+            return false;
998
+        }
999
+        $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
1000
+        return ($result === 'yes');
1001
+    }
1002
+
1003
+    /**
1004
+     * @inheritdoc
1005
+     */
1006
+    public function getAccessList($nodes, $currentAccess) {
1007
+        $ids = [];
1008
+        foreach ($nodes as $node) {
1009
+            $ids[] = $node->getId();
1010
+        }
1011
+
1012
+        $qb = $this->dbConnection->getQueryBuilder();
1013
+        $qb->select('share_with', 'token', 'file_source')
1014
+            ->from('share')
1015
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
1016
+            ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1017
+            ->andWhere($qb->expr()->orX(
1018
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1019
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1020
+            ));
1021
+        $cursor = $qb->execute();
1022
+
1023
+        if ($currentAccess === false) {
1024
+            $remote = $cursor->fetch() !== false;
1025
+            $cursor->closeCursor();
1026
+
1027
+            return ['remote' => $remote];
1028
+        }
1029
+
1030
+        $remote = [];
1031
+        while ($row = $cursor->fetch()) {
1032
+            $remote[$row['share_with']] = [
1033
+                'node_id' => $row['file_source'],
1034
+                'token' => $row['token'],
1035
+            ];
1036
+        }
1037
+        $cursor->closeCursor();
1038
+
1039
+        return ['remote' => $remote];
1040
+    }
1041 1041
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/lib/Controller/RequestHandlerController.php 2 patches
Indentation   +635 added lines, -635 removed lines patch added patch discarded remove patch
@@ -51,639 +51,639 @@
 block discarded – undo
51 51
 
52 52
 class RequestHandlerController extends OCSController {
53 53
 
54
-	/** @var FederatedShareProvider */
55
-	private $federatedShareProvider;
56
-
57
-	/** @var IDBConnection */
58
-	private $connection;
59
-
60
-	/** @var Share\IManager */
61
-	private $shareManager;
62
-
63
-	/** @var Notifications */
64
-	private $notifications;
65
-
66
-	/** @var AddressHandler */
67
-	private $addressHandler;
68
-
69
-	/** @var  IUserManager */
70
-	private $userManager;
71
-
72
-	/** @var string */
73
-	private $shareTable = 'share';
74
-
75
-	/** @var ICloudIdManager */
76
-	private $cloudIdManager;
77
-
78
-	/** @var ILogger */
79
-	private $logger;
80
-
81
-	/**
82
-	 * Server2Server constructor.
83
-	 *
84
-	 * @param string $appName
85
-	 * @param IRequest $request
86
-	 * @param FederatedShareProvider $federatedShareProvider
87
-	 * @param IDBConnection $connection
88
-	 * @param Share\IManager $shareManager
89
-	 * @param Notifications $notifications
90
-	 * @param AddressHandler $addressHandler
91
-	 * @param IUserManager $userManager
92
-	 * @param ICloudIdManager $cloudIdManager
93
-	 */
94
-	public function __construct($appName,
95
-								IRequest $request,
96
-								FederatedShareProvider $federatedShareProvider,
97
-								IDBConnection $connection,
98
-								Share\IManager $shareManager,
99
-								Notifications $notifications,
100
-								AddressHandler $addressHandler,
101
-								IUserManager $userManager,
102
-								ICloudIdManager $cloudIdManager,
103
-								ILogger $logger
104
-	) {
105
-		parent::__construct($appName, $request);
106
-
107
-		$this->federatedShareProvider = $federatedShareProvider;
108
-		$this->connection = $connection;
109
-		$this->shareManager = $shareManager;
110
-		$this->notifications = $notifications;
111
-		$this->addressHandler = $addressHandler;
112
-		$this->userManager = $userManager;
113
-		$this->cloudIdManager = $cloudIdManager;
114
-		$this->logger = $logger;
115
-	}
116
-
117
-	/**
118
-	 * @NoCSRFRequired
119
-	 * @PublicPage
120
-	 *
121
-	 * create a new share
122
-	 *
123
-	 * @return Http\DataResponse
124
-	 * @throws OCSException
125
-	 */
126
-	public function createShare() {
127
-
128
-		if (!$this->isS2SEnabled(true)) {
129
-			throw new OCSException('Server does not support federated cloud sharing', 503);
130
-		}
131
-
132
-		$remote = isset($_POST['remote']) ? $_POST['remote'] : null;
133
-		$token = isset($_POST['token']) ? $_POST['token'] : null;
134
-		$name = isset($_POST['name']) ? $_POST['name'] : null;
135
-		$owner = isset($_POST['owner']) ? $_POST['owner'] : null;
136
-		$sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null;
137
-		$shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
138
-		$remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
139
-		$sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null;
140
-		$ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null;
141
-
142
-		if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
143
-
144
-			if (!\OCP\Util::isValidFileName($name)) {
145
-				throw new OCSException('The mountpoint name contains invalid characters.', 400);
146
-			}
147
-
148
-			// FIXME this should be a method in the user management instead
149
-			$this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
150
-			\OCP\Util::emitHook(
151
-				'\OCA\Files_Sharing\API\Server2Server',
152
-				'preLoginNameUsedAsUserName',
153
-				array('uid' => &$shareWith)
154
-			);
155
-			$this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
156
-
157
-			if (!\OC::$server->getUserManager()->userExists($shareWith)) {
158
-				throw new OCSException('User does not exists', 400);
159
-			}
160
-
161
-			\OC_Util::setupFS($shareWith);
162
-
163
-			$externalManager = new \OCA\Files_Sharing\External\Manager(
164
-					\OC::$server->getDatabaseConnection(),
165
-					\OC\Files\Filesystem::getMountManager(),
166
-					\OC\Files\Filesystem::getLoader(),
167
-					\OC::$server->getHTTPClientService(),
168
-					\OC::$server->getNotificationManager(),
169
-					\OC::$server->query(\OCP\OCS\IDiscoveryService::class),
170
-					$shareWith
171
-				);
172
-
173
-			try {
174
-				$externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId);
175
-				$shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
176
-
177
-				if ($ownerFederatedId === null) {
178
-					$ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
179
-				}
180
-				// if the owner of the share and the initiator are the same user
181
-				// we also complete the federated share ID for the initiator
182
-				if ($sharedByFederatedId === null && $owner === $sharedBy) {
183
-					$sharedByFederatedId = $ownerFederatedId;
184
-				}
185
-
186
-				$event = \OC::$server->getActivityManager()->generateEvent();
187
-				$event->setApp('files_sharing')
188
-					->setType('remote_share')
189
-					->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
190
-					->setAffectedUser($shareWith)
191
-					->setObject('remote_share', (int)$shareId, $name);
192
-				\OC::$server->getActivityManager()->publish($event);
193
-
194
-				$urlGenerator = \OC::$server->getURLGenerator();
195
-
196
-				$notificationManager = \OC::$server->getNotificationManager();
197
-				$notification = $notificationManager->createNotification();
198
-				$notification->setApp('files_sharing')
199
-					->setUser($shareWith)
200
-					->setDateTime(new \DateTime())
201
-					->setObject('remote_share', $shareId)
202
-					->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]);
203
-
204
-				$declineAction = $notification->createAction();
205
-				$declineAction->setLabel('decline')
206
-					->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
207
-				$notification->addAction($declineAction);
208
-
209
-				$acceptAction = $notification->createAction();
210
-				$acceptAction->setLabel('accept')
211
-					->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
212
-				$notification->addAction($acceptAction);
213
-
214
-				$notificationManager->notify($notification);
215
-
216
-				return new Http\DataResponse();
217
-			} catch (\Exception $e) {
218
-				$this->logger->logException($e, [
219
-					'message' => 'Server can not add remote share.',
220
-					'level' => ILogger::ERROR,
221
-					'app' => 'files_sharing'
222
-				]);
223
-				throw new OCSException('internal server error, was not able to add share from ' . $remote, 500);
224
-			}
225
-		}
226
-
227
-		throw new OCSException('server can not add remote share, missing parameter', 400);
228
-	}
229
-
230
-	/**
231
-	 * @NoCSRFRequired
232
-	 * @PublicPage
233
-	 *
234
-	 * create re-share on behalf of another user
235
-	 *
236
-	 * @param int $id
237
-	 * @return Http\DataResponse
238
-	 * @throws OCSBadRequestException
239
-	 * @throws OCSForbiddenException
240
-	 * @throws OCSNotFoundException
241
-	 */
242
-	public function reShare($id) {
243
-
244
-		$token = $this->request->getParam('token', null);
245
-		$shareWith = $this->request->getParam('shareWith', null);
246
-		$permission = (int)$this->request->getParam('permission', null);
247
-		$remoteId = (int)$this->request->getParam('remoteId', null);
248
-
249
-		if ($id === null ||
250
-			$token === null ||
251
-			$shareWith === null ||
252
-			$permission === null ||
253
-			$remoteId === null
254
-		) {
255
-			throw new OCSBadRequestException();
256
-		}
257
-
258
-		try {
259
-			$share = $this->federatedShareProvider->getShareById($id);
260
-		} catch (Share\Exceptions\ShareNotFound $e) {
261
-			throw new OCSNotFoundException();
262
-		}
263
-
264
-		// don't allow to share a file back to the owner
265
-		list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith);
266
-		$owner = $share->getShareOwner();
267
-		$currentServer = $this->addressHandler->generateRemoteURL();
268
-		if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
269
-			throw new OCSForbiddenException();
270
-		}
271
-
272
-		if ($this->verifyShare($share, $token)) {
273
-
274
-			// check if re-sharing is allowed
275
-			if ($share->getPermissions() | ~Constants::PERMISSION_SHARE) {
276
-				$share->setPermissions($share->getPermissions() & $permission);
277
-				// the recipient of the initial share is now the initiator for the re-share
278
-				$share->setSharedBy($share->getSharedWith());
279
-				$share->setSharedWith($shareWith);
280
-				try {
281
-					$result = $this->federatedShareProvider->create($share);
282
-					$this->federatedShareProvider->storeRemoteId((int)$result->getId(), $remoteId);
283
-					return new Http\DataResponse([
284
-						'token' => $result->getToken(),
285
-						'remoteId' => $result->getId()
286
-					]);
287
-				} catch (\Exception $e) {
288
-					throw new OCSBadRequestException();
289
-				}
290
-			} else {
291
-				throw new OCSForbiddenException();
292
-			}
293
-		}
294
-		throw new OCSBadRequestException();
295
-	}
296
-
297
-	/**
298
-	 * @NoCSRFRequired
299
-	 * @PublicPage
300
-	 *
301
-	 * accept server-to-server share
302
-	 *
303
-	 * @param int $id
304
-	 * @return Http\DataResponse
305
-	 * @throws OCSException
306
-	 */
307
-	public function acceptShare($id) {
308
-
309
-		if (!$this->isS2SEnabled()) {
310
-			throw new OCSException('Server does not support federated cloud sharing', 503);
311
-		}
312
-
313
-		$token = isset($_POST['token']) ? $_POST['token'] : null;
314
-
315
-		try {
316
-			$share = $this->federatedShareProvider->getShareById($id);
317
-		} catch (Share\Exceptions\ShareNotFound $e) {
318
-			return new Http\DataResponse();
319
-		}
320
-
321
-		if ($this->verifyShare($share, $token)) {
322
-			$this->executeAcceptShare($share);
323
-			if ($share->getShareOwner() !== $share->getSharedBy()) {
324
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
325
-				$remoteId = $this->federatedShareProvider->getRemoteId($share);
326
-				$this->notifications->sendAcceptShare($remote, $remoteId, $share->getToken());
327
-			}
328
-		}
329
-
330
-		return new Http\DataResponse();
331
-	}
332
-
333
-	protected function executeAcceptShare(Share\IShare $share) {
334
-		$fileId = (int) $share->getNode()->getId();
335
-		list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId);
336
-
337
-		$event = \OC::$server->getActivityManager()->generateEvent();
338
-		$event->setApp('files_sharing')
339
-			->setType('remote_share')
340
-			->setAffectedUser($this->getCorrectUid($share))
341
-			->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
342
-			->setObject('files', $fileId, $file)
343
-			->setLink($link);
344
-		\OC::$server->getActivityManager()->publish($event);
345
-	}
346
-
347
-	/**
348
-	 * @NoCSRFRequired
349
-	 * @PublicPage
350
-	 *
351
-	 * decline server-to-server share
352
-	 *
353
-	 * @param int $id
354
-	 * @return Http\DataResponse
355
-	 * @throws OCSException
356
-	 */
357
-	public function declineShare($id) {
358
-
359
-		if (!$this->isS2SEnabled()) {
360
-			throw new OCSException('Server does not support federated cloud sharing', 503);
361
-		}
362
-
363
-		$token = isset($_POST['token']) ? $_POST['token'] : null;
364
-
365
-		try {
366
-			$share = $this->federatedShareProvider->getShareById($id);
367
-		} catch (Share\Exceptions\ShareNotFound $e) {
368
-			return new Http\DataResponse();
369
-		}
370
-
371
-		if ($this->verifyShare($share, $token)) {
372
-			if ($share->getShareOwner() !== $share->getSharedBy()) {
373
-				list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
374
-				$remoteId = $this->federatedShareProvider->getRemoteId($share);
375
-				$this->notifications->sendDeclineShare($remote, $remoteId, $share->getToken());
376
-			}
377
-			$this->executeDeclineShare($share);
378
-		}
379
-
380
-		return new Http\DataResponse();
381
-	}
382
-
383
-	/**
384
-	 * delete declined share and create a activity
385
-	 *
386
-	 * @param Share\IShare $share
387
-	 */
388
-	protected function executeDeclineShare(Share\IShare $share) {
389
-		$this->federatedShareProvider->removeShareFromTable($share);
390
-		$fileId = (int) $share->getNode()->getId();
391
-		list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId);
392
-
393
-		$event = \OC::$server->getActivityManager()->generateEvent();
394
-		$event->setApp('files_sharing')
395
-			->setType('remote_share')
396
-			->setAffectedUser($this->getCorrectUid($share))
397
-			->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
398
-			->setObject('files', $fileId, $file)
399
-			->setLink($link);
400
-		\OC::$server->getActivityManager()->publish($event);
401
-
402
-	}
403
-
404
-	/**
405
-	 * check if we are the initiator or the owner of a re-share and return the correct UID
406
-	 *
407
-	 * @param Share\IShare $share
408
-	 * @return string
409
-	 */
410
-	protected function getCorrectUid(Share\IShare $share) {
411
-		if ($this->userManager->userExists($share->getShareOwner())) {
412
-			return $share->getShareOwner();
413
-		}
414
-
415
-		return $share->getSharedBy();
416
-	}
417
-
418
-	/**
419
-	 * @NoCSRFRequired
420
-	 * @PublicPage
421
-	 *
422
-	 * remove server-to-server share if it was unshared by the owner
423
-	 *
424
-	 * @param int $id
425
-	 * @return Http\DataResponse
426
-	 * @throws OCSException
427
-	 */
428
-	public function unshare($id) {
429
-
430
-		if (!$this->isS2SEnabled()) {
431
-			throw new OCSException('Server does not support federated cloud sharing', 503);
432
-		}
433
-
434
-		$token = isset($_POST['token']) ? $_POST['token'] : null;
435
-
436
-		$qb = $this->connection->getQueryBuilder();
437
-		$qb->select('*')
438
-			->from('share_external')
439
-			->where(
440
-				$qb->expr()->andX(
441
-					$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
442
-					$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
443
-				)
444
-			);
445
-
446
-		$result = $qb->execute();
447
-		$share = $result->fetch();
448
-		$result->closeCursor();
449
-
450
-		if ($token && $id && !empty($share)) {
451
-
452
-			$remote = $this->cleanupRemote($share['remote']);
453
-
454
-			$owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
455
-			$mountpoint = $share['mountpoint'];
456
-			$user = $share['user'];
457
-
458
-			$qb = $this->connection->getQueryBuilder();
459
-			$qb->delete('share_external')
460
-				->where(
461
-					$qb->expr()->andX(
462
-						$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
463
-						$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
464
-					)
465
-				);
466
-
467
-			$result = $qb->execute();
468
-			$result->closeCursor();
469
-
470
-			if ($share['accepted']) {
471
-				$path = trim($mountpoint, '/');
472
-			} else {
473
-				$path = trim($share['name'], '/');
474
-			}
475
-
476
-			$notificationManager = \OC::$server->getNotificationManager();
477
-			$notification = $notificationManager->createNotification();
478
-			$notification->setApp('files_sharing')
479
-				->setUser($share['user'])
480
-				->setObject('remote_share', (int)$share['id']);
481
-			$notificationManager->markProcessed($notification);
482
-
483
-			$event = \OC::$server->getActivityManager()->generateEvent();
484
-			$event->setApp('files_sharing')
485
-				->setType('remote_share')
486
-				->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
487
-				->setAffectedUser($user)
488
-				->setObject('remote_share', (int)$share['id'], $path);
489
-			\OC::$server->getActivityManager()->publish($event);
490
-		}
491
-
492
-		return new Http\DataResponse();
493
-	}
494
-
495
-	private function cleanupRemote($remote) {
496
-		$remote = substr($remote, strpos($remote, '://') + 3);
497
-
498
-		return rtrim($remote, '/');
499
-	}
500
-
501
-
502
-	/**
503
-	 * @NoCSRFRequired
504
-	 * @PublicPage
505
-	 *
506
-	 * federated share was revoked, either by the owner or the re-sharer
507
-	 *
508
-	 * @param int $id
509
-	 * @return Http\DataResponse
510
-	 * @throws OCSBadRequestException
511
-	 */
512
-	public function revoke($id) {
513
-		$token = $this->request->getParam('token');
514
-
515
-		$share = $this->federatedShareProvider->getShareById($id);
516
-
517
-		if ($this->verifyShare($share, $token)) {
518
-			$this->federatedShareProvider->removeShareFromTable($share);
519
-			return new Http\DataResponse();
520
-		}
521
-
522
-		throw new OCSBadRequestException();
523
-	}
524
-
525
-	/**
526
-	 * get share
527
-	 *
528
-	 * @param int $id
529
-	 * @param string $token
530
-	 * @return array|bool
531
-	 */
532
-	protected function getShare($id, $token) {
533
-		$query = $this->connection->getQueryBuilder();
534
-		$query->select('*')->from($this->shareTable)
535
-			->where($query->expr()->eq('token', $query->createNamedParameter($token)))
536
-			->andWhere($query->expr()->eq('share_type', $query->createNamedParameter(FederatedShareProvider::SHARE_TYPE_REMOTE)))
537
-			->andWhere($query->expr()->eq('id', $query->createNamedParameter($id)));
538
-
539
-		$result = $query->execute()->fetchAll();
540
-
541
-		if (!empty($result) && isset($result[0])) {
542
-			return $result[0];
543
-		}
544
-
545
-		return false;
546
-	}
547
-
548
-	/**
549
-	 * get file
550
-	 *
551
-	 * @param string $user
552
-	 * @param int $fileSource
553
-	 * @return array with internal path of the file and a absolute link to it
554
-	 */
555
-	private function getFile($user, $fileSource) {
556
-		\OC_Util::setupFS($user);
557
-
558
-		try {
559
-			$file = \OC\Files\Filesystem::getPath($fileSource);
560
-		} catch (NotFoundException $e) {
561
-			$file = null;
562
-		}
563
-		$args = \OC\Files\Filesystem::is_dir($file) ? array('dir' => $file) : array('dir' => dirname($file), 'scrollto' => $file);
564
-		$link = \OCP\Util::linkToAbsolute('files', 'index.php', $args);
565
-
566
-		return array($file, $link);
567
-
568
-	}
569
-
570
-	/**
571
-	 * check if server-to-server sharing is enabled
572
-	 *
573
-	 * @param bool $incoming
574
-	 * @return bool
575
-	 */
576
-	private function isS2SEnabled($incoming = false) {
577
-
578
-		$result = \OCP\App::isEnabled('files_sharing');
579
-
580
-		if ($incoming) {
581
-			$result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
582
-		} else {
583
-			$result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
584
-		}
585
-
586
-		return $result;
587
-	}
588
-
589
-	/**
590
-	 * check if we got the right share
591
-	 *
592
-	 * @param Share\IShare $share
593
-	 * @param string $token
594
-	 * @return bool
595
-	 */
596
-	protected function verifyShare(Share\IShare $share, $token) {
597
-		if (
598
-			$share->getShareType() === FederatedShareProvider::SHARE_TYPE_REMOTE &&
599
-			$share->getToken() === $token
600
-		) {
601
-			return true;
602
-		}
603
-
604
-		return false;
605
-	}
606
-
607
-	/**
608
-	 * @NoCSRFRequired
609
-	 * @PublicPage
610
-	 *
611
-	 * update share information to keep federated re-shares in sync
612
-	 *
613
-	 * @param int $id
614
-	 * @return Http\DataResponse
615
-	 * @throws OCSBadRequestException
616
-	 */
617
-	public function updatePermissions($id) {
618
-		$token = $this->request->getParam('token', null);
619
-		$permissions = $this->request->getParam('permissions', null);
620
-
621
-		try {
622
-			$share = $this->federatedShareProvider->getShareById($id);
623
-		} catch (Share\Exceptions\ShareNotFound $e) {
624
-			throw new OCSBadRequestException();
625
-		}
626
-
627
-		$validPermission = ctype_digit($permissions);
628
-		$validToken = $this->verifyShare($share, $token);
629
-		if ($validPermission && $validToken) {
630
-			$this->updatePermissionsInDatabase($share, (int)$permissions);
631
-		} else {
632
-			throw new OCSBadRequestException();
633
-		}
634
-
635
-		return new Http\DataResponse();
636
-	}
637
-
638
-	/**
639
-	 * update permissions in database
640
-	 *
641
-	 * @param IShare $share
642
-	 * @param int $permissions
643
-	 */
644
-	protected function updatePermissionsInDatabase(IShare $share, $permissions) {
645
-		$query = $this->connection->getQueryBuilder();
646
-		$query->update('share')
647
-			->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
648
-			->set('permissions', $query->createNamedParameter($permissions))
649
-			->execute();
650
-	}
651
-
652
-	/**
653
-	 * @NoCSRFRequired
654
-	 * @PublicPage
655
-	 *
656
-	 * change the owner of a server-to-server share
657
-	 *
658
-	 * @param int $id
659
-	 * @return Http\DataResponse
660
-	 * @throws \InvalidArgumentException
661
-	 * @throws OCSException
662
-	 */
663
-	public function move($id) {
664
-
665
-		if (!$this->isS2SEnabled()) {
666
-			throw new OCSException('Server does not support federated cloud sharing', 503);
667
-		}
668
-
669
-		$token = $this->request->getParam('token');
670
-		$remote = $this->request->getParam('remote');
671
-		$newRemoteId = $this->request->getParam('remote_id', $id);
672
-		$cloudId = $this->cloudIdManager->resolveCloudId($remote);
673
-
674
-		$qb = $this->connection->getQueryBuilder();
675
-		$query = $qb->update('share_external')
676
-			->set('remote', $qb->createNamedParameter($cloudId->getRemote()))
677
-			->set('owner', $qb->createNamedParameter($cloudId->getUser()))
678
-			->set('remote_id', $qb->createNamedParameter($newRemoteId))
679
-			->where($qb->expr()->eq('remote_id', $qb->createNamedParameter($id)))
680
-			->andWhere($qb->expr()->eq('share_token', $qb->createNamedParameter($token)));
681
-		$affected = $query->execute();
682
-
683
-		if ($affected > 0) {
684
-			return new Http\DataResponse(['remote' => $cloudId->getRemote(), 'owner' => $cloudId->getUser()]);
685
-		} else {
686
-			throw new OCSBadRequestException('Share not found or token invalid');
687
-		}
688
-	}
54
+    /** @var FederatedShareProvider */
55
+    private $federatedShareProvider;
56
+
57
+    /** @var IDBConnection */
58
+    private $connection;
59
+
60
+    /** @var Share\IManager */
61
+    private $shareManager;
62
+
63
+    /** @var Notifications */
64
+    private $notifications;
65
+
66
+    /** @var AddressHandler */
67
+    private $addressHandler;
68
+
69
+    /** @var  IUserManager */
70
+    private $userManager;
71
+
72
+    /** @var string */
73
+    private $shareTable = 'share';
74
+
75
+    /** @var ICloudIdManager */
76
+    private $cloudIdManager;
77
+
78
+    /** @var ILogger */
79
+    private $logger;
80
+
81
+    /**
82
+     * Server2Server constructor.
83
+     *
84
+     * @param string $appName
85
+     * @param IRequest $request
86
+     * @param FederatedShareProvider $federatedShareProvider
87
+     * @param IDBConnection $connection
88
+     * @param Share\IManager $shareManager
89
+     * @param Notifications $notifications
90
+     * @param AddressHandler $addressHandler
91
+     * @param IUserManager $userManager
92
+     * @param ICloudIdManager $cloudIdManager
93
+     */
94
+    public function __construct($appName,
95
+                                IRequest $request,
96
+                                FederatedShareProvider $federatedShareProvider,
97
+                                IDBConnection $connection,
98
+                                Share\IManager $shareManager,
99
+                                Notifications $notifications,
100
+                                AddressHandler $addressHandler,
101
+                                IUserManager $userManager,
102
+                                ICloudIdManager $cloudIdManager,
103
+                                ILogger $logger
104
+    ) {
105
+        parent::__construct($appName, $request);
106
+
107
+        $this->federatedShareProvider = $federatedShareProvider;
108
+        $this->connection = $connection;
109
+        $this->shareManager = $shareManager;
110
+        $this->notifications = $notifications;
111
+        $this->addressHandler = $addressHandler;
112
+        $this->userManager = $userManager;
113
+        $this->cloudIdManager = $cloudIdManager;
114
+        $this->logger = $logger;
115
+    }
116
+
117
+    /**
118
+     * @NoCSRFRequired
119
+     * @PublicPage
120
+     *
121
+     * create a new share
122
+     *
123
+     * @return Http\DataResponse
124
+     * @throws OCSException
125
+     */
126
+    public function createShare() {
127
+
128
+        if (!$this->isS2SEnabled(true)) {
129
+            throw new OCSException('Server does not support federated cloud sharing', 503);
130
+        }
131
+
132
+        $remote = isset($_POST['remote']) ? $_POST['remote'] : null;
133
+        $token = isset($_POST['token']) ? $_POST['token'] : null;
134
+        $name = isset($_POST['name']) ? $_POST['name'] : null;
135
+        $owner = isset($_POST['owner']) ? $_POST['owner'] : null;
136
+        $sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null;
137
+        $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
138
+        $remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
139
+        $sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null;
140
+        $ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null;
141
+
142
+        if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
143
+
144
+            if (!\OCP\Util::isValidFileName($name)) {
145
+                throw new OCSException('The mountpoint name contains invalid characters.', 400);
146
+            }
147
+
148
+            // FIXME this should be a method in the user management instead
149
+            $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
150
+            \OCP\Util::emitHook(
151
+                '\OCA\Files_Sharing\API\Server2Server',
152
+                'preLoginNameUsedAsUserName',
153
+                array('uid' => &$shareWith)
154
+            );
155
+            $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
156
+
157
+            if (!\OC::$server->getUserManager()->userExists($shareWith)) {
158
+                throw new OCSException('User does not exists', 400);
159
+            }
160
+
161
+            \OC_Util::setupFS($shareWith);
162
+
163
+            $externalManager = new \OCA\Files_Sharing\External\Manager(
164
+                    \OC::$server->getDatabaseConnection(),
165
+                    \OC\Files\Filesystem::getMountManager(),
166
+                    \OC\Files\Filesystem::getLoader(),
167
+                    \OC::$server->getHTTPClientService(),
168
+                    \OC::$server->getNotificationManager(),
169
+                    \OC::$server->query(\OCP\OCS\IDiscoveryService::class),
170
+                    $shareWith
171
+                );
172
+
173
+            try {
174
+                $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId);
175
+                $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
176
+
177
+                if ($ownerFederatedId === null) {
178
+                    $ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
179
+                }
180
+                // if the owner of the share and the initiator are the same user
181
+                // we also complete the federated share ID for the initiator
182
+                if ($sharedByFederatedId === null && $owner === $sharedBy) {
183
+                    $sharedByFederatedId = $ownerFederatedId;
184
+                }
185
+
186
+                $event = \OC::$server->getActivityManager()->generateEvent();
187
+                $event->setApp('files_sharing')
188
+                    ->setType('remote_share')
189
+                    ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
190
+                    ->setAffectedUser($shareWith)
191
+                    ->setObject('remote_share', (int)$shareId, $name);
192
+                \OC::$server->getActivityManager()->publish($event);
193
+
194
+                $urlGenerator = \OC::$server->getURLGenerator();
195
+
196
+                $notificationManager = \OC::$server->getNotificationManager();
197
+                $notification = $notificationManager->createNotification();
198
+                $notification->setApp('files_sharing')
199
+                    ->setUser($shareWith)
200
+                    ->setDateTime(new \DateTime())
201
+                    ->setObject('remote_share', $shareId)
202
+                    ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]);
203
+
204
+                $declineAction = $notification->createAction();
205
+                $declineAction->setLabel('decline')
206
+                    ->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
207
+                $notification->addAction($declineAction);
208
+
209
+                $acceptAction = $notification->createAction();
210
+                $acceptAction->setLabel('accept')
211
+                    ->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
212
+                $notification->addAction($acceptAction);
213
+
214
+                $notificationManager->notify($notification);
215
+
216
+                return new Http\DataResponse();
217
+            } catch (\Exception $e) {
218
+                $this->logger->logException($e, [
219
+                    'message' => 'Server can not add remote share.',
220
+                    'level' => ILogger::ERROR,
221
+                    'app' => 'files_sharing'
222
+                ]);
223
+                throw new OCSException('internal server error, was not able to add share from ' . $remote, 500);
224
+            }
225
+        }
226
+
227
+        throw new OCSException('server can not add remote share, missing parameter', 400);
228
+    }
229
+
230
+    /**
231
+     * @NoCSRFRequired
232
+     * @PublicPage
233
+     *
234
+     * create re-share on behalf of another user
235
+     *
236
+     * @param int $id
237
+     * @return Http\DataResponse
238
+     * @throws OCSBadRequestException
239
+     * @throws OCSForbiddenException
240
+     * @throws OCSNotFoundException
241
+     */
242
+    public function reShare($id) {
243
+
244
+        $token = $this->request->getParam('token', null);
245
+        $shareWith = $this->request->getParam('shareWith', null);
246
+        $permission = (int)$this->request->getParam('permission', null);
247
+        $remoteId = (int)$this->request->getParam('remoteId', null);
248
+
249
+        if ($id === null ||
250
+            $token === null ||
251
+            $shareWith === null ||
252
+            $permission === null ||
253
+            $remoteId === null
254
+        ) {
255
+            throw new OCSBadRequestException();
256
+        }
257
+
258
+        try {
259
+            $share = $this->federatedShareProvider->getShareById($id);
260
+        } catch (Share\Exceptions\ShareNotFound $e) {
261
+            throw new OCSNotFoundException();
262
+        }
263
+
264
+        // don't allow to share a file back to the owner
265
+        list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith);
266
+        $owner = $share->getShareOwner();
267
+        $currentServer = $this->addressHandler->generateRemoteURL();
268
+        if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) {
269
+            throw new OCSForbiddenException();
270
+        }
271
+
272
+        if ($this->verifyShare($share, $token)) {
273
+
274
+            // check if re-sharing is allowed
275
+            if ($share->getPermissions() | ~Constants::PERMISSION_SHARE) {
276
+                $share->setPermissions($share->getPermissions() & $permission);
277
+                // the recipient of the initial share is now the initiator for the re-share
278
+                $share->setSharedBy($share->getSharedWith());
279
+                $share->setSharedWith($shareWith);
280
+                try {
281
+                    $result = $this->federatedShareProvider->create($share);
282
+                    $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $remoteId);
283
+                    return new Http\DataResponse([
284
+                        'token' => $result->getToken(),
285
+                        'remoteId' => $result->getId()
286
+                    ]);
287
+                } catch (\Exception $e) {
288
+                    throw new OCSBadRequestException();
289
+                }
290
+            } else {
291
+                throw new OCSForbiddenException();
292
+            }
293
+        }
294
+        throw new OCSBadRequestException();
295
+    }
296
+
297
+    /**
298
+     * @NoCSRFRequired
299
+     * @PublicPage
300
+     *
301
+     * accept server-to-server share
302
+     *
303
+     * @param int $id
304
+     * @return Http\DataResponse
305
+     * @throws OCSException
306
+     */
307
+    public function acceptShare($id) {
308
+
309
+        if (!$this->isS2SEnabled()) {
310
+            throw new OCSException('Server does not support federated cloud sharing', 503);
311
+        }
312
+
313
+        $token = isset($_POST['token']) ? $_POST['token'] : null;
314
+
315
+        try {
316
+            $share = $this->federatedShareProvider->getShareById($id);
317
+        } catch (Share\Exceptions\ShareNotFound $e) {
318
+            return new Http\DataResponse();
319
+        }
320
+
321
+        if ($this->verifyShare($share, $token)) {
322
+            $this->executeAcceptShare($share);
323
+            if ($share->getShareOwner() !== $share->getSharedBy()) {
324
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
325
+                $remoteId = $this->federatedShareProvider->getRemoteId($share);
326
+                $this->notifications->sendAcceptShare($remote, $remoteId, $share->getToken());
327
+            }
328
+        }
329
+
330
+        return new Http\DataResponse();
331
+    }
332
+
333
+    protected function executeAcceptShare(Share\IShare $share) {
334
+        $fileId = (int) $share->getNode()->getId();
335
+        list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId);
336
+
337
+        $event = \OC::$server->getActivityManager()->generateEvent();
338
+        $event->setApp('files_sharing')
339
+            ->setType('remote_share')
340
+            ->setAffectedUser($this->getCorrectUid($share))
341
+            ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
342
+            ->setObject('files', $fileId, $file)
343
+            ->setLink($link);
344
+        \OC::$server->getActivityManager()->publish($event);
345
+    }
346
+
347
+    /**
348
+     * @NoCSRFRequired
349
+     * @PublicPage
350
+     *
351
+     * decline server-to-server share
352
+     *
353
+     * @param int $id
354
+     * @return Http\DataResponse
355
+     * @throws OCSException
356
+     */
357
+    public function declineShare($id) {
358
+
359
+        if (!$this->isS2SEnabled()) {
360
+            throw new OCSException('Server does not support federated cloud sharing', 503);
361
+        }
362
+
363
+        $token = isset($_POST['token']) ? $_POST['token'] : null;
364
+
365
+        try {
366
+            $share = $this->federatedShareProvider->getShareById($id);
367
+        } catch (Share\Exceptions\ShareNotFound $e) {
368
+            return new Http\DataResponse();
369
+        }
370
+
371
+        if ($this->verifyShare($share, $token)) {
372
+            if ($share->getShareOwner() !== $share->getSharedBy()) {
373
+                list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
374
+                $remoteId = $this->federatedShareProvider->getRemoteId($share);
375
+                $this->notifications->sendDeclineShare($remote, $remoteId, $share->getToken());
376
+            }
377
+            $this->executeDeclineShare($share);
378
+        }
379
+
380
+        return new Http\DataResponse();
381
+    }
382
+
383
+    /**
384
+     * delete declined share and create a activity
385
+     *
386
+     * @param Share\IShare $share
387
+     */
388
+    protected function executeDeclineShare(Share\IShare $share) {
389
+        $this->federatedShareProvider->removeShareFromTable($share);
390
+        $fileId = (int) $share->getNode()->getId();
391
+        list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId);
392
+
393
+        $event = \OC::$server->getActivityManager()->generateEvent();
394
+        $event->setApp('files_sharing')
395
+            ->setType('remote_share')
396
+            ->setAffectedUser($this->getCorrectUid($share))
397
+            ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
398
+            ->setObject('files', $fileId, $file)
399
+            ->setLink($link);
400
+        \OC::$server->getActivityManager()->publish($event);
401
+
402
+    }
403
+
404
+    /**
405
+     * check if we are the initiator or the owner of a re-share and return the correct UID
406
+     *
407
+     * @param Share\IShare $share
408
+     * @return string
409
+     */
410
+    protected function getCorrectUid(Share\IShare $share) {
411
+        if ($this->userManager->userExists($share->getShareOwner())) {
412
+            return $share->getShareOwner();
413
+        }
414
+
415
+        return $share->getSharedBy();
416
+    }
417
+
418
+    /**
419
+     * @NoCSRFRequired
420
+     * @PublicPage
421
+     *
422
+     * remove server-to-server share if it was unshared by the owner
423
+     *
424
+     * @param int $id
425
+     * @return Http\DataResponse
426
+     * @throws OCSException
427
+     */
428
+    public function unshare($id) {
429
+
430
+        if (!$this->isS2SEnabled()) {
431
+            throw new OCSException('Server does not support federated cloud sharing', 503);
432
+        }
433
+
434
+        $token = isset($_POST['token']) ? $_POST['token'] : null;
435
+
436
+        $qb = $this->connection->getQueryBuilder();
437
+        $qb->select('*')
438
+            ->from('share_external')
439
+            ->where(
440
+                $qb->expr()->andX(
441
+                    $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
442
+                    $qb->expr()->eq('share_token', $qb->createNamedParameter($token))
443
+                )
444
+            );
445
+
446
+        $result = $qb->execute();
447
+        $share = $result->fetch();
448
+        $result->closeCursor();
449
+
450
+        if ($token && $id && !empty($share)) {
451
+
452
+            $remote = $this->cleanupRemote($share['remote']);
453
+
454
+            $owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
455
+            $mountpoint = $share['mountpoint'];
456
+            $user = $share['user'];
457
+
458
+            $qb = $this->connection->getQueryBuilder();
459
+            $qb->delete('share_external')
460
+                ->where(
461
+                    $qb->expr()->andX(
462
+                        $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
463
+                        $qb->expr()->eq('share_token', $qb->createNamedParameter($token))
464
+                    )
465
+                );
466
+
467
+            $result = $qb->execute();
468
+            $result->closeCursor();
469
+
470
+            if ($share['accepted']) {
471
+                $path = trim($mountpoint, '/');
472
+            } else {
473
+                $path = trim($share['name'], '/');
474
+            }
475
+
476
+            $notificationManager = \OC::$server->getNotificationManager();
477
+            $notification = $notificationManager->createNotification();
478
+            $notification->setApp('files_sharing')
479
+                ->setUser($share['user'])
480
+                ->setObject('remote_share', (int)$share['id']);
481
+            $notificationManager->markProcessed($notification);
482
+
483
+            $event = \OC::$server->getActivityManager()->generateEvent();
484
+            $event->setApp('files_sharing')
485
+                ->setType('remote_share')
486
+                ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
487
+                ->setAffectedUser($user)
488
+                ->setObject('remote_share', (int)$share['id'], $path);
489
+            \OC::$server->getActivityManager()->publish($event);
490
+        }
491
+
492
+        return new Http\DataResponse();
493
+    }
494
+
495
+    private function cleanupRemote($remote) {
496
+        $remote = substr($remote, strpos($remote, '://') + 3);
497
+
498
+        return rtrim($remote, '/');
499
+    }
500
+
501
+
502
+    /**
503
+     * @NoCSRFRequired
504
+     * @PublicPage
505
+     *
506
+     * federated share was revoked, either by the owner or the re-sharer
507
+     *
508
+     * @param int $id
509
+     * @return Http\DataResponse
510
+     * @throws OCSBadRequestException
511
+     */
512
+    public function revoke($id) {
513
+        $token = $this->request->getParam('token');
514
+
515
+        $share = $this->federatedShareProvider->getShareById($id);
516
+
517
+        if ($this->verifyShare($share, $token)) {
518
+            $this->federatedShareProvider->removeShareFromTable($share);
519
+            return new Http\DataResponse();
520
+        }
521
+
522
+        throw new OCSBadRequestException();
523
+    }
524
+
525
+    /**
526
+     * get share
527
+     *
528
+     * @param int $id
529
+     * @param string $token
530
+     * @return array|bool
531
+     */
532
+    protected function getShare($id, $token) {
533
+        $query = $this->connection->getQueryBuilder();
534
+        $query->select('*')->from($this->shareTable)
535
+            ->where($query->expr()->eq('token', $query->createNamedParameter($token)))
536
+            ->andWhere($query->expr()->eq('share_type', $query->createNamedParameter(FederatedShareProvider::SHARE_TYPE_REMOTE)))
537
+            ->andWhere($query->expr()->eq('id', $query->createNamedParameter($id)));
538
+
539
+        $result = $query->execute()->fetchAll();
540
+
541
+        if (!empty($result) && isset($result[0])) {
542
+            return $result[0];
543
+        }
544
+
545
+        return false;
546
+    }
547
+
548
+    /**
549
+     * get file
550
+     *
551
+     * @param string $user
552
+     * @param int $fileSource
553
+     * @return array with internal path of the file and a absolute link to it
554
+     */
555
+    private function getFile($user, $fileSource) {
556
+        \OC_Util::setupFS($user);
557
+
558
+        try {
559
+            $file = \OC\Files\Filesystem::getPath($fileSource);
560
+        } catch (NotFoundException $e) {
561
+            $file = null;
562
+        }
563
+        $args = \OC\Files\Filesystem::is_dir($file) ? array('dir' => $file) : array('dir' => dirname($file), 'scrollto' => $file);
564
+        $link = \OCP\Util::linkToAbsolute('files', 'index.php', $args);
565
+
566
+        return array($file, $link);
567
+
568
+    }
569
+
570
+    /**
571
+     * check if server-to-server sharing is enabled
572
+     *
573
+     * @param bool $incoming
574
+     * @return bool
575
+     */
576
+    private function isS2SEnabled($incoming = false) {
577
+
578
+        $result = \OCP\App::isEnabled('files_sharing');
579
+
580
+        if ($incoming) {
581
+            $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled();
582
+        } else {
583
+            $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
584
+        }
585
+
586
+        return $result;
587
+    }
588
+
589
+    /**
590
+     * check if we got the right share
591
+     *
592
+     * @param Share\IShare $share
593
+     * @param string $token
594
+     * @return bool
595
+     */
596
+    protected function verifyShare(Share\IShare $share, $token) {
597
+        if (
598
+            $share->getShareType() === FederatedShareProvider::SHARE_TYPE_REMOTE &&
599
+            $share->getToken() === $token
600
+        ) {
601
+            return true;
602
+        }
603
+
604
+        return false;
605
+    }
606
+
607
+    /**
608
+     * @NoCSRFRequired
609
+     * @PublicPage
610
+     *
611
+     * update share information to keep federated re-shares in sync
612
+     *
613
+     * @param int $id
614
+     * @return Http\DataResponse
615
+     * @throws OCSBadRequestException
616
+     */
617
+    public function updatePermissions($id) {
618
+        $token = $this->request->getParam('token', null);
619
+        $permissions = $this->request->getParam('permissions', null);
620
+
621
+        try {
622
+            $share = $this->federatedShareProvider->getShareById($id);
623
+        } catch (Share\Exceptions\ShareNotFound $e) {
624
+            throw new OCSBadRequestException();
625
+        }
626
+
627
+        $validPermission = ctype_digit($permissions);
628
+        $validToken = $this->verifyShare($share, $token);
629
+        if ($validPermission && $validToken) {
630
+            $this->updatePermissionsInDatabase($share, (int)$permissions);
631
+        } else {
632
+            throw new OCSBadRequestException();
633
+        }
634
+
635
+        return new Http\DataResponse();
636
+    }
637
+
638
+    /**
639
+     * update permissions in database
640
+     *
641
+     * @param IShare $share
642
+     * @param int $permissions
643
+     */
644
+    protected function updatePermissionsInDatabase(IShare $share, $permissions) {
645
+        $query = $this->connection->getQueryBuilder();
646
+        $query->update('share')
647
+            ->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
648
+            ->set('permissions', $query->createNamedParameter($permissions))
649
+            ->execute();
650
+    }
651
+
652
+    /**
653
+     * @NoCSRFRequired
654
+     * @PublicPage
655
+     *
656
+     * change the owner of a server-to-server share
657
+     *
658
+     * @param int $id
659
+     * @return Http\DataResponse
660
+     * @throws \InvalidArgumentException
661
+     * @throws OCSException
662
+     */
663
+    public function move($id) {
664
+
665
+        if (!$this->isS2SEnabled()) {
666
+            throw new OCSException('Server does not support federated cloud sharing', 503);
667
+        }
668
+
669
+        $token = $this->request->getParam('token');
670
+        $remote = $this->request->getParam('remote');
671
+        $newRemoteId = $this->request->getParam('remote_id', $id);
672
+        $cloudId = $this->cloudIdManager->resolveCloudId($remote);
673
+
674
+        $qb = $this->connection->getQueryBuilder();
675
+        $query = $qb->update('share_external')
676
+            ->set('remote', $qb->createNamedParameter($cloudId->getRemote()))
677
+            ->set('owner', $qb->createNamedParameter($cloudId->getUser()))
678
+            ->set('remote_id', $qb->createNamedParameter($newRemoteId))
679
+            ->where($qb->expr()->eq('remote_id', $qb->createNamedParameter($id)))
680
+            ->andWhere($qb->expr()->eq('share_token', $qb->createNamedParameter($token)));
681
+        $affected = $query->execute();
682
+
683
+        if ($affected > 0) {
684
+            return new Http\DataResponse(['remote' => $cloudId->getRemote(), 'owner' => $cloudId->getUser()]);
685
+        } else {
686
+            throw new OCSBadRequestException('Share not found or token invalid');
687
+        }
688
+    }
689 689
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -135,7 +135,7 @@  discard block
 block discarded – undo
135 135
 		$owner = isset($_POST['owner']) ? $_POST['owner'] : null;
136 136
 		$sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null;
137 137
 		$shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
138
-		$remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
138
+		$remoteId = isset($_POST['remoteId']) ? (int) $_POST['remoteId'] : null;
139 139
 		$sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null;
140 140
 		$ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null;
141 141
 
@@ -146,13 +146,13 @@  discard block
 block discarded – undo
146 146
 			}
147 147
 
148 148
 			// FIXME this should be a method in the user management instead
149
-			$this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
149
+			$this->logger->debug('shareWith before, '.$shareWith, ['app' => 'files_sharing']);
150 150
 			\OCP\Util::emitHook(
151 151
 				'\OCA\Files_Sharing\API\Server2Server',
152 152
 				'preLoginNameUsedAsUserName',
153 153
 				array('uid' => &$shareWith)
154 154
 			);
155
-			$this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
155
+			$this->logger->debug('shareWith after, '.$shareWith, ['app' => 'files_sharing']);
156 156
 
157 157
 			if (!\OC::$server->getUserManager()->userExists($shareWith)) {
158 158
 				throw new OCSException('User does not exists', 400);
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
 					->setType('remote_share')
189 189
 					->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')])
190 190
 					->setAffectedUser($shareWith)
191
-					->setObject('remote_share', (int)$shareId, $name);
191
+					->setObject('remote_share', (int) $shareId, $name);
192 192
 				\OC::$server->getActivityManager()->publish($event);
193 193
 
194 194
 				$urlGenerator = \OC::$server->getURLGenerator();
@@ -203,12 +203,12 @@  discard block
 block discarded – undo
203 203
 
204 204
 				$declineAction = $notification->createAction();
205 205
 				$declineAction->setLabel('decline')
206
-					->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE');
206
+					->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/'.$shareId)), 'DELETE');
207 207
 				$notification->addAction($declineAction);
208 208
 
209 209
 				$acceptAction = $notification->createAction();
210 210
 				$acceptAction->setLabel('accept')
211
-					->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST');
211
+					->setLink($urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/'.$shareId)), 'POST');
212 212
 				$notification->addAction($acceptAction);
213 213
 
214 214
 				$notificationManager->notify($notification);
@@ -220,7 +220,7 @@  discard block
 block discarded – undo
220 220
 					'level' => ILogger::ERROR,
221 221
 					'app' => 'files_sharing'
222 222
 				]);
223
-				throw new OCSException('internal server error, was not able to add share from ' . $remote, 500);
223
+				throw new OCSException('internal server error, was not able to add share from '.$remote, 500);
224 224
 			}
225 225
 		}
226 226
 
@@ -243,8 +243,8 @@  discard block
 block discarded – undo
243 243
 
244 244
 		$token = $this->request->getParam('token', null);
245 245
 		$shareWith = $this->request->getParam('shareWith', null);
246
-		$permission = (int)$this->request->getParam('permission', null);
247
-		$remoteId = (int)$this->request->getParam('remoteId', null);
246
+		$permission = (int) $this->request->getParam('permission', null);
247
+		$remoteId = (int) $this->request->getParam('remoteId', null);
248 248
 
249 249
 		if ($id === null ||
250 250
 			$token === null ||
@@ -279,7 +279,7 @@  discard block
 block discarded – undo
279 279
 				$share->setSharedWith($shareWith);
280 280
 				try {
281 281
 					$result = $this->federatedShareProvider->create($share);
282
-					$this->federatedShareProvider->storeRemoteId((int)$result->getId(), $remoteId);
282
+					$this->federatedShareProvider->storeRemoteId((int) $result->getId(), $remoteId);
283 283
 					return new Http\DataResponse([
284 284
 						'token' => $result->getToken(),
285 285
 						'remoteId' => $result->getId()
@@ -477,7 +477,7 @@  discard block
 block discarded – undo
477 477
 			$notification = $notificationManager->createNotification();
478 478
 			$notification->setApp('files_sharing')
479 479
 				->setUser($share['user'])
480
-				->setObject('remote_share', (int)$share['id']);
480
+				->setObject('remote_share', (int) $share['id']);
481 481
 			$notificationManager->markProcessed($notification);
482 482
 
483 483
 			$event = \OC::$server->getActivityManager()->generateEvent();
@@ -485,7 +485,7 @@  discard block
 block discarded – undo
485 485
 				->setType('remote_share')
486 486
 				->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path])
487 487
 				->setAffectedUser($user)
488
-				->setObject('remote_share', (int)$share['id'], $path);
488
+				->setObject('remote_share', (int) $share['id'], $path);
489 489
 			\OC::$server->getActivityManager()->publish($event);
490 490
 		}
491 491
 
@@ -627,7 +627,7 @@  discard block
 block discarded – undo
627 627
 		$validPermission = ctype_digit($permissions);
628 628
 		$validToken = $this->verifyShare($share, $token);
629 629
 		if ($validPermission && $validToken) {
630
-			$this->updatePermissionsInDatabase($share, (int)$permissions);
630
+			$this->updatePermissionsInDatabase($share, (int) $permissions);
631 631
 		} else {
632 632
 			throw new OCSBadRequestException();
633 633
 		}
Please login to merge, or discard this patch.
apps/sharebymail/lib/ShareByMailProvider.php 1 patch
Indentation   +1018 added lines, -1018 removed lines patch added patch discarded remove patch
@@ -53,1036 +53,1036 @@
 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
-				$share->getExpirationDate()
352
-			);
353
-		} catch (HintException $hintException) {
354
-			$this->logger->logException($hintException, [
355
-				'message' => 'Failed to send share by mail.',
356
-				'level' => ILogger::ERROR,
357
-				'app' => 'sharebymail',
358
-			]);
359
-			$this->removeShareFromTable($shareId);
360
-			throw $hintException;
361
-		} catch (\Exception $e) {
362
-			$this->logger->logException($e, [
363
-				'message' => 'Failed to send share by mail.',
364
-				'level' => ILogger::ERROR,
365
-				'app' => 'sharebymail',
366
-			]);
367
-			$this->removeShareFromTable($shareId);
368
-			throw new HintException('Failed to send share by mail',
369
-				$this->l->t('Failed to send share by email'));
370
-		}
371
-
372
-		return $shareId;
373
-
374
-	}
375
-
376
-	/**
377
-	 * @param string $filename
378
-	 * @param string $link
379
-	 * @param string $initiator
380
-	 * @param string $shareWith
381
-	 * @param \DateTime|null $expiration
382
-	 * @throws \Exception If mail couldn't be sent
383
-	 */
384
-	protected function sendMailNotification($filename,
385
-											$link,
386
-											$initiator,
387
-											$shareWith,
388
-											\DateTime $expiration = null) {
389
-		$initiatorUser = $this->userManager->get($initiator);
390
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
391
-		$message = $this->mailer->createMessage();
392
-
393
-		$emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [
394
-			'filename' => $filename,
395
-			'link' => $link,
396
-			'initiator' => $initiatorDisplayName,
397
-			'expiration' => $expiration,
398
-			'shareWith' => $shareWith,
399
-		]);
400
-
401
-		$emailTemplate->setSubject($this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename)));
402
-		$emailTemplate->addHeader();
403
-		$emailTemplate->addHeading($this->l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false);
404
-		$text = $this->l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
405
-
406
-		$emailTemplate->addBodyText(
407
-			htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')),
408
-			$text
409
-		);
410
-		$emailTemplate->addBodyButton(
411
-			$this->l->t('Open »%s«', [$filename]),
412
-			$link
413
-		);
414
-
415
-		$message->setTo([$shareWith]);
416
-
417
-		// The "From" contains the sharers name
418
-		$instanceName = $this->defaults->getName();
419
-		$senderName = $this->l->t(
420
-			'%s via %s',
421
-			[
422
-				$initiatorDisplayName,
423
-				$instanceName
424
-			]
425
-		);
426
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
427
-
428
-		// The "Reply-To" is set to the sharer if an mail address is configured
429
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
430
-		$initiatorEmail = $initiatorUser->getEMailAddress();
431
-		if($initiatorEmail !== null) {
432
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
433
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
434
-		} else {
435
-			$emailTemplate->addFooter();
436
-		}
437
-
438
-		$message->useTemplate($emailTemplate);
439
-		$this->mailer->send($message);
440
-	}
441
-
442
-	/**
443
-	 * send password to recipient of a mail share
444
-	 *
445
-	 * @param IShare $share
446
-	 * @param string $password
447
-	 * @return bool
448
-	 */
449
-	protected function sendPassword(IShare $share, $password) {
450
-
451
-		$filename = $share->getNode()->getName();
452
-		$initiator = $share->getSharedBy();
453
-		$shareWith = $share->getSharedWith();
454
-
455
-		if ($password === '' || $this->settingsManager->sendPasswordByMail() === false) {
456
-			return false;
457
-		}
458
-
459
-		$initiatorUser = $this->userManager->get($initiator);
460
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
461
-		$initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
462
-
463
-		$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]);
464
-		$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]);
465
-
466
-		$message = $this->mailer->createMessage();
467
-
468
-		$emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [
469
-			'filename' => $filename,
470
-			'password' => $password,
471
-			'initiator' => $initiatorDisplayName,
472
-			'initiatorEmail' => $initiatorEmailAddress,
473
-			'shareWith' => $shareWith,
474
-		]);
475
-
476
-		$emailTemplate->setSubject($this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]));
477
-		$emailTemplate->addHeader();
478
-		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
479
-		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
480
-		$emailTemplate->addBodyText($this->l->t('It is protected with the following password: %s', [$password]));
481
-
482
-		// The "From" contains the sharers name
483
-		$instanceName = $this->defaults->getName();
484
-		$senderName = $this->l->t(
485
-			'%s via %s',
486
-			[
487
-				$initiatorDisplayName,
488
-				$instanceName
489
-			]
490
-		);
491
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
492
-		if ($initiatorEmailAddress !== null) {
493
-			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
494
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
495
-		} else {
496
-			$emailTemplate->addFooter();
497
-		}
498
-
499
-		$message->setTo([$shareWith]);
500
-		$message->useTemplate($emailTemplate);
501
-		$this->mailer->send($message);
502
-
503
-		$this->createPasswordSendActivity($share, $shareWith, false);
504
-
505
-		return true;
506
-	}
507
-
508
-	/**
509
-	 * send auto generated password to the owner. This happens if the admin enforces
510
-	 * a password for mail shares and forbid to send the password by mail to the recipient
511
-	 *
512
-	 * @param IShare $share
513
-	 * @param string $password
514
-	 * @return bool
515
-	 * @throws \Exception
516
-	 */
517
-	protected function sendPasswordToOwner(IShare $share, $password) {
518
-
519
-		$filename = $share->getNode()->getName();
520
-		$initiator = $this->userManager->get($share->getSharedBy());
521
-		$initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
522
-		$initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
523
-		$shareWith = $share->getSharedWith();
524
-
525
-		if ($initiatorEMailAddress === null) {
526
-			throw new \Exception(
527
-				$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.")
528
-			);
529
-		}
530
-
531
-		$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()]);
532
-
533
-		$message = $this->mailer->createMessage();
534
-		$emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [
535
-			'filename' => $filename,
536
-			'password' => $password,
537
-			'initiator' => $initiatorDisplayName,
538
-			'initiatorEmail' => $initiatorEMailAddress,
539
-			'shareWith' => $shareWith,
540
-		]);
541
-
542
-		$emailTemplate->setSubject($this->l->t('Password to access »%s« shared with %s', [$filename, $shareWith]));
543
-		$emailTemplate->addHeader();
544
-		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
545
-		$emailTemplate->addBodyText($bodyPart);
546
-		$emailTemplate->addBodyText($this->l->t('This is the password: %s', [$password]));
547
-		$emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
548
-		$emailTemplate->addFooter();
549
-
550
-		if ($initiatorEMailAddress) {
551
-			$message->setFrom([$initiatorEMailAddress => $initiatorDisplayName]);
552
-		}
553
-		$message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
554
-		$message->useTemplate($emailTemplate);
555
-		$this->mailer->send($message);
556
-
557
-		$this->createPasswordSendActivity($share, $shareWith, true);
558
-
559
-		return true;
560
-	}
561
-
562
-	/**
563
-	 * generate share token
564
-	 *
565
-	 * @return string
566
-	 */
567
-	protected function generateToken($size = 15) {
568
-		$token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE);
569
-		return $token;
570
-	}
571
-
572
-	/**
573
-	 * Get all children of this share
574
-	 *
575
-	 * @param IShare $parent
576
-	 * @return IShare[]
577
-	 */
578
-	public function getChildren(IShare $parent) {
579
-		$children = [];
580
-
581
-		$qb = $this->dbConnection->getQueryBuilder();
582
-		$qb->select('*')
583
-			->from('share')
584
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
585
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
586
-			->orderBy('id');
587
-
588
-		$cursor = $qb->execute();
589
-		while($data = $cursor->fetch()) {
590
-			$children[] = $this->createShareObject($data);
591
-		}
592
-		$cursor->closeCursor();
593
-
594
-		return $children;
595
-	}
596
-
597
-	/**
598
-	 * add share to the database and return the ID
599
-	 *
600
-	 * @param int $itemSource
601
-	 * @param string $itemType
602
-	 * @param string $shareWith
603
-	 * @param string $sharedBy
604
-	 * @param string $uidOwner
605
-	 * @param int $permissions
606
-	 * @param string $token
607
-	 * @return int
608
-	 */
609
-	protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password) {
610
-		$qb = $this->dbConnection->getQueryBuilder();
611
-		$qb->insert('share')
612
-			->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
613
-			->setValue('item_type', $qb->createNamedParameter($itemType))
614
-			->setValue('item_source', $qb->createNamedParameter($itemSource))
615
-			->setValue('file_source', $qb->createNamedParameter($itemSource))
616
-			->setValue('share_with', $qb->createNamedParameter($shareWith))
617
-			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
618
-			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
619
-			->setValue('permissions', $qb->createNamedParameter($permissions))
620
-			->setValue('token', $qb->createNamedParameter($token))
621
-			->setValue('password', $qb->createNamedParameter($password))
622
-			->setValue('stime', $qb->createNamedParameter(time()));
623
-
624
-		/*
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
+                $share->getExpirationDate()
352
+            );
353
+        } catch (HintException $hintException) {
354
+            $this->logger->logException($hintException, [
355
+                'message' => 'Failed to send share by mail.',
356
+                'level' => ILogger::ERROR,
357
+                'app' => 'sharebymail',
358
+            ]);
359
+            $this->removeShareFromTable($shareId);
360
+            throw $hintException;
361
+        } catch (\Exception $e) {
362
+            $this->logger->logException($e, [
363
+                'message' => 'Failed to send share by mail.',
364
+                'level' => ILogger::ERROR,
365
+                'app' => 'sharebymail',
366
+            ]);
367
+            $this->removeShareFromTable($shareId);
368
+            throw new HintException('Failed to send share by mail',
369
+                $this->l->t('Failed to send share by email'));
370
+        }
371
+
372
+        return $shareId;
373
+
374
+    }
375
+
376
+    /**
377
+     * @param string $filename
378
+     * @param string $link
379
+     * @param string $initiator
380
+     * @param string $shareWith
381
+     * @param \DateTime|null $expiration
382
+     * @throws \Exception If mail couldn't be sent
383
+     */
384
+    protected function sendMailNotification($filename,
385
+                                            $link,
386
+                                            $initiator,
387
+                                            $shareWith,
388
+                                            \DateTime $expiration = null) {
389
+        $initiatorUser = $this->userManager->get($initiator);
390
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
391
+        $message = $this->mailer->createMessage();
392
+
393
+        $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [
394
+            'filename' => $filename,
395
+            'link' => $link,
396
+            'initiator' => $initiatorDisplayName,
397
+            'expiration' => $expiration,
398
+            'shareWith' => $shareWith,
399
+        ]);
400
+
401
+        $emailTemplate->setSubject($this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename)));
402
+        $emailTemplate->addHeader();
403
+        $emailTemplate->addHeading($this->l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false);
404
+        $text = $this->l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
405
+
406
+        $emailTemplate->addBodyText(
407
+            htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')),
408
+            $text
409
+        );
410
+        $emailTemplate->addBodyButton(
411
+            $this->l->t('Open »%s«', [$filename]),
412
+            $link
413
+        );
414
+
415
+        $message->setTo([$shareWith]);
416
+
417
+        // The "From" contains the sharers name
418
+        $instanceName = $this->defaults->getName();
419
+        $senderName = $this->l->t(
420
+            '%s via %s',
421
+            [
422
+                $initiatorDisplayName,
423
+                $instanceName
424
+            ]
425
+        );
426
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
427
+
428
+        // The "Reply-To" is set to the sharer if an mail address is configured
429
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
430
+        $initiatorEmail = $initiatorUser->getEMailAddress();
431
+        if($initiatorEmail !== null) {
432
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
433
+            $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
434
+        } else {
435
+            $emailTemplate->addFooter();
436
+        }
437
+
438
+        $message->useTemplate($emailTemplate);
439
+        $this->mailer->send($message);
440
+    }
441
+
442
+    /**
443
+     * send password to recipient of a mail share
444
+     *
445
+     * @param IShare $share
446
+     * @param string $password
447
+     * @return bool
448
+     */
449
+    protected function sendPassword(IShare $share, $password) {
450
+
451
+        $filename = $share->getNode()->getName();
452
+        $initiator = $share->getSharedBy();
453
+        $shareWith = $share->getSharedWith();
454
+
455
+        if ($password === '' || $this->settingsManager->sendPasswordByMail() === false) {
456
+            return false;
457
+        }
458
+
459
+        $initiatorUser = $this->userManager->get($initiator);
460
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
461
+        $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
462
+
463
+        $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]);
464
+        $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]);
465
+
466
+        $message = $this->mailer->createMessage();
467
+
468
+        $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [
469
+            'filename' => $filename,
470
+            'password' => $password,
471
+            'initiator' => $initiatorDisplayName,
472
+            'initiatorEmail' => $initiatorEmailAddress,
473
+            'shareWith' => $shareWith,
474
+        ]);
475
+
476
+        $emailTemplate->setSubject($this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]));
477
+        $emailTemplate->addHeader();
478
+        $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
479
+        $emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
480
+        $emailTemplate->addBodyText($this->l->t('It is protected with the following password: %s', [$password]));
481
+
482
+        // The "From" contains the sharers name
483
+        $instanceName = $this->defaults->getName();
484
+        $senderName = $this->l->t(
485
+            '%s via %s',
486
+            [
487
+                $initiatorDisplayName,
488
+                $instanceName
489
+            ]
490
+        );
491
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
492
+        if ($initiatorEmailAddress !== null) {
493
+            $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
494
+            $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
495
+        } else {
496
+            $emailTemplate->addFooter();
497
+        }
498
+
499
+        $message->setTo([$shareWith]);
500
+        $message->useTemplate($emailTemplate);
501
+        $this->mailer->send($message);
502
+
503
+        $this->createPasswordSendActivity($share, $shareWith, false);
504
+
505
+        return true;
506
+    }
507
+
508
+    /**
509
+     * send auto generated password to the owner. This happens if the admin enforces
510
+     * a password for mail shares and forbid to send the password by mail to the recipient
511
+     *
512
+     * @param IShare $share
513
+     * @param string $password
514
+     * @return bool
515
+     * @throws \Exception
516
+     */
517
+    protected function sendPasswordToOwner(IShare $share, $password) {
518
+
519
+        $filename = $share->getNode()->getName();
520
+        $initiator = $this->userManager->get($share->getSharedBy());
521
+        $initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
522
+        $initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
523
+        $shareWith = $share->getSharedWith();
524
+
525
+        if ($initiatorEMailAddress === null) {
526
+            throw new \Exception(
527
+                $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.")
528
+            );
529
+        }
530
+
531
+        $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()]);
532
+
533
+        $message = $this->mailer->createMessage();
534
+        $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [
535
+            'filename' => $filename,
536
+            'password' => $password,
537
+            'initiator' => $initiatorDisplayName,
538
+            'initiatorEmail' => $initiatorEMailAddress,
539
+            'shareWith' => $shareWith,
540
+        ]);
541
+
542
+        $emailTemplate->setSubject($this->l->t('Password to access »%s« shared with %s', [$filename, $shareWith]));
543
+        $emailTemplate->addHeader();
544
+        $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
545
+        $emailTemplate->addBodyText($bodyPart);
546
+        $emailTemplate->addBodyText($this->l->t('This is the password: %s', [$password]));
547
+        $emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
548
+        $emailTemplate->addFooter();
549
+
550
+        if ($initiatorEMailAddress) {
551
+            $message->setFrom([$initiatorEMailAddress => $initiatorDisplayName]);
552
+        }
553
+        $message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
554
+        $message->useTemplate($emailTemplate);
555
+        $this->mailer->send($message);
556
+
557
+        $this->createPasswordSendActivity($share, $shareWith, true);
558
+
559
+        return true;
560
+    }
561
+
562
+    /**
563
+     * generate share token
564
+     *
565
+     * @return string
566
+     */
567
+    protected function generateToken($size = 15) {
568
+        $token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE);
569
+        return $token;
570
+    }
571
+
572
+    /**
573
+     * Get all children of this share
574
+     *
575
+     * @param IShare $parent
576
+     * @return IShare[]
577
+     */
578
+    public function getChildren(IShare $parent) {
579
+        $children = [];
580
+
581
+        $qb = $this->dbConnection->getQueryBuilder();
582
+        $qb->select('*')
583
+            ->from('share')
584
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
585
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
586
+            ->orderBy('id');
587
+
588
+        $cursor = $qb->execute();
589
+        while($data = $cursor->fetch()) {
590
+            $children[] = $this->createShareObject($data);
591
+        }
592
+        $cursor->closeCursor();
593
+
594
+        return $children;
595
+    }
596
+
597
+    /**
598
+     * add share to the database and return the ID
599
+     *
600
+     * @param int $itemSource
601
+     * @param string $itemType
602
+     * @param string $shareWith
603
+     * @param string $sharedBy
604
+     * @param string $uidOwner
605
+     * @param int $permissions
606
+     * @param string $token
607
+     * @return int
608
+     */
609
+    protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password) {
610
+        $qb = $this->dbConnection->getQueryBuilder();
611
+        $qb->insert('share')
612
+            ->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
613
+            ->setValue('item_type', $qb->createNamedParameter($itemType))
614
+            ->setValue('item_source', $qb->createNamedParameter($itemSource))
615
+            ->setValue('file_source', $qb->createNamedParameter($itemSource))
616
+            ->setValue('share_with', $qb->createNamedParameter($shareWith))
617
+            ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
618
+            ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
619
+            ->setValue('permissions', $qb->createNamedParameter($permissions))
620
+            ->setValue('token', $qb->createNamedParameter($token))
621
+            ->setValue('password', $qb->createNamedParameter($password))
622
+            ->setValue('stime', $qb->createNamedParameter(time()));
623
+
624
+        /*
625 625
 		 * Added to fix https://github.com/owncloud/core/issues/22215
626 626
 		 * Can be removed once we get rid of ajax/share.php
627 627
 		 */
628
-		$qb->setValue('file_target', $qb->createNamedParameter(''));
628
+        $qb->setValue('file_target', $qb->createNamedParameter(''));
629 629
 
630
-		$qb->execute();
631
-		$id = $qb->getLastInsertId();
630
+        $qb->execute();
631
+        $id = $qb->getLastInsertId();
632 632
 
633
-		return (int)$id;
634
-	}
633
+        return (int)$id;
634
+    }
635 635
 
636
-	/**
637
-	 * Update a share
638
-	 *
639
-	 * @param IShare $share
640
-	 * @param string|null $plainTextPassword
641
-	 * @return IShare The share object
642
-	 */
643
-	public function update(IShare $share, $plainTextPassword = null) {
636
+    /**
637
+     * Update a share
638
+     *
639
+     * @param IShare $share
640
+     * @param string|null $plainTextPassword
641
+     * @return IShare The share object
642
+     */
643
+    public function update(IShare $share, $plainTextPassword = null) {
644 644
 
645
-		$originalShare = $this->getShareById($share->getId());
645
+        $originalShare = $this->getShareById($share->getId());
646 646
 
647
-		// a real password was given
648
-		$validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
647
+        // a real password was given
648
+        $validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
649 649
 
650
-		if($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
651
-			$this->sendPassword($share, $plainTextPassword);
652
-		}
653
-		/*
650
+        if($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
651
+            $this->sendPassword($share, $plainTextPassword);
652
+        }
653
+        /*
654 654
 		 * We allow updating the permissions and password of mail shares
655 655
 		 */
656
-		$qb = $this->dbConnection->getQueryBuilder();
657
-		$qb->update('share')
658
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
659
-			->set('permissions', $qb->createNamedParameter($share->getPermissions()))
660
-			->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
661
-			->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
662
-			->set('password', $qb->createNamedParameter($share->getPassword()))
663
-			->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
664
-			->execute();
665
-
666
-		return $share;
667
-	}
668
-
669
-	/**
670
-	 * @inheritdoc
671
-	 */
672
-	public function move(IShare $share, $recipient) {
673
-		/**
674
-		 * nothing to do here, mail shares are only outgoing shares
675
-		 */
676
-		return $share;
677
-	}
678
-
679
-	/**
680
-	 * Delete a share (owner unShares the file)
681
-	 *
682
-	 * @param IShare $share
683
-	 */
684
-	public function delete(IShare $share) {
685
-		$this->removeShareFromTable($share->getId());
686
-	}
687
-
688
-	/**
689
-	 * @inheritdoc
690
-	 */
691
-	public function deleteFromSelf(IShare $share, $recipient) {
692
-		// nothing to do here, mail shares are only outgoing shares
693
-	}
694
-
695
-	/**
696
-	 * @inheritdoc
697
-	 */
698
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
699
-		$qb = $this->dbConnection->getQueryBuilder();
700
-		$qb->select('*')
701
-			->from('share');
702
-
703
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
704
-
705
-		/**
706
-		 * Reshares for this user are shares where they are the owner.
707
-		 */
708
-		if ($reshares === false) {
709
-			//Special case for old shares created via the web UI
710
-			$or1 = $qb->expr()->andX(
711
-				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
712
-				$qb->expr()->isNull('uid_initiator')
713
-			);
714
-
715
-			$qb->andWhere(
716
-				$qb->expr()->orX(
717
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
718
-					$or1
719
-				)
720
-			);
721
-		} else {
722
-			$qb->andWhere(
723
-				$qb->expr()->orX(
724
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
725
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
726
-				)
727
-			);
728
-		}
729
-
730
-		if ($node !== null) {
731
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
732
-		}
733
-
734
-		if ($limit !== -1) {
735
-			$qb->setMaxResults($limit);
736
-		}
737
-
738
-		$qb->setFirstResult($offset);
739
-		$qb->orderBy('id');
740
-
741
-		$cursor = $qb->execute();
742
-		$shares = [];
743
-		while($data = $cursor->fetch()) {
744
-			$shares[] = $this->createShareObject($data);
745
-		}
746
-		$cursor->closeCursor();
747
-
748
-		return $shares;
749
-	}
750
-
751
-	/**
752
-	 * @inheritdoc
753
-	 */
754
-	public function getShareById($id, $recipientId = null) {
755
-		$qb = $this->dbConnection->getQueryBuilder();
756
-
757
-		$qb->select('*')
758
-			->from('share')
759
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
760
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
761
-
762
-		$cursor = $qb->execute();
763
-		$data = $cursor->fetch();
764
-		$cursor->closeCursor();
765
-
766
-		if ($data === false) {
767
-			throw new ShareNotFound();
768
-		}
769
-
770
-		try {
771
-			$share = $this->createShareObject($data);
772
-		} catch (InvalidShare $e) {
773
-			throw new ShareNotFound();
774
-		}
775
-
776
-		return $share;
777
-	}
778
-
779
-	/**
780
-	 * Get shares for a given path
781
-	 *
782
-	 * @param \OCP\Files\Node $path
783
-	 * @return IShare[]
784
-	 */
785
-	public function getSharesByPath(Node $path) {
786
-		$qb = $this->dbConnection->getQueryBuilder();
787
-
788
-		$cursor = $qb->select('*')
789
-			->from('share')
790
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
791
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
792
-			->execute();
793
-
794
-		$shares = [];
795
-		while($data = $cursor->fetch()) {
796
-			$shares[] = $this->createShareObject($data);
797
-		}
798
-		$cursor->closeCursor();
799
-
800
-		return $shares;
801
-	}
802
-
803
-	/**
804
-	 * @inheritdoc
805
-	 */
806
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
807
-		/** @var IShare[] $shares */
808
-		$shares = [];
809
-
810
-		//Get shares directly with this user
811
-		$qb = $this->dbConnection->getQueryBuilder();
812
-		$qb->select('*')
813
-			->from('share');
814
-
815
-		// Order by id
816
-		$qb->orderBy('id');
817
-
818
-		// Set limit and offset
819
-		if ($limit !== -1) {
820
-			$qb->setMaxResults($limit);
821
-		}
822
-		$qb->setFirstResult($offset);
823
-
824
-		$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
825
-		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
826
-
827
-		// Filter by node if provided
828
-		if ($node !== null) {
829
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
830
-		}
831
-
832
-		$cursor = $qb->execute();
833
-
834
-		while($data = $cursor->fetch()) {
835
-			$shares[] = $this->createShareObject($data);
836
-		}
837
-		$cursor->closeCursor();
838
-
839
-
840
-		return $shares;
841
-	}
842
-
843
-	/**
844
-	 * Get a share by token
845
-	 *
846
-	 * @param string $token
847
-	 * @return IShare
848
-	 * @throws ShareNotFound
849
-	 */
850
-	public function getShareByToken($token) {
851
-		$qb = $this->dbConnection->getQueryBuilder();
852
-
853
-		$cursor = $qb->select('*')
854
-			->from('share')
855
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
856
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
857
-			->execute();
858
-
859
-		$data = $cursor->fetch();
860
-
861
-		if ($data === false) {
862
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
863
-		}
864
-
865
-		try {
866
-			$share = $this->createShareObject($data);
867
-		} catch (InvalidShare $e) {
868
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
869
-		}
870
-
871
-		return $share;
872
-	}
873
-
874
-	/**
875
-	 * remove share from table
876
-	 *
877
-	 * @param string $shareId
878
-	 */
879
-	protected function removeShareFromTable($shareId) {
880
-		$qb = $this->dbConnection->getQueryBuilder();
881
-		$qb->delete('share')
882
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
883
-		$qb->execute();
884
-	}
885
-
886
-	/**
887
-	 * Create a share object from an database row
888
-	 *
889
-	 * @param array $data
890
-	 * @return IShare
891
-	 * @throws InvalidShare
892
-	 * @throws ShareNotFound
893
-	 */
894
-	protected function createShareObject($data) {
895
-
896
-		$share = new Share($this->rootFolder, $this->userManager);
897
-		$share->setId((int)$data['id'])
898
-			->setShareType((int)$data['share_type'])
899
-			->setPermissions((int)$data['permissions'])
900
-			->setTarget($data['file_target'])
901
-			->setMailSend((bool)$data['mail_send'])
902
-			->setToken($data['token']);
903
-
904
-		$shareTime = new \DateTime();
905
-		$shareTime->setTimestamp((int)$data['stime']);
906
-		$share->setShareTime($shareTime);
907
-		$share->setSharedWith($data['share_with']);
908
-		$share->setPassword($data['password']);
909
-
910
-		if ($data['uid_initiator'] !== null) {
911
-			$share->setShareOwner($data['uid_owner']);
912
-			$share->setSharedBy($data['uid_initiator']);
913
-		} else {
914
-			//OLD SHARE
915
-			$share->setSharedBy($data['uid_owner']);
916
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
917
-
918
-			$owner = $path->getOwner();
919
-			$share->setShareOwner($owner->getUID());
920
-		}
921
-
922
-		if ($data['expiration'] !== null) {
923
-			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
924
-			if ($expiration !== false) {
925
-				$share->setExpirationDate($expiration);
926
-			}
927
-		}
928
-
929
-		$share->setNodeId((int)$data['file_source']);
930
-		$share->setNodeType($data['item_type']);
931
-
932
-		$share->setProviderId($this->identifier());
933
-
934
-		return $share;
935
-	}
936
-
937
-	/**
938
-	 * Get the node with file $id for $user
939
-	 *
940
-	 * @param string $userId
941
-	 * @param int $id
942
-	 * @return \OCP\Files\File|\OCP\Files\Folder
943
-	 * @throws InvalidShare
944
-	 */
945
-	private function getNode($userId, $id) {
946
-		try {
947
-			$userFolder = $this->rootFolder->getUserFolder($userId);
948
-		} catch (NoUserException $e) {
949
-			throw new InvalidShare();
950
-		}
951
-
952
-		$nodes = $userFolder->getById($id);
953
-
954
-		if (empty($nodes)) {
955
-			throw new InvalidShare();
956
-		}
957
-
958
-		return $nodes[0];
959
-	}
960
-
961
-	/**
962
-	 * A user is deleted from the system
963
-	 * So clean up the relevant shares.
964
-	 *
965
-	 * @param string $uid
966
-	 * @param int $shareType
967
-	 */
968
-	public function userDeleted($uid, $shareType) {
969
-		$qb = $this->dbConnection->getQueryBuilder();
970
-
971
-		$qb->delete('share')
972
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
973
-			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
974
-			->execute();
975
-	}
976
-
977
-	/**
978
-	 * This provider does not support group shares
979
-	 *
980
-	 * @param string $gid
981
-	 */
982
-	public function groupDeleted($gid) {
983
-	}
984
-
985
-	/**
986
-	 * This provider does not support group shares
987
-	 *
988
-	 * @param string $uid
989
-	 * @param string $gid
990
-	 */
991
-	public function userDeletedFromGroup($uid, $gid) {
992
-	}
993
-
994
-	/**
995
-	 * get database row of a give share
996
-	 *
997
-	 * @param $id
998
-	 * @return array
999
-	 * @throws ShareNotFound
1000
-	 */
1001
-	protected function getRawShare($id) {
1002
-
1003
-		// Now fetch the inserted share and create a complete share object
1004
-		$qb = $this->dbConnection->getQueryBuilder();
1005
-		$qb->select('*')
1006
-			->from('share')
1007
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
1008
-
1009
-		$cursor = $qb->execute();
1010
-		$data = $cursor->fetch();
1011
-		$cursor->closeCursor();
1012
-
1013
-		if ($data === false) {
1014
-			throw new ShareNotFound;
1015
-		}
1016
-
1017
-		return $data;
1018
-	}
1019
-
1020
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
1021
-		$qb = $this->dbConnection->getQueryBuilder();
1022
-		$qb->select('*')
1023
-			->from('share', 's')
1024
-			->andWhere($qb->expr()->orX(
1025
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1026
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1027
-			))
1028
-			->andWhere(
1029
-				$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
1030
-			);
1031
-
1032
-		/**
1033
-		 * Reshares for this user are shares where they are the owner.
1034
-		 */
1035
-		if ($reshares === false) {
1036
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
1037
-		} else {
1038
-			$qb->andWhere(
1039
-				$qb->expr()->orX(
1040
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
1041
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
1042
-				)
1043
-			);
1044
-		}
1045
-
1046
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1047
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1048
-
1049
-		$qb->orderBy('id');
1050
-
1051
-		$cursor = $qb->execute();
1052
-		$shares = [];
1053
-		while ($data = $cursor->fetch()) {
1054
-			$shares[$data['fileid']][] = $this->createShareObject($data);
1055
-		}
1056
-		$cursor->closeCursor();
1057
-
1058
-		return $shares;
1059
-	}
1060
-
1061
-	/**
1062
-	 * @inheritdoc
1063
-	 */
1064
-	public function getAccessList($nodes, $currentAccess) {
1065
-		$ids = [];
1066
-		foreach ($nodes as $node) {
1067
-			$ids[] = $node->getId();
1068
-		}
1069
-
1070
-		$qb = $this->dbConnection->getQueryBuilder();
1071
-		$qb->select('share_with')
1072
-			->from('share')
1073
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
1074
-			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1075
-			->andWhere($qb->expr()->orX(
1076
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1077
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1078
-			))
1079
-			->setMaxResults(1);
1080
-		$cursor = $qb->execute();
1081
-
1082
-		$mail = $cursor->fetch() !== false;
1083
-		$cursor->closeCursor();
1084
-
1085
-		return ['public' => $mail];
1086
-	}
656
+        $qb = $this->dbConnection->getQueryBuilder();
657
+        $qb->update('share')
658
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
659
+            ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
660
+            ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
661
+            ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
662
+            ->set('password', $qb->createNamedParameter($share->getPassword()))
663
+            ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
664
+            ->execute();
665
+
666
+        return $share;
667
+    }
668
+
669
+    /**
670
+     * @inheritdoc
671
+     */
672
+    public function move(IShare $share, $recipient) {
673
+        /**
674
+         * nothing to do here, mail shares are only outgoing shares
675
+         */
676
+        return $share;
677
+    }
678
+
679
+    /**
680
+     * Delete a share (owner unShares the file)
681
+     *
682
+     * @param IShare $share
683
+     */
684
+    public function delete(IShare $share) {
685
+        $this->removeShareFromTable($share->getId());
686
+    }
687
+
688
+    /**
689
+     * @inheritdoc
690
+     */
691
+    public function deleteFromSelf(IShare $share, $recipient) {
692
+        // nothing to do here, mail shares are only outgoing shares
693
+    }
694
+
695
+    /**
696
+     * @inheritdoc
697
+     */
698
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
699
+        $qb = $this->dbConnection->getQueryBuilder();
700
+        $qb->select('*')
701
+            ->from('share');
702
+
703
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
704
+
705
+        /**
706
+         * Reshares for this user are shares where they are the owner.
707
+         */
708
+        if ($reshares === false) {
709
+            //Special case for old shares created via the web UI
710
+            $or1 = $qb->expr()->andX(
711
+                $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
712
+                $qb->expr()->isNull('uid_initiator')
713
+            );
714
+
715
+            $qb->andWhere(
716
+                $qb->expr()->orX(
717
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
718
+                    $or1
719
+                )
720
+            );
721
+        } else {
722
+            $qb->andWhere(
723
+                $qb->expr()->orX(
724
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
725
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
726
+                )
727
+            );
728
+        }
729
+
730
+        if ($node !== null) {
731
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
732
+        }
733
+
734
+        if ($limit !== -1) {
735
+            $qb->setMaxResults($limit);
736
+        }
737
+
738
+        $qb->setFirstResult($offset);
739
+        $qb->orderBy('id');
740
+
741
+        $cursor = $qb->execute();
742
+        $shares = [];
743
+        while($data = $cursor->fetch()) {
744
+            $shares[] = $this->createShareObject($data);
745
+        }
746
+        $cursor->closeCursor();
747
+
748
+        return $shares;
749
+    }
750
+
751
+    /**
752
+     * @inheritdoc
753
+     */
754
+    public function getShareById($id, $recipientId = null) {
755
+        $qb = $this->dbConnection->getQueryBuilder();
756
+
757
+        $qb->select('*')
758
+            ->from('share')
759
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
760
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
761
+
762
+        $cursor = $qb->execute();
763
+        $data = $cursor->fetch();
764
+        $cursor->closeCursor();
765
+
766
+        if ($data === false) {
767
+            throw new ShareNotFound();
768
+        }
769
+
770
+        try {
771
+            $share = $this->createShareObject($data);
772
+        } catch (InvalidShare $e) {
773
+            throw new ShareNotFound();
774
+        }
775
+
776
+        return $share;
777
+    }
778
+
779
+    /**
780
+     * Get shares for a given path
781
+     *
782
+     * @param \OCP\Files\Node $path
783
+     * @return IShare[]
784
+     */
785
+    public function getSharesByPath(Node $path) {
786
+        $qb = $this->dbConnection->getQueryBuilder();
787
+
788
+        $cursor = $qb->select('*')
789
+            ->from('share')
790
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
791
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
792
+            ->execute();
793
+
794
+        $shares = [];
795
+        while($data = $cursor->fetch()) {
796
+            $shares[] = $this->createShareObject($data);
797
+        }
798
+        $cursor->closeCursor();
799
+
800
+        return $shares;
801
+    }
802
+
803
+    /**
804
+     * @inheritdoc
805
+     */
806
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
807
+        /** @var IShare[] $shares */
808
+        $shares = [];
809
+
810
+        //Get shares directly with this user
811
+        $qb = $this->dbConnection->getQueryBuilder();
812
+        $qb->select('*')
813
+            ->from('share');
814
+
815
+        // Order by id
816
+        $qb->orderBy('id');
817
+
818
+        // Set limit and offset
819
+        if ($limit !== -1) {
820
+            $qb->setMaxResults($limit);
821
+        }
822
+        $qb->setFirstResult($offset);
823
+
824
+        $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
825
+        $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
826
+
827
+        // Filter by node if provided
828
+        if ($node !== null) {
829
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
830
+        }
831
+
832
+        $cursor = $qb->execute();
833
+
834
+        while($data = $cursor->fetch()) {
835
+            $shares[] = $this->createShareObject($data);
836
+        }
837
+        $cursor->closeCursor();
838
+
839
+
840
+        return $shares;
841
+    }
842
+
843
+    /**
844
+     * Get a share by token
845
+     *
846
+     * @param string $token
847
+     * @return IShare
848
+     * @throws ShareNotFound
849
+     */
850
+    public function getShareByToken($token) {
851
+        $qb = $this->dbConnection->getQueryBuilder();
852
+
853
+        $cursor = $qb->select('*')
854
+            ->from('share')
855
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
856
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
857
+            ->execute();
858
+
859
+        $data = $cursor->fetch();
860
+
861
+        if ($data === false) {
862
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
863
+        }
864
+
865
+        try {
866
+            $share = $this->createShareObject($data);
867
+        } catch (InvalidShare $e) {
868
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
869
+        }
870
+
871
+        return $share;
872
+    }
873
+
874
+    /**
875
+     * remove share from table
876
+     *
877
+     * @param string $shareId
878
+     */
879
+    protected function removeShareFromTable($shareId) {
880
+        $qb = $this->dbConnection->getQueryBuilder();
881
+        $qb->delete('share')
882
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
883
+        $qb->execute();
884
+    }
885
+
886
+    /**
887
+     * Create a share object from an database row
888
+     *
889
+     * @param array $data
890
+     * @return IShare
891
+     * @throws InvalidShare
892
+     * @throws ShareNotFound
893
+     */
894
+    protected function createShareObject($data) {
895
+
896
+        $share = new Share($this->rootFolder, $this->userManager);
897
+        $share->setId((int)$data['id'])
898
+            ->setShareType((int)$data['share_type'])
899
+            ->setPermissions((int)$data['permissions'])
900
+            ->setTarget($data['file_target'])
901
+            ->setMailSend((bool)$data['mail_send'])
902
+            ->setToken($data['token']);
903
+
904
+        $shareTime = new \DateTime();
905
+        $shareTime->setTimestamp((int)$data['stime']);
906
+        $share->setShareTime($shareTime);
907
+        $share->setSharedWith($data['share_with']);
908
+        $share->setPassword($data['password']);
909
+
910
+        if ($data['uid_initiator'] !== null) {
911
+            $share->setShareOwner($data['uid_owner']);
912
+            $share->setSharedBy($data['uid_initiator']);
913
+        } else {
914
+            //OLD SHARE
915
+            $share->setSharedBy($data['uid_owner']);
916
+            $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
917
+
918
+            $owner = $path->getOwner();
919
+            $share->setShareOwner($owner->getUID());
920
+        }
921
+
922
+        if ($data['expiration'] !== null) {
923
+            $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
924
+            if ($expiration !== false) {
925
+                $share->setExpirationDate($expiration);
926
+            }
927
+        }
928
+
929
+        $share->setNodeId((int)$data['file_source']);
930
+        $share->setNodeType($data['item_type']);
931
+
932
+        $share->setProviderId($this->identifier());
933
+
934
+        return $share;
935
+    }
936
+
937
+    /**
938
+     * Get the node with file $id for $user
939
+     *
940
+     * @param string $userId
941
+     * @param int $id
942
+     * @return \OCP\Files\File|\OCP\Files\Folder
943
+     * @throws InvalidShare
944
+     */
945
+    private function getNode($userId, $id) {
946
+        try {
947
+            $userFolder = $this->rootFolder->getUserFolder($userId);
948
+        } catch (NoUserException $e) {
949
+            throw new InvalidShare();
950
+        }
951
+
952
+        $nodes = $userFolder->getById($id);
953
+
954
+        if (empty($nodes)) {
955
+            throw new InvalidShare();
956
+        }
957
+
958
+        return $nodes[0];
959
+    }
960
+
961
+    /**
962
+     * A user is deleted from the system
963
+     * So clean up the relevant shares.
964
+     *
965
+     * @param string $uid
966
+     * @param int $shareType
967
+     */
968
+    public function userDeleted($uid, $shareType) {
969
+        $qb = $this->dbConnection->getQueryBuilder();
970
+
971
+        $qb->delete('share')
972
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
973
+            ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
974
+            ->execute();
975
+    }
976
+
977
+    /**
978
+     * This provider does not support group shares
979
+     *
980
+     * @param string $gid
981
+     */
982
+    public function groupDeleted($gid) {
983
+    }
984
+
985
+    /**
986
+     * This provider does not support group shares
987
+     *
988
+     * @param string $uid
989
+     * @param string $gid
990
+     */
991
+    public function userDeletedFromGroup($uid, $gid) {
992
+    }
993
+
994
+    /**
995
+     * get database row of a give share
996
+     *
997
+     * @param $id
998
+     * @return array
999
+     * @throws ShareNotFound
1000
+     */
1001
+    protected function getRawShare($id) {
1002
+
1003
+        // Now fetch the inserted share and create a complete share object
1004
+        $qb = $this->dbConnection->getQueryBuilder();
1005
+        $qb->select('*')
1006
+            ->from('share')
1007
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
1008
+
1009
+        $cursor = $qb->execute();
1010
+        $data = $cursor->fetch();
1011
+        $cursor->closeCursor();
1012
+
1013
+        if ($data === false) {
1014
+            throw new ShareNotFound;
1015
+        }
1016
+
1017
+        return $data;
1018
+    }
1019
+
1020
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
1021
+        $qb = $this->dbConnection->getQueryBuilder();
1022
+        $qb->select('*')
1023
+            ->from('share', 's')
1024
+            ->andWhere($qb->expr()->orX(
1025
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1026
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1027
+            ))
1028
+            ->andWhere(
1029
+                $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
1030
+            );
1031
+
1032
+        /**
1033
+         * Reshares for this user are shares where they are the owner.
1034
+         */
1035
+        if ($reshares === false) {
1036
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
1037
+        } else {
1038
+            $qb->andWhere(
1039
+                $qb->expr()->orX(
1040
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
1041
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
1042
+                )
1043
+            );
1044
+        }
1045
+
1046
+        $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1047
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1048
+
1049
+        $qb->orderBy('id');
1050
+
1051
+        $cursor = $qb->execute();
1052
+        $shares = [];
1053
+        while ($data = $cursor->fetch()) {
1054
+            $shares[$data['fileid']][] = $this->createShareObject($data);
1055
+        }
1056
+        $cursor->closeCursor();
1057
+
1058
+        return $shares;
1059
+    }
1060
+
1061
+    /**
1062
+     * @inheritdoc
1063
+     */
1064
+    public function getAccessList($nodes, $currentAccess) {
1065
+        $ids = [];
1066
+        foreach ($nodes as $node) {
1067
+            $ids[] = $node->getId();
1068
+        }
1069
+
1070
+        $qb = $this->dbConnection->getQueryBuilder();
1071
+        $qb->select('share_with')
1072
+            ->from('share')
1073
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
1074
+            ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1075
+            ->andWhere($qb->expr()->orX(
1076
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1077
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1078
+            ))
1079
+            ->setMaxResults(1);
1080
+        $cursor = $qb->execute();
1081
+
1082
+        $mail = $cursor->fetch() !== false;
1083
+        $cursor->closeCursor();
1084
+
1085
+        return ['public' => $mail];
1086
+    }
1087 1087
 
1088 1088
 }
Please login to merge, or discard this patch.
apps/federation/lib/SyncJob.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -28,32 +28,32 @@
 block discarded – undo
28 28
 
29 29
 class SyncJob extends TimedJob {
30 30
 
31
-	/** @var SyncFederationAddressBooks */
32
-	protected $syncService;
31
+    /** @var SyncFederationAddressBooks */
32
+    protected $syncService;
33 33
 
34
-	/** @var ILogger */
35
-	protected $logger;
34
+    /** @var ILogger */
35
+    protected $logger;
36 36
 
37
-	/**
38
-	 * @param SyncFederationAddressBooks $syncService
39
-	 * @param ILogger $logger
40
-	 */
41
-	public function __construct(SyncFederationAddressBooks $syncService, ILogger $logger) {
42
-		// Run once a day
43
-		$this->setInterval(24 * 60 * 60);
44
-		$this->syncService = $syncService;
45
-		$this->logger = $logger;
46
-	}
37
+    /**
38
+     * @param SyncFederationAddressBooks $syncService
39
+     * @param ILogger $logger
40
+     */
41
+    public function __construct(SyncFederationAddressBooks $syncService, ILogger $logger) {
42
+        // Run once a day
43
+        $this->setInterval(24 * 60 * 60);
44
+        $this->syncService = $syncService;
45
+        $this->logger = $logger;
46
+    }
47 47
 
48
-	protected function run($argument) {
49
-		$this->syncService->syncThemAll(function($url, $ex) {
50
-			if ($ex instanceof \Exception) {
51
-				$this->logger->logException($ex, [
52
-					'message' => "Error while syncing $url.",
53
-					'level' => ILogger::ERROR,
54
-					'app' => 'fed-sync',
55
-				]);
56
-			}
57
-		});
58
-	}
48
+    protected function run($argument) {
49
+        $this->syncService->syncThemAll(function($url, $ex) {
50
+            if ($ex instanceof \Exception) {
51
+                $this->logger->logException($ex, [
52
+                    'message' => "Error while syncing $url.",
53
+                    'level' => ILogger::ERROR,
54
+                    'app' => 'fed-sync',
55
+                ]);
56
+            }
57
+        });
58
+    }
59 59
 }
Please login to merge, or discard this patch.
apps/federation/lib/BackgroundJob/GetSharedSecret.php 2 patches
Indentation   +209 added lines, -209 removed lines patch added patch discarded remove patch
@@ -56,213 +56,213 @@
 block discarded – undo
56 56
  */
57 57
 class GetSharedSecret extends Job {
58 58
 
59
-	/** @var IClient */
60
-	private $httpClient;
61
-
62
-	/** @var IJobList */
63
-	private $jobList;
64
-
65
-	/** @var IURLGenerator */
66
-	private $urlGenerator;
67
-
68
-	/** @var TrustedServers  */
69
-	private $trustedServers;
70
-
71
-	/** @var DbHandler */
72
-	private $dbHandler;
73
-
74
-	/** @var IDiscoveryService  */
75
-	private $ocsDiscoveryService;
76
-
77
-	/** @var ILogger */
78
-	private $logger;
79
-
80
-	/** @var ITimeFactory */
81
-	private $timeFactory;
82
-
83
-	/** @var bool */
84
-	protected $retainJob = false;
85
-
86
-	private $format = '?format=json';
87
-
88
-	private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret';
89
-
90
-	/** @var  int  30 day = 2592000sec */
91
-	private $maxLifespan = 2592000;
92
-
93
-	/**
94
-	 * RequestSharedSecret constructor.
95
-	 *
96
-	 * @param IClientService $httpClientService
97
-	 * @param IURLGenerator $urlGenerator
98
-	 * @param IJobList $jobList
99
-	 * @param TrustedServers $trustedServers
100
-	 * @param ILogger $logger
101
-	 * @param DbHandler $dbHandler
102
-	 * @param IDiscoveryService $ocsDiscoveryService
103
-	 * @param ITimeFactory $timeFactory
104
-	 */
105
-	public function __construct(
106
-		IClientService $httpClientService,
107
-		IURLGenerator $urlGenerator,
108
-		IJobList $jobList,
109
-		TrustedServers $trustedServers,
110
-		ILogger $logger,
111
-		DbHandler $dbHandler,
112
-		IDiscoveryService $ocsDiscoveryService,
113
-		ITimeFactory $timeFactory
114
-	) {
115
-		$this->logger = $logger;
116
-		$this->httpClient = $httpClientService->newClient();
117
-		$this->jobList = $jobList;
118
-		$this->urlGenerator = $urlGenerator;
119
-		$this->dbHandler = $dbHandler;
120
-		$this->ocsDiscoveryService = $ocsDiscoveryService;
121
-		$this->trustedServers = $trustedServers;
122
-		$this->timeFactory = $timeFactory;
123
-	}
124
-
125
-	/**
126
-	 * run the job, then remove it from the joblist
127
-	 *
128
-	 * @param JobList $jobList
129
-	 * @param ILogger|null $logger
130
-	 */
131
-	public function execute($jobList, ILogger $logger = null) {
132
-		$target = $this->argument['url'];
133
-		// only execute if target is still in the list of trusted domains
134
-		if ($this->trustedServers->isTrustedServer($target)) {
135
-			$this->parentExecute($jobList, $logger);
136
-		}
137
-
138
-		$jobList->remove($this, $this->argument);
139
-
140
-		if ($this->retainJob) {
141
-			$this->reAddJob($this->argument);
142
-		}
143
-	}
144
-
145
-	/**
146
-	 * call execute() method of parent
147
-	 *
148
-	 * @param JobList $jobList
149
-	 * @param ILogger $logger
150
-	 */
151
-	protected function parentExecute($jobList, $logger = null) {
152
-		parent::execute($jobList, $logger);
153
-	}
154
-
155
-	protected function run($argument) {
156
-		$target = $argument['url'];
157
-		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
158
-		$currentTime = $this->timeFactory->getTime();
159
-		$source = $this->urlGenerator->getAbsoluteURL('/');
160
-		$source = rtrim($source, '/');
161
-		$token = $argument['token'];
162
-
163
-		// kill job after 30 days of trying
164
-		$deadline = $currentTime - $this->maxLifespan;
165
-		if ($created < $deadline) {
166
-			$this->retainJob = false;
167
-			$this->trustedServers->setServerStatus($target,TrustedServers::STATUS_FAILURE);
168
-			return;
169
-		}
170
-
171
-		$endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING');
172
-		$endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint;
173
-
174
-		// make sure that we have a well formatted url
175
-		$url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format;
176
-
177
-		$result = null;
178
-		try {
179
-			$result = $this->httpClient->get(
180
-				$url,
181
-				[
182
-					'query' =>
183
-						[
184
-							'url' => $source,
185
-							'token' => $token
186
-						],
187
-					'timeout' => 3,
188
-					'connect_timeout' => 3,
189
-				]
190
-			);
191
-
192
-			$status = $result->getStatusCode();
193
-
194
-		} catch (ClientException $e) {
195
-			$status = $e->getCode();
196
-			if ($status === Http::STATUS_FORBIDDEN) {
197
-				$this->logger->info($target . ' refused to exchange a shared secret with you.', ['app' => 'federation']);
198
-			} else {
199
-				$this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']);
200
-			}
201
-		} catch (RequestException $e) {
202
-			$status = -1; // There is no status code if we could not connect
203
-			$this->logger->logException($e, [
204
-				'message' => 'Could not connect to ' . $target,
205
-				'level' => ILogger::INFO,
206
-				'app' => 'federation',
207
-			]);
208
-		} catch (RingException $e) {
209
-			$status = -1; // There is no status code if we could not connect
210
-			$this->logger->logException($e, [
211
-				'message' => 'Could not connect to ' . $target,
212
-				'level' => ILogger::INFO,
213
-				'app' => 'federation',
214
-			]);
215
-		} catch (\Exception $e) {
216
-			$status = Http::STATUS_INTERNAL_SERVER_ERROR;
217
-			$this->logger->logException($e, ['app' => 'federation']);
218
-		}
219
-
220
-		// if we received a unexpected response we try again later
221
-		if (
222
-			$status !== Http::STATUS_OK
223
-			&& $status !== Http::STATUS_FORBIDDEN
224
-		) {
225
-			$this->retainJob = true;
226
-		}  else {
227
-			// reset token if we received a valid response
228
-			$this->dbHandler->addToken($target, '');
229
-		}
230
-
231
-		if ($status === Http::STATUS_OK && $result instanceof IResponse) {
232
-			$body = $result->getBody();
233
-			$result = json_decode($body, true);
234
-			if (isset($result['ocs']['data']['sharedSecret'])) {
235
-				$this->trustedServers->addSharedSecret(
236
-						$target,
237
-						$result['ocs']['data']['sharedSecret']
238
-				);
239
-			} else {
240
-				$this->logger->error(
241
-						'remote server "' . $target . '"" does not return a valid shared secret',
242
-						['app' => 'federation']
243
-				);
244
-				$this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
245
-			}
246
-		}
247
-
248
-	}
249
-
250
-	/**
251
-	 * re-add background job
252
-	 *
253
-	 * @param array $argument
254
-	 */
255
-	protected function reAddJob(array $argument) {
256
-		$url = $argument['url'];
257
-		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
258
-		$token = $argument['token'];
259
-		$this->jobList->add(
260
-			GetSharedSecret::class,
261
-			[
262
-				'url' => $url,
263
-				'token' => $token,
264
-				'created' => $created
265
-			]
266
-		);
267
-	}
59
+    /** @var IClient */
60
+    private $httpClient;
61
+
62
+    /** @var IJobList */
63
+    private $jobList;
64
+
65
+    /** @var IURLGenerator */
66
+    private $urlGenerator;
67
+
68
+    /** @var TrustedServers  */
69
+    private $trustedServers;
70
+
71
+    /** @var DbHandler */
72
+    private $dbHandler;
73
+
74
+    /** @var IDiscoveryService  */
75
+    private $ocsDiscoveryService;
76
+
77
+    /** @var ILogger */
78
+    private $logger;
79
+
80
+    /** @var ITimeFactory */
81
+    private $timeFactory;
82
+
83
+    /** @var bool */
84
+    protected $retainJob = false;
85
+
86
+    private $format = '?format=json';
87
+
88
+    private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret';
89
+
90
+    /** @var  int  30 day = 2592000sec */
91
+    private $maxLifespan = 2592000;
92
+
93
+    /**
94
+     * RequestSharedSecret constructor.
95
+     *
96
+     * @param IClientService $httpClientService
97
+     * @param IURLGenerator $urlGenerator
98
+     * @param IJobList $jobList
99
+     * @param TrustedServers $trustedServers
100
+     * @param ILogger $logger
101
+     * @param DbHandler $dbHandler
102
+     * @param IDiscoveryService $ocsDiscoveryService
103
+     * @param ITimeFactory $timeFactory
104
+     */
105
+    public function __construct(
106
+        IClientService $httpClientService,
107
+        IURLGenerator $urlGenerator,
108
+        IJobList $jobList,
109
+        TrustedServers $trustedServers,
110
+        ILogger $logger,
111
+        DbHandler $dbHandler,
112
+        IDiscoveryService $ocsDiscoveryService,
113
+        ITimeFactory $timeFactory
114
+    ) {
115
+        $this->logger = $logger;
116
+        $this->httpClient = $httpClientService->newClient();
117
+        $this->jobList = $jobList;
118
+        $this->urlGenerator = $urlGenerator;
119
+        $this->dbHandler = $dbHandler;
120
+        $this->ocsDiscoveryService = $ocsDiscoveryService;
121
+        $this->trustedServers = $trustedServers;
122
+        $this->timeFactory = $timeFactory;
123
+    }
124
+
125
+    /**
126
+     * run the job, then remove it from the joblist
127
+     *
128
+     * @param JobList $jobList
129
+     * @param ILogger|null $logger
130
+     */
131
+    public function execute($jobList, ILogger $logger = null) {
132
+        $target = $this->argument['url'];
133
+        // only execute if target is still in the list of trusted domains
134
+        if ($this->trustedServers->isTrustedServer($target)) {
135
+            $this->parentExecute($jobList, $logger);
136
+        }
137
+
138
+        $jobList->remove($this, $this->argument);
139
+
140
+        if ($this->retainJob) {
141
+            $this->reAddJob($this->argument);
142
+        }
143
+    }
144
+
145
+    /**
146
+     * call execute() method of parent
147
+     *
148
+     * @param JobList $jobList
149
+     * @param ILogger $logger
150
+     */
151
+    protected function parentExecute($jobList, $logger = null) {
152
+        parent::execute($jobList, $logger);
153
+    }
154
+
155
+    protected function run($argument) {
156
+        $target = $argument['url'];
157
+        $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
158
+        $currentTime = $this->timeFactory->getTime();
159
+        $source = $this->urlGenerator->getAbsoluteURL('/');
160
+        $source = rtrim($source, '/');
161
+        $token = $argument['token'];
162
+
163
+        // kill job after 30 days of trying
164
+        $deadline = $currentTime - $this->maxLifespan;
165
+        if ($created < $deadline) {
166
+            $this->retainJob = false;
167
+            $this->trustedServers->setServerStatus($target,TrustedServers::STATUS_FAILURE);
168
+            return;
169
+        }
170
+
171
+        $endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING');
172
+        $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint;
173
+
174
+        // make sure that we have a well formatted url
175
+        $url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format;
176
+
177
+        $result = null;
178
+        try {
179
+            $result = $this->httpClient->get(
180
+                $url,
181
+                [
182
+                    'query' =>
183
+                        [
184
+                            'url' => $source,
185
+                            'token' => $token
186
+                        ],
187
+                    'timeout' => 3,
188
+                    'connect_timeout' => 3,
189
+                ]
190
+            );
191
+
192
+            $status = $result->getStatusCode();
193
+
194
+        } catch (ClientException $e) {
195
+            $status = $e->getCode();
196
+            if ($status === Http::STATUS_FORBIDDEN) {
197
+                $this->logger->info($target . ' refused to exchange a shared secret with you.', ['app' => 'federation']);
198
+            } else {
199
+                $this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']);
200
+            }
201
+        } catch (RequestException $e) {
202
+            $status = -1; // There is no status code if we could not connect
203
+            $this->logger->logException($e, [
204
+                'message' => 'Could not connect to ' . $target,
205
+                'level' => ILogger::INFO,
206
+                'app' => 'federation',
207
+            ]);
208
+        } catch (RingException $e) {
209
+            $status = -1; // There is no status code if we could not connect
210
+            $this->logger->logException($e, [
211
+                'message' => 'Could not connect to ' . $target,
212
+                'level' => ILogger::INFO,
213
+                'app' => 'federation',
214
+            ]);
215
+        } catch (\Exception $e) {
216
+            $status = Http::STATUS_INTERNAL_SERVER_ERROR;
217
+            $this->logger->logException($e, ['app' => 'federation']);
218
+        }
219
+
220
+        // if we received a unexpected response we try again later
221
+        if (
222
+            $status !== Http::STATUS_OK
223
+            && $status !== Http::STATUS_FORBIDDEN
224
+        ) {
225
+            $this->retainJob = true;
226
+        }  else {
227
+            // reset token if we received a valid response
228
+            $this->dbHandler->addToken($target, '');
229
+        }
230
+
231
+        if ($status === Http::STATUS_OK && $result instanceof IResponse) {
232
+            $body = $result->getBody();
233
+            $result = json_decode($body, true);
234
+            if (isset($result['ocs']['data']['sharedSecret'])) {
235
+                $this->trustedServers->addSharedSecret(
236
+                        $target,
237
+                        $result['ocs']['data']['sharedSecret']
238
+                );
239
+            } else {
240
+                $this->logger->error(
241
+                        'remote server "' . $target . '"" does not return a valid shared secret',
242
+                        ['app' => 'federation']
243
+                );
244
+                $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
245
+            }
246
+        }
247
+
248
+    }
249
+
250
+    /**
251
+     * re-add background job
252
+     *
253
+     * @param array $argument
254
+     */
255
+    protected function reAddJob(array $argument) {
256
+        $url = $argument['url'];
257
+        $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
258
+        $token = $argument['token'];
259
+        $this->jobList->add(
260
+            GetSharedSecret::class,
261
+            [
262
+                'url' => $url,
263
+                'token' => $token,
264
+                'created' => $created
265
+            ]
266
+        );
267
+    }
268 268
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
 
155 155
 	protected function run($argument) {
156 156
 		$target = $argument['url'];
157
-		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
157
+		$created = isset($argument['created']) ? (int) $argument['created'] : $this->timeFactory->getTime();
158 158
 		$currentTime = $this->timeFactory->getTime();
159 159
 		$source = $this->urlGenerator->getAbsoluteURL('/');
160 160
 		$source = rtrim($source, '/');
@@ -164,7 +164,7 @@  discard block
 block discarded – undo
164 164
 		$deadline = $currentTime - $this->maxLifespan;
165 165
 		if ($created < $deadline) {
166 166
 			$this->retainJob = false;
167
-			$this->trustedServers->setServerStatus($target,TrustedServers::STATUS_FAILURE);
167
+			$this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
168 168
 			return;
169 169
 		}
170 170
 
@@ -172,7 +172,7 @@  discard block
 block discarded – undo
172 172
 		$endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint;
173 173
 
174 174
 		// make sure that we have a well formatted url
175
-		$url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format;
175
+		$url = rtrim($target, '/').'/'.trim($endPoint, '/').$this->format;
176 176
 
177 177
 		$result = null;
178 178
 		try {
@@ -194,21 +194,21 @@  discard block
 block discarded – undo
194 194
 		} catch (ClientException $e) {
195 195
 			$status = $e->getCode();
196 196
 			if ($status === Http::STATUS_FORBIDDEN) {
197
-				$this->logger->info($target . ' refused to exchange a shared secret with you.', ['app' => 'federation']);
197
+				$this->logger->info($target.' refused to exchange a shared secret with you.', ['app' => 'federation']);
198 198
 			} else {
199
-				$this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']);
199
+				$this->logger->info($target.' responded with a '.$status.' containing: '.$e->getMessage(), ['app' => 'federation']);
200 200
 			}
201 201
 		} catch (RequestException $e) {
202 202
 			$status = -1; // There is no status code if we could not connect
203 203
 			$this->logger->logException($e, [
204
-				'message' => 'Could not connect to ' . $target,
204
+				'message' => 'Could not connect to '.$target,
205 205
 				'level' => ILogger::INFO,
206 206
 				'app' => 'federation',
207 207
 			]);
208 208
 		} catch (RingException $e) {
209 209
 			$status = -1; // There is no status code if we could not connect
210 210
 			$this->logger->logException($e, [
211
-				'message' => 'Could not connect to ' . $target,
211
+				'message' => 'Could not connect to '.$target,
212 212
 				'level' => ILogger::INFO,
213 213
 				'app' => 'federation',
214 214
 			]);
@@ -223,7 +223,7 @@  discard block
 block discarded – undo
223 223
 			&& $status !== Http::STATUS_FORBIDDEN
224 224
 		) {
225 225
 			$this->retainJob = true;
226
-		}  else {
226
+		} else {
227 227
 			// reset token if we received a valid response
228 228
 			$this->dbHandler->addToken($target, '');
229 229
 		}
@@ -238,7 +238,7 @@  discard block
 block discarded – undo
238 238
 				);
239 239
 			} else {
240 240
 				$this->logger->error(
241
-						'remote server "' . $target . '"" does not return a valid shared secret',
241
+						'remote server "'.$target.'"" does not return a valid shared secret',
242 242
 						['app' => 'federation']
243 243
 				);
244 244
 				$this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
@@ -254,7 +254,7 @@  discard block
 block discarded – undo
254 254
 	 */
255 255
 	protected function reAddJob(array $argument) {
256 256
 		$url = $argument['url'];
257
-		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
257
+		$created = isset($argument['created']) ? (int) $argument['created'] : $this->timeFactory->getTime();
258 258
 		$token = $argument['token'];
259 259
 		$this->jobList->add(
260 260
 			GetSharedSecret::class,
Please login to merge, or discard this patch.
apps/federation/lib/Middleware/AddServerMiddleware.php 1 patch
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -38,54 +38,54 @@
 block discarded – undo
38 38
 
39 39
 class AddServerMiddleware extends Middleware {
40 40
 
41
-	/** @var  string */
42
-	protected $appName;
41
+    /** @var  string */
42
+    protected $appName;
43 43
 
44
-	/** @var  IL10N */
45
-	protected $l;
44
+    /** @var  IL10N */
45
+    protected $l;
46 46
 
47
-	/** @var  ILogger */
48
-	protected $logger;
47
+    /** @var  ILogger */
48
+    protected $logger;
49 49
 
50
-	/**
51
-	 * @param string $appName
52
-	 * @param IL10N $l
53
-	 * @param ILogger $logger
54
-	 */
55
-	public function __construct($appName, IL10N $l, ILogger $logger) {
56
-		$this->appName = $appName;
57
-		$this->l = $l;
58
-		$this->logger = $logger;
59
-	}
50
+    /**
51
+     * @param string $appName
52
+     * @param IL10N $l
53
+     * @param ILogger $logger
54
+     */
55
+    public function __construct($appName, IL10N $l, ILogger $logger) {
56
+        $this->appName = $appName;
57
+        $this->l = $l;
58
+        $this->logger = $logger;
59
+    }
60 60
 
61
-	/**
62
-	 * Log error message and return a response which can be displayed to the user
63
-	 *
64
-	 * @param Controller $controller
65
-	 * @param string $methodName
66
-	 * @param \Exception $exception
67
-	 * @return JSONResponse
68
-	 * @throws \Exception
69
-	 */
70
-	public function afterException($controller, $methodName, \Exception $exception) {
71
-		if (($controller instanceof SettingsController) === false) {
72
-			throw $exception;
73
-		}
74
-		$this->logger->logException($exception, [
75
-			'level' => ILogger::ERROR,
76
-			'app' => $this->appName,
77
-		]);
78
-		if ($exception instanceof HintException) {
79
-			$message = $exception->getHint();
80
-		} else {
81
-			$message = $exception->getMessage();
82
-		}
61
+    /**
62
+     * Log error message and return a response which can be displayed to the user
63
+     *
64
+     * @param Controller $controller
65
+     * @param string $methodName
66
+     * @param \Exception $exception
67
+     * @return JSONResponse
68
+     * @throws \Exception
69
+     */
70
+    public function afterException($controller, $methodName, \Exception $exception) {
71
+        if (($controller instanceof SettingsController) === false) {
72
+            throw $exception;
73
+        }
74
+        $this->logger->logException($exception, [
75
+            'level' => ILogger::ERROR,
76
+            'app' => $this->appName,
77
+        ]);
78
+        if ($exception instanceof HintException) {
79
+            $message = $exception->getHint();
80
+        } else {
81
+            $message = $exception->getMessage();
82
+        }
83 83
 
84
-		return new JSONResponse(
85
-			['message' => $message],
86
-			Http::STATUS_BAD_REQUEST
87
-		);
84
+        return new JSONResponse(
85
+            ['message' => $message],
86
+            Http::STATUS_BAD_REQUEST
87
+        );
88 88
 
89
-	}
89
+    }
90 90
 
91 91
 }
Please login to merge, or discard this patch.
apps/federation/lib/TrustedServers.php 1 patch
Indentation   +248 added lines, -248 removed lines patch added patch discarded remove patch
@@ -41,252 +41,252 @@
 block discarded – undo
41 41
 
42 42
 class TrustedServers {
43 43
 
44
-	/** after a user list was exchanged at least once successfully */
45
-	const STATUS_OK = 1;
46
-	/** waiting for shared secret or initial user list exchange */
47
-	const STATUS_PENDING = 2;
48
-	/** something went wrong, misconfigured server, software bug,... user interaction needed */
49
-	const STATUS_FAILURE = 3;
50
-	/** remote server revoked access */
51
-	const STATUS_ACCESS_REVOKED = 4;
52
-
53
-	/** @var  dbHandler */
54
-	private $dbHandler;
55
-
56
-	/** @var  IClientService */
57
-	private $httpClientService;
58
-
59
-	/** @var ILogger */
60
-	private $logger;
61
-
62
-	/** @var IJobList */
63
-	private $jobList;
64
-
65
-	/** @var ISecureRandom */
66
-	private $secureRandom;
67
-
68
-	/** @var IConfig */
69
-	private $config;
70
-
71
-	/** @var EventDispatcherInterface */
72
-	private $dispatcher;
73
-
74
-	/** @var ITimeFactory */
75
-	private $timeFactory;
76
-
77
-	/**
78
-	 * @param DbHandler $dbHandler
79
-	 * @param IClientService $httpClientService
80
-	 * @param ILogger $logger
81
-	 * @param IJobList $jobList
82
-	 * @param ISecureRandom $secureRandom
83
-	 * @param IConfig $config
84
-	 * @param EventDispatcherInterface $dispatcher
85
-	 * @param ITimeFactory $timeFactory
86
-	 */
87
-	public function __construct(
88
-		DbHandler $dbHandler,
89
-		IClientService $httpClientService,
90
-		ILogger $logger,
91
-		IJobList $jobList,
92
-		ISecureRandom $secureRandom,
93
-		IConfig $config,
94
-		EventDispatcherInterface $dispatcher,
95
-		ITimeFactory $timeFactory
96
-	) {
97
-		$this->dbHandler = $dbHandler;
98
-		$this->httpClientService = $httpClientService;
99
-		$this->logger = $logger;
100
-		$this->jobList = $jobList;
101
-		$this->secureRandom = $secureRandom;
102
-		$this->config = $config;
103
-		$this->dispatcher = $dispatcher;
104
-		$this->timeFactory = $timeFactory;
105
-	}
106
-
107
-	/**
108
-	 * add server to the list of trusted servers
109
-	 *
110
-	 * @param $url
111
-	 * @return int server id
112
-	 */
113
-	public function addServer($url) {
114
-		$url = $this->updateProtocol($url);
115
-		$result = $this->dbHandler->addServer($url);
116
-		if ($result) {
117
-			$token = $this->secureRandom->generate(16);
118
-			$this->dbHandler->addToken($url, $token);
119
-			$this->jobList->add(
120
-				RequestSharedSecret::class,
121
-				[
122
-					'url' => $url,
123
-					'token' => $token,
124
-					'created' => $this->timeFactory->getTime()
125
-				]
126
-			);
127
-		}
128
-
129
-		return $result;
130
-	}
131
-
132
-	/**
133
-	 * enable/disable to automatically add servers to the list of trusted servers
134
-	 * once a federated share was created and accepted successfully
135
-	 *
136
-	 * @param bool $status
137
-	 */
138
-	public function setAutoAddServers($status) {
139
-		$value = $status ? '1' : '0';
140
-		$this->config->setAppValue('federation', 'autoAddServers', $value);
141
-	}
142
-
143
-	/**
144
-	 * return if we automatically add servers to the list of trusted servers
145
-	 * once a federated share was created and accepted successfully
146
-	 *
147
-	 * @return bool
148
-	 */
149
-	public function getAutoAddServers() {
150
-		$value = $this->config->getAppValue('federation', 'autoAddServers', '0');
151
-		return $value === '1';
152
-	}
153
-
154
-	/**
155
-	 * get shared secret for the given server
156
-	 *
157
-	 * @param string $url
158
-	 * @return string
159
-	 */
160
-	public function getSharedSecret($url) {
161
-		return $this->dbHandler->getSharedSecret($url);
162
-	}
163
-
164
-	/**
165
-	 * add shared secret for the given server
166
-	 *
167
-	 * @param string $url
168
-	 * @param $sharedSecret
169
-	 */
170
-	public function addSharedSecret($url, $sharedSecret) {
171
-		$this->dbHandler->addSharedSecret($url, $sharedSecret);
172
-	}
173
-
174
-	/**
175
-	 * remove server from the list of trusted servers
176
-	 *
177
-	 * @param int $id
178
-	 */
179
-	public function removeServer($id) {
180
-		$server = $this->dbHandler->getServerById($id);
181
-		$this->dbHandler->removeServer($id);
182
-		$event = new GenericEvent($server['url_hash']);
183
-		$this->dispatcher->dispatch('OCP\Federation\TrustedServerEvent::remove', $event);
184
-	}
185
-
186
-	/**
187
-	 * get all trusted servers
188
-	 *
189
-	 * @return array
190
-	 */
191
-	public function getServers() {
192
-		return $this->dbHandler->getAllServer();
193
-	}
194
-
195
-	/**
196
-	 * check if given server is a trusted Nextcloud server
197
-	 *
198
-	 * @param string $url
199
-	 * @return bool
200
-	 */
201
-	public function isTrustedServer($url) {
202
-		return $this->dbHandler->serverExists($url);
203
-	}
204
-
205
-	/**
206
-	 * set server status
207
-	 *
208
-	 * @param string $url
209
-	 * @param int $status
210
-	 */
211
-	public function setServerStatus($url, $status) {
212
-		$this->dbHandler->setServerStatus($url, $status);
213
-	}
214
-
215
-	/**
216
-	 * @param string $url
217
-	 * @return int
218
-	 */
219
-	public function getServerStatus($url) {
220
-		return $this->dbHandler->getServerStatus($url);
221
-	}
222
-
223
-	/**
224
-	 * check if URL point to a ownCloud/Nextcloud server
225
-	 *
226
-	 * @param string $url
227
-	 * @return bool
228
-	 */
229
-	public function isOwnCloudServer($url) {
230
-		$isValidOwnCloud = false;
231
-		$client = $this->httpClientService->newClient();
232
-		try {
233
-			$result = $client->get(
234
-				$url . '/status.php',
235
-				[
236
-					'timeout' => 3,
237
-					'connect_timeout' => 3,
238
-				]
239
-			);
240
-			if ($result->getStatusCode() === Http::STATUS_OK) {
241
-				$isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody());
242
-
243
-			}
244
-		} catch (\Exception $e) {
245
-			\OC::$server->getLogger()->logException($e, [
246
-				'message' => 'No Nextcloud server.',
247
-				'level' => ILogger::DEBUG,
248
-				'app' => 'federation',
249
-			]);
250
-			return false;
251
-		}
252
-
253
-		return $isValidOwnCloud;
254
-	}
255
-
256
-	/**
257
-	 * check if ownCloud version is >= 9.0
258
-	 *
259
-	 * @param $status
260
-	 * @return bool
261
-	 * @throws HintException
262
-	 */
263
-	protected function checkOwnCloudVersion($status) {
264
-		$decoded = json_decode($status, true);
265
-		if (!empty($decoded) && isset($decoded['version'])) {
266
-			if (!version_compare($decoded['version'], '9.0.0', '>=')) {
267
-				throw new HintException('Remote server version is too low. 9.0 is required.');
268
-			}
269
-			return true;
270
-		}
271
-		return false;
272
-	}
273
-
274
-	/**
275
-	 * check if the URL contain a protocol, if not add https
276
-	 *
277
-	 * @param string $url
278
-	 * @return string
279
-	 */
280
-	protected function updateProtocol($url) {
281
-		if (
282
-			strpos($url, 'https://') === 0
283
-			|| strpos($url, 'http://') === 0
284
-		) {
285
-
286
-			return $url;
287
-
288
-		}
289
-
290
-		return 'https://' . $url;
291
-	}
44
+    /** after a user list was exchanged at least once successfully */
45
+    const STATUS_OK = 1;
46
+    /** waiting for shared secret or initial user list exchange */
47
+    const STATUS_PENDING = 2;
48
+    /** something went wrong, misconfigured server, software bug,... user interaction needed */
49
+    const STATUS_FAILURE = 3;
50
+    /** remote server revoked access */
51
+    const STATUS_ACCESS_REVOKED = 4;
52
+
53
+    /** @var  dbHandler */
54
+    private $dbHandler;
55
+
56
+    /** @var  IClientService */
57
+    private $httpClientService;
58
+
59
+    /** @var ILogger */
60
+    private $logger;
61
+
62
+    /** @var IJobList */
63
+    private $jobList;
64
+
65
+    /** @var ISecureRandom */
66
+    private $secureRandom;
67
+
68
+    /** @var IConfig */
69
+    private $config;
70
+
71
+    /** @var EventDispatcherInterface */
72
+    private $dispatcher;
73
+
74
+    /** @var ITimeFactory */
75
+    private $timeFactory;
76
+
77
+    /**
78
+     * @param DbHandler $dbHandler
79
+     * @param IClientService $httpClientService
80
+     * @param ILogger $logger
81
+     * @param IJobList $jobList
82
+     * @param ISecureRandom $secureRandom
83
+     * @param IConfig $config
84
+     * @param EventDispatcherInterface $dispatcher
85
+     * @param ITimeFactory $timeFactory
86
+     */
87
+    public function __construct(
88
+        DbHandler $dbHandler,
89
+        IClientService $httpClientService,
90
+        ILogger $logger,
91
+        IJobList $jobList,
92
+        ISecureRandom $secureRandom,
93
+        IConfig $config,
94
+        EventDispatcherInterface $dispatcher,
95
+        ITimeFactory $timeFactory
96
+    ) {
97
+        $this->dbHandler = $dbHandler;
98
+        $this->httpClientService = $httpClientService;
99
+        $this->logger = $logger;
100
+        $this->jobList = $jobList;
101
+        $this->secureRandom = $secureRandom;
102
+        $this->config = $config;
103
+        $this->dispatcher = $dispatcher;
104
+        $this->timeFactory = $timeFactory;
105
+    }
106
+
107
+    /**
108
+     * add server to the list of trusted servers
109
+     *
110
+     * @param $url
111
+     * @return int server id
112
+     */
113
+    public function addServer($url) {
114
+        $url = $this->updateProtocol($url);
115
+        $result = $this->dbHandler->addServer($url);
116
+        if ($result) {
117
+            $token = $this->secureRandom->generate(16);
118
+            $this->dbHandler->addToken($url, $token);
119
+            $this->jobList->add(
120
+                RequestSharedSecret::class,
121
+                [
122
+                    'url' => $url,
123
+                    'token' => $token,
124
+                    'created' => $this->timeFactory->getTime()
125
+                ]
126
+            );
127
+        }
128
+
129
+        return $result;
130
+    }
131
+
132
+    /**
133
+     * enable/disable to automatically add servers to the list of trusted servers
134
+     * once a federated share was created and accepted successfully
135
+     *
136
+     * @param bool $status
137
+     */
138
+    public function setAutoAddServers($status) {
139
+        $value = $status ? '1' : '0';
140
+        $this->config->setAppValue('federation', 'autoAddServers', $value);
141
+    }
142
+
143
+    /**
144
+     * return if we automatically add servers to the list of trusted servers
145
+     * once a federated share was created and accepted successfully
146
+     *
147
+     * @return bool
148
+     */
149
+    public function getAutoAddServers() {
150
+        $value = $this->config->getAppValue('federation', 'autoAddServers', '0');
151
+        return $value === '1';
152
+    }
153
+
154
+    /**
155
+     * get shared secret for the given server
156
+     *
157
+     * @param string $url
158
+     * @return string
159
+     */
160
+    public function getSharedSecret($url) {
161
+        return $this->dbHandler->getSharedSecret($url);
162
+    }
163
+
164
+    /**
165
+     * add shared secret for the given server
166
+     *
167
+     * @param string $url
168
+     * @param $sharedSecret
169
+     */
170
+    public function addSharedSecret($url, $sharedSecret) {
171
+        $this->dbHandler->addSharedSecret($url, $sharedSecret);
172
+    }
173
+
174
+    /**
175
+     * remove server from the list of trusted servers
176
+     *
177
+     * @param int $id
178
+     */
179
+    public function removeServer($id) {
180
+        $server = $this->dbHandler->getServerById($id);
181
+        $this->dbHandler->removeServer($id);
182
+        $event = new GenericEvent($server['url_hash']);
183
+        $this->dispatcher->dispatch('OCP\Federation\TrustedServerEvent::remove', $event);
184
+    }
185
+
186
+    /**
187
+     * get all trusted servers
188
+     *
189
+     * @return array
190
+     */
191
+    public function getServers() {
192
+        return $this->dbHandler->getAllServer();
193
+    }
194
+
195
+    /**
196
+     * check if given server is a trusted Nextcloud server
197
+     *
198
+     * @param string $url
199
+     * @return bool
200
+     */
201
+    public function isTrustedServer($url) {
202
+        return $this->dbHandler->serverExists($url);
203
+    }
204
+
205
+    /**
206
+     * set server status
207
+     *
208
+     * @param string $url
209
+     * @param int $status
210
+     */
211
+    public function setServerStatus($url, $status) {
212
+        $this->dbHandler->setServerStatus($url, $status);
213
+    }
214
+
215
+    /**
216
+     * @param string $url
217
+     * @return int
218
+     */
219
+    public function getServerStatus($url) {
220
+        return $this->dbHandler->getServerStatus($url);
221
+    }
222
+
223
+    /**
224
+     * check if URL point to a ownCloud/Nextcloud server
225
+     *
226
+     * @param string $url
227
+     * @return bool
228
+     */
229
+    public function isOwnCloudServer($url) {
230
+        $isValidOwnCloud = false;
231
+        $client = $this->httpClientService->newClient();
232
+        try {
233
+            $result = $client->get(
234
+                $url . '/status.php',
235
+                [
236
+                    'timeout' => 3,
237
+                    'connect_timeout' => 3,
238
+                ]
239
+            );
240
+            if ($result->getStatusCode() === Http::STATUS_OK) {
241
+                $isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody());
242
+
243
+            }
244
+        } catch (\Exception $e) {
245
+            \OC::$server->getLogger()->logException($e, [
246
+                'message' => 'No Nextcloud server.',
247
+                'level' => ILogger::DEBUG,
248
+                'app' => 'federation',
249
+            ]);
250
+            return false;
251
+        }
252
+
253
+        return $isValidOwnCloud;
254
+    }
255
+
256
+    /**
257
+     * check if ownCloud version is >= 9.0
258
+     *
259
+     * @param $status
260
+     * @return bool
261
+     * @throws HintException
262
+     */
263
+    protected function checkOwnCloudVersion($status) {
264
+        $decoded = json_decode($status, true);
265
+        if (!empty($decoded) && isset($decoded['version'])) {
266
+            if (!version_compare($decoded['version'], '9.0.0', '>=')) {
267
+                throw new HintException('Remote server version is too low. 9.0 is required.');
268
+            }
269
+            return true;
270
+        }
271
+        return false;
272
+    }
273
+
274
+    /**
275
+     * check if the URL contain a protocol, if not add https
276
+     *
277
+     * @param string $url
278
+     * @return string
279
+     */
280
+    protected function updateProtocol($url) {
281
+        if (
282
+            strpos($url, 'https://') === 0
283
+            || strpos($url, 'http://') === 0
284
+        ) {
285
+
286
+            return $url;
287
+
288
+        }
289
+
290
+        return 'https://' . $url;
291
+    }
292 292
 }
Please login to merge, or discard this patch.
apps/encryption/lib/KeyManager.php 2 patches
Indentation   +681 added lines, -681 removed lines patch added patch discarded remove patch
@@ -40,685 +40,685 @@
 block discarded – undo
40 40
 
41 41
 class KeyManager {
42 42
 
43
-	/**
44
-	 * @var Session
45
-	 */
46
-	protected $session;
47
-	/**
48
-	 * @var IStorage
49
-	 */
50
-	private $keyStorage;
51
-	/**
52
-	 * @var Crypt
53
-	 */
54
-	private $crypt;
55
-	/**
56
-	 * @var string
57
-	 */
58
-	private $recoveryKeyId;
59
-	/**
60
-	 * @var string
61
-	 */
62
-	private $publicShareKeyId;
63
-	/**
64
-	 * @var string
65
-	 */
66
-	private $masterKeyId;
67
-	/**
68
-	 * @var string UserID
69
-	 */
70
-	private $keyId;
71
-	/**
72
-	 * @var string
73
-	 */
74
-	private $publicKeyId = 'publicKey';
75
-	/**
76
-	 * @var string
77
-	 */
78
-	private $privateKeyId = 'privateKey';
79
-
80
-	/**
81
-	 * @var string
82
-	 */
83
-	private $shareKeyId = 'shareKey';
84
-
85
-	/**
86
-	 * @var string
87
-	 */
88
-	private $fileKeyId = 'fileKey';
89
-	/**
90
-	 * @var IConfig
91
-	 */
92
-	private $config;
93
-	/**
94
-	 * @var ILogger
95
-	 */
96
-	private $log;
97
-	/**
98
-	 * @var Util
99
-	 */
100
-	private $util;
101
-
102
-	/**
103
-	 * @param IStorage $keyStorage
104
-	 * @param Crypt $crypt
105
-	 * @param IConfig $config
106
-	 * @param IUserSession $userSession
107
-	 * @param Session $session
108
-	 * @param ILogger $log
109
-	 * @param Util $util
110
-	 */
111
-	public function __construct(
112
-		IStorage $keyStorage,
113
-		Crypt $crypt,
114
-		IConfig $config,
115
-		IUserSession $userSession,
116
-		Session $session,
117
-		ILogger $log,
118
-		Util $util
119
-	) {
120
-
121
-		$this->util = $util;
122
-		$this->session = $session;
123
-		$this->keyStorage = $keyStorage;
124
-		$this->crypt = $crypt;
125
-		$this->config = $config;
126
-		$this->log = $log;
127
-
128
-		$this->recoveryKeyId = $this->config->getAppValue('encryption',
129
-			'recoveryKeyId');
130
-		if (empty($this->recoveryKeyId)) {
131
-			$this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
132
-			$this->config->setAppValue('encryption',
133
-				'recoveryKeyId',
134
-				$this->recoveryKeyId);
135
-		}
136
-
137
-		$this->publicShareKeyId = $this->config->getAppValue('encryption',
138
-			'publicShareKeyId');
139
-		if (empty($this->publicShareKeyId)) {
140
-			$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
141
-			$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
142
-		}
143
-
144
-		$this->masterKeyId = $this->config->getAppValue('encryption',
145
-			'masterKeyId');
146
-		if (empty($this->masterKeyId)) {
147
-			$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
148
-			$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
149
-		}
150
-
151
-		$this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false;
152
-		$this->log = $log;
153
-	}
154
-
155
-	/**
156
-	 * check if key pair for public link shares exists, if not we create one
157
-	 */
158
-	public function validateShareKey() {
159
-		$shareKey = $this->getPublicShareKey();
160
-		if (empty($shareKey)) {
161
-			$keyPair = $this->crypt->createKeyPair();
162
-
163
-			// Save public key
164
-			$this->keyStorage->setSystemUserKey(
165
-				$this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
166
-				Encryption::ID);
167
-
168
-			// Encrypt private key empty passphrase
169
-			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
170
-			$header = $this->crypt->generateHeader();
171
-			$this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
172
-		}
173
-	}
174
-
175
-	/**
176
-	 * check if a key pair for the master key exists, if not we create one
177
-	 */
178
-	public function validateMasterKey() {
179
-
180
-		if ($this->util->isMasterKeyEnabled() === false) {
181
-			return;
182
-		}
183
-
184
-		$publicMasterKey = $this->getPublicMasterKey();
185
-		if (empty($publicMasterKey)) {
186
-			$keyPair = $this->crypt->createKeyPair();
187
-
188
-			// Save public key
189
-			$this->keyStorage->setSystemUserKey(
190
-				$this->masterKeyId . '.publicKey', $keyPair['publicKey'],
191
-				Encryption::ID);
192
-
193
-			// Encrypt private key with system password
194
-			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
195
-			$header = $this->crypt->generateHeader();
196
-			$this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
197
-		}
198
-
199
-		if (!$this->session->isPrivateKeySet()) {
200
-			$masterKey = $this->getSystemPrivateKey($this->masterKeyId);
201
-			$decryptedMasterKey = $this->crypt->decryptPrivateKey($masterKey, $this->getMasterKeyPassword(), $this->masterKeyId);
202
-			$this->session->setPrivateKey($decryptedMasterKey);
203
-		}
204
-
205
-		// after the encryption key is available we are ready to go
206
-		$this->session->setStatus(Session::INIT_SUCCESSFUL);
207
-	}
208
-
209
-	/**
210
-	 * @return bool
211
-	 */
212
-	public function recoveryKeyExists() {
213
-		$key = $this->getRecoveryKey();
214
-		return !empty($key);
215
-	}
216
-
217
-	/**
218
-	 * get recovery key
219
-	 *
220
-	 * @return string
221
-	 */
222
-	public function getRecoveryKey() {
223
-		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
224
-	}
225
-
226
-	/**
227
-	 * get recovery key ID
228
-	 *
229
-	 * @return string
230
-	 */
231
-	public function getRecoveryKeyId() {
232
-		return $this->recoveryKeyId;
233
-	}
234
-
235
-	/**
236
-	 * @param string $password
237
-	 * @return bool
238
-	 */
239
-	public function checkRecoveryPassword($password) {
240
-		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
241
-		$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
242
-
243
-		if ($decryptedRecoveryKey) {
244
-			return true;
245
-		}
246
-		return false;
247
-	}
248
-
249
-	/**
250
-	 * @param string $uid
251
-	 * @param string $password
252
-	 * @param string $keyPair
253
-	 * @return bool
254
-	 */
255
-	public function storeKeyPair($uid, $password, $keyPair) {
256
-		// Save Public Key
257
-		$this->setPublicKey($uid, $keyPair['publicKey']);
258
-
259
-		$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password, $uid);
260
-
261
-		$header = $this->crypt->generateHeader();
262
-
263
-		if ($encryptedKey) {
264
-			$this->setPrivateKey($uid, $header . $encryptedKey);
265
-			return true;
266
-		}
267
-		return false;
268
-	}
269
-
270
-	/**
271
-	 * @param string $password
272
-	 * @param array $keyPair
273
-	 * @return bool
274
-	 */
275
-	public function setRecoveryKey($password, $keyPair) {
276
-		// Save Public Key
277
-		$this->keyStorage->setSystemUserKey($this->getRecoveryKeyId().
278
-			'.publicKey',
279
-			$keyPair['publicKey'],
280
-			Encryption::ID);
281
-
282
-		$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password);
283
-		$header = $this->crypt->generateHeader();
284
-
285
-		if ($encryptedKey) {
286
-			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
287
-			return true;
288
-		}
289
-		return false;
290
-	}
291
-
292
-	/**
293
-	 * @param $userId
294
-	 * @param $key
295
-	 * @return bool
296
-	 */
297
-	public function setPublicKey($userId, $key) {
298
-		return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key, Encryption::ID);
299
-	}
300
-
301
-	/**
302
-	 * @param $userId
303
-	 * @param string $key
304
-	 * @return bool
305
-	 */
306
-	public function setPrivateKey($userId, $key) {
307
-		return $this->keyStorage->setUserKey($userId,
308
-			$this->privateKeyId,
309
-			$key,
310
-			Encryption::ID);
311
-	}
312
-
313
-	/**
314
-	 * write file key to key storage
315
-	 *
316
-	 * @param string $path
317
-	 * @param string $key
318
-	 * @return boolean
319
-	 */
320
-	public function setFileKey($path, $key) {
321
-		return $this->keyStorage->setFileKey($path, $this->fileKeyId, $key, Encryption::ID);
322
-	}
323
-
324
-	/**
325
-	 * set all file keys (the file key and the corresponding share keys)
326
-	 *
327
-	 * @param string $path
328
-	 * @param array $keys
329
-	 */
330
-	public function setAllFileKeys($path, $keys) {
331
-		$this->setFileKey($path, $keys['data']);
332
-		foreach ($keys['keys'] as $uid => $keyFile) {
333
-			$this->setShareKey($path, $uid, $keyFile);
334
-		}
335
-	}
336
-
337
-	/**
338
-	 * write share key to the key storage
339
-	 *
340
-	 * @param string $path
341
-	 * @param string $uid
342
-	 * @param string $key
343
-	 * @return boolean
344
-	 */
345
-	public function setShareKey($path, $uid, $key) {
346
-		$keyId = $uid . '.' . $this->shareKeyId;
347
-		return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
348
-	}
349
-
350
-	/**
351
-	 * Decrypt private key and store it
352
-	 *
353
-	 * @param string $uid user id
354
-	 * @param string $passPhrase users password
355
-	 * @return boolean
356
-	 */
357
-	public function init($uid, $passPhrase) {
358
-
359
-		$this->session->setStatus(Session::INIT_EXECUTED);
360
-
361
-		try {
362
-			if($this->util->isMasterKeyEnabled()) {
363
-				$uid = $this->getMasterKeyId();
364
-				$passPhrase = $this->getMasterKeyPassword();
365
-				$privateKey = $this->getSystemPrivateKey($uid);
366
-			} else {
367
-				$privateKey = $this->getPrivateKey($uid);
368
-			}
369
-			$privateKey = $this->crypt->decryptPrivateKey($privateKey, $passPhrase, $uid);
370
-		} catch (PrivateKeyMissingException $e) {
371
-			return false;
372
-		} catch (DecryptionFailedException $e) {
373
-			return false;
374
-		} catch (\Exception $e) {
375
-			$this->log->logException($e, [
376
-				'message' => 'Could not decrypt the private key from user "' . $uid . '"" during login. Assume password change on the user back-end.',
377
-				'level' => ILogger::WARN,
378
-				'app' => 'encryption',
379
-			]);
380
-			return false;
381
-		}
382
-
383
-		if ($privateKey) {
384
-			$this->session->setPrivateKey($privateKey);
385
-			$this->session->setStatus(Session::INIT_SUCCESSFUL);
386
-			return true;
387
-		}
388
-
389
-		return false;
390
-	}
391
-
392
-	/**
393
-	 * @param $userId
394
-	 * @return string
395
-	 * @throws PrivateKeyMissingException
396
-	 */
397
-	public function getPrivateKey($userId) {
398
-		$privateKey = $this->keyStorage->getUserKey($userId,
399
-			$this->privateKeyId, Encryption::ID);
400
-
401
-		if (strlen($privateKey) !== 0) {
402
-			return $privateKey;
403
-		}
404
-		throw new PrivateKeyMissingException($userId);
405
-	}
406
-
407
-	/**
408
-	 * @param string $path
409
-	 * @param $uid
410
-	 * @return string
411
-	 */
412
-	public function getFileKey($path, $uid) {
413
-		if ($uid === '') {
414
-			$uid = null;
415
-		}
416
-		$publicAccess = is_null($uid);
417
-		$encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
418
-
419
-		if (empty($encryptedFileKey)) {
420
-			return '';
421
-		}
422
-
423
-		if ($this->util->isMasterKeyEnabled()) {
424
-			$uid = $this->getMasterKeyId();
425
-			$shareKey = $this->getShareKey($path, $uid);
426
-			if ($publicAccess) {
427
-				$privateKey = $this->getSystemPrivateKey($uid);
428
-				$privateKey = $this->crypt->decryptPrivateKey($privateKey, $this->getMasterKeyPassword(), $uid);
429
-			} else {
430
-				// when logged in, the master key is already decrypted in the session
431
-				$privateKey = $this->session->getPrivateKey();
432
-			}
433
-		} else if ($publicAccess) {
434
-			// use public share key for public links
435
-			$uid = $this->getPublicShareKeyId();
436
-			$shareKey = $this->getShareKey($path, $uid);
437
-			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
438
-			$privateKey = $this->crypt->decryptPrivateKey($privateKey);
439
-		} else {
440
-			$shareKey = $this->getShareKey($path, $uid);
441
-			$privateKey = $this->session->getPrivateKey();
442
-		}
443
-
444
-		if ($encryptedFileKey && $shareKey && $privateKey) {
445
-			return $this->crypt->multiKeyDecrypt($encryptedFileKey,
446
-				$shareKey,
447
-				$privateKey);
448
-		}
449
-
450
-		return '';
451
-	}
452
-
453
-	/**
454
-	 * Get the current version of a file
455
-	 *
456
-	 * @param string $path
457
-	 * @param View $view
458
-	 * @return int
459
-	 */
460
-	public function getVersion($path, View $view) {
461
-		$fileInfo = $view->getFileInfo($path);
462
-		if($fileInfo === false) {
463
-			return 0;
464
-		}
465
-		return $fileInfo->getEncryptedVersion();
466
-	}
467
-
468
-	/**
469
-	 * Set the current version of a file
470
-	 *
471
-	 * @param string $path
472
-	 * @param int $version
473
-	 * @param View $view
474
-	 */
475
-	public function setVersion($path, $version, View $view) {
476
-		$fileInfo= $view->getFileInfo($path);
477
-
478
-		if($fileInfo !== false) {
479
-			$cache = $fileInfo->getStorage()->getCache();
480
-			$cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
481
-		}
482
-	}
483
-
484
-	/**
485
-	 * get the encrypted file key
486
-	 *
487
-	 * @param string $path
488
-	 * @return string
489
-	 */
490
-	public function getEncryptedFileKey($path) {
491
-		$encryptedFileKey = $this->keyStorage->getFileKey($path,
492
-			$this->fileKeyId, Encryption::ID);
493
-
494
-		return $encryptedFileKey;
495
-	}
496
-
497
-	/**
498
-	 * delete share key
499
-	 *
500
-	 * @param string $path
501
-	 * @param string $keyId
502
-	 * @return boolean
503
-	 */
504
-	public function deleteShareKey($path, $keyId) {
505
-		return $this->keyStorage->deleteFileKey(
506
-			$path,
507
-			$keyId . '.' . $this->shareKeyId,
508
-			Encryption::ID);
509
-	}
510
-
511
-
512
-	/**
513
-	 * @param $path
514
-	 * @param $uid
515
-	 * @return mixed
516
-	 */
517
-	public function getShareKey($path, $uid) {
518
-		$keyId = $uid . '.' . $this->shareKeyId;
519
-		return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
520
-	}
521
-
522
-	/**
523
-	 * check if user has a private and a public key
524
-	 *
525
-	 * @param string $userId
526
-	 * @return bool
527
-	 * @throws PrivateKeyMissingException
528
-	 * @throws PublicKeyMissingException
529
-	 */
530
-	public function userHasKeys($userId) {
531
-		$privateKey = $publicKey = true;
532
-		$exception = null;
533
-
534
-		try {
535
-			$this->getPrivateKey($userId);
536
-		} catch (PrivateKeyMissingException $e) {
537
-			$privateKey = false;
538
-			$exception = $e;
539
-		}
540
-		try {
541
-			$this->getPublicKey($userId);
542
-		} catch (PublicKeyMissingException $e) {
543
-			$publicKey = false;
544
-			$exception = $e;
545
-		}
546
-
547
-		if ($privateKey && $publicKey) {
548
-			return true;
549
-		} elseif (!$privateKey && !$publicKey) {
550
-			return false;
551
-		} else {
552
-			throw $exception;
553
-		}
554
-	}
555
-
556
-	/**
557
-	 * @param $userId
558
-	 * @return mixed
559
-	 * @throws PublicKeyMissingException
560
-	 */
561
-	public function getPublicKey($userId) {
562
-		$publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId, Encryption::ID);
563
-
564
-		if (strlen($publicKey) !== 0) {
565
-			return $publicKey;
566
-		}
567
-		throw new PublicKeyMissingException($userId);
568
-	}
569
-
570
-	public function getPublicShareKeyId() {
571
-		return $this->publicShareKeyId;
572
-	}
573
-
574
-	/**
575
-	 * get public key for public link shares
576
-	 *
577
-	 * @return string
578
-	 */
579
-	public function getPublicShareKey() {
580
-		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
581
-	}
582
-
583
-	/**
584
-	 * @param string $purpose
585
-	 * @param string $uid
586
-	 */
587
-	public function backupUserKeys($purpose, $uid) {
588
-		$this->keyStorage->backupUserKeys(Encryption::ID, $purpose, $uid);
589
-	}
590
-
591
-	/**
592
-	 * creat a backup of the users private and public key and then  delete it
593
-	 *
594
-	 * @param string $uid
595
-	 */
596
-	public function deleteUserKeys($uid) {
597
-		$this->deletePublicKey($uid);
598
-		$this->deletePrivateKey($uid);
599
-	}
600
-
601
-	/**
602
-	 * @param $uid
603
-	 * @return bool
604
-	 */
605
-	public function deletePublicKey($uid) {
606
-		return $this->keyStorage->deleteUserKey($uid, $this->publicKeyId, Encryption::ID);
607
-	}
608
-
609
-	/**
610
-	 * @param string $uid
611
-	 * @return bool
612
-	 */
613
-	private function deletePrivateKey($uid) {
614
-		return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId, Encryption::ID);
615
-	}
616
-
617
-	/**
618
-	 * @param string $path
619
-	 * @return bool
620
-	 */
621
-	public function deleteAllFileKeys($path) {
622
-		return $this->keyStorage->deleteAllFileKeys($path);
623
-	}
624
-
625
-	/**
626
-	 * @param array $userIds
627
-	 * @return array
628
-	 * @throws PublicKeyMissingException
629
-	 */
630
-	public function getPublicKeys(array $userIds) {
631
-		$keys = [];
632
-
633
-		foreach ($userIds as $userId) {
634
-			try {
635
-				$keys[$userId] = $this->getPublicKey($userId);
636
-			} catch (PublicKeyMissingException $e) {
637
-				continue;
638
-			}
639
-		}
640
-
641
-		return $keys;
642
-
643
-	}
644
-
645
-	/**
646
-	 * @param string $keyId
647
-	 * @return string returns openssl key
648
-	 */
649
-	public function getSystemPrivateKey($keyId) {
650
-		return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
651
-	}
652
-
653
-	/**
654
-	 * @param string $keyId
655
-	 * @param string $key
656
-	 * @return string returns openssl key
657
-	 */
658
-	public function setSystemPrivateKey($keyId, $key) {
659
-		return $this->keyStorage->setSystemUserKey(
660
-			$keyId . '.' . $this->privateKeyId,
661
-			$key,
662
-			Encryption::ID);
663
-	}
664
-
665
-	/**
666
-	 * add system keys such as the public share key and the recovery key
667
-	 *
668
-	 * @param array $accessList
669
-	 * @param array $publicKeys
670
-	 * @param string $uid
671
-	 * @return array
672
-	 * @throws PublicKeyMissingException
673
-	 */
674
-	public function addSystemKeys(array $accessList, array $publicKeys, $uid) {
675
-		if (!empty($accessList['public'])) {
676
-			$publicShareKey = $this->getPublicShareKey();
677
-			if (empty($publicShareKey)) {
678
-				throw new PublicKeyMissingException($this->getPublicShareKeyId());
679
-			}
680
-			$publicKeys[$this->getPublicShareKeyId()] = $publicShareKey;
681
-		}
682
-
683
-		if ($this->recoveryKeyExists() &&
684
-			$this->util->isRecoveryEnabledForUser($uid)) {
685
-
686
-			$publicKeys[$this->getRecoveryKeyId()] = $this->getRecoveryKey();
687
-		}
688
-
689
-		return $publicKeys;
690
-	}
691
-
692
-	/**
693
-	 * get master key password
694
-	 *
695
-	 * @return string
696
-	 * @throws \Exception
697
-	 */
698
-	public function getMasterKeyPassword() {
699
-		$password = $this->config->getSystemValue('secret');
700
-		if (empty($password)){
701
-			throw new \Exception('Can not get secret from Nextcloud instance');
702
-		}
703
-
704
-		return $password;
705
-	}
706
-
707
-	/**
708
-	 * return master key id
709
-	 *
710
-	 * @return string
711
-	 */
712
-	public function getMasterKeyId() {
713
-		return $this->masterKeyId;
714
-	}
715
-
716
-	/**
717
-	 * get public master key
718
-	 *
719
-	 * @return string
720
-	 */
721
-	public function getPublicMasterKey() {
722
-		return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
723
-	}
43
+    /**
44
+     * @var Session
45
+     */
46
+    protected $session;
47
+    /**
48
+     * @var IStorage
49
+     */
50
+    private $keyStorage;
51
+    /**
52
+     * @var Crypt
53
+     */
54
+    private $crypt;
55
+    /**
56
+     * @var string
57
+     */
58
+    private $recoveryKeyId;
59
+    /**
60
+     * @var string
61
+     */
62
+    private $publicShareKeyId;
63
+    /**
64
+     * @var string
65
+     */
66
+    private $masterKeyId;
67
+    /**
68
+     * @var string UserID
69
+     */
70
+    private $keyId;
71
+    /**
72
+     * @var string
73
+     */
74
+    private $publicKeyId = 'publicKey';
75
+    /**
76
+     * @var string
77
+     */
78
+    private $privateKeyId = 'privateKey';
79
+
80
+    /**
81
+     * @var string
82
+     */
83
+    private $shareKeyId = 'shareKey';
84
+
85
+    /**
86
+     * @var string
87
+     */
88
+    private $fileKeyId = 'fileKey';
89
+    /**
90
+     * @var IConfig
91
+     */
92
+    private $config;
93
+    /**
94
+     * @var ILogger
95
+     */
96
+    private $log;
97
+    /**
98
+     * @var Util
99
+     */
100
+    private $util;
101
+
102
+    /**
103
+     * @param IStorage $keyStorage
104
+     * @param Crypt $crypt
105
+     * @param IConfig $config
106
+     * @param IUserSession $userSession
107
+     * @param Session $session
108
+     * @param ILogger $log
109
+     * @param Util $util
110
+     */
111
+    public function __construct(
112
+        IStorage $keyStorage,
113
+        Crypt $crypt,
114
+        IConfig $config,
115
+        IUserSession $userSession,
116
+        Session $session,
117
+        ILogger $log,
118
+        Util $util
119
+    ) {
120
+
121
+        $this->util = $util;
122
+        $this->session = $session;
123
+        $this->keyStorage = $keyStorage;
124
+        $this->crypt = $crypt;
125
+        $this->config = $config;
126
+        $this->log = $log;
127
+
128
+        $this->recoveryKeyId = $this->config->getAppValue('encryption',
129
+            'recoveryKeyId');
130
+        if (empty($this->recoveryKeyId)) {
131
+            $this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
132
+            $this->config->setAppValue('encryption',
133
+                'recoveryKeyId',
134
+                $this->recoveryKeyId);
135
+        }
136
+
137
+        $this->publicShareKeyId = $this->config->getAppValue('encryption',
138
+            'publicShareKeyId');
139
+        if (empty($this->publicShareKeyId)) {
140
+            $this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
141
+            $this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
142
+        }
143
+
144
+        $this->masterKeyId = $this->config->getAppValue('encryption',
145
+            'masterKeyId');
146
+        if (empty($this->masterKeyId)) {
147
+            $this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
148
+            $this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
149
+        }
150
+
151
+        $this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false;
152
+        $this->log = $log;
153
+    }
154
+
155
+    /**
156
+     * check if key pair for public link shares exists, if not we create one
157
+     */
158
+    public function validateShareKey() {
159
+        $shareKey = $this->getPublicShareKey();
160
+        if (empty($shareKey)) {
161
+            $keyPair = $this->crypt->createKeyPair();
162
+
163
+            // Save public key
164
+            $this->keyStorage->setSystemUserKey(
165
+                $this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
166
+                Encryption::ID);
167
+
168
+            // Encrypt private key empty passphrase
169
+            $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
170
+            $header = $this->crypt->generateHeader();
171
+            $this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
172
+        }
173
+    }
174
+
175
+    /**
176
+     * check if a key pair for the master key exists, if not we create one
177
+     */
178
+    public function validateMasterKey() {
179
+
180
+        if ($this->util->isMasterKeyEnabled() === false) {
181
+            return;
182
+        }
183
+
184
+        $publicMasterKey = $this->getPublicMasterKey();
185
+        if (empty($publicMasterKey)) {
186
+            $keyPair = $this->crypt->createKeyPair();
187
+
188
+            // Save public key
189
+            $this->keyStorage->setSystemUserKey(
190
+                $this->masterKeyId . '.publicKey', $keyPair['publicKey'],
191
+                Encryption::ID);
192
+
193
+            // Encrypt private key with system password
194
+            $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
195
+            $header = $this->crypt->generateHeader();
196
+            $this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
197
+        }
198
+
199
+        if (!$this->session->isPrivateKeySet()) {
200
+            $masterKey = $this->getSystemPrivateKey($this->masterKeyId);
201
+            $decryptedMasterKey = $this->crypt->decryptPrivateKey($masterKey, $this->getMasterKeyPassword(), $this->masterKeyId);
202
+            $this->session->setPrivateKey($decryptedMasterKey);
203
+        }
204
+
205
+        // after the encryption key is available we are ready to go
206
+        $this->session->setStatus(Session::INIT_SUCCESSFUL);
207
+    }
208
+
209
+    /**
210
+     * @return bool
211
+     */
212
+    public function recoveryKeyExists() {
213
+        $key = $this->getRecoveryKey();
214
+        return !empty($key);
215
+    }
216
+
217
+    /**
218
+     * get recovery key
219
+     *
220
+     * @return string
221
+     */
222
+    public function getRecoveryKey() {
223
+        return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
224
+    }
225
+
226
+    /**
227
+     * get recovery key ID
228
+     *
229
+     * @return string
230
+     */
231
+    public function getRecoveryKeyId() {
232
+        return $this->recoveryKeyId;
233
+    }
234
+
235
+    /**
236
+     * @param string $password
237
+     * @return bool
238
+     */
239
+    public function checkRecoveryPassword($password) {
240
+        $recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
241
+        $decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
242
+
243
+        if ($decryptedRecoveryKey) {
244
+            return true;
245
+        }
246
+        return false;
247
+    }
248
+
249
+    /**
250
+     * @param string $uid
251
+     * @param string $password
252
+     * @param string $keyPair
253
+     * @return bool
254
+     */
255
+    public function storeKeyPair($uid, $password, $keyPair) {
256
+        // Save Public Key
257
+        $this->setPublicKey($uid, $keyPair['publicKey']);
258
+
259
+        $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password, $uid);
260
+
261
+        $header = $this->crypt->generateHeader();
262
+
263
+        if ($encryptedKey) {
264
+            $this->setPrivateKey($uid, $header . $encryptedKey);
265
+            return true;
266
+        }
267
+        return false;
268
+    }
269
+
270
+    /**
271
+     * @param string $password
272
+     * @param array $keyPair
273
+     * @return bool
274
+     */
275
+    public function setRecoveryKey($password, $keyPair) {
276
+        // Save Public Key
277
+        $this->keyStorage->setSystemUserKey($this->getRecoveryKeyId().
278
+            '.publicKey',
279
+            $keyPair['publicKey'],
280
+            Encryption::ID);
281
+
282
+        $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password);
283
+        $header = $this->crypt->generateHeader();
284
+
285
+        if ($encryptedKey) {
286
+            $this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
287
+            return true;
288
+        }
289
+        return false;
290
+    }
291
+
292
+    /**
293
+     * @param $userId
294
+     * @param $key
295
+     * @return bool
296
+     */
297
+    public function setPublicKey($userId, $key) {
298
+        return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key, Encryption::ID);
299
+    }
300
+
301
+    /**
302
+     * @param $userId
303
+     * @param string $key
304
+     * @return bool
305
+     */
306
+    public function setPrivateKey($userId, $key) {
307
+        return $this->keyStorage->setUserKey($userId,
308
+            $this->privateKeyId,
309
+            $key,
310
+            Encryption::ID);
311
+    }
312
+
313
+    /**
314
+     * write file key to key storage
315
+     *
316
+     * @param string $path
317
+     * @param string $key
318
+     * @return boolean
319
+     */
320
+    public function setFileKey($path, $key) {
321
+        return $this->keyStorage->setFileKey($path, $this->fileKeyId, $key, Encryption::ID);
322
+    }
323
+
324
+    /**
325
+     * set all file keys (the file key and the corresponding share keys)
326
+     *
327
+     * @param string $path
328
+     * @param array $keys
329
+     */
330
+    public function setAllFileKeys($path, $keys) {
331
+        $this->setFileKey($path, $keys['data']);
332
+        foreach ($keys['keys'] as $uid => $keyFile) {
333
+            $this->setShareKey($path, $uid, $keyFile);
334
+        }
335
+    }
336
+
337
+    /**
338
+     * write share key to the key storage
339
+     *
340
+     * @param string $path
341
+     * @param string $uid
342
+     * @param string $key
343
+     * @return boolean
344
+     */
345
+    public function setShareKey($path, $uid, $key) {
346
+        $keyId = $uid . '.' . $this->shareKeyId;
347
+        return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
348
+    }
349
+
350
+    /**
351
+     * Decrypt private key and store it
352
+     *
353
+     * @param string $uid user id
354
+     * @param string $passPhrase users password
355
+     * @return boolean
356
+     */
357
+    public function init($uid, $passPhrase) {
358
+
359
+        $this->session->setStatus(Session::INIT_EXECUTED);
360
+
361
+        try {
362
+            if($this->util->isMasterKeyEnabled()) {
363
+                $uid = $this->getMasterKeyId();
364
+                $passPhrase = $this->getMasterKeyPassword();
365
+                $privateKey = $this->getSystemPrivateKey($uid);
366
+            } else {
367
+                $privateKey = $this->getPrivateKey($uid);
368
+            }
369
+            $privateKey = $this->crypt->decryptPrivateKey($privateKey, $passPhrase, $uid);
370
+        } catch (PrivateKeyMissingException $e) {
371
+            return false;
372
+        } catch (DecryptionFailedException $e) {
373
+            return false;
374
+        } catch (\Exception $e) {
375
+            $this->log->logException($e, [
376
+                'message' => 'Could not decrypt the private key from user "' . $uid . '"" during login. Assume password change on the user back-end.',
377
+                'level' => ILogger::WARN,
378
+                'app' => 'encryption',
379
+            ]);
380
+            return false;
381
+        }
382
+
383
+        if ($privateKey) {
384
+            $this->session->setPrivateKey($privateKey);
385
+            $this->session->setStatus(Session::INIT_SUCCESSFUL);
386
+            return true;
387
+        }
388
+
389
+        return false;
390
+    }
391
+
392
+    /**
393
+     * @param $userId
394
+     * @return string
395
+     * @throws PrivateKeyMissingException
396
+     */
397
+    public function getPrivateKey($userId) {
398
+        $privateKey = $this->keyStorage->getUserKey($userId,
399
+            $this->privateKeyId, Encryption::ID);
400
+
401
+        if (strlen($privateKey) !== 0) {
402
+            return $privateKey;
403
+        }
404
+        throw new PrivateKeyMissingException($userId);
405
+    }
406
+
407
+    /**
408
+     * @param string $path
409
+     * @param $uid
410
+     * @return string
411
+     */
412
+    public function getFileKey($path, $uid) {
413
+        if ($uid === '') {
414
+            $uid = null;
415
+        }
416
+        $publicAccess = is_null($uid);
417
+        $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
418
+
419
+        if (empty($encryptedFileKey)) {
420
+            return '';
421
+        }
422
+
423
+        if ($this->util->isMasterKeyEnabled()) {
424
+            $uid = $this->getMasterKeyId();
425
+            $shareKey = $this->getShareKey($path, $uid);
426
+            if ($publicAccess) {
427
+                $privateKey = $this->getSystemPrivateKey($uid);
428
+                $privateKey = $this->crypt->decryptPrivateKey($privateKey, $this->getMasterKeyPassword(), $uid);
429
+            } else {
430
+                // when logged in, the master key is already decrypted in the session
431
+                $privateKey = $this->session->getPrivateKey();
432
+            }
433
+        } else if ($publicAccess) {
434
+            // use public share key for public links
435
+            $uid = $this->getPublicShareKeyId();
436
+            $shareKey = $this->getShareKey($path, $uid);
437
+            $privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
438
+            $privateKey = $this->crypt->decryptPrivateKey($privateKey);
439
+        } else {
440
+            $shareKey = $this->getShareKey($path, $uid);
441
+            $privateKey = $this->session->getPrivateKey();
442
+        }
443
+
444
+        if ($encryptedFileKey && $shareKey && $privateKey) {
445
+            return $this->crypt->multiKeyDecrypt($encryptedFileKey,
446
+                $shareKey,
447
+                $privateKey);
448
+        }
449
+
450
+        return '';
451
+    }
452
+
453
+    /**
454
+     * Get the current version of a file
455
+     *
456
+     * @param string $path
457
+     * @param View $view
458
+     * @return int
459
+     */
460
+    public function getVersion($path, View $view) {
461
+        $fileInfo = $view->getFileInfo($path);
462
+        if($fileInfo === false) {
463
+            return 0;
464
+        }
465
+        return $fileInfo->getEncryptedVersion();
466
+    }
467
+
468
+    /**
469
+     * Set the current version of a file
470
+     *
471
+     * @param string $path
472
+     * @param int $version
473
+     * @param View $view
474
+     */
475
+    public function setVersion($path, $version, View $view) {
476
+        $fileInfo= $view->getFileInfo($path);
477
+
478
+        if($fileInfo !== false) {
479
+            $cache = $fileInfo->getStorage()->getCache();
480
+            $cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
481
+        }
482
+    }
483
+
484
+    /**
485
+     * get the encrypted file key
486
+     *
487
+     * @param string $path
488
+     * @return string
489
+     */
490
+    public function getEncryptedFileKey($path) {
491
+        $encryptedFileKey = $this->keyStorage->getFileKey($path,
492
+            $this->fileKeyId, Encryption::ID);
493
+
494
+        return $encryptedFileKey;
495
+    }
496
+
497
+    /**
498
+     * delete share key
499
+     *
500
+     * @param string $path
501
+     * @param string $keyId
502
+     * @return boolean
503
+     */
504
+    public function deleteShareKey($path, $keyId) {
505
+        return $this->keyStorage->deleteFileKey(
506
+            $path,
507
+            $keyId . '.' . $this->shareKeyId,
508
+            Encryption::ID);
509
+    }
510
+
511
+
512
+    /**
513
+     * @param $path
514
+     * @param $uid
515
+     * @return mixed
516
+     */
517
+    public function getShareKey($path, $uid) {
518
+        $keyId = $uid . '.' . $this->shareKeyId;
519
+        return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
520
+    }
521
+
522
+    /**
523
+     * check if user has a private and a public key
524
+     *
525
+     * @param string $userId
526
+     * @return bool
527
+     * @throws PrivateKeyMissingException
528
+     * @throws PublicKeyMissingException
529
+     */
530
+    public function userHasKeys($userId) {
531
+        $privateKey = $publicKey = true;
532
+        $exception = null;
533
+
534
+        try {
535
+            $this->getPrivateKey($userId);
536
+        } catch (PrivateKeyMissingException $e) {
537
+            $privateKey = false;
538
+            $exception = $e;
539
+        }
540
+        try {
541
+            $this->getPublicKey($userId);
542
+        } catch (PublicKeyMissingException $e) {
543
+            $publicKey = false;
544
+            $exception = $e;
545
+        }
546
+
547
+        if ($privateKey && $publicKey) {
548
+            return true;
549
+        } elseif (!$privateKey && !$publicKey) {
550
+            return false;
551
+        } else {
552
+            throw $exception;
553
+        }
554
+    }
555
+
556
+    /**
557
+     * @param $userId
558
+     * @return mixed
559
+     * @throws PublicKeyMissingException
560
+     */
561
+    public function getPublicKey($userId) {
562
+        $publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId, Encryption::ID);
563
+
564
+        if (strlen($publicKey) !== 0) {
565
+            return $publicKey;
566
+        }
567
+        throw new PublicKeyMissingException($userId);
568
+    }
569
+
570
+    public function getPublicShareKeyId() {
571
+        return $this->publicShareKeyId;
572
+    }
573
+
574
+    /**
575
+     * get public key for public link shares
576
+     *
577
+     * @return string
578
+     */
579
+    public function getPublicShareKey() {
580
+        return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
581
+    }
582
+
583
+    /**
584
+     * @param string $purpose
585
+     * @param string $uid
586
+     */
587
+    public function backupUserKeys($purpose, $uid) {
588
+        $this->keyStorage->backupUserKeys(Encryption::ID, $purpose, $uid);
589
+    }
590
+
591
+    /**
592
+     * creat a backup of the users private and public key and then  delete it
593
+     *
594
+     * @param string $uid
595
+     */
596
+    public function deleteUserKeys($uid) {
597
+        $this->deletePublicKey($uid);
598
+        $this->deletePrivateKey($uid);
599
+    }
600
+
601
+    /**
602
+     * @param $uid
603
+     * @return bool
604
+     */
605
+    public function deletePublicKey($uid) {
606
+        return $this->keyStorage->deleteUserKey($uid, $this->publicKeyId, Encryption::ID);
607
+    }
608
+
609
+    /**
610
+     * @param string $uid
611
+     * @return bool
612
+     */
613
+    private function deletePrivateKey($uid) {
614
+        return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId, Encryption::ID);
615
+    }
616
+
617
+    /**
618
+     * @param string $path
619
+     * @return bool
620
+     */
621
+    public function deleteAllFileKeys($path) {
622
+        return $this->keyStorage->deleteAllFileKeys($path);
623
+    }
624
+
625
+    /**
626
+     * @param array $userIds
627
+     * @return array
628
+     * @throws PublicKeyMissingException
629
+     */
630
+    public function getPublicKeys(array $userIds) {
631
+        $keys = [];
632
+
633
+        foreach ($userIds as $userId) {
634
+            try {
635
+                $keys[$userId] = $this->getPublicKey($userId);
636
+            } catch (PublicKeyMissingException $e) {
637
+                continue;
638
+            }
639
+        }
640
+
641
+        return $keys;
642
+
643
+    }
644
+
645
+    /**
646
+     * @param string $keyId
647
+     * @return string returns openssl key
648
+     */
649
+    public function getSystemPrivateKey($keyId) {
650
+        return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
651
+    }
652
+
653
+    /**
654
+     * @param string $keyId
655
+     * @param string $key
656
+     * @return string returns openssl key
657
+     */
658
+    public function setSystemPrivateKey($keyId, $key) {
659
+        return $this->keyStorage->setSystemUserKey(
660
+            $keyId . '.' . $this->privateKeyId,
661
+            $key,
662
+            Encryption::ID);
663
+    }
664
+
665
+    /**
666
+     * add system keys such as the public share key and the recovery key
667
+     *
668
+     * @param array $accessList
669
+     * @param array $publicKeys
670
+     * @param string $uid
671
+     * @return array
672
+     * @throws PublicKeyMissingException
673
+     */
674
+    public function addSystemKeys(array $accessList, array $publicKeys, $uid) {
675
+        if (!empty($accessList['public'])) {
676
+            $publicShareKey = $this->getPublicShareKey();
677
+            if (empty($publicShareKey)) {
678
+                throw new PublicKeyMissingException($this->getPublicShareKeyId());
679
+            }
680
+            $publicKeys[$this->getPublicShareKeyId()] = $publicShareKey;
681
+        }
682
+
683
+        if ($this->recoveryKeyExists() &&
684
+            $this->util->isRecoveryEnabledForUser($uid)) {
685
+
686
+            $publicKeys[$this->getRecoveryKeyId()] = $this->getRecoveryKey();
687
+        }
688
+
689
+        return $publicKeys;
690
+    }
691
+
692
+    /**
693
+     * get master key password
694
+     *
695
+     * @return string
696
+     * @throws \Exception
697
+     */
698
+    public function getMasterKeyPassword() {
699
+        $password = $this->config->getSystemValue('secret');
700
+        if (empty($password)){
701
+            throw new \Exception('Can not get secret from Nextcloud instance');
702
+        }
703
+
704
+        return $password;
705
+    }
706
+
707
+    /**
708
+     * return master key id
709
+     *
710
+     * @return string
711
+     */
712
+    public function getMasterKeyId() {
713
+        return $this->masterKeyId;
714
+    }
715
+
716
+    /**
717
+     * get public master key
718
+     *
719
+     * @return string
720
+     */
721
+    public function getPublicMasterKey() {
722
+        return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
723
+    }
724 724
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -128,7 +128,7 @@  discard block
 block discarded – undo
128 128
 		$this->recoveryKeyId = $this->config->getAppValue('encryption',
129 129
 			'recoveryKeyId');
130 130
 		if (empty($this->recoveryKeyId)) {
131
-			$this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
131
+			$this->recoveryKeyId = 'recoveryKey_'.substr(md5(time()), 0, 8);
132 132
 			$this->config->setAppValue('encryption',
133 133
 				'recoveryKeyId',
134 134
 				$this->recoveryKeyId);
@@ -137,14 +137,14 @@  discard block
 block discarded – undo
137 137
 		$this->publicShareKeyId = $this->config->getAppValue('encryption',
138 138
 			'publicShareKeyId');
139 139
 		if (empty($this->publicShareKeyId)) {
140
-			$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
140
+			$this->publicShareKeyId = 'pubShare_'.substr(md5(time()), 0, 8);
141 141
 			$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
142 142
 		}
143 143
 
144 144
 		$this->masterKeyId = $this->config->getAppValue('encryption',
145 145
 			'masterKeyId');
146 146
 		if (empty($this->masterKeyId)) {
147
-			$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
147
+			$this->masterKeyId = 'master_'.substr(md5(time()), 0, 8);
148 148
 			$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
149 149
 		}
150 150
 
@@ -162,13 +162,13 @@  discard block
 block discarded – undo
162 162
 
163 163
 			// Save public key
164 164
 			$this->keyStorage->setSystemUserKey(
165
-				$this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
165
+				$this->publicShareKeyId.'.publicKey', $keyPair['publicKey'],
166 166
 				Encryption::ID);
167 167
 
168 168
 			// Encrypt private key empty passphrase
169 169
 			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
170 170
 			$header = $this->crypt->generateHeader();
171
-			$this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
171
+			$this->setSystemPrivateKey($this->publicShareKeyId, $header.$encryptedKey);
172 172
 		}
173 173
 	}
174 174
 
@@ -187,13 +187,13 @@  discard block
 block discarded – undo
187 187
 
188 188
 			// Save public key
189 189
 			$this->keyStorage->setSystemUserKey(
190
-				$this->masterKeyId . '.publicKey', $keyPair['publicKey'],
190
+				$this->masterKeyId.'.publicKey', $keyPair['publicKey'],
191 191
 				Encryption::ID);
192 192
 
193 193
 			// Encrypt private key with system password
194 194
 			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
195 195
 			$header = $this->crypt->generateHeader();
196
-			$this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
196
+			$this->setSystemPrivateKey($this->masterKeyId, $header.$encryptedKey);
197 197
 		}
198 198
 
199 199
 		if (!$this->session->isPrivateKeySet()) {
@@ -220,7 +220,7 @@  discard block
 block discarded – undo
220 220
 	 * @return string
221 221
 	 */
222 222
 	public function getRecoveryKey() {
223
-		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
223
+		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId.'.publicKey', Encryption::ID);
224 224
 	}
225 225
 
226 226
 	/**
@@ -237,7 +237,7 @@  discard block
 block discarded – undo
237 237
 	 * @return bool
238 238
 	 */
239 239
 	public function checkRecoveryPassword($password) {
240
-		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
240
+		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId.'.privateKey', Encryption::ID);
241 241
 		$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
242 242
 
243 243
 		if ($decryptedRecoveryKey) {
@@ -261,7 +261,7 @@  discard block
 block discarded – undo
261 261
 		$header = $this->crypt->generateHeader();
262 262
 
263 263
 		if ($encryptedKey) {
264
-			$this->setPrivateKey($uid, $header . $encryptedKey);
264
+			$this->setPrivateKey($uid, $header.$encryptedKey);
265 265
 			return true;
266 266
 		}
267 267
 		return false;
@@ -283,7 +283,7 @@  discard block
 block discarded – undo
283 283
 		$header = $this->crypt->generateHeader();
284 284
 
285 285
 		if ($encryptedKey) {
286
-			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
286
+			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header.$encryptedKey);
287 287
 			return true;
288 288
 		}
289 289
 		return false;
@@ -343,7 +343,7 @@  discard block
 block discarded – undo
343 343
 	 * @return boolean
344 344
 	 */
345 345
 	public function setShareKey($path, $uid, $key) {
346
-		$keyId = $uid . '.' . $this->shareKeyId;
346
+		$keyId = $uid.'.'.$this->shareKeyId;
347 347
 		return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
348 348
 	}
349 349
 
@@ -359,7 +359,7 @@  discard block
 block discarded – undo
359 359
 		$this->session->setStatus(Session::INIT_EXECUTED);
360 360
 
361 361
 		try {
362
-			if($this->util->isMasterKeyEnabled()) {
362
+			if ($this->util->isMasterKeyEnabled()) {
363 363
 				$uid = $this->getMasterKeyId();
364 364
 				$passPhrase = $this->getMasterKeyPassword();
365 365
 				$privateKey = $this->getSystemPrivateKey($uid);
@@ -373,7 +373,7 @@  discard block
 block discarded – undo
373 373
 			return false;
374 374
 		} catch (\Exception $e) {
375 375
 			$this->log->logException($e, [
376
-				'message' => 'Could not decrypt the private key from user "' . $uid . '"" during login. Assume password change on the user back-end.',
376
+				'message' => 'Could not decrypt the private key from user "'.$uid.'"" during login. Assume password change on the user back-end.',
377 377
 				'level' => ILogger::WARN,
378 378
 				'app' => 'encryption',
379 379
 			]);
@@ -434,7 +434,7 @@  discard block
 block discarded – undo
434 434
 			// use public share key for public links
435 435
 			$uid = $this->getPublicShareKeyId();
436 436
 			$shareKey = $this->getShareKey($path, $uid);
437
-			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
437
+			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId.'.privateKey', Encryption::ID);
438 438
 			$privateKey = $this->crypt->decryptPrivateKey($privateKey);
439 439
 		} else {
440 440
 			$shareKey = $this->getShareKey($path, $uid);
@@ -459,7 +459,7 @@  discard block
 block discarded – undo
459 459
 	 */
460 460
 	public function getVersion($path, View $view) {
461 461
 		$fileInfo = $view->getFileInfo($path);
462
-		if($fileInfo === false) {
462
+		if ($fileInfo === false) {
463 463
 			return 0;
464 464
 		}
465 465
 		return $fileInfo->getEncryptedVersion();
@@ -473,9 +473,9 @@  discard block
 block discarded – undo
473 473
 	 * @param View $view
474 474
 	 */
475 475
 	public function setVersion($path, $version, View $view) {
476
-		$fileInfo= $view->getFileInfo($path);
476
+		$fileInfo = $view->getFileInfo($path);
477 477
 
478
-		if($fileInfo !== false) {
478
+		if ($fileInfo !== false) {
479 479
 			$cache = $fileInfo->getStorage()->getCache();
480 480
 			$cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
481 481
 		}
@@ -504,7 +504,7 @@  discard block
 block discarded – undo
504 504
 	public function deleteShareKey($path, $keyId) {
505 505
 		return $this->keyStorage->deleteFileKey(
506 506
 			$path,
507
-			$keyId . '.' . $this->shareKeyId,
507
+			$keyId.'.'.$this->shareKeyId,
508 508
 			Encryption::ID);
509 509
 	}
510 510
 
@@ -515,7 +515,7 @@  discard block
 block discarded – undo
515 515
 	 * @return mixed
516 516
 	 */
517 517
 	public function getShareKey($path, $uid) {
518
-		$keyId = $uid . '.' . $this->shareKeyId;
518
+		$keyId = $uid.'.'.$this->shareKeyId;
519 519
 		return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
520 520
 	}
521 521
 
@@ -577,7 +577,7 @@  discard block
 block discarded – undo
577 577
 	 * @return string
578 578
 	 */
579 579
 	public function getPublicShareKey() {
580
-		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
580
+		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId.'.publicKey', Encryption::ID);
581 581
 	}
582 582
 
583 583
 	/**
@@ -647,7 +647,7 @@  discard block
 block discarded – undo
647 647
 	 * @return string returns openssl key
648 648
 	 */
649 649
 	public function getSystemPrivateKey($keyId) {
650
-		return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
650
+		return $this->keyStorage->getSystemUserKey($keyId.'.'.$this->privateKeyId, Encryption::ID);
651 651
 	}
652 652
 
653 653
 	/**
@@ -657,7 +657,7 @@  discard block
 block discarded – undo
657 657
 	 */
658 658
 	public function setSystemPrivateKey($keyId, $key) {
659 659
 		return $this->keyStorage->setSystemUserKey(
660
-			$keyId . '.' . $this->privateKeyId,
660
+			$keyId.'.'.$this->privateKeyId,
661 661
 			$key,
662 662
 			Encryption::ID);
663 663
 	}
@@ -697,7 +697,7 @@  discard block
 block discarded – undo
697 697
 	 */
698 698
 	public function getMasterKeyPassword() {
699 699
 		$password = $this->config->getSystemValue('secret');
700
-		if (empty($password)){
700
+		if (empty($password)) {
701 701
 			throw new \Exception('Can not get secret from Nextcloud instance');
702 702
 		}
703 703
 
@@ -719,6 +719,6 @@  discard block
 block discarded – undo
719 719
 	 * @return string
720 720
 	 */
721 721
 	public function getPublicMasterKey() {
722
-		return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
722
+		return $this->keyStorage->getSystemUserKey($this->masterKeyId.'.publicKey', Encryption::ID);
723 723
 	}
724 724
 }
Please login to merge, or discard this patch.