@@ -40,87 +40,87 @@ |
||
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 | } |
@@ -53,989 +53,989 @@ |
||
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 | } |
@@ -51,639 +51,639 @@ |
||
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 | } |
@@ -135,7 +135,7 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 | } |
@@ -53,1036 +53,1036 @@ |
||
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 | } |
@@ -28,32 +28,32 @@ |
||
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 | } |
@@ -56,213 +56,213 @@ |
||
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 | } |
@@ -154,7 +154,7 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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, |
@@ -38,54 +38,54 @@ |
||
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 | } |
@@ -41,252 +41,252 @@ |
||
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 | } |
@@ -40,685 +40,685 @@ |
||
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 | } |
@@ -128,7 +128,7 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 | } |