@@ -36,60 +36,60 @@ |
||
36 | 36 | */ |
37 | 37 | class SetPasswordColumn implements IRepairStep { |
38 | 38 | |
39 | - /** @var IDBConnection */ |
|
40 | - private $connection; |
|
39 | + /** @var IDBConnection */ |
|
40 | + private $connection; |
|
41 | 41 | |
42 | - /** @var IConfig */ |
|
43 | - private $config; |
|
42 | + /** @var IConfig */ |
|
43 | + private $config; |
|
44 | 44 | |
45 | 45 | |
46 | - public function __construct(IDBConnection $connection, IConfig $config) { |
|
47 | - $this->connection = $connection; |
|
48 | - $this->config = $config; |
|
49 | - } |
|
46 | + public function __construct(IDBConnection $connection, IConfig $config) { |
|
47 | + $this->connection = $connection; |
|
48 | + $this->config = $config; |
|
49 | + } |
|
50 | 50 | |
51 | - /** |
|
52 | - * Returns the step's name |
|
53 | - * |
|
54 | - * @return string |
|
55 | - * @since 9.1.0 |
|
56 | - */ |
|
57 | - public function getName() { |
|
58 | - return 'Copy the share password into the dedicated column'; |
|
59 | - } |
|
51 | + /** |
|
52 | + * Returns the step's name |
|
53 | + * |
|
54 | + * @return string |
|
55 | + * @since 9.1.0 |
|
56 | + */ |
|
57 | + public function getName() { |
|
58 | + return 'Copy the share password into the dedicated column'; |
|
59 | + } |
|
60 | 60 | |
61 | - /** |
|
62 | - * @param IOutput $output |
|
63 | - */ |
|
64 | - public function run(IOutput $output) { |
|
65 | - if (!$this->shouldRun()) { |
|
66 | - return; |
|
67 | - } |
|
61 | + /** |
|
62 | + * @param IOutput $output |
|
63 | + */ |
|
64 | + public function run(IOutput $output) { |
|
65 | + if (!$this->shouldRun()) { |
|
66 | + return; |
|
67 | + } |
|
68 | 68 | |
69 | - $query = $this->connection->getQueryBuilder(); |
|
70 | - $query |
|
71 | - ->update('share') |
|
72 | - ->set('password', 'share_with') |
|
73 | - ->where($query->expr()->eq('share_type', $query->createNamedParameter(IShare::TYPE_LINK))) |
|
74 | - ->andWhere($query->expr()->isNotNull('share_with')); |
|
75 | - $result = $query->execute(); |
|
69 | + $query = $this->connection->getQueryBuilder(); |
|
70 | + $query |
|
71 | + ->update('share') |
|
72 | + ->set('password', 'share_with') |
|
73 | + ->where($query->expr()->eq('share_type', $query->createNamedParameter(IShare::TYPE_LINK))) |
|
74 | + ->andWhere($query->expr()->isNotNull('share_with')); |
|
75 | + $result = $query->execute(); |
|
76 | 76 | |
77 | - if ($result === 0) { |
|
78 | - // No link updated, no need to run the second query |
|
79 | - return; |
|
80 | - } |
|
77 | + if ($result === 0) { |
|
78 | + // No link updated, no need to run the second query |
|
79 | + return; |
|
80 | + } |
|
81 | 81 | |
82 | - $clearQuery = $this->connection->getQueryBuilder(); |
|
83 | - $clearQuery |
|
84 | - ->update('share') |
|
85 | - ->set('share_with', $clearQuery->createNamedParameter(null)) |
|
86 | - ->where($clearQuery->expr()->eq('share_type', $clearQuery->createNamedParameter(IShare::TYPE_LINK))); |
|
82 | + $clearQuery = $this->connection->getQueryBuilder(); |
|
83 | + $clearQuery |
|
84 | + ->update('share') |
|
85 | + ->set('share_with', $clearQuery->createNamedParameter(null)) |
|
86 | + ->where($clearQuery->expr()->eq('share_type', $clearQuery->createNamedParameter(IShare::TYPE_LINK))); |
|
87 | 87 | |
88 | - $clearQuery->execute(); |
|
89 | - } |
|
88 | + $clearQuery->execute(); |
|
89 | + } |
|
90 | 90 | |
91 | - protected function shouldRun() { |
|
92 | - $appVersion = $this->config->getAppValue('files_sharing', 'installed_version', '0.0.0'); |
|
93 | - return version_compare($appVersion, '1.4.0', '<'); |
|
94 | - } |
|
91 | + protected function shouldRun() { |
|
92 | + $appVersion = $this->config->getAppValue('files_sharing', 'installed_version', '0.0.0'); |
|
93 | + return version_compare($appVersion, '1.4.0', '<'); |
|
94 | + } |
|
95 | 95 | } |
@@ -37,46 +37,46 @@ |
||
37 | 37 | */ |
38 | 38 | class OwncloudGuestShareType implements IRepairStep { |
39 | 39 | |
40 | - /** @var IDBConnection */ |
|
41 | - private $connection; |
|
40 | + /** @var IDBConnection */ |
|
41 | + private $connection; |
|
42 | 42 | |
43 | - /** @var IConfig */ |
|
44 | - private $config; |
|
43 | + /** @var IConfig */ |
|
44 | + private $config; |
|
45 | 45 | |
46 | 46 | |
47 | - public function __construct(IDBConnection $connection, IConfig $config) { |
|
48 | - $this->connection = $connection; |
|
49 | - $this->config = $config; |
|
50 | - } |
|
47 | + public function __construct(IDBConnection $connection, IConfig $config) { |
|
48 | + $this->connection = $connection; |
|
49 | + $this->config = $config; |
|
50 | + } |
|
51 | 51 | |
52 | - /** |
|
53 | - * Returns the step's name |
|
54 | - * |
|
55 | - * @return string |
|
56 | - * @since 9.1.0 |
|
57 | - */ |
|
58 | - public function getName() { |
|
59 | - return 'Fix the share type of guest shares when migrating from ownCloud'; |
|
60 | - } |
|
52 | + /** |
|
53 | + * Returns the step's name |
|
54 | + * |
|
55 | + * @return string |
|
56 | + * @since 9.1.0 |
|
57 | + */ |
|
58 | + public function getName() { |
|
59 | + return 'Fix the share type of guest shares when migrating from ownCloud'; |
|
60 | + } |
|
61 | 61 | |
62 | - /** |
|
63 | - * @param IOutput $output |
|
64 | - */ |
|
65 | - public function run(IOutput $output) { |
|
66 | - if (!$this->shouldRun()) { |
|
67 | - return; |
|
68 | - } |
|
62 | + /** |
|
63 | + * @param IOutput $output |
|
64 | + */ |
|
65 | + public function run(IOutput $output) { |
|
66 | + if (!$this->shouldRun()) { |
|
67 | + return; |
|
68 | + } |
|
69 | 69 | |
70 | - $query = $this->connection->getQueryBuilder(); |
|
71 | - $query->update('share') |
|
72 | - ->set('share_type', $query->createNamedParameter(IShare::TYPE_GUEST)) |
|
73 | - ->where($query->expr()->eq('share_type', $query->createNamedParameter(IShare::TYPE_EMAIL))); |
|
74 | - $query->execute(); |
|
75 | - } |
|
70 | + $query = $this->connection->getQueryBuilder(); |
|
71 | + $query->update('share') |
|
72 | + ->set('share_type', $query->createNamedParameter(IShare::TYPE_GUEST)) |
|
73 | + ->where($query->expr()->eq('share_type', $query->createNamedParameter(IShare::TYPE_EMAIL))); |
|
74 | + $query->execute(); |
|
75 | + } |
|
76 | 76 | |
77 | - protected function shouldRun() { |
|
78 | - $appVersion = $this->config->getAppValue('files_sharing', 'installed_version', '0.0.0'); |
|
79 | - return $appVersion === '0.10.0' || |
|
80 | - $this->config->getAppValue('core', 'vendor', '') === 'owncloud'; |
|
81 | - } |
|
77 | + protected function shouldRun() { |
|
78 | + $appVersion = $this->config->getAppValue('files_sharing', 'installed_version', '0.0.0'); |
|
79 | + return $appVersion === '0.10.0' || |
|
80 | + $this->config->getAppValue('core', 'vendor', '') === 'owncloud'; |
|
81 | + } |
|
82 | 82 | } |
@@ -69,7 +69,7 @@ |
||
69 | 69 | |
70 | 70 | $query = $this->connection->getQueryBuilder(); |
71 | 71 | $query->update('share') |
72 | - ->set('share_type', $query->createNamedParameter(IShare::TYPE_GUEST)) |
|
72 | + ->set('share_type', $query->createNamedParameter(IShare::TYPE_GUEST)) |
|
73 | 73 | ->where($query->expr()->eq('share_type', $query->createNamedParameter(IShare::TYPE_EMAIL))); |
74 | 74 | $query->execute(); |
75 | 75 | } |
@@ -49,168 +49,168 @@ |
||
49 | 49 | |
50 | 50 | class DeletedShareAPIController extends OCSController { |
51 | 51 | |
52 | - /** @var ShareManager */ |
|
53 | - private $shareManager; |
|
54 | - |
|
55 | - /** @var string */ |
|
56 | - private $userId; |
|
57 | - |
|
58 | - /** @var IUserManager */ |
|
59 | - private $userManager; |
|
60 | - |
|
61 | - /** @var IGroupManager */ |
|
62 | - private $groupManager; |
|
63 | - |
|
64 | - /** @var IRootFolder */ |
|
65 | - private $rootFolder; |
|
66 | - |
|
67 | - /** @var IAppManager */ |
|
68 | - private $appManager; |
|
69 | - |
|
70 | - /** @var IServerContainer */ |
|
71 | - private $serverContainer; |
|
72 | - |
|
73 | - public function __construct(string $appName, |
|
74 | - IRequest $request, |
|
75 | - ShareManager $shareManager, |
|
76 | - string $UserId, |
|
77 | - IUserManager $userManager, |
|
78 | - IGroupManager $groupManager, |
|
79 | - IRootFolder $rootFolder, |
|
80 | - IAppManager $appManager, |
|
81 | - IServerContainer $serverContainer) { |
|
82 | - parent::__construct($appName, $request); |
|
83 | - |
|
84 | - $this->shareManager = $shareManager; |
|
85 | - $this->userId = $UserId; |
|
86 | - $this->userManager = $userManager; |
|
87 | - $this->groupManager = $groupManager; |
|
88 | - $this->rootFolder = $rootFolder; |
|
89 | - $this->appManager = $appManager; |
|
90 | - $this->serverContainer = $serverContainer; |
|
91 | - } |
|
92 | - |
|
93 | - /** |
|
94 | - * @suppress PhanUndeclaredClassMethod |
|
95 | - */ |
|
96 | - private function formatShare(IShare $share): array { |
|
97 | - $result = [ |
|
98 | - 'id' => $share->getFullId(), |
|
99 | - 'share_type' => $share->getShareType(), |
|
100 | - 'uid_owner' => $share->getSharedBy(), |
|
101 | - 'displayname_owner' => $this->userManager->get($share->getSharedBy())->getDisplayName(), |
|
102 | - 'permissions' => 0, |
|
103 | - 'stime' => $share->getShareTime()->getTimestamp(), |
|
104 | - 'parent' => null, |
|
105 | - 'expiration' => null, |
|
106 | - 'token' => null, |
|
107 | - 'uid_file_owner' => $share->getShareOwner(), |
|
108 | - 'displayname_file_owner' => $this->userManager->get($share->getShareOwner())->getDisplayName(), |
|
109 | - 'path' => $share->getTarget(), |
|
110 | - ]; |
|
111 | - $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
112 | - $nodes = $userFolder->getById($share->getNodeId()); |
|
113 | - if (empty($nodes)) { |
|
114 | - // fallback to guessing the path |
|
115 | - $node = $userFolder->get($share->getTarget()); |
|
116 | - if ($node === null || $share->getTarget() === '') { |
|
117 | - throw new NotFoundException(); |
|
118 | - } |
|
119 | - } else { |
|
120 | - $node = $nodes[0]; |
|
121 | - } |
|
122 | - |
|
123 | - $result['path'] = $userFolder->getRelativePath($node->getPath()); |
|
124 | - if ($node instanceof \OCP\Files\Folder) { |
|
125 | - $result['item_type'] = 'folder'; |
|
126 | - } else { |
|
127 | - $result['item_type'] = 'file'; |
|
128 | - } |
|
129 | - $result['mimetype'] = $node->getMimetype(); |
|
130 | - $result['storage_id'] = $node->getStorage()->getId(); |
|
131 | - $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId(); |
|
132 | - $result['item_source'] = $node->getId(); |
|
133 | - $result['file_source'] = $node->getId(); |
|
134 | - $result['file_parent'] = $node->getParent()->getId(); |
|
135 | - $result['file_target'] = $share->getTarget(); |
|
136 | - |
|
137 | - $expiration = $share->getExpirationDate(); |
|
138 | - if ($expiration !== null) { |
|
139 | - $result['expiration'] = $expiration->format('Y-m-d 00:00:00'); |
|
140 | - } |
|
141 | - |
|
142 | - if ($share->getShareType() === IShare::TYPE_GROUP) { |
|
143 | - $group = $this->groupManager->get($share->getSharedWith()); |
|
144 | - $result['share_with'] = $share->getSharedWith(); |
|
145 | - $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith(); |
|
146 | - } elseif ($share->getShareType() === IShare::TYPE_ROOM) { |
|
147 | - $result['share_with'] = $share->getSharedWith(); |
|
148 | - $result['share_with_displayname'] = ''; |
|
149 | - |
|
150 | - try { |
|
151 | - $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share)); |
|
152 | - } catch (QueryException $e) { |
|
153 | - } |
|
154 | - } |
|
155 | - |
|
156 | - return $result; |
|
157 | - } |
|
158 | - |
|
159 | - /** |
|
160 | - * @NoAdminRequired |
|
161 | - */ |
|
162 | - public function index(): DataResponse { |
|
163 | - $groupShares = $this->shareManager->getDeletedSharedWith($this->userId, IShare::TYPE_GROUP, null, -1, 0); |
|
164 | - $roomShares = $this->shareManager->getDeletedSharedWith($this->userId, IShare::TYPE_ROOM, null, -1, 0); |
|
165 | - |
|
166 | - $shares = array_merge($groupShares, $roomShares); |
|
167 | - |
|
168 | - $shares = array_map(function (IShare $share) { |
|
169 | - return $this->formatShare($share); |
|
170 | - }, $shares); |
|
171 | - |
|
172 | - return new DataResponse($shares); |
|
173 | - } |
|
174 | - |
|
175 | - /** |
|
176 | - * @NoAdminRequired |
|
177 | - * |
|
178 | - * @throws OCSException |
|
179 | - */ |
|
180 | - public function undelete(string $id): DataResponse { |
|
181 | - try { |
|
182 | - $share = $this->shareManager->getShareById($id, $this->userId); |
|
183 | - } catch (ShareNotFound $e) { |
|
184 | - throw new OCSNotFoundException('Share not found'); |
|
185 | - } |
|
186 | - |
|
187 | - if ($share->getPermissions() !== 0) { |
|
188 | - throw new OCSNotFoundException('No deleted share found'); |
|
189 | - } |
|
190 | - |
|
191 | - try { |
|
192 | - $this->shareManager->restoreShare($share, $this->userId); |
|
193 | - } catch (GenericShareException $e) { |
|
194 | - throw new OCSException('Something went wrong'); |
|
195 | - } |
|
196 | - |
|
197 | - return new DataResponse([]); |
|
198 | - } |
|
199 | - |
|
200 | - /** |
|
201 | - * Returns the helper of DeletedShareAPIController for room shares. |
|
202 | - * |
|
203 | - * If the Talk application is not enabled or the helper is not available |
|
204 | - * a QueryException is thrown instead. |
|
205 | - * |
|
206 | - * @return \OCA\Talk\Share\Helper\DeletedShareAPIController |
|
207 | - * @throws QueryException |
|
208 | - */ |
|
209 | - private function getRoomShareHelper() { |
|
210 | - if (!$this->appManager->isEnabledForUser('spreed')) { |
|
211 | - throw new QueryException(); |
|
212 | - } |
|
213 | - |
|
214 | - return $this->serverContainer->query('\OCA\Talk\Share\Helper\DeletedShareAPIController'); |
|
215 | - } |
|
52 | + /** @var ShareManager */ |
|
53 | + private $shareManager; |
|
54 | + |
|
55 | + /** @var string */ |
|
56 | + private $userId; |
|
57 | + |
|
58 | + /** @var IUserManager */ |
|
59 | + private $userManager; |
|
60 | + |
|
61 | + /** @var IGroupManager */ |
|
62 | + private $groupManager; |
|
63 | + |
|
64 | + /** @var IRootFolder */ |
|
65 | + private $rootFolder; |
|
66 | + |
|
67 | + /** @var IAppManager */ |
|
68 | + private $appManager; |
|
69 | + |
|
70 | + /** @var IServerContainer */ |
|
71 | + private $serverContainer; |
|
72 | + |
|
73 | + public function __construct(string $appName, |
|
74 | + IRequest $request, |
|
75 | + ShareManager $shareManager, |
|
76 | + string $UserId, |
|
77 | + IUserManager $userManager, |
|
78 | + IGroupManager $groupManager, |
|
79 | + IRootFolder $rootFolder, |
|
80 | + IAppManager $appManager, |
|
81 | + IServerContainer $serverContainer) { |
|
82 | + parent::__construct($appName, $request); |
|
83 | + |
|
84 | + $this->shareManager = $shareManager; |
|
85 | + $this->userId = $UserId; |
|
86 | + $this->userManager = $userManager; |
|
87 | + $this->groupManager = $groupManager; |
|
88 | + $this->rootFolder = $rootFolder; |
|
89 | + $this->appManager = $appManager; |
|
90 | + $this->serverContainer = $serverContainer; |
|
91 | + } |
|
92 | + |
|
93 | + /** |
|
94 | + * @suppress PhanUndeclaredClassMethod |
|
95 | + */ |
|
96 | + private function formatShare(IShare $share): array { |
|
97 | + $result = [ |
|
98 | + 'id' => $share->getFullId(), |
|
99 | + 'share_type' => $share->getShareType(), |
|
100 | + 'uid_owner' => $share->getSharedBy(), |
|
101 | + 'displayname_owner' => $this->userManager->get($share->getSharedBy())->getDisplayName(), |
|
102 | + 'permissions' => 0, |
|
103 | + 'stime' => $share->getShareTime()->getTimestamp(), |
|
104 | + 'parent' => null, |
|
105 | + 'expiration' => null, |
|
106 | + 'token' => null, |
|
107 | + 'uid_file_owner' => $share->getShareOwner(), |
|
108 | + 'displayname_file_owner' => $this->userManager->get($share->getShareOwner())->getDisplayName(), |
|
109 | + 'path' => $share->getTarget(), |
|
110 | + ]; |
|
111 | + $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
112 | + $nodes = $userFolder->getById($share->getNodeId()); |
|
113 | + if (empty($nodes)) { |
|
114 | + // fallback to guessing the path |
|
115 | + $node = $userFolder->get($share->getTarget()); |
|
116 | + if ($node === null || $share->getTarget() === '') { |
|
117 | + throw new NotFoundException(); |
|
118 | + } |
|
119 | + } else { |
|
120 | + $node = $nodes[0]; |
|
121 | + } |
|
122 | + |
|
123 | + $result['path'] = $userFolder->getRelativePath($node->getPath()); |
|
124 | + if ($node instanceof \OCP\Files\Folder) { |
|
125 | + $result['item_type'] = 'folder'; |
|
126 | + } else { |
|
127 | + $result['item_type'] = 'file'; |
|
128 | + } |
|
129 | + $result['mimetype'] = $node->getMimetype(); |
|
130 | + $result['storage_id'] = $node->getStorage()->getId(); |
|
131 | + $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId(); |
|
132 | + $result['item_source'] = $node->getId(); |
|
133 | + $result['file_source'] = $node->getId(); |
|
134 | + $result['file_parent'] = $node->getParent()->getId(); |
|
135 | + $result['file_target'] = $share->getTarget(); |
|
136 | + |
|
137 | + $expiration = $share->getExpirationDate(); |
|
138 | + if ($expiration !== null) { |
|
139 | + $result['expiration'] = $expiration->format('Y-m-d 00:00:00'); |
|
140 | + } |
|
141 | + |
|
142 | + if ($share->getShareType() === IShare::TYPE_GROUP) { |
|
143 | + $group = $this->groupManager->get($share->getSharedWith()); |
|
144 | + $result['share_with'] = $share->getSharedWith(); |
|
145 | + $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith(); |
|
146 | + } elseif ($share->getShareType() === IShare::TYPE_ROOM) { |
|
147 | + $result['share_with'] = $share->getSharedWith(); |
|
148 | + $result['share_with_displayname'] = ''; |
|
149 | + |
|
150 | + try { |
|
151 | + $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share)); |
|
152 | + } catch (QueryException $e) { |
|
153 | + } |
|
154 | + } |
|
155 | + |
|
156 | + return $result; |
|
157 | + } |
|
158 | + |
|
159 | + /** |
|
160 | + * @NoAdminRequired |
|
161 | + */ |
|
162 | + public function index(): DataResponse { |
|
163 | + $groupShares = $this->shareManager->getDeletedSharedWith($this->userId, IShare::TYPE_GROUP, null, -1, 0); |
|
164 | + $roomShares = $this->shareManager->getDeletedSharedWith($this->userId, IShare::TYPE_ROOM, null, -1, 0); |
|
165 | + |
|
166 | + $shares = array_merge($groupShares, $roomShares); |
|
167 | + |
|
168 | + $shares = array_map(function (IShare $share) { |
|
169 | + return $this->formatShare($share); |
|
170 | + }, $shares); |
|
171 | + |
|
172 | + return new DataResponse($shares); |
|
173 | + } |
|
174 | + |
|
175 | + /** |
|
176 | + * @NoAdminRequired |
|
177 | + * |
|
178 | + * @throws OCSException |
|
179 | + */ |
|
180 | + public function undelete(string $id): DataResponse { |
|
181 | + try { |
|
182 | + $share = $this->shareManager->getShareById($id, $this->userId); |
|
183 | + } catch (ShareNotFound $e) { |
|
184 | + throw new OCSNotFoundException('Share not found'); |
|
185 | + } |
|
186 | + |
|
187 | + if ($share->getPermissions() !== 0) { |
|
188 | + throw new OCSNotFoundException('No deleted share found'); |
|
189 | + } |
|
190 | + |
|
191 | + try { |
|
192 | + $this->shareManager->restoreShare($share, $this->userId); |
|
193 | + } catch (GenericShareException $e) { |
|
194 | + throw new OCSException('Something went wrong'); |
|
195 | + } |
|
196 | + |
|
197 | + return new DataResponse([]); |
|
198 | + } |
|
199 | + |
|
200 | + /** |
|
201 | + * Returns the helper of DeletedShareAPIController for room shares. |
|
202 | + * |
|
203 | + * If the Talk application is not enabled or the helper is not available |
|
204 | + * a QueryException is thrown instead. |
|
205 | + * |
|
206 | + * @return \OCA\Talk\Share\Helper\DeletedShareAPIController |
|
207 | + * @throws QueryException |
|
208 | + */ |
|
209 | + private function getRoomShareHelper() { |
|
210 | + if (!$this->appManager->isEnabledForUser('spreed')) { |
|
211 | + throw new QueryException(); |
|
212 | + } |
|
213 | + |
|
214 | + return $this->serverContainer->query('\OCA\Talk\Share\Helper\DeletedShareAPIController'); |
|
215 | + } |
|
216 | 216 | } |
@@ -85,666 +85,666 @@ |
||
85 | 85 | */ |
86 | 86 | class ShareController extends AuthPublicShareController { |
87 | 87 | |
88 | - /** @var IConfig */ |
|
89 | - protected $config; |
|
90 | - /** @var IUserManager */ |
|
91 | - protected $userManager; |
|
92 | - /** @var ILogger */ |
|
93 | - protected $logger; |
|
94 | - /** @var \OCP\Activity\IManager */ |
|
95 | - protected $activityManager; |
|
96 | - /** @var IPreview */ |
|
97 | - protected $previewManager; |
|
98 | - /** @var IRootFolder */ |
|
99 | - protected $rootFolder; |
|
100 | - /** @var FederatedShareProvider */ |
|
101 | - protected $federatedShareProvider; |
|
102 | - /** @var IAccountManager */ |
|
103 | - protected $accountManager; |
|
104 | - /** @var EventDispatcherInterface */ |
|
105 | - protected $eventDispatcher; |
|
106 | - /** @var IL10N */ |
|
107 | - protected $l10n; |
|
108 | - /** @var Defaults */ |
|
109 | - protected $defaults; |
|
110 | - /** @var ShareManager */ |
|
111 | - protected $shareManager; |
|
112 | - |
|
113 | - /** @var Share\IShare */ |
|
114 | - protected $share; |
|
115 | - |
|
116 | - /** |
|
117 | - * @param string $appName |
|
118 | - * @param IRequest $request |
|
119 | - * @param IConfig $config |
|
120 | - * @param IURLGenerator $urlGenerator |
|
121 | - * @param IUserManager $userManager |
|
122 | - * @param ILogger $logger |
|
123 | - * @param \OCP\Activity\IManager $activityManager |
|
124 | - * @param \OCP\Share\IManager $shareManager |
|
125 | - * @param ISession $session |
|
126 | - * @param IPreview $previewManager |
|
127 | - * @param IRootFolder $rootFolder |
|
128 | - * @param FederatedShareProvider $federatedShareProvider |
|
129 | - * @param IAccountManager $accountManager |
|
130 | - * @param EventDispatcherInterface $eventDispatcher |
|
131 | - * @param IL10N $l10n |
|
132 | - * @param Defaults $defaults |
|
133 | - */ |
|
134 | - public function __construct(string $appName, |
|
135 | - IRequest $request, |
|
136 | - IConfig $config, |
|
137 | - IURLGenerator $urlGenerator, |
|
138 | - IUserManager $userManager, |
|
139 | - ILogger $logger, |
|
140 | - \OCP\Activity\IManager $activityManager, |
|
141 | - ShareManager $shareManager, |
|
142 | - ISession $session, |
|
143 | - IPreview $previewManager, |
|
144 | - IRootFolder $rootFolder, |
|
145 | - FederatedShareProvider $federatedShareProvider, |
|
146 | - IAccountManager $accountManager, |
|
147 | - EventDispatcherInterface $eventDispatcher, |
|
148 | - IL10N $l10n, |
|
149 | - Defaults $defaults) { |
|
150 | - parent::__construct($appName, $request, $session, $urlGenerator); |
|
151 | - |
|
152 | - $this->config = $config; |
|
153 | - $this->userManager = $userManager; |
|
154 | - $this->logger = $logger; |
|
155 | - $this->activityManager = $activityManager; |
|
156 | - $this->previewManager = $previewManager; |
|
157 | - $this->rootFolder = $rootFolder; |
|
158 | - $this->federatedShareProvider = $federatedShareProvider; |
|
159 | - $this->accountManager = $accountManager; |
|
160 | - $this->eventDispatcher = $eventDispatcher; |
|
161 | - $this->l10n = $l10n; |
|
162 | - $this->defaults = $defaults; |
|
163 | - $this->shareManager = $shareManager; |
|
164 | - } |
|
165 | - |
|
166 | - /** |
|
167 | - * @PublicPage |
|
168 | - * @NoCSRFRequired |
|
169 | - * |
|
170 | - * Show the authentication page |
|
171 | - * The form has to submit to the authenticate method route |
|
172 | - */ |
|
173 | - public function showAuthenticate(): TemplateResponse { |
|
174 | - $templateParameters = ['share' => $this->share]; |
|
175 | - |
|
176 | - $event = new GenericEvent(null, $templateParameters); |
|
177 | - $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event); |
|
178 | - |
|
179 | - $response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest'); |
|
180 | - if ($this->share->getSendPasswordByTalk()) { |
|
181 | - $csp = new ContentSecurityPolicy(); |
|
182 | - $csp->addAllowedConnectDomain('*'); |
|
183 | - $csp->addAllowedMediaDomain('blob:'); |
|
184 | - $response->setContentSecurityPolicy($csp); |
|
185 | - } |
|
186 | - |
|
187 | - return $response; |
|
188 | - } |
|
189 | - |
|
190 | - /** |
|
191 | - * The template to show when authentication failed |
|
192 | - */ |
|
193 | - protected function showAuthFailed(): TemplateResponse { |
|
194 | - $templateParameters = ['share' => $this->share, 'wrongpw' => true]; |
|
195 | - |
|
196 | - $event = new GenericEvent(null, $templateParameters); |
|
197 | - $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event); |
|
198 | - |
|
199 | - $response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest'); |
|
200 | - if ($this->share->getSendPasswordByTalk()) { |
|
201 | - $csp = new ContentSecurityPolicy(); |
|
202 | - $csp->addAllowedConnectDomain('*'); |
|
203 | - $csp->addAllowedMediaDomain('blob:'); |
|
204 | - $response->setContentSecurityPolicy($csp); |
|
205 | - } |
|
206 | - |
|
207 | - return $response; |
|
208 | - } |
|
209 | - |
|
210 | - protected function verifyPassword(string $password): bool { |
|
211 | - return $this->shareManager->checkPassword($this->share, $password); |
|
212 | - } |
|
213 | - |
|
214 | - protected function getPasswordHash(): string { |
|
215 | - return $this->share->getPassword(); |
|
216 | - } |
|
217 | - |
|
218 | - public function isValidToken(): bool { |
|
219 | - try { |
|
220 | - $this->share = $this->shareManager->getShareByToken($this->getToken()); |
|
221 | - } catch (ShareNotFound $e) { |
|
222 | - return false; |
|
223 | - } |
|
224 | - |
|
225 | - return true; |
|
226 | - } |
|
227 | - |
|
228 | - protected function isPasswordProtected(): bool { |
|
229 | - return $this->share->getPassword() !== null; |
|
230 | - } |
|
231 | - |
|
232 | - protected function authSucceeded() { |
|
233 | - // For share this was always set so it is still used in other apps |
|
234 | - $this->session->set('public_link_authenticated', (string)$this->share->getId()); |
|
235 | - } |
|
236 | - |
|
237 | - protected function authFailed() { |
|
238 | - $this->emitAccessShareHook($this->share, 403, 'Wrong password'); |
|
239 | - } |
|
240 | - |
|
241 | - /** |
|
242 | - * throws hooks when a share is attempted to be accessed |
|
243 | - * |
|
244 | - * @param \OCP\Share\IShare|string $share the Share instance if available, |
|
245 | - * otherwise token |
|
246 | - * @param int $errorCode |
|
247 | - * @param string $errorMessage |
|
248 | - * @throws \OC\HintException |
|
249 | - * @throws \OC\ServerNotAvailableException |
|
250 | - */ |
|
251 | - protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') { |
|
252 | - $itemType = $itemSource = $uidOwner = ''; |
|
253 | - $token = $share; |
|
254 | - $exception = null; |
|
255 | - if ($share instanceof \OCP\Share\IShare) { |
|
256 | - try { |
|
257 | - $token = $share->getToken(); |
|
258 | - $uidOwner = $share->getSharedBy(); |
|
259 | - $itemType = $share->getNodeType(); |
|
260 | - $itemSource = $share->getNodeId(); |
|
261 | - } catch (\Exception $e) { |
|
262 | - // we log what we know and pass on the exception afterwards |
|
263 | - $exception = $e; |
|
264 | - } |
|
265 | - } |
|
266 | - \OC_Hook::emit(Share::class, 'share_link_access', [ |
|
267 | - 'itemType' => $itemType, |
|
268 | - 'itemSource' => $itemSource, |
|
269 | - 'uidOwner' => $uidOwner, |
|
270 | - 'token' => $token, |
|
271 | - 'errorCode' => $errorCode, |
|
272 | - 'errorMessage' => $errorMessage, |
|
273 | - ]); |
|
274 | - if (!is_null($exception)) { |
|
275 | - throw $exception; |
|
276 | - } |
|
277 | - } |
|
278 | - |
|
279 | - /** |
|
280 | - * Validate the permissions of the share |
|
281 | - * |
|
282 | - * @param Share\IShare $share |
|
283 | - * @return bool |
|
284 | - */ |
|
285 | - private function validateShare(\OCP\Share\IShare $share) { |
|
286 | - // If the owner is disabled no access to the linke is granted |
|
287 | - $owner = $this->userManager->get($share->getShareOwner()); |
|
288 | - if ($owner === null || !$owner->isEnabled()) { |
|
289 | - return false; |
|
290 | - } |
|
291 | - |
|
292 | - // If the initiator of the share is disabled no access is granted |
|
293 | - $initiator = $this->userManager->get($share->getSharedBy()); |
|
294 | - if ($initiator === null || !$initiator->isEnabled()) { |
|
295 | - return false; |
|
296 | - } |
|
297 | - |
|
298 | - return $share->getNode()->isReadable() && $share->getNode()->isShareable(); |
|
299 | - } |
|
300 | - |
|
301 | - /** |
|
302 | - * @PublicPage |
|
303 | - * @NoCSRFRequired |
|
304 | - * |
|
305 | - * |
|
306 | - * @param string $path |
|
307 | - * @return TemplateResponse |
|
308 | - * @throws NotFoundException |
|
309 | - * @throws \Exception |
|
310 | - */ |
|
311 | - public function showShare($path = ''): TemplateResponse { |
|
312 | - \OC_User::setIncognitoMode(true); |
|
313 | - |
|
314 | - // Check whether share exists |
|
315 | - try { |
|
316 | - $share = $this->shareManager->getShareByToken($this->getToken()); |
|
317 | - } catch (ShareNotFound $e) { |
|
318 | - $this->emitAccessShareHook($this->getToken(), 404, 'Share not found'); |
|
319 | - throw new NotFoundException(); |
|
320 | - } |
|
321 | - |
|
322 | - if (!$this->validateShare($share)) { |
|
323 | - throw new NotFoundException(); |
|
324 | - } |
|
325 | - |
|
326 | - $shareNode = $share->getNode(); |
|
327 | - |
|
328 | - // We can't get the path of a file share |
|
329 | - try { |
|
330 | - if ($shareNode instanceof \OCP\Files\File && $path !== '') { |
|
331 | - $this->emitAccessShareHook($share, 404, 'Share not found'); |
|
332 | - throw new NotFoundException(); |
|
333 | - } |
|
334 | - } catch (\Exception $e) { |
|
335 | - $this->emitAccessShareHook($share, 404, 'Share not found'); |
|
336 | - throw $e; |
|
337 | - } |
|
338 | - |
|
339 | - $shareTmpl = []; |
|
340 | - $shareTmpl['owner'] = ''; |
|
341 | - $shareTmpl['shareOwner'] = ''; |
|
342 | - |
|
343 | - $owner = $this->userManager->get($share->getShareOwner()); |
|
344 | - if ($owner instanceof IUser) { |
|
345 | - $ownerAccount = $this->accountManager->getAccount($owner); |
|
346 | - |
|
347 | - $ownerName = $ownerAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME); |
|
348 | - if ($ownerName->getScope() === IAccountManager::VISIBILITY_PUBLIC) { |
|
349 | - $shareTmpl['owner'] = $owner->getUID(); |
|
350 | - $shareTmpl['shareOwner'] = $owner->getDisplayName(); |
|
351 | - } |
|
352 | - } |
|
353 | - |
|
354 | - $shareTmpl['filename'] = $shareNode->getName(); |
|
355 | - $shareTmpl['directory_path'] = $share->getTarget(); |
|
356 | - $shareTmpl['note'] = $share->getNote(); |
|
357 | - $shareTmpl['mimetype'] = $shareNode->getMimetype(); |
|
358 | - $shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($shareNode->getMimetype()); |
|
359 | - $shareTmpl['dirToken'] = $this->getToken(); |
|
360 | - $shareTmpl['sharingToken'] = $this->getToken(); |
|
361 | - $shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled(); |
|
362 | - $shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false'; |
|
363 | - $shareTmpl['dir'] = ''; |
|
364 | - $shareTmpl['nonHumanFileSize'] = $shareNode->getSize(); |
|
365 | - $shareTmpl['fileSize'] = \OCP\Util::humanFileSize($shareNode->getSize()); |
|
366 | - $shareTmpl['hideDownload'] = $share->getHideDownload(); |
|
367 | - |
|
368 | - $hideFileList = false; |
|
369 | - |
|
370 | - if ($shareNode instanceof \OCP\Files\Folder) { |
|
371 | - $shareIsFolder = true; |
|
372 | - |
|
373 | - try { |
|
374 | - $folderNode = $shareNode->get($path); |
|
375 | - } catch (\OCP\Files\NotFoundException $e) { |
|
376 | - $this->emitAccessShareHook($share, 404, 'Share not found'); |
|
377 | - throw new NotFoundException(); |
|
378 | - } |
|
379 | - |
|
380 | - $shareTmpl['dir'] = $shareNode->getRelativePath($folderNode->getPath()); |
|
381 | - |
|
382 | - /* |
|
88 | + /** @var IConfig */ |
|
89 | + protected $config; |
|
90 | + /** @var IUserManager */ |
|
91 | + protected $userManager; |
|
92 | + /** @var ILogger */ |
|
93 | + protected $logger; |
|
94 | + /** @var \OCP\Activity\IManager */ |
|
95 | + protected $activityManager; |
|
96 | + /** @var IPreview */ |
|
97 | + protected $previewManager; |
|
98 | + /** @var IRootFolder */ |
|
99 | + protected $rootFolder; |
|
100 | + /** @var FederatedShareProvider */ |
|
101 | + protected $federatedShareProvider; |
|
102 | + /** @var IAccountManager */ |
|
103 | + protected $accountManager; |
|
104 | + /** @var EventDispatcherInterface */ |
|
105 | + protected $eventDispatcher; |
|
106 | + /** @var IL10N */ |
|
107 | + protected $l10n; |
|
108 | + /** @var Defaults */ |
|
109 | + protected $defaults; |
|
110 | + /** @var ShareManager */ |
|
111 | + protected $shareManager; |
|
112 | + |
|
113 | + /** @var Share\IShare */ |
|
114 | + protected $share; |
|
115 | + |
|
116 | + /** |
|
117 | + * @param string $appName |
|
118 | + * @param IRequest $request |
|
119 | + * @param IConfig $config |
|
120 | + * @param IURLGenerator $urlGenerator |
|
121 | + * @param IUserManager $userManager |
|
122 | + * @param ILogger $logger |
|
123 | + * @param \OCP\Activity\IManager $activityManager |
|
124 | + * @param \OCP\Share\IManager $shareManager |
|
125 | + * @param ISession $session |
|
126 | + * @param IPreview $previewManager |
|
127 | + * @param IRootFolder $rootFolder |
|
128 | + * @param FederatedShareProvider $federatedShareProvider |
|
129 | + * @param IAccountManager $accountManager |
|
130 | + * @param EventDispatcherInterface $eventDispatcher |
|
131 | + * @param IL10N $l10n |
|
132 | + * @param Defaults $defaults |
|
133 | + */ |
|
134 | + public function __construct(string $appName, |
|
135 | + IRequest $request, |
|
136 | + IConfig $config, |
|
137 | + IURLGenerator $urlGenerator, |
|
138 | + IUserManager $userManager, |
|
139 | + ILogger $logger, |
|
140 | + \OCP\Activity\IManager $activityManager, |
|
141 | + ShareManager $shareManager, |
|
142 | + ISession $session, |
|
143 | + IPreview $previewManager, |
|
144 | + IRootFolder $rootFolder, |
|
145 | + FederatedShareProvider $federatedShareProvider, |
|
146 | + IAccountManager $accountManager, |
|
147 | + EventDispatcherInterface $eventDispatcher, |
|
148 | + IL10N $l10n, |
|
149 | + Defaults $defaults) { |
|
150 | + parent::__construct($appName, $request, $session, $urlGenerator); |
|
151 | + |
|
152 | + $this->config = $config; |
|
153 | + $this->userManager = $userManager; |
|
154 | + $this->logger = $logger; |
|
155 | + $this->activityManager = $activityManager; |
|
156 | + $this->previewManager = $previewManager; |
|
157 | + $this->rootFolder = $rootFolder; |
|
158 | + $this->federatedShareProvider = $federatedShareProvider; |
|
159 | + $this->accountManager = $accountManager; |
|
160 | + $this->eventDispatcher = $eventDispatcher; |
|
161 | + $this->l10n = $l10n; |
|
162 | + $this->defaults = $defaults; |
|
163 | + $this->shareManager = $shareManager; |
|
164 | + } |
|
165 | + |
|
166 | + /** |
|
167 | + * @PublicPage |
|
168 | + * @NoCSRFRequired |
|
169 | + * |
|
170 | + * Show the authentication page |
|
171 | + * The form has to submit to the authenticate method route |
|
172 | + */ |
|
173 | + public function showAuthenticate(): TemplateResponse { |
|
174 | + $templateParameters = ['share' => $this->share]; |
|
175 | + |
|
176 | + $event = new GenericEvent(null, $templateParameters); |
|
177 | + $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event); |
|
178 | + |
|
179 | + $response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest'); |
|
180 | + if ($this->share->getSendPasswordByTalk()) { |
|
181 | + $csp = new ContentSecurityPolicy(); |
|
182 | + $csp->addAllowedConnectDomain('*'); |
|
183 | + $csp->addAllowedMediaDomain('blob:'); |
|
184 | + $response->setContentSecurityPolicy($csp); |
|
185 | + } |
|
186 | + |
|
187 | + return $response; |
|
188 | + } |
|
189 | + |
|
190 | + /** |
|
191 | + * The template to show when authentication failed |
|
192 | + */ |
|
193 | + protected function showAuthFailed(): TemplateResponse { |
|
194 | + $templateParameters = ['share' => $this->share, 'wrongpw' => true]; |
|
195 | + |
|
196 | + $event = new GenericEvent(null, $templateParameters); |
|
197 | + $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts::publicShareAuth', $event); |
|
198 | + |
|
199 | + $response = new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest'); |
|
200 | + if ($this->share->getSendPasswordByTalk()) { |
|
201 | + $csp = new ContentSecurityPolicy(); |
|
202 | + $csp->addAllowedConnectDomain('*'); |
|
203 | + $csp->addAllowedMediaDomain('blob:'); |
|
204 | + $response->setContentSecurityPolicy($csp); |
|
205 | + } |
|
206 | + |
|
207 | + return $response; |
|
208 | + } |
|
209 | + |
|
210 | + protected function verifyPassword(string $password): bool { |
|
211 | + return $this->shareManager->checkPassword($this->share, $password); |
|
212 | + } |
|
213 | + |
|
214 | + protected function getPasswordHash(): string { |
|
215 | + return $this->share->getPassword(); |
|
216 | + } |
|
217 | + |
|
218 | + public function isValidToken(): bool { |
|
219 | + try { |
|
220 | + $this->share = $this->shareManager->getShareByToken($this->getToken()); |
|
221 | + } catch (ShareNotFound $e) { |
|
222 | + return false; |
|
223 | + } |
|
224 | + |
|
225 | + return true; |
|
226 | + } |
|
227 | + |
|
228 | + protected function isPasswordProtected(): bool { |
|
229 | + return $this->share->getPassword() !== null; |
|
230 | + } |
|
231 | + |
|
232 | + protected function authSucceeded() { |
|
233 | + // For share this was always set so it is still used in other apps |
|
234 | + $this->session->set('public_link_authenticated', (string)$this->share->getId()); |
|
235 | + } |
|
236 | + |
|
237 | + protected function authFailed() { |
|
238 | + $this->emitAccessShareHook($this->share, 403, 'Wrong password'); |
|
239 | + } |
|
240 | + |
|
241 | + /** |
|
242 | + * throws hooks when a share is attempted to be accessed |
|
243 | + * |
|
244 | + * @param \OCP\Share\IShare|string $share the Share instance if available, |
|
245 | + * otherwise token |
|
246 | + * @param int $errorCode |
|
247 | + * @param string $errorMessage |
|
248 | + * @throws \OC\HintException |
|
249 | + * @throws \OC\ServerNotAvailableException |
|
250 | + */ |
|
251 | + protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') { |
|
252 | + $itemType = $itemSource = $uidOwner = ''; |
|
253 | + $token = $share; |
|
254 | + $exception = null; |
|
255 | + if ($share instanceof \OCP\Share\IShare) { |
|
256 | + try { |
|
257 | + $token = $share->getToken(); |
|
258 | + $uidOwner = $share->getSharedBy(); |
|
259 | + $itemType = $share->getNodeType(); |
|
260 | + $itemSource = $share->getNodeId(); |
|
261 | + } catch (\Exception $e) { |
|
262 | + // we log what we know and pass on the exception afterwards |
|
263 | + $exception = $e; |
|
264 | + } |
|
265 | + } |
|
266 | + \OC_Hook::emit(Share::class, 'share_link_access', [ |
|
267 | + 'itemType' => $itemType, |
|
268 | + 'itemSource' => $itemSource, |
|
269 | + 'uidOwner' => $uidOwner, |
|
270 | + 'token' => $token, |
|
271 | + 'errorCode' => $errorCode, |
|
272 | + 'errorMessage' => $errorMessage, |
|
273 | + ]); |
|
274 | + if (!is_null($exception)) { |
|
275 | + throw $exception; |
|
276 | + } |
|
277 | + } |
|
278 | + |
|
279 | + /** |
|
280 | + * Validate the permissions of the share |
|
281 | + * |
|
282 | + * @param Share\IShare $share |
|
283 | + * @return bool |
|
284 | + */ |
|
285 | + private function validateShare(\OCP\Share\IShare $share) { |
|
286 | + // If the owner is disabled no access to the linke is granted |
|
287 | + $owner = $this->userManager->get($share->getShareOwner()); |
|
288 | + if ($owner === null || !$owner->isEnabled()) { |
|
289 | + return false; |
|
290 | + } |
|
291 | + |
|
292 | + // If the initiator of the share is disabled no access is granted |
|
293 | + $initiator = $this->userManager->get($share->getSharedBy()); |
|
294 | + if ($initiator === null || !$initiator->isEnabled()) { |
|
295 | + return false; |
|
296 | + } |
|
297 | + |
|
298 | + return $share->getNode()->isReadable() && $share->getNode()->isShareable(); |
|
299 | + } |
|
300 | + |
|
301 | + /** |
|
302 | + * @PublicPage |
|
303 | + * @NoCSRFRequired |
|
304 | + * |
|
305 | + * |
|
306 | + * @param string $path |
|
307 | + * @return TemplateResponse |
|
308 | + * @throws NotFoundException |
|
309 | + * @throws \Exception |
|
310 | + */ |
|
311 | + public function showShare($path = ''): TemplateResponse { |
|
312 | + \OC_User::setIncognitoMode(true); |
|
313 | + |
|
314 | + // Check whether share exists |
|
315 | + try { |
|
316 | + $share = $this->shareManager->getShareByToken($this->getToken()); |
|
317 | + } catch (ShareNotFound $e) { |
|
318 | + $this->emitAccessShareHook($this->getToken(), 404, 'Share not found'); |
|
319 | + throw new NotFoundException(); |
|
320 | + } |
|
321 | + |
|
322 | + if (!$this->validateShare($share)) { |
|
323 | + throw new NotFoundException(); |
|
324 | + } |
|
325 | + |
|
326 | + $shareNode = $share->getNode(); |
|
327 | + |
|
328 | + // We can't get the path of a file share |
|
329 | + try { |
|
330 | + if ($shareNode instanceof \OCP\Files\File && $path !== '') { |
|
331 | + $this->emitAccessShareHook($share, 404, 'Share not found'); |
|
332 | + throw new NotFoundException(); |
|
333 | + } |
|
334 | + } catch (\Exception $e) { |
|
335 | + $this->emitAccessShareHook($share, 404, 'Share not found'); |
|
336 | + throw $e; |
|
337 | + } |
|
338 | + |
|
339 | + $shareTmpl = []; |
|
340 | + $shareTmpl['owner'] = ''; |
|
341 | + $shareTmpl['shareOwner'] = ''; |
|
342 | + |
|
343 | + $owner = $this->userManager->get($share->getShareOwner()); |
|
344 | + if ($owner instanceof IUser) { |
|
345 | + $ownerAccount = $this->accountManager->getAccount($owner); |
|
346 | + |
|
347 | + $ownerName = $ownerAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME); |
|
348 | + if ($ownerName->getScope() === IAccountManager::VISIBILITY_PUBLIC) { |
|
349 | + $shareTmpl['owner'] = $owner->getUID(); |
|
350 | + $shareTmpl['shareOwner'] = $owner->getDisplayName(); |
|
351 | + } |
|
352 | + } |
|
353 | + |
|
354 | + $shareTmpl['filename'] = $shareNode->getName(); |
|
355 | + $shareTmpl['directory_path'] = $share->getTarget(); |
|
356 | + $shareTmpl['note'] = $share->getNote(); |
|
357 | + $shareTmpl['mimetype'] = $shareNode->getMimetype(); |
|
358 | + $shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($shareNode->getMimetype()); |
|
359 | + $shareTmpl['dirToken'] = $this->getToken(); |
|
360 | + $shareTmpl['sharingToken'] = $this->getToken(); |
|
361 | + $shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled(); |
|
362 | + $shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false'; |
|
363 | + $shareTmpl['dir'] = ''; |
|
364 | + $shareTmpl['nonHumanFileSize'] = $shareNode->getSize(); |
|
365 | + $shareTmpl['fileSize'] = \OCP\Util::humanFileSize($shareNode->getSize()); |
|
366 | + $shareTmpl['hideDownload'] = $share->getHideDownload(); |
|
367 | + |
|
368 | + $hideFileList = false; |
|
369 | + |
|
370 | + if ($shareNode instanceof \OCP\Files\Folder) { |
|
371 | + $shareIsFolder = true; |
|
372 | + |
|
373 | + try { |
|
374 | + $folderNode = $shareNode->get($path); |
|
375 | + } catch (\OCP\Files\NotFoundException $e) { |
|
376 | + $this->emitAccessShareHook($share, 404, 'Share not found'); |
|
377 | + throw new NotFoundException(); |
|
378 | + } |
|
379 | + |
|
380 | + $shareTmpl['dir'] = $shareNode->getRelativePath($folderNode->getPath()); |
|
381 | + |
|
382 | + /* |
|
383 | 383 | * The OC_Util methods require a view. This just uses the node API |
384 | 384 | */ |
385 | - $freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath()); |
|
386 | - if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
387 | - $freeSpace = max($freeSpace, 0); |
|
388 | - } else { |
|
389 | - $freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188 |
|
390 | - } |
|
391 | - |
|
392 | - $hideFileList = !($share->getPermissions() & \OCP\Constants::PERMISSION_READ); |
|
393 | - $maxUploadFilesize = $freeSpace; |
|
394 | - |
|
395 | - $folder = new Template('files', 'list', ''); |
|
396 | - |
|
397 | - $folder->assign('dir', $shareNode->getRelativePath($folderNode->getPath())); |
|
398 | - $folder->assign('dirToken', $this->getToken()); |
|
399 | - $folder->assign('permissions', \OCP\Constants::PERMISSION_READ); |
|
400 | - $folder->assign('isPublic', true); |
|
401 | - $folder->assign('hideFileList', $hideFileList); |
|
402 | - $folder->assign('publicUploadEnabled', 'no'); |
|
403 | - // default to list view |
|
404 | - $folder->assign('showgridview', false); |
|
405 | - $folder->assign('uploadMaxFilesize', $maxUploadFilesize); |
|
406 | - $folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize)); |
|
407 | - $folder->assign('freeSpace', $freeSpace); |
|
408 | - $folder->assign('usedSpacePercent', 0); |
|
409 | - $folder->assign('trash', false); |
|
410 | - $shareTmpl['folder'] = $folder->fetchPage(); |
|
411 | - } else { |
|
412 | - $shareIsFolder = false; |
|
413 | - } |
|
414 | - |
|
415 | - // default to list view |
|
416 | - $shareTmpl['showgridview'] = false; |
|
417 | - |
|
418 | - $shareTmpl['hideFileList'] = $hideFileList; |
|
419 | - $shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $this->getToken()]); |
|
420 | - $shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $this->getToken()]); |
|
421 | - $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10); |
|
422 | - $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true); |
|
423 | - $shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024); |
|
424 | - $shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024); |
|
425 | - $shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null); |
|
426 | - $shareTmpl['previewURL'] = $shareTmpl['downloadURL']; |
|
427 | - |
|
428 | - if ($shareTmpl['previewSupported']) { |
|
429 | - $shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview', |
|
430 | - ['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 'token' => $shareTmpl['dirToken']]); |
|
431 | - $ogPreview = $shareTmpl['previewImage']; |
|
432 | - |
|
433 | - // We just have direct previews for image files |
|
434 | - if ($shareNode->getMimePart() === 'image') { |
|
435 | - $shareTmpl['previewURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.publicpreview.directLink', ['token' => $this->getToken()]); |
|
436 | - |
|
437 | - $ogPreview = $shareTmpl['previewURL']; |
|
438 | - |
|
439 | - //Whatapp is kind of picky about their size requirements |
|
440 | - if ($this->request->isUserAgent(['/^WhatsApp/'])) { |
|
441 | - $ogPreview = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview', [ |
|
442 | - 'token' => $this->getToken(), |
|
443 | - 'x' => 256, |
|
444 | - 'y' => 256, |
|
445 | - 'a' => true, |
|
446 | - ]); |
|
447 | - } |
|
448 | - } |
|
449 | - } else { |
|
450 | - $shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png')); |
|
451 | - $ogPreview = $shareTmpl['previewImage']; |
|
452 | - } |
|
453 | - |
|
454 | - // Load files we need |
|
455 | - \OCP\Util::addScript('files', 'semaphore'); |
|
456 | - \OCP\Util::addScript('files', 'file-upload'); |
|
457 | - \OCP\Util::addStyle('files_sharing', 'publicView'); |
|
458 | - \OCP\Util::addScript('files_sharing', 'public'); |
|
459 | - \OCP\Util::addScript('files_sharing', 'templates'); |
|
460 | - \OCP\Util::addScript('files', 'fileactions'); |
|
461 | - \OCP\Util::addScript('files', 'fileactionsmenu'); |
|
462 | - \OCP\Util::addScript('files', 'jquery.fileupload'); |
|
463 | - \OCP\Util::addScript('files_sharing', 'files_drop'); |
|
464 | - |
|
465 | - if (isset($shareTmpl['folder'])) { |
|
466 | - // JS required for folders |
|
467 | - \OCP\Util::addStyle('files', 'merged'); |
|
468 | - \OCP\Util::addScript('files', 'filesummary'); |
|
469 | - \OCP\Util::addScript('files', 'templates'); |
|
470 | - \OCP\Util::addScript('files', 'breadcrumb'); |
|
471 | - \OCP\Util::addScript('files', 'fileinfomodel'); |
|
472 | - \OCP\Util::addScript('files', 'newfilemenu'); |
|
473 | - \OCP\Util::addScript('files', 'files'); |
|
474 | - \OCP\Util::addScript('files', 'filemultiselectmenu'); |
|
475 | - \OCP\Util::addScript('files', 'filelist'); |
|
476 | - \OCP\Util::addScript('files', 'keyboardshortcuts'); |
|
477 | - \OCP\Util::addScript('files', 'operationprogressbar'); |
|
478 | - |
|
479 | - // Load Viewer scripts |
|
480 | - if (class_exists(LoadViewer::class)) { |
|
481 | - $this->eventDispatcher->dispatch(LoadViewer::class, new LoadViewer()); |
|
482 | - } |
|
483 | - } |
|
484 | - |
|
485 | - // OpenGraph Support: http://ogp.me/ |
|
486 | - \OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $shareTmpl['filename']]); |
|
487 | - \OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->defaults->getName() . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')]); |
|
488 | - \OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]); |
|
489 | - \OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]); |
|
490 | - \OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]); |
|
491 | - \OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $ogPreview]); |
|
492 | - |
|
493 | - $event = new GenericEvent(null, ['share' => $share]); |
|
494 | - $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts', $event); |
|
495 | - |
|
496 | - $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); |
|
497 | - $csp->addAllowedFrameDomain('\'self\''); |
|
498 | - |
|
499 | - $response = new PublicTemplateResponse($this->appName, 'public', $shareTmpl); |
|
500 | - $response->setHeaderTitle($shareTmpl['filename']); |
|
501 | - if ($shareTmpl['shareOwner'] !== '') { |
|
502 | - $response->setHeaderDetails($this->l10n->t('shared by %s', [$shareTmpl['shareOwner']])); |
|
503 | - } |
|
504 | - |
|
505 | - $isNoneFileDropFolder = $shareIsFolder === false || $share->getPermissions() !== \OCP\Constants::PERMISSION_CREATE; |
|
506 | - |
|
507 | - if ($isNoneFileDropFolder && !$share->getHideDownload()) { |
|
508 | - \OCP\Util::addScript('files_sharing', 'public_note'); |
|
509 | - |
|
510 | - $downloadWhite = new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $shareTmpl['downloadURL'], 0); |
|
511 | - $downloadAllWhite = new SimpleMenuAction('download', $this->l10n->t('Download all files'), 'icon-download-white', $shareTmpl['downloadURL'], 0); |
|
512 | - $download = new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']); |
|
513 | - $downloadAll = new SimpleMenuAction('download', $this->l10n->t('Download all files'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']); |
|
514 | - $directLink = new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $shareTmpl['previewURL']); |
|
515 | - $externalShare = new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $shareTmpl['owner'], $shareTmpl['shareOwner'], $shareTmpl['filename']); |
|
516 | - |
|
517 | - $responseComposer = []; |
|
518 | - |
|
519 | - if ($shareIsFolder) { |
|
520 | - $responseComposer[] = $downloadAllWhite; |
|
521 | - $responseComposer[] = $downloadAll; |
|
522 | - } else { |
|
523 | - $responseComposer[] = $downloadWhite; |
|
524 | - $responseComposer[] = $download; |
|
525 | - } |
|
526 | - $responseComposer[] = $directLink; |
|
527 | - if ($this->federatedShareProvider->isOutgoingServer2serverShareEnabled()) { |
|
528 | - $responseComposer[] = $externalShare; |
|
529 | - } |
|
530 | - |
|
531 | - $response->setHeaderActions($responseComposer); |
|
532 | - } |
|
533 | - |
|
534 | - $response->setContentSecurityPolicy($csp); |
|
535 | - |
|
536 | - $this->emitAccessShareHook($share); |
|
537 | - |
|
538 | - return $response; |
|
539 | - } |
|
540 | - |
|
541 | - /** |
|
542 | - * @PublicPage |
|
543 | - * @NoCSRFRequired |
|
544 | - * @NoSameSiteCookieRequired |
|
545 | - * |
|
546 | - * @param string $token |
|
547 | - * @param string $files |
|
548 | - * @param string $path |
|
549 | - * @param string $downloadStartSecret |
|
550 | - * @return void|\OCP\AppFramework\Http\Response |
|
551 | - * @throws NotFoundException |
|
552 | - */ |
|
553 | - public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') { |
|
554 | - \OC_User::setIncognitoMode(true); |
|
555 | - |
|
556 | - $share = $this->shareManager->getShareByToken($token); |
|
557 | - |
|
558 | - if (!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) { |
|
559 | - return new \OCP\AppFramework\Http\DataResponse('Share is read-only'); |
|
560 | - } |
|
561 | - |
|
562 | - $files_list = null; |
|
563 | - if (!is_null($files)) { // download selected files |
|
564 | - $files_list = json_decode($files); |
|
565 | - // in case we get only a single file |
|
566 | - if ($files_list === null) { |
|
567 | - $files_list = [$files]; |
|
568 | - } |
|
569 | - // Just in case $files is a single int like '1234' |
|
570 | - if (!is_array($files_list)) { |
|
571 | - $files_list = [$files_list]; |
|
572 | - } |
|
573 | - } |
|
574 | - |
|
575 | - if (!$this->validateShare($share)) { |
|
576 | - throw new NotFoundException(); |
|
577 | - } |
|
578 | - |
|
579 | - $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
|
580 | - $originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath()); |
|
581 | - |
|
582 | - |
|
583 | - // Single file share |
|
584 | - if ($share->getNode() instanceof \OCP\Files\File) { |
|
585 | - // Single file download |
|
586 | - $this->singleFileDownloaded($share, $share->getNode()); |
|
587 | - } |
|
588 | - // Directory share |
|
589 | - else { |
|
590 | - /** @var \OCP\Files\Folder $node */ |
|
591 | - $node = $share->getNode(); |
|
592 | - |
|
593 | - // Try to get the path |
|
594 | - if ($path !== '') { |
|
595 | - try { |
|
596 | - $node = $node->get($path); |
|
597 | - } catch (NotFoundException $e) { |
|
598 | - $this->emitAccessShareHook($share, 404, 'Share not found'); |
|
599 | - return new NotFoundResponse(); |
|
600 | - } |
|
601 | - } |
|
602 | - |
|
603 | - $originalSharePath = $userFolder->getRelativePath($node->getPath()); |
|
604 | - |
|
605 | - if ($node instanceof \OCP\Files\File) { |
|
606 | - // Single file download |
|
607 | - $this->singleFileDownloaded($share, $share->getNode()); |
|
608 | - } else { |
|
609 | - try { |
|
610 | - if (!empty($files_list)) { |
|
611 | - $this->fileListDownloaded($share, $files_list, $node); |
|
612 | - } else { |
|
613 | - // The folder is downloaded |
|
614 | - $this->singleFileDownloaded($share, $share->getNode()); |
|
615 | - } |
|
616 | - } catch (NotFoundException $e) { |
|
617 | - return new NotFoundResponse(); |
|
618 | - } |
|
619 | - } |
|
620 | - } |
|
621 | - |
|
622 | - /* FIXME: We should do this all nicely in OCP */ |
|
623 | - OC_Util::tearDownFS(); |
|
624 | - OC_Util::setupFS($share->getShareOwner()); |
|
625 | - |
|
626 | - /** |
|
627 | - * this sets a cookie to be able to recognize the start of the download |
|
628 | - * the content must not be longer than 32 characters and must only contain |
|
629 | - * alphanumeric characters |
|
630 | - */ |
|
631 | - if (!empty($downloadStartSecret) |
|
632 | - && !isset($downloadStartSecret[32]) |
|
633 | - && preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) { |
|
634 | - |
|
635 | - // FIXME: set on the response once we use an actual app framework response |
|
636 | - setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/'); |
|
637 | - } |
|
638 | - |
|
639 | - $this->emitAccessShareHook($share); |
|
640 | - |
|
641 | - $server_params = [ 'head' => $this->request->getMethod() === 'HEAD' ]; |
|
642 | - |
|
643 | - /** |
|
644 | - * Http range requests support |
|
645 | - */ |
|
646 | - if (isset($_SERVER['HTTP_RANGE'])) { |
|
647 | - $server_params['range'] = $this->request->getHeader('Range'); |
|
648 | - } |
|
649 | - |
|
650 | - // download selected files |
|
651 | - if (!is_null($files) && $files !== '') { |
|
652 | - // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well |
|
653 | - // after dispatching the request which results in a "Cannot modify header information" notice. |
|
654 | - OC_Files::get($originalSharePath, $files_list, $server_params); |
|
655 | - exit(); |
|
656 | - } else { |
|
657 | - // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well |
|
658 | - // after dispatching the request which results in a "Cannot modify header information" notice. |
|
659 | - OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params); |
|
660 | - exit(); |
|
661 | - } |
|
662 | - } |
|
663 | - |
|
664 | - /** |
|
665 | - * create activity for every downloaded file |
|
666 | - * |
|
667 | - * @param Share\IShare $share |
|
668 | - * @param array $files_list |
|
669 | - * @param \OCP\Files\Folder $node |
|
670 | - * @throws NotFoundException when trying to download a folder or multiple files of a "hide download" share |
|
671 | - */ |
|
672 | - protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) { |
|
673 | - if ($share->getHideDownload() && count($files_list) > 1) { |
|
674 | - throw new NotFoundException('Downloading more than 1 file'); |
|
675 | - } |
|
676 | - |
|
677 | - foreach ($files_list as $file) { |
|
678 | - $subNode = $node->get($file); |
|
679 | - $this->singleFileDownloaded($share, $subNode); |
|
680 | - } |
|
681 | - } |
|
682 | - |
|
683 | - /** |
|
684 | - * create activity if a single file was downloaded from a link share |
|
685 | - * |
|
686 | - * @param Share\IShare $share |
|
687 | - * @throws NotFoundException when trying to download a folder of a "hide download" share |
|
688 | - */ |
|
689 | - protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) { |
|
690 | - if ($share->getHideDownload() && $node instanceof Folder) { |
|
691 | - throw new NotFoundException('Downloading a folder'); |
|
692 | - } |
|
693 | - |
|
694 | - $fileId = $node->getId(); |
|
695 | - |
|
696 | - $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
697 | - $userNodeList = $userFolder->getById($fileId); |
|
698 | - $userNode = $userNodeList[0]; |
|
699 | - $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
|
700 | - $userPath = $userFolder->getRelativePath($userNode->getPath()); |
|
701 | - $ownerPath = $ownerFolder->getRelativePath($node->getPath()); |
|
702 | - |
|
703 | - $parameters = [$userPath]; |
|
704 | - |
|
705 | - if ($share->getShareType() === IShare::TYPE_EMAIL) { |
|
706 | - if ($node instanceof \OCP\Files\File) { |
|
707 | - $subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED; |
|
708 | - } else { |
|
709 | - $subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED; |
|
710 | - } |
|
711 | - $parameters[] = $share->getSharedWith(); |
|
712 | - } else { |
|
713 | - if ($node instanceof \OCP\Files\File) { |
|
714 | - $subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED; |
|
715 | - } else { |
|
716 | - $subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED; |
|
717 | - } |
|
718 | - } |
|
719 | - |
|
720 | - $this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath); |
|
721 | - |
|
722 | - if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
723 | - $parameters[0] = $ownerPath; |
|
724 | - $this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath); |
|
725 | - } |
|
726 | - } |
|
727 | - |
|
728 | - /** |
|
729 | - * publish activity |
|
730 | - * |
|
731 | - * @param string $subject |
|
732 | - * @param array $parameters |
|
733 | - * @param string $affectedUser |
|
734 | - * @param int $fileId |
|
735 | - * @param string $filePath |
|
736 | - */ |
|
737 | - protected function publishActivity($subject, |
|
738 | - array $parameters, |
|
739 | - $affectedUser, |
|
740 | - $fileId, |
|
741 | - $filePath) { |
|
742 | - $event = $this->activityManager->generateEvent(); |
|
743 | - $event->setApp('files_sharing') |
|
744 | - ->setType('public_links') |
|
745 | - ->setSubject($subject, $parameters) |
|
746 | - ->setAffectedUser($affectedUser) |
|
747 | - ->setObject('files', $fileId, $filePath); |
|
748 | - $this->activityManager->publish($event); |
|
749 | - } |
|
385 | + $freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath()); |
|
386 | + if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
387 | + $freeSpace = max($freeSpace, 0); |
|
388 | + } else { |
|
389 | + $freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188 |
|
390 | + } |
|
391 | + |
|
392 | + $hideFileList = !($share->getPermissions() & \OCP\Constants::PERMISSION_READ); |
|
393 | + $maxUploadFilesize = $freeSpace; |
|
394 | + |
|
395 | + $folder = new Template('files', 'list', ''); |
|
396 | + |
|
397 | + $folder->assign('dir', $shareNode->getRelativePath($folderNode->getPath())); |
|
398 | + $folder->assign('dirToken', $this->getToken()); |
|
399 | + $folder->assign('permissions', \OCP\Constants::PERMISSION_READ); |
|
400 | + $folder->assign('isPublic', true); |
|
401 | + $folder->assign('hideFileList', $hideFileList); |
|
402 | + $folder->assign('publicUploadEnabled', 'no'); |
|
403 | + // default to list view |
|
404 | + $folder->assign('showgridview', false); |
|
405 | + $folder->assign('uploadMaxFilesize', $maxUploadFilesize); |
|
406 | + $folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize)); |
|
407 | + $folder->assign('freeSpace', $freeSpace); |
|
408 | + $folder->assign('usedSpacePercent', 0); |
|
409 | + $folder->assign('trash', false); |
|
410 | + $shareTmpl['folder'] = $folder->fetchPage(); |
|
411 | + } else { |
|
412 | + $shareIsFolder = false; |
|
413 | + } |
|
414 | + |
|
415 | + // default to list view |
|
416 | + $shareTmpl['showgridview'] = false; |
|
417 | + |
|
418 | + $shareTmpl['hideFileList'] = $hideFileList; |
|
419 | + $shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $this->getToken()]); |
|
420 | + $shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $this->getToken()]); |
|
421 | + $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10); |
|
422 | + $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true); |
|
423 | + $shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024); |
|
424 | + $shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024); |
|
425 | + $shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null); |
|
426 | + $shareTmpl['previewURL'] = $shareTmpl['downloadURL']; |
|
427 | + |
|
428 | + if ($shareTmpl['previewSupported']) { |
|
429 | + $shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview', |
|
430 | + ['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 'token' => $shareTmpl['dirToken']]); |
|
431 | + $ogPreview = $shareTmpl['previewImage']; |
|
432 | + |
|
433 | + // We just have direct previews for image files |
|
434 | + if ($shareNode->getMimePart() === 'image') { |
|
435 | + $shareTmpl['previewURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.publicpreview.directLink', ['token' => $this->getToken()]); |
|
436 | + |
|
437 | + $ogPreview = $shareTmpl['previewURL']; |
|
438 | + |
|
439 | + //Whatapp is kind of picky about their size requirements |
|
440 | + if ($this->request->isUserAgent(['/^WhatsApp/'])) { |
|
441 | + $ogPreview = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview', [ |
|
442 | + 'token' => $this->getToken(), |
|
443 | + 'x' => 256, |
|
444 | + 'y' => 256, |
|
445 | + 'a' => true, |
|
446 | + ]); |
|
447 | + } |
|
448 | + } |
|
449 | + } else { |
|
450 | + $shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png')); |
|
451 | + $ogPreview = $shareTmpl['previewImage']; |
|
452 | + } |
|
453 | + |
|
454 | + // Load files we need |
|
455 | + \OCP\Util::addScript('files', 'semaphore'); |
|
456 | + \OCP\Util::addScript('files', 'file-upload'); |
|
457 | + \OCP\Util::addStyle('files_sharing', 'publicView'); |
|
458 | + \OCP\Util::addScript('files_sharing', 'public'); |
|
459 | + \OCP\Util::addScript('files_sharing', 'templates'); |
|
460 | + \OCP\Util::addScript('files', 'fileactions'); |
|
461 | + \OCP\Util::addScript('files', 'fileactionsmenu'); |
|
462 | + \OCP\Util::addScript('files', 'jquery.fileupload'); |
|
463 | + \OCP\Util::addScript('files_sharing', 'files_drop'); |
|
464 | + |
|
465 | + if (isset($shareTmpl['folder'])) { |
|
466 | + // JS required for folders |
|
467 | + \OCP\Util::addStyle('files', 'merged'); |
|
468 | + \OCP\Util::addScript('files', 'filesummary'); |
|
469 | + \OCP\Util::addScript('files', 'templates'); |
|
470 | + \OCP\Util::addScript('files', 'breadcrumb'); |
|
471 | + \OCP\Util::addScript('files', 'fileinfomodel'); |
|
472 | + \OCP\Util::addScript('files', 'newfilemenu'); |
|
473 | + \OCP\Util::addScript('files', 'files'); |
|
474 | + \OCP\Util::addScript('files', 'filemultiselectmenu'); |
|
475 | + \OCP\Util::addScript('files', 'filelist'); |
|
476 | + \OCP\Util::addScript('files', 'keyboardshortcuts'); |
|
477 | + \OCP\Util::addScript('files', 'operationprogressbar'); |
|
478 | + |
|
479 | + // Load Viewer scripts |
|
480 | + if (class_exists(LoadViewer::class)) { |
|
481 | + $this->eventDispatcher->dispatch(LoadViewer::class, new LoadViewer()); |
|
482 | + } |
|
483 | + } |
|
484 | + |
|
485 | + // OpenGraph Support: http://ogp.me/ |
|
486 | + \OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $shareTmpl['filename']]); |
|
487 | + \OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->defaults->getName() . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')]); |
|
488 | + \OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]); |
|
489 | + \OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]); |
|
490 | + \OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]); |
|
491 | + \OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $ogPreview]); |
|
492 | + |
|
493 | + $event = new GenericEvent(null, ['share' => $share]); |
|
494 | + $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts', $event); |
|
495 | + |
|
496 | + $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); |
|
497 | + $csp->addAllowedFrameDomain('\'self\''); |
|
498 | + |
|
499 | + $response = new PublicTemplateResponse($this->appName, 'public', $shareTmpl); |
|
500 | + $response->setHeaderTitle($shareTmpl['filename']); |
|
501 | + if ($shareTmpl['shareOwner'] !== '') { |
|
502 | + $response->setHeaderDetails($this->l10n->t('shared by %s', [$shareTmpl['shareOwner']])); |
|
503 | + } |
|
504 | + |
|
505 | + $isNoneFileDropFolder = $shareIsFolder === false || $share->getPermissions() !== \OCP\Constants::PERMISSION_CREATE; |
|
506 | + |
|
507 | + if ($isNoneFileDropFolder && !$share->getHideDownload()) { |
|
508 | + \OCP\Util::addScript('files_sharing', 'public_note'); |
|
509 | + |
|
510 | + $downloadWhite = new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $shareTmpl['downloadURL'], 0); |
|
511 | + $downloadAllWhite = new SimpleMenuAction('download', $this->l10n->t('Download all files'), 'icon-download-white', $shareTmpl['downloadURL'], 0); |
|
512 | + $download = new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']); |
|
513 | + $downloadAll = new SimpleMenuAction('download', $this->l10n->t('Download all files'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']); |
|
514 | + $directLink = new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $shareTmpl['previewURL']); |
|
515 | + $externalShare = new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $shareTmpl['owner'], $shareTmpl['shareOwner'], $shareTmpl['filename']); |
|
516 | + |
|
517 | + $responseComposer = []; |
|
518 | + |
|
519 | + if ($shareIsFolder) { |
|
520 | + $responseComposer[] = $downloadAllWhite; |
|
521 | + $responseComposer[] = $downloadAll; |
|
522 | + } else { |
|
523 | + $responseComposer[] = $downloadWhite; |
|
524 | + $responseComposer[] = $download; |
|
525 | + } |
|
526 | + $responseComposer[] = $directLink; |
|
527 | + if ($this->federatedShareProvider->isOutgoingServer2serverShareEnabled()) { |
|
528 | + $responseComposer[] = $externalShare; |
|
529 | + } |
|
530 | + |
|
531 | + $response->setHeaderActions($responseComposer); |
|
532 | + } |
|
533 | + |
|
534 | + $response->setContentSecurityPolicy($csp); |
|
535 | + |
|
536 | + $this->emitAccessShareHook($share); |
|
537 | + |
|
538 | + return $response; |
|
539 | + } |
|
540 | + |
|
541 | + /** |
|
542 | + * @PublicPage |
|
543 | + * @NoCSRFRequired |
|
544 | + * @NoSameSiteCookieRequired |
|
545 | + * |
|
546 | + * @param string $token |
|
547 | + * @param string $files |
|
548 | + * @param string $path |
|
549 | + * @param string $downloadStartSecret |
|
550 | + * @return void|\OCP\AppFramework\Http\Response |
|
551 | + * @throws NotFoundException |
|
552 | + */ |
|
553 | + public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') { |
|
554 | + \OC_User::setIncognitoMode(true); |
|
555 | + |
|
556 | + $share = $this->shareManager->getShareByToken($token); |
|
557 | + |
|
558 | + if (!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) { |
|
559 | + return new \OCP\AppFramework\Http\DataResponse('Share is read-only'); |
|
560 | + } |
|
561 | + |
|
562 | + $files_list = null; |
|
563 | + if (!is_null($files)) { // download selected files |
|
564 | + $files_list = json_decode($files); |
|
565 | + // in case we get only a single file |
|
566 | + if ($files_list === null) { |
|
567 | + $files_list = [$files]; |
|
568 | + } |
|
569 | + // Just in case $files is a single int like '1234' |
|
570 | + if (!is_array($files_list)) { |
|
571 | + $files_list = [$files_list]; |
|
572 | + } |
|
573 | + } |
|
574 | + |
|
575 | + if (!$this->validateShare($share)) { |
|
576 | + throw new NotFoundException(); |
|
577 | + } |
|
578 | + |
|
579 | + $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
|
580 | + $originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath()); |
|
581 | + |
|
582 | + |
|
583 | + // Single file share |
|
584 | + if ($share->getNode() instanceof \OCP\Files\File) { |
|
585 | + // Single file download |
|
586 | + $this->singleFileDownloaded($share, $share->getNode()); |
|
587 | + } |
|
588 | + // Directory share |
|
589 | + else { |
|
590 | + /** @var \OCP\Files\Folder $node */ |
|
591 | + $node = $share->getNode(); |
|
592 | + |
|
593 | + // Try to get the path |
|
594 | + if ($path !== '') { |
|
595 | + try { |
|
596 | + $node = $node->get($path); |
|
597 | + } catch (NotFoundException $e) { |
|
598 | + $this->emitAccessShareHook($share, 404, 'Share not found'); |
|
599 | + return new NotFoundResponse(); |
|
600 | + } |
|
601 | + } |
|
602 | + |
|
603 | + $originalSharePath = $userFolder->getRelativePath($node->getPath()); |
|
604 | + |
|
605 | + if ($node instanceof \OCP\Files\File) { |
|
606 | + // Single file download |
|
607 | + $this->singleFileDownloaded($share, $share->getNode()); |
|
608 | + } else { |
|
609 | + try { |
|
610 | + if (!empty($files_list)) { |
|
611 | + $this->fileListDownloaded($share, $files_list, $node); |
|
612 | + } else { |
|
613 | + // The folder is downloaded |
|
614 | + $this->singleFileDownloaded($share, $share->getNode()); |
|
615 | + } |
|
616 | + } catch (NotFoundException $e) { |
|
617 | + return new NotFoundResponse(); |
|
618 | + } |
|
619 | + } |
|
620 | + } |
|
621 | + |
|
622 | + /* FIXME: We should do this all nicely in OCP */ |
|
623 | + OC_Util::tearDownFS(); |
|
624 | + OC_Util::setupFS($share->getShareOwner()); |
|
625 | + |
|
626 | + /** |
|
627 | + * this sets a cookie to be able to recognize the start of the download |
|
628 | + * the content must not be longer than 32 characters and must only contain |
|
629 | + * alphanumeric characters |
|
630 | + */ |
|
631 | + if (!empty($downloadStartSecret) |
|
632 | + && !isset($downloadStartSecret[32]) |
|
633 | + && preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) { |
|
634 | + |
|
635 | + // FIXME: set on the response once we use an actual app framework response |
|
636 | + setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/'); |
|
637 | + } |
|
638 | + |
|
639 | + $this->emitAccessShareHook($share); |
|
640 | + |
|
641 | + $server_params = [ 'head' => $this->request->getMethod() === 'HEAD' ]; |
|
642 | + |
|
643 | + /** |
|
644 | + * Http range requests support |
|
645 | + */ |
|
646 | + if (isset($_SERVER['HTTP_RANGE'])) { |
|
647 | + $server_params['range'] = $this->request->getHeader('Range'); |
|
648 | + } |
|
649 | + |
|
650 | + // download selected files |
|
651 | + if (!is_null($files) && $files !== '') { |
|
652 | + // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well |
|
653 | + // after dispatching the request which results in a "Cannot modify header information" notice. |
|
654 | + OC_Files::get($originalSharePath, $files_list, $server_params); |
|
655 | + exit(); |
|
656 | + } else { |
|
657 | + // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well |
|
658 | + // after dispatching the request which results in a "Cannot modify header information" notice. |
|
659 | + OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params); |
|
660 | + exit(); |
|
661 | + } |
|
662 | + } |
|
663 | + |
|
664 | + /** |
|
665 | + * create activity for every downloaded file |
|
666 | + * |
|
667 | + * @param Share\IShare $share |
|
668 | + * @param array $files_list |
|
669 | + * @param \OCP\Files\Folder $node |
|
670 | + * @throws NotFoundException when trying to download a folder or multiple files of a "hide download" share |
|
671 | + */ |
|
672 | + protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) { |
|
673 | + if ($share->getHideDownload() && count($files_list) > 1) { |
|
674 | + throw new NotFoundException('Downloading more than 1 file'); |
|
675 | + } |
|
676 | + |
|
677 | + foreach ($files_list as $file) { |
|
678 | + $subNode = $node->get($file); |
|
679 | + $this->singleFileDownloaded($share, $subNode); |
|
680 | + } |
|
681 | + } |
|
682 | + |
|
683 | + /** |
|
684 | + * create activity if a single file was downloaded from a link share |
|
685 | + * |
|
686 | + * @param Share\IShare $share |
|
687 | + * @throws NotFoundException when trying to download a folder of a "hide download" share |
|
688 | + */ |
|
689 | + protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) { |
|
690 | + if ($share->getHideDownload() && $node instanceof Folder) { |
|
691 | + throw new NotFoundException('Downloading a folder'); |
|
692 | + } |
|
693 | + |
|
694 | + $fileId = $node->getId(); |
|
695 | + |
|
696 | + $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
697 | + $userNodeList = $userFolder->getById($fileId); |
|
698 | + $userNode = $userNodeList[0]; |
|
699 | + $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
|
700 | + $userPath = $userFolder->getRelativePath($userNode->getPath()); |
|
701 | + $ownerPath = $ownerFolder->getRelativePath($node->getPath()); |
|
702 | + |
|
703 | + $parameters = [$userPath]; |
|
704 | + |
|
705 | + if ($share->getShareType() === IShare::TYPE_EMAIL) { |
|
706 | + if ($node instanceof \OCP\Files\File) { |
|
707 | + $subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED; |
|
708 | + } else { |
|
709 | + $subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED; |
|
710 | + } |
|
711 | + $parameters[] = $share->getSharedWith(); |
|
712 | + } else { |
|
713 | + if ($node instanceof \OCP\Files\File) { |
|
714 | + $subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED; |
|
715 | + } else { |
|
716 | + $subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED; |
|
717 | + } |
|
718 | + } |
|
719 | + |
|
720 | + $this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath); |
|
721 | + |
|
722 | + if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
723 | + $parameters[0] = $ownerPath; |
|
724 | + $this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath); |
|
725 | + } |
|
726 | + } |
|
727 | + |
|
728 | + /** |
|
729 | + * publish activity |
|
730 | + * |
|
731 | + * @param string $subject |
|
732 | + * @param array $parameters |
|
733 | + * @param string $affectedUser |
|
734 | + * @param int $fileId |
|
735 | + * @param string $filePath |
|
736 | + */ |
|
737 | + protected function publishActivity($subject, |
|
738 | + array $parameters, |
|
739 | + $affectedUser, |
|
740 | + $fileId, |
|
741 | + $filePath) { |
|
742 | + $event = $this->activityManager->generateEvent(); |
|
743 | + $event->setApp('files_sharing') |
|
744 | + ->setType('public_links') |
|
745 | + ->setSubject($subject, $parameters) |
|
746 | + ->setAffectedUser($affectedUser) |
|
747 | + ->setObject('files', $fileId, $filePath); |
|
748 | + $this->activityManager->publish($event); |
|
749 | + } |
|
750 | 750 | } |
@@ -48,372 +48,372 @@ |
||
48 | 48 | |
49 | 49 | abstract class Node implements \Sabre\DAV\INode { |
50 | 50 | |
51 | - /** |
|
52 | - * @var \OC\Files\View |
|
53 | - */ |
|
54 | - protected $fileView; |
|
55 | - |
|
56 | - /** |
|
57 | - * The path to the current node |
|
58 | - * |
|
59 | - * @var string |
|
60 | - */ |
|
61 | - protected $path; |
|
62 | - |
|
63 | - /** |
|
64 | - * node properties cache |
|
65 | - * |
|
66 | - * @var array |
|
67 | - */ |
|
68 | - protected $property_cache = null; |
|
69 | - |
|
70 | - /** |
|
71 | - * @var \OCP\Files\FileInfo |
|
72 | - */ |
|
73 | - protected $info; |
|
74 | - |
|
75 | - /** |
|
76 | - * @var IManager |
|
77 | - */ |
|
78 | - protected $shareManager; |
|
79 | - |
|
80 | - /** |
|
81 | - * Sets up the node, expects a full path name |
|
82 | - * |
|
83 | - * @param \OC\Files\View $view |
|
84 | - * @param \OCP\Files\FileInfo $info |
|
85 | - * @param IManager $shareManager |
|
86 | - */ |
|
87 | - public function __construct(View $view, FileInfo $info, IManager $shareManager = null) { |
|
88 | - $this->fileView = $view; |
|
89 | - $this->path = $this->fileView->getRelativePath($info->getPath()); |
|
90 | - $this->info = $info; |
|
91 | - if ($shareManager) { |
|
92 | - $this->shareManager = $shareManager; |
|
93 | - } else { |
|
94 | - $this->shareManager = \OC::$server->getShareManager(); |
|
95 | - } |
|
96 | - } |
|
97 | - |
|
98 | - protected function refreshInfo() { |
|
99 | - $this->info = $this->fileView->getFileInfo($this->path); |
|
100 | - } |
|
101 | - |
|
102 | - /** |
|
103 | - * Returns the name of the node |
|
104 | - * |
|
105 | - * @return string |
|
106 | - */ |
|
107 | - public function getName() { |
|
108 | - return $this->info->getName(); |
|
109 | - } |
|
110 | - |
|
111 | - /** |
|
112 | - * Returns the full path |
|
113 | - * |
|
114 | - * @return string |
|
115 | - */ |
|
116 | - public function getPath() { |
|
117 | - return $this->path; |
|
118 | - } |
|
119 | - |
|
120 | - /** |
|
121 | - * Renames the node |
|
122 | - * |
|
123 | - * @param string $name The new name |
|
124 | - * @throws \Sabre\DAV\Exception\BadRequest |
|
125 | - * @throws \Sabre\DAV\Exception\Forbidden |
|
126 | - */ |
|
127 | - public function setName($name) { |
|
128 | - |
|
129 | - // rename is only allowed if the update privilege is granted |
|
130 | - if (!$this->info->isUpdateable()) { |
|
131 | - throw new \Sabre\DAV\Exception\Forbidden(); |
|
132 | - } |
|
133 | - |
|
134 | - list($parentPath,) = \Sabre\Uri\split($this->path); |
|
135 | - list(, $newName) = \Sabre\Uri\split($name); |
|
136 | - |
|
137 | - // verify path of the target |
|
138 | - $this->verifyPath(); |
|
139 | - |
|
140 | - $newPath = $parentPath . '/' . $newName; |
|
141 | - |
|
142 | - if (!$this->fileView->rename($this->path, $newPath)) { |
|
143 | - throw new \Sabre\DAV\Exception('Failed to rename '. $this->path . ' to ' . $newPath); |
|
144 | - } |
|
145 | - |
|
146 | - $this->path = $newPath; |
|
147 | - |
|
148 | - $this->refreshInfo(); |
|
149 | - } |
|
150 | - |
|
151 | - public function setPropertyCache($property_cache) { |
|
152 | - $this->property_cache = $property_cache; |
|
153 | - } |
|
154 | - |
|
155 | - /** |
|
156 | - * Returns the last modification time, as a unix timestamp |
|
157 | - * |
|
158 | - * @return int timestamp as integer |
|
159 | - */ |
|
160 | - public function getLastModified() { |
|
161 | - $timestamp = $this->info->getMtime(); |
|
162 | - if (!empty($timestamp)) { |
|
163 | - return (int)$timestamp; |
|
164 | - } |
|
165 | - return $timestamp; |
|
166 | - } |
|
167 | - |
|
168 | - /** |
|
169 | - * sets the last modification time of the file (mtime) to the value given |
|
170 | - * in the second parameter or to now if the second param is empty. |
|
171 | - * Even if the modification time is set to a custom value the access time is set to now. |
|
172 | - */ |
|
173 | - public function touch($mtime) { |
|
174 | - $mtime = $this->sanitizeMtime($mtime); |
|
175 | - $this->fileView->touch($this->path, $mtime); |
|
176 | - $this->refreshInfo(); |
|
177 | - } |
|
178 | - |
|
179 | - /** |
|
180 | - * Returns the ETag for a file |
|
181 | - * |
|
182 | - * An ETag is a unique identifier representing the current version of the |
|
183 | - * file. If the file changes, the ETag MUST change. The ETag is an |
|
184 | - * arbitrary string, but MUST be surrounded by double-quotes. |
|
185 | - * |
|
186 | - * Return null if the ETag can not effectively be determined |
|
187 | - * |
|
188 | - * @return string |
|
189 | - */ |
|
190 | - public function getETag() { |
|
191 | - return '"' . $this->info->getEtag() . '"'; |
|
192 | - } |
|
193 | - |
|
194 | - /** |
|
195 | - * Sets the ETag |
|
196 | - * |
|
197 | - * @param string $etag |
|
198 | - * |
|
199 | - * @return int file id of updated file or -1 on failure |
|
200 | - */ |
|
201 | - public function setETag($etag) { |
|
202 | - return $this->fileView->putFileInfo($this->path, ['etag' => $etag]); |
|
203 | - } |
|
204 | - |
|
205 | - public function setCreationTime(int $time) { |
|
206 | - return $this->fileView->putFileInfo($this->path, ['creation_time' => $time]); |
|
207 | - } |
|
208 | - |
|
209 | - public function setUploadTime(int $time) { |
|
210 | - return $this->fileView->putFileInfo($this->path, ['upload_time' => $time]); |
|
211 | - } |
|
212 | - |
|
213 | - /** |
|
214 | - * Returns the size of the node, in bytes |
|
215 | - * |
|
216 | - * @return integer |
|
217 | - */ |
|
218 | - public function getSize() { |
|
219 | - return $this->info->getSize(); |
|
220 | - } |
|
221 | - |
|
222 | - /** |
|
223 | - * Returns the cache's file id |
|
224 | - * |
|
225 | - * @return int |
|
226 | - */ |
|
227 | - public function getId() { |
|
228 | - return $this->info->getId(); |
|
229 | - } |
|
230 | - |
|
231 | - /** |
|
232 | - * @return string|null |
|
233 | - */ |
|
234 | - public function getFileId() { |
|
235 | - if ($this->info->getId()) { |
|
236 | - $instanceId = \OC_Util::getInstanceId(); |
|
237 | - $id = sprintf('%08d', $this->info->getId()); |
|
238 | - return $id . $instanceId; |
|
239 | - } |
|
240 | - |
|
241 | - return null; |
|
242 | - } |
|
243 | - |
|
244 | - /** |
|
245 | - * @return integer |
|
246 | - */ |
|
247 | - public function getInternalFileId() { |
|
248 | - return $this->info->getId(); |
|
249 | - } |
|
250 | - |
|
251 | - /** |
|
252 | - * @param string $user |
|
253 | - * @return int |
|
254 | - */ |
|
255 | - public function getSharePermissions($user) { |
|
256 | - |
|
257 | - // check of we access a federated share |
|
258 | - if ($user !== null) { |
|
259 | - try { |
|
260 | - $share = $this->shareManager->getShareByToken($user); |
|
261 | - return $share->getPermissions(); |
|
262 | - } catch (ShareNotFound $e) { |
|
263 | - // ignore |
|
264 | - } |
|
265 | - } |
|
266 | - |
|
267 | - try { |
|
268 | - $storage = $this->info->getStorage(); |
|
269 | - } catch (StorageNotAvailableException $e) { |
|
270 | - $storage = null; |
|
271 | - } |
|
272 | - |
|
273 | - if ($storage && $storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { |
|
274 | - /** @var \OCA\Files_Sharing\SharedStorage $storage */ |
|
275 | - $permissions = (int)$storage->getShare()->getPermissions(); |
|
276 | - } else { |
|
277 | - $permissions = $this->info->getPermissions(); |
|
278 | - } |
|
279 | - |
|
280 | - /* |
|
51 | + /** |
|
52 | + * @var \OC\Files\View |
|
53 | + */ |
|
54 | + protected $fileView; |
|
55 | + |
|
56 | + /** |
|
57 | + * The path to the current node |
|
58 | + * |
|
59 | + * @var string |
|
60 | + */ |
|
61 | + protected $path; |
|
62 | + |
|
63 | + /** |
|
64 | + * node properties cache |
|
65 | + * |
|
66 | + * @var array |
|
67 | + */ |
|
68 | + protected $property_cache = null; |
|
69 | + |
|
70 | + /** |
|
71 | + * @var \OCP\Files\FileInfo |
|
72 | + */ |
|
73 | + protected $info; |
|
74 | + |
|
75 | + /** |
|
76 | + * @var IManager |
|
77 | + */ |
|
78 | + protected $shareManager; |
|
79 | + |
|
80 | + /** |
|
81 | + * Sets up the node, expects a full path name |
|
82 | + * |
|
83 | + * @param \OC\Files\View $view |
|
84 | + * @param \OCP\Files\FileInfo $info |
|
85 | + * @param IManager $shareManager |
|
86 | + */ |
|
87 | + public function __construct(View $view, FileInfo $info, IManager $shareManager = null) { |
|
88 | + $this->fileView = $view; |
|
89 | + $this->path = $this->fileView->getRelativePath($info->getPath()); |
|
90 | + $this->info = $info; |
|
91 | + if ($shareManager) { |
|
92 | + $this->shareManager = $shareManager; |
|
93 | + } else { |
|
94 | + $this->shareManager = \OC::$server->getShareManager(); |
|
95 | + } |
|
96 | + } |
|
97 | + |
|
98 | + protected function refreshInfo() { |
|
99 | + $this->info = $this->fileView->getFileInfo($this->path); |
|
100 | + } |
|
101 | + |
|
102 | + /** |
|
103 | + * Returns the name of the node |
|
104 | + * |
|
105 | + * @return string |
|
106 | + */ |
|
107 | + public function getName() { |
|
108 | + return $this->info->getName(); |
|
109 | + } |
|
110 | + |
|
111 | + /** |
|
112 | + * Returns the full path |
|
113 | + * |
|
114 | + * @return string |
|
115 | + */ |
|
116 | + public function getPath() { |
|
117 | + return $this->path; |
|
118 | + } |
|
119 | + |
|
120 | + /** |
|
121 | + * Renames the node |
|
122 | + * |
|
123 | + * @param string $name The new name |
|
124 | + * @throws \Sabre\DAV\Exception\BadRequest |
|
125 | + * @throws \Sabre\DAV\Exception\Forbidden |
|
126 | + */ |
|
127 | + public function setName($name) { |
|
128 | + |
|
129 | + // rename is only allowed if the update privilege is granted |
|
130 | + if (!$this->info->isUpdateable()) { |
|
131 | + throw new \Sabre\DAV\Exception\Forbidden(); |
|
132 | + } |
|
133 | + |
|
134 | + list($parentPath,) = \Sabre\Uri\split($this->path); |
|
135 | + list(, $newName) = \Sabre\Uri\split($name); |
|
136 | + |
|
137 | + // verify path of the target |
|
138 | + $this->verifyPath(); |
|
139 | + |
|
140 | + $newPath = $parentPath . '/' . $newName; |
|
141 | + |
|
142 | + if (!$this->fileView->rename($this->path, $newPath)) { |
|
143 | + throw new \Sabre\DAV\Exception('Failed to rename '. $this->path . ' to ' . $newPath); |
|
144 | + } |
|
145 | + |
|
146 | + $this->path = $newPath; |
|
147 | + |
|
148 | + $this->refreshInfo(); |
|
149 | + } |
|
150 | + |
|
151 | + public function setPropertyCache($property_cache) { |
|
152 | + $this->property_cache = $property_cache; |
|
153 | + } |
|
154 | + |
|
155 | + /** |
|
156 | + * Returns the last modification time, as a unix timestamp |
|
157 | + * |
|
158 | + * @return int timestamp as integer |
|
159 | + */ |
|
160 | + public function getLastModified() { |
|
161 | + $timestamp = $this->info->getMtime(); |
|
162 | + if (!empty($timestamp)) { |
|
163 | + return (int)$timestamp; |
|
164 | + } |
|
165 | + return $timestamp; |
|
166 | + } |
|
167 | + |
|
168 | + /** |
|
169 | + * sets the last modification time of the file (mtime) to the value given |
|
170 | + * in the second parameter or to now if the second param is empty. |
|
171 | + * Even if the modification time is set to a custom value the access time is set to now. |
|
172 | + */ |
|
173 | + public function touch($mtime) { |
|
174 | + $mtime = $this->sanitizeMtime($mtime); |
|
175 | + $this->fileView->touch($this->path, $mtime); |
|
176 | + $this->refreshInfo(); |
|
177 | + } |
|
178 | + |
|
179 | + /** |
|
180 | + * Returns the ETag for a file |
|
181 | + * |
|
182 | + * An ETag is a unique identifier representing the current version of the |
|
183 | + * file. If the file changes, the ETag MUST change. The ETag is an |
|
184 | + * arbitrary string, but MUST be surrounded by double-quotes. |
|
185 | + * |
|
186 | + * Return null if the ETag can not effectively be determined |
|
187 | + * |
|
188 | + * @return string |
|
189 | + */ |
|
190 | + public function getETag() { |
|
191 | + return '"' . $this->info->getEtag() . '"'; |
|
192 | + } |
|
193 | + |
|
194 | + /** |
|
195 | + * Sets the ETag |
|
196 | + * |
|
197 | + * @param string $etag |
|
198 | + * |
|
199 | + * @return int file id of updated file or -1 on failure |
|
200 | + */ |
|
201 | + public function setETag($etag) { |
|
202 | + return $this->fileView->putFileInfo($this->path, ['etag' => $etag]); |
|
203 | + } |
|
204 | + |
|
205 | + public function setCreationTime(int $time) { |
|
206 | + return $this->fileView->putFileInfo($this->path, ['creation_time' => $time]); |
|
207 | + } |
|
208 | + |
|
209 | + public function setUploadTime(int $time) { |
|
210 | + return $this->fileView->putFileInfo($this->path, ['upload_time' => $time]); |
|
211 | + } |
|
212 | + |
|
213 | + /** |
|
214 | + * Returns the size of the node, in bytes |
|
215 | + * |
|
216 | + * @return integer |
|
217 | + */ |
|
218 | + public function getSize() { |
|
219 | + return $this->info->getSize(); |
|
220 | + } |
|
221 | + |
|
222 | + /** |
|
223 | + * Returns the cache's file id |
|
224 | + * |
|
225 | + * @return int |
|
226 | + */ |
|
227 | + public function getId() { |
|
228 | + return $this->info->getId(); |
|
229 | + } |
|
230 | + |
|
231 | + /** |
|
232 | + * @return string|null |
|
233 | + */ |
|
234 | + public function getFileId() { |
|
235 | + if ($this->info->getId()) { |
|
236 | + $instanceId = \OC_Util::getInstanceId(); |
|
237 | + $id = sprintf('%08d', $this->info->getId()); |
|
238 | + return $id . $instanceId; |
|
239 | + } |
|
240 | + |
|
241 | + return null; |
|
242 | + } |
|
243 | + |
|
244 | + /** |
|
245 | + * @return integer |
|
246 | + */ |
|
247 | + public function getInternalFileId() { |
|
248 | + return $this->info->getId(); |
|
249 | + } |
|
250 | + |
|
251 | + /** |
|
252 | + * @param string $user |
|
253 | + * @return int |
|
254 | + */ |
|
255 | + public function getSharePermissions($user) { |
|
256 | + |
|
257 | + // check of we access a federated share |
|
258 | + if ($user !== null) { |
|
259 | + try { |
|
260 | + $share = $this->shareManager->getShareByToken($user); |
|
261 | + return $share->getPermissions(); |
|
262 | + } catch (ShareNotFound $e) { |
|
263 | + // ignore |
|
264 | + } |
|
265 | + } |
|
266 | + |
|
267 | + try { |
|
268 | + $storage = $this->info->getStorage(); |
|
269 | + } catch (StorageNotAvailableException $e) { |
|
270 | + $storage = null; |
|
271 | + } |
|
272 | + |
|
273 | + if ($storage && $storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { |
|
274 | + /** @var \OCA\Files_Sharing\SharedStorage $storage */ |
|
275 | + $permissions = (int)$storage->getShare()->getPermissions(); |
|
276 | + } else { |
|
277 | + $permissions = $this->info->getPermissions(); |
|
278 | + } |
|
279 | + |
|
280 | + /* |
|
281 | 281 | * We can always share non moveable mount points with DELETE and UPDATE |
282 | 282 | * Eventually we need to do this properly |
283 | 283 | */ |
284 | - $mountpoint = $this->info->getMountPoint(); |
|
285 | - if (!($mountpoint instanceof MoveableMount)) { |
|
286 | - $mountpointpath = $mountpoint->getMountPoint(); |
|
287 | - if (substr($mountpointpath, -1) === '/') { |
|
288 | - $mountpointpath = substr($mountpointpath, 0, -1); |
|
289 | - } |
|
290 | - |
|
291 | - if (!$mountpoint->getOption('readonly', false) && $mountpointpath === $this->info->getPath()) { |
|
292 | - $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE; |
|
293 | - } |
|
294 | - } |
|
295 | - |
|
296 | - /* |
|
284 | + $mountpoint = $this->info->getMountPoint(); |
|
285 | + if (!($mountpoint instanceof MoveableMount)) { |
|
286 | + $mountpointpath = $mountpoint->getMountPoint(); |
|
287 | + if (substr($mountpointpath, -1) === '/') { |
|
288 | + $mountpointpath = substr($mountpointpath, 0, -1); |
|
289 | + } |
|
290 | + |
|
291 | + if (!$mountpoint->getOption('readonly', false) && $mountpointpath === $this->info->getPath()) { |
|
292 | + $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE; |
|
293 | + } |
|
294 | + } |
|
295 | + |
|
296 | + /* |
|
297 | 297 | * Files can't have create or delete permissions |
298 | 298 | */ |
299 | - if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) { |
|
300 | - $permissions &= ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE); |
|
301 | - } |
|
302 | - |
|
303 | - return $permissions; |
|
304 | - } |
|
305 | - |
|
306 | - /** |
|
307 | - * @param string $user |
|
308 | - * @return string |
|
309 | - */ |
|
310 | - public function getNoteFromShare($user) { |
|
311 | - if ($user === null) { |
|
312 | - return ''; |
|
313 | - } |
|
314 | - |
|
315 | - $types = [ |
|
316 | - IShare::TYPE_USER, |
|
317 | - IShare::TYPE_GROUP, |
|
318 | - IShare::TYPE_CIRCLE, |
|
319 | - IShare::TYPE_ROOM |
|
320 | - ]; |
|
321 | - |
|
322 | - foreach ($types as $shareType) { |
|
323 | - $shares = $this->shareManager->getSharedWith($user, $shareType, $this, -1); |
|
324 | - foreach ($shares as $share) { |
|
325 | - $note = $share->getNote(); |
|
326 | - if ($share->getShareOwner() !== $user && !empty($note)) { |
|
327 | - return $note; |
|
328 | - } |
|
329 | - } |
|
330 | - } |
|
331 | - |
|
332 | - return ''; |
|
333 | - } |
|
334 | - |
|
335 | - /** |
|
336 | - * @return string |
|
337 | - */ |
|
338 | - public function getDavPermissions() { |
|
339 | - $p = ''; |
|
340 | - if ($this->info->isShared()) { |
|
341 | - $p .= 'S'; |
|
342 | - } |
|
343 | - if ($this->info->isShareable()) { |
|
344 | - $p .= 'R'; |
|
345 | - } |
|
346 | - if ($this->info->isMounted()) { |
|
347 | - $p .= 'M'; |
|
348 | - } |
|
349 | - if ($this->info->isReadable()) { |
|
350 | - $p .= 'G'; |
|
351 | - } |
|
352 | - if ($this->info->isDeletable()) { |
|
353 | - $p .= 'D'; |
|
354 | - } |
|
355 | - if ($this->info->isUpdateable()) { |
|
356 | - $p .= 'NV'; // Renameable, Moveable |
|
357 | - } |
|
358 | - if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) { |
|
359 | - if ($this->info->isUpdateable()) { |
|
360 | - $p .= 'W'; |
|
361 | - } |
|
362 | - } else { |
|
363 | - if ($this->info->isCreatable()) { |
|
364 | - $p .= 'CK'; |
|
365 | - } |
|
366 | - } |
|
367 | - return $p; |
|
368 | - } |
|
369 | - |
|
370 | - public function getOwner() { |
|
371 | - return $this->info->getOwner(); |
|
372 | - } |
|
373 | - |
|
374 | - protected function verifyPath() { |
|
375 | - try { |
|
376 | - $fileName = basename($this->info->getPath()); |
|
377 | - $this->fileView->verifyPath($this->path, $fileName); |
|
378 | - } catch (\OCP\Files\InvalidPathException $ex) { |
|
379 | - throw new InvalidPath($ex->getMessage()); |
|
380 | - } |
|
381 | - } |
|
382 | - |
|
383 | - /** |
|
384 | - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
385 | - */ |
|
386 | - public function acquireLock($type) { |
|
387 | - $this->fileView->lockFile($this->path, $type); |
|
388 | - } |
|
389 | - |
|
390 | - /** |
|
391 | - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
392 | - */ |
|
393 | - public function releaseLock($type) { |
|
394 | - $this->fileView->unlockFile($this->path, $type); |
|
395 | - } |
|
396 | - |
|
397 | - /** |
|
398 | - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
399 | - */ |
|
400 | - public function changeLock($type) { |
|
401 | - $this->fileView->changeLock($this->path, $type); |
|
402 | - } |
|
403 | - |
|
404 | - public function getFileInfo() { |
|
405 | - return $this->info; |
|
406 | - } |
|
407 | - |
|
408 | - protected function sanitizeMtime($mtimeFromRequest) { |
|
409 | - // In PHP 5.X "is_numeric" returns true for strings in hexadecimal |
|
410 | - // notation. This is no longer the case in PHP 7.X, so this check |
|
411 | - // ensures that strings with hexadecimal notations fail too in PHP 5.X. |
|
412 | - $isHexadecimal = is_string($mtimeFromRequest) && preg_match('/^\s*0[xX]/', $mtimeFromRequest); |
|
413 | - if ($isHexadecimal || !is_numeric($mtimeFromRequest)) { |
|
414 | - throw new \InvalidArgumentException('X-OC-MTime header must be an integer (unix timestamp).'); |
|
415 | - } |
|
416 | - |
|
417 | - return (int)$mtimeFromRequest; |
|
418 | - } |
|
299 | + if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) { |
|
300 | + $permissions &= ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE); |
|
301 | + } |
|
302 | + |
|
303 | + return $permissions; |
|
304 | + } |
|
305 | + |
|
306 | + /** |
|
307 | + * @param string $user |
|
308 | + * @return string |
|
309 | + */ |
|
310 | + public function getNoteFromShare($user) { |
|
311 | + if ($user === null) { |
|
312 | + return ''; |
|
313 | + } |
|
314 | + |
|
315 | + $types = [ |
|
316 | + IShare::TYPE_USER, |
|
317 | + IShare::TYPE_GROUP, |
|
318 | + IShare::TYPE_CIRCLE, |
|
319 | + IShare::TYPE_ROOM |
|
320 | + ]; |
|
321 | + |
|
322 | + foreach ($types as $shareType) { |
|
323 | + $shares = $this->shareManager->getSharedWith($user, $shareType, $this, -1); |
|
324 | + foreach ($shares as $share) { |
|
325 | + $note = $share->getNote(); |
|
326 | + if ($share->getShareOwner() !== $user && !empty($note)) { |
|
327 | + return $note; |
|
328 | + } |
|
329 | + } |
|
330 | + } |
|
331 | + |
|
332 | + return ''; |
|
333 | + } |
|
334 | + |
|
335 | + /** |
|
336 | + * @return string |
|
337 | + */ |
|
338 | + public function getDavPermissions() { |
|
339 | + $p = ''; |
|
340 | + if ($this->info->isShared()) { |
|
341 | + $p .= 'S'; |
|
342 | + } |
|
343 | + if ($this->info->isShareable()) { |
|
344 | + $p .= 'R'; |
|
345 | + } |
|
346 | + if ($this->info->isMounted()) { |
|
347 | + $p .= 'M'; |
|
348 | + } |
|
349 | + if ($this->info->isReadable()) { |
|
350 | + $p .= 'G'; |
|
351 | + } |
|
352 | + if ($this->info->isDeletable()) { |
|
353 | + $p .= 'D'; |
|
354 | + } |
|
355 | + if ($this->info->isUpdateable()) { |
|
356 | + $p .= 'NV'; // Renameable, Moveable |
|
357 | + } |
|
358 | + if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) { |
|
359 | + if ($this->info->isUpdateable()) { |
|
360 | + $p .= 'W'; |
|
361 | + } |
|
362 | + } else { |
|
363 | + if ($this->info->isCreatable()) { |
|
364 | + $p .= 'CK'; |
|
365 | + } |
|
366 | + } |
|
367 | + return $p; |
|
368 | + } |
|
369 | + |
|
370 | + public function getOwner() { |
|
371 | + return $this->info->getOwner(); |
|
372 | + } |
|
373 | + |
|
374 | + protected function verifyPath() { |
|
375 | + try { |
|
376 | + $fileName = basename($this->info->getPath()); |
|
377 | + $this->fileView->verifyPath($this->path, $fileName); |
|
378 | + } catch (\OCP\Files\InvalidPathException $ex) { |
|
379 | + throw new InvalidPath($ex->getMessage()); |
|
380 | + } |
|
381 | + } |
|
382 | + |
|
383 | + /** |
|
384 | + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
385 | + */ |
|
386 | + public function acquireLock($type) { |
|
387 | + $this->fileView->lockFile($this->path, $type); |
|
388 | + } |
|
389 | + |
|
390 | + /** |
|
391 | + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
392 | + */ |
|
393 | + public function releaseLock($type) { |
|
394 | + $this->fileView->unlockFile($this->path, $type); |
|
395 | + } |
|
396 | + |
|
397 | + /** |
|
398 | + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
399 | + */ |
|
400 | + public function changeLock($type) { |
|
401 | + $this->fileView->changeLock($this->path, $type); |
|
402 | + } |
|
403 | + |
|
404 | + public function getFileInfo() { |
|
405 | + return $this->info; |
|
406 | + } |
|
407 | + |
|
408 | + protected function sanitizeMtime($mtimeFromRequest) { |
|
409 | + // In PHP 5.X "is_numeric" returns true for strings in hexadecimal |
|
410 | + // notation. This is no longer the case in PHP 7.X, so this check |
|
411 | + // ensures that strings with hexadecimal notations fail too in PHP 5.X. |
|
412 | + $isHexadecimal = is_string($mtimeFromRequest) && preg_match('/^\s*0[xX]/', $mtimeFromRequest); |
|
413 | + if ($isHexadecimal || !is_numeric($mtimeFromRequest)) { |
|
414 | + throw new \InvalidArgumentException('X-OC-MTime header must be an integer (unix timestamp).'); |
|
415 | + } |
|
416 | + |
|
417 | + return (int)$mtimeFromRequest; |
|
418 | + } |
|
419 | 419 | } |
@@ -35,181 +35,181 @@ |
||
35 | 35 | * Sabre Plugin to provide share-related properties |
36 | 36 | */ |
37 | 37 | class SharesPlugin extends \Sabre\DAV\ServerPlugin { |
38 | - public const NS_OWNCLOUD = 'http://owncloud.org/ns'; |
|
39 | - public const NS_NEXTCLOUD = 'http://nextcloud.org/ns'; |
|
40 | - public const SHARETYPES_PROPERTYNAME = '{http://owncloud.org/ns}share-types'; |
|
41 | - public const SHAREES_PROPERTYNAME = '{http://nextcloud.org/ns}sharees'; |
|
42 | - |
|
43 | - /** |
|
44 | - * Reference to main server object |
|
45 | - * |
|
46 | - * @var \Sabre\DAV\Server |
|
47 | - */ |
|
48 | - private $server; |
|
49 | - |
|
50 | - /** |
|
51 | - * @var \OCP\Share\IManager |
|
52 | - */ |
|
53 | - private $shareManager; |
|
54 | - |
|
55 | - /** |
|
56 | - * @var \Sabre\DAV\Tree |
|
57 | - */ |
|
58 | - private $tree; |
|
59 | - |
|
60 | - /** |
|
61 | - * @var string |
|
62 | - */ |
|
63 | - private $userId; |
|
64 | - |
|
65 | - /** |
|
66 | - * @var \OCP\Files\Folder |
|
67 | - */ |
|
68 | - private $userFolder; |
|
69 | - |
|
70 | - /** @var IShare[] */ |
|
71 | - private $cachedShares = []; |
|
72 | - |
|
73 | - private $cachedFolders = []; |
|
74 | - |
|
75 | - /** |
|
76 | - * @param \Sabre\DAV\Tree $tree tree |
|
77 | - * @param IUserSession $userSession user session |
|
78 | - * @param \OCP\Files\Folder $userFolder user home folder |
|
79 | - * @param \OCP\Share\IManager $shareManager share manager |
|
80 | - */ |
|
81 | - public function __construct( |
|
82 | - \Sabre\DAV\Tree $tree, |
|
83 | - IUserSession $userSession, |
|
84 | - \OCP\Files\Folder $userFolder, |
|
85 | - \OCP\Share\IManager $shareManager |
|
86 | - ) { |
|
87 | - $this->tree = $tree; |
|
88 | - $this->shareManager = $shareManager; |
|
89 | - $this->userFolder = $userFolder; |
|
90 | - $this->userId = $userSession->getUser()->getUID(); |
|
91 | - } |
|
92 | - |
|
93 | - /** |
|
94 | - * This initializes the plugin. |
|
95 | - * |
|
96 | - * This function is called by \Sabre\DAV\Server, after |
|
97 | - * addPlugin is called. |
|
98 | - * |
|
99 | - * This method should set up the required event subscriptions. |
|
100 | - * |
|
101 | - * @param \Sabre\DAV\Server $server |
|
102 | - */ |
|
103 | - public function initialize(\Sabre\DAV\Server $server) { |
|
104 | - $server->xml->namespacesMap[self::NS_OWNCLOUD] = 'oc'; |
|
105 | - $server->xml->elementMap[self::SHARETYPES_PROPERTYNAME] = ShareTypeList::class; |
|
106 | - $server->protectedProperties[] = self::SHARETYPES_PROPERTYNAME; |
|
107 | - $server->protectedProperties[] = self::SHAREES_PROPERTYNAME; |
|
108 | - |
|
109 | - $this->server = $server; |
|
110 | - $this->server->on('propFind', [$this, 'handleGetProperties']); |
|
111 | - } |
|
112 | - |
|
113 | - private function getShare(\OCP\Files\Node $node): array { |
|
114 | - $result = []; |
|
115 | - $requestedShareTypes = [ |
|
116 | - IShare::TYPE_USER, |
|
117 | - IShare::TYPE_GROUP, |
|
118 | - IShare::TYPE_LINK, |
|
119 | - IShare::TYPE_REMOTE, |
|
120 | - IShare::TYPE_EMAIL, |
|
121 | - IShare::TYPE_ROOM, |
|
122 | - IShare::TYPE_CIRCLE, |
|
123 | - ]; |
|
124 | - foreach ($requestedShareTypes as $requestedShareType) { |
|
125 | - $shares = $this->shareManager->getSharesBy( |
|
126 | - $this->userId, |
|
127 | - $requestedShareType, |
|
128 | - $node, |
|
129 | - false, |
|
130 | - -1 |
|
131 | - ); |
|
132 | - foreach ($shares as $share) { |
|
133 | - $result[] = $share; |
|
134 | - } |
|
135 | - } |
|
136 | - return $result; |
|
137 | - } |
|
138 | - |
|
139 | - private function getSharesFolder(\OCP\Files\Folder $node): array { |
|
140 | - return $this->shareManager->getSharesInFolder( |
|
141 | - $this->userId, |
|
142 | - $node, |
|
143 | - true |
|
144 | - ); |
|
145 | - } |
|
146 | - |
|
147 | - private function getShares(\Sabre\DAV\INode $sabreNode): array { |
|
148 | - if (isset($this->cachedShares[$sabreNode->getId()])) { |
|
149 | - $shares = $this->cachedShares[$sabreNode->getId()]; |
|
150 | - } else { |
|
151 | - list($parentPath,) = \Sabre\Uri\split($sabreNode->getPath()); |
|
152 | - if ($parentPath === '') { |
|
153 | - $parentPath = '/'; |
|
154 | - } |
|
155 | - // if we already cached the folder this file is in we know there are no shares for this file |
|
156 | - if (array_search($parentPath, $this->cachedFolders) === false) { |
|
157 | - $node = $this->userFolder->get($sabreNode->getPath()); |
|
158 | - $shares = $this->getShare($node); |
|
159 | - $this->cachedShares[$sabreNode->getId()] = $shares; |
|
160 | - } else { |
|
161 | - return []; |
|
162 | - } |
|
163 | - } |
|
164 | - |
|
165 | - return $shares; |
|
166 | - } |
|
167 | - |
|
168 | - /** |
|
169 | - * Adds shares to propfind response |
|
170 | - * |
|
171 | - * @param PropFind $propFind propfind object |
|
172 | - * @param \Sabre\DAV\INode $sabreNode sabre node |
|
173 | - */ |
|
174 | - public function handleGetProperties( |
|
175 | - PropFind $propFind, |
|
176 | - \Sabre\DAV\INode $sabreNode |
|
177 | - ) { |
|
178 | - if (!($sabreNode instanceof \OCA\DAV\Connector\Sabre\Node)) { |
|
179 | - return; |
|
180 | - } |
|
181 | - |
|
182 | - // need prefetch ? |
|
183 | - if ($sabreNode instanceof \OCA\DAV\Connector\Sabre\Directory |
|
184 | - && $propFind->getDepth() !== 0 |
|
185 | - && ( |
|
186 | - !is_null($propFind->getStatus(self::SHARETYPES_PROPERTYNAME)) || |
|
187 | - !is_null($propFind->getStatus(self::SHAREES_PROPERTYNAME)) |
|
188 | - ) |
|
189 | - ) { |
|
190 | - $folderNode = $this->userFolder->get($sabreNode->getPath()); |
|
191 | - |
|
192 | - $this->cachedFolders[] = $sabreNode->getPath(); |
|
193 | - $childShares = $this->getSharesFolder($folderNode); |
|
194 | - foreach ($childShares as $id => $shares) { |
|
195 | - $this->cachedShares[$id] = $shares; |
|
196 | - } |
|
197 | - } |
|
198 | - |
|
199 | - $propFind->handle(self::SHARETYPES_PROPERTYNAME, function () use ($sabreNode) { |
|
200 | - $shares = $this->getShares($sabreNode); |
|
201 | - |
|
202 | - $shareTypes = array_unique(array_map(function (IShare $share) { |
|
203 | - return $share->getShareType(); |
|
204 | - }, $shares)); |
|
205 | - |
|
206 | - return new ShareTypeList($shareTypes); |
|
207 | - }); |
|
208 | - |
|
209 | - $propFind->handle(self::SHAREES_PROPERTYNAME, function () use ($sabreNode) { |
|
210 | - $shares = $this->getShares($sabreNode); |
|
211 | - |
|
212 | - return new ShareeList($shares); |
|
213 | - }); |
|
214 | - } |
|
38 | + public const NS_OWNCLOUD = 'http://owncloud.org/ns'; |
|
39 | + public const NS_NEXTCLOUD = 'http://nextcloud.org/ns'; |
|
40 | + public const SHARETYPES_PROPERTYNAME = '{http://owncloud.org/ns}share-types'; |
|
41 | + public const SHAREES_PROPERTYNAME = '{http://nextcloud.org/ns}sharees'; |
|
42 | + |
|
43 | + /** |
|
44 | + * Reference to main server object |
|
45 | + * |
|
46 | + * @var \Sabre\DAV\Server |
|
47 | + */ |
|
48 | + private $server; |
|
49 | + |
|
50 | + /** |
|
51 | + * @var \OCP\Share\IManager |
|
52 | + */ |
|
53 | + private $shareManager; |
|
54 | + |
|
55 | + /** |
|
56 | + * @var \Sabre\DAV\Tree |
|
57 | + */ |
|
58 | + private $tree; |
|
59 | + |
|
60 | + /** |
|
61 | + * @var string |
|
62 | + */ |
|
63 | + private $userId; |
|
64 | + |
|
65 | + /** |
|
66 | + * @var \OCP\Files\Folder |
|
67 | + */ |
|
68 | + private $userFolder; |
|
69 | + |
|
70 | + /** @var IShare[] */ |
|
71 | + private $cachedShares = []; |
|
72 | + |
|
73 | + private $cachedFolders = []; |
|
74 | + |
|
75 | + /** |
|
76 | + * @param \Sabre\DAV\Tree $tree tree |
|
77 | + * @param IUserSession $userSession user session |
|
78 | + * @param \OCP\Files\Folder $userFolder user home folder |
|
79 | + * @param \OCP\Share\IManager $shareManager share manager |
|
80 | + */ |
|
81 | + public function __construct( |
|
82 | + \Sabre\DAV\Tree $tree, |
|
83 | + IUserSession $userSession, |
|
84 | + \OCP\Files\Folder $userFolder, |
|
85 | + \OCP\Share\IManager $shareManager |
|
86 | + ) { |
|
87 | + $this->tree = $tree; |
|
88 | + $this->shareManager = $shareManager; |
|
89 | + $this->userFolder = $userFolder; |
|
90 | + $this->userId = $userSession->getUser()->getUID(); |
|
91 | + } |
|
92 | + |
|
93 | + /** |
|
94 | + * This initializes the plugin. |
|
95 | + * |
|
96 | + * This function is called by \Sabre\DAV\Server, after |
|
97 | + * addPlugin is called. |
|
98 | + * |
|
99 | + * This method should set up the required event subscriptions. |
|
100 | + * |
|
101 | + * @param \Sabre\DAV\Server $server |
|
102 | + */ |
|
103 | + public function initialize(\Sabre\DAV\Server $server) { |
|
104 | + $server->xml->namespacesMap[self::NS_OWNCLOUD] = 'oc'; |
|
105 | + $server->xml->elementMap[self::SHARETYPES_PROPERTYNAME] = ShareTypeList::class; |
|
106 | + $server->protectedProperties[] = self::SHARETYPES_PROPERTYNAME; |
|
107 | + $server->protectedProperties[] = self::SHAREES_PROPERTYNAME; |
|
108 | + |
|
109 | + $this->server = $server; |
|
110 | + $this->server->on('propFind', [$this, 'handleGetProperties']); |
|
111 | + } |
|
112 | + |
|
113 | + private function getShare(\OCP\Files\Node $node): array { |
|
114 | + $result = []; |
|
115 | + $requestedShareTypes = [ |
|
116 | + IShare::TYPE_USER, |
|
117 | + IShare::TYPE_GROUP, |
|
118 | + IShare::TYPE_LINK, |
|
119 | + IShare::TYPE_REMOTE, |
|
120 | + IShare::TYPE_EMAIL, |
|
121 | + IShare::TYPE_ROOM, |
|
122 | + IShare::TYPE_CIRCLE, |
|
123 | + ]; |
|
124 | + foreach ($requestedShareTypes as $requestedShareType) { |
|
125 | + $shares = $this->shareManager->getSharesBy( |
|
126 | + $this->userId, |
|
127 | + $requestedShareType, |
|
128 | + $node, |
|
129 | + false, |
|
130 | + -1 |
|
131 | + ); |
|
132 | + foreach ($shares as $share) { |
|
133 | + $result[] = $share; |
|
134 | + } |
|
135 | + } |
|
136 | + return $result; |
|
137 | + } |
|
138 | + |
|
139 | + private function getSharesFolder(\OCP\Files\Folder $node): array { |
|
140 | + return $this->shareManager->getSharesInFolder( |
|
141 | + $this->userId, |
|
142 | + $node, |
|
143 | + true |
|
144 | + ); |
|
145 | + } |
|
146 | + |
|
147 | + private function getShares(\Sabre\DAV\INode $sabreNode): array { |
|
148 | + if (isset($this->cachedShares[$sabreNode->getId()])) { |
|
149 | + $shares = $this->cachedShares[$sabreNode->getId()]; |
|
150 | + } else { |
|
151 | + list($parentPath,) = \Sabre\Uri\split($sabreNode->getPath()); |
|
152 | + if ($parentPath === '') { |
|
153 | + $parentPath = '/'; |
|
154 | + } |
|
155 | + // if we already cached the folder this file is in we know there are no shares for this file |
|
156 | + if (array_search($parentPath, $this->cachedFolders) === false) { |
|
157 | + $node = $this->userFolder->get($sabreNode->getPath()); |
|
158 | + $shares = $this->getShare($node); |
|
159 | + $this->cachedShares[$sabreNode->getId()] = $shares; |
|
160 | + } else { |
|
161 | + return []; |
|
162 | + } |
|
163 | + } |
|
164 | + |
|
165 | + return $shares; |
|
166 | + } |
|
167 | + |
|
168 | + /** |
|
169 | + * Adds shares to propfind response |
|
170 | + * |
|
171 | + * @param PropFind $propFind propfind object |
|
172 | + * @param \Sabre\DAV\INode $sabreNode sabre node |
|
173 | + */ |
|
174 | + public function handleGetProperties( |
|
175 | + PropFind $propFind, |
|
176 | + \Sabre\DAV\INode $sabreNode |
|
177 | + ) { |
|
178 | + if (!($sabreNode instanceof \OCA\DAV\Connector\Sabre\Node)) { |
|
179 | + return; |
|
180 | + } |
|
181 | + |
|
182 | + // need prefetch ? |
|
183 | + if ($sabreNode instanceof \OCA\DAV\Connector\Sabre\Directory |
|
184 | + && $propFind->getDepth() !== 0 |
|
185 | + && ( |
|
186 | + !is_null($propFind->getStatus(self::SHARETYPES_PROPERTYNAME)) || |
|
187 | + !is_null($propFind->getStatus(self::SHAREES_PROPERTYNAME)) |
|
188 | + ) |
|
189 | + ) { |
|
190 | + $folderNode = $this->userFolder->get($sabreNode->getPath()); |
|
191 | + |
|
192 | + $this->cachedFolders[] = $sabreNode->getPath(); |
|
193 | + $childShares = $this->getSharesFolder($folderNode); |
|
194 | + foreach ($childShares as $id => $shares) { |
|
195 | + $this->cachedShares[$id] = $shares; |
|
196 | + } |
|
197 | + } |
|
198 | + |
|
199 | + $propFind->handle(self::SHARETYPES_PROPERTYNAME, function () use ($sabreNode) { |
|
200 | + $shares = $this->getShares($sabreNode); |
|
201 | + |
|
202 | + $shareTypes = array_unique(array_map(function (IShare $share) { |
|
203 | + return $share->getShareType(); |
|
204 | + }, $shares)); |
|
205 | + |
|
206 | + return new ShareTypeList($shareTypes); |
|
207 | + }); |
|
208 | + |
|
209 | + $propFind->handle(self::SHAREES_PROPERTYNAME, function () use ($sabreNode) { |
|
210 | + $shares = $this->getShares($sabreNode); |
|
211 | + |
|
212 | + return new ShareeList($shares); |
|
213 | + }); |
|
214 | + } |
|
215 | 215 | } |
@@ -69,1141 +69,1141 @@ |
||
69 | 69 | */ |
70 | 70 | class ShareByMailProvider implements IShareProvider { |
71 | 71 | |
72 | - /** @var IDBConnection */ |
|
73 | - private $dbConnection; |
|
74 | - |
|
75 | - /** @var ILogger */ |
|
76 | - private $logger; |
|
77 | - |
|
78 | - /** @var ISecureRandom */ |
|
79 | - private $secureRandom; |
|
80 | - |
|
81 | - /** @var IUserManager */ |
|
82 | - private $userManager; |
|
83 | - |
|
84 | - /** @var IRootFolder */ |
|
85 | - private $rootFolder; |
|
86 | - |
|
87 | - /** @var IL10N */ |
|
88 | - private $l; |
|
89 | - |
|
90 | - /** @var IMailer */ |
|
91 | - private $mailer; |
|
92 | - |
|
93 | - /** @var IURLGenerator */ |
|
94 | - private $urlGenerator; |
|
95 | - |
|
96 | - /** @var IManager */ |
|
97 | - private $activityManager; |
|
98 | - |
|
99 | - /** @var SettingsManager */ |
|
100 | - private $settingsManager; |
|
101 | - |
|
102 | - /** @var Defaults */ |
|
103 | - private $defaults; |
|
104 | - |
|
105 | - /** @var IHasher */ |
|
106 | - private $hasher; |
|
107 | - |
|
108 | - /** @var CapabilitiesManager */ |
|
109 | - private $capabilitiesManager; |
|
110 | - |
|
111 | - /** |
|
112 | - * Return the identifier of this provider. |
|
113 | - * |
|
114 | - * @return string Containing only [a-zA-Z0-9] |
|
115 | - */ |
|
116 | - public function identifier() { |
|
117 | - return 'ocMailShare'; |
|
118 | - } |
|
119 | - |
|
120 | - /** |
|
121 | - * DefaultShareProvider constructor. |
|
122 | - * |
|
123 | - * @param IDBConnection $connection |
|
124 | - * @param ISecureRandom $secureRandom |
|
125 | - * @param IUserManager $userManager |
|
126 | - * @param IRootFolder $rootFolder |
|
127 | - * @param IL10N $l |
|
128 | - * @param ILogger $logger |
|
129 | - * @param IMailer $mailer |
|
130 | - * @param IURLGenerator $urlGenerator |
|
131 | - * @param IManager $activityManager |
|
132 | - * @param SettingsManager $settingsManager |
|
133 | - * @param Defaults $defaults |
|
134 | - * @param IHasher $hasher |
|
135 | - * @param CapabilitiesManager $capabilitiesManager |
|
136 | - */ |
|
137 | - public function __construct( |
|
138 | - IDBConnection $connection, |
|
139 | - ISecureRandom $secureRandom, |
|
140 | - IUserManager $userManager, |
|
141 | - IRootFolder $rootFolder, |
|
142 | - IL10N $l, |
|
143 | - ILogger $logger, |
|
144 | - IMailer $mailer, |
|
145 | - IURLGenerator $urlGenerator, |
|
146 | - IManager $activityManager, |
|
147 | - SettingsManager $settingsManager, |
|
148 | - Defaults $defaults, |
|
149 | - IHasher $hasher, |
|
150 | - CapabilitiesManager $capabilitiesManager |
|
151 | - ) { |
|
152 | - $this->dbConnection = $connection; |
|
153 | - $this->secureRandom = $secureRandom; |
|
154 | - $this->userManager = $userManager; |
|
155 | - $this->rootFolder = $rootFolder; |
|
156 | - $this->l = $l; |
|
157 | - $this->logger = $logger; |
|
158 | - $this->mailer = $mailer; |
|
159 | - $this->urlGenerator = $urlGenerator; |
|
160 | - $this->activityManager = $activityManager; |
|
161 | - $this->settingsManager = $settingsManager; |
|
162 | - $this->defaults = $defaults; |
|
163 | - $this->hasher = $hasher; |
|
164 | - $this->capabilitiesManager = $capabilitiesManager; |
|
165 | - } |
|
166 | - |
|
167 | - /** |
|
168 | - * Share a path |
|
169 | - * |
|
170 | - * @param IShare $share |
|
171 | - * @return IShare The share object |
|
172 | - * @throws ShareNotFound |
|
173 | - * @throws \Exception |
|
174 | - */ |
|
175 | - public function create(IShare $share) { |
|
176 | - $shareWith = $share->getSharedWith(); |
|
177 | - /* |
|
72 | + /** @var IDBConnection */ |
|
73 | + private $dbConnection; |
|
74 | + |
|
75 | + /** @var ILogger */ |
|
76 | + private $logger; |
|
77 | + |
|
78 | + /** @var ISecureRandom */ |
|
79 | + private $secureRandom; |
|
80 | + |
|
81 | + /** @var IUserManager */ |
|
82 | + private $userManager; |
|
83 | + |
|
84 | + /** @var IRootFolder */ |
|
85 | + private $rootFolder; |
|
86 | + |
|
87 | + /** @var IL10N */ |
|
88 | + private $l; |
|
89 | + |
|
90 | + /** @var IMailer */ |
|
91 | + private $mailer; |
|
92 | + |
|
93 | + /** @var IURLGenerator */ |
|
94 | + private $urlGenerator; |
|
95 | + |
|
96 | + /** @var IManager */ |
|
97 | + private $activityManager; |
|
98 | + |
|
99 | + /** @var SettingsManager */ |
|
100 | + private $settingsManager; |
|
101 | + |
|
102 | + /** @var Defaults */ |
|
103 | + private $defaults; |
|
104 | + |
|
105 | + /** @var IHasher */ |
|
106 | + private $hasher; |
|
107 | + |
|
108 | + /** @var CapabilitiesManager */ |
|
109 | + private $capabilitiesManager; |
|
110 | + |
|
111 | + /** |
|
112 | + * Return the identifier of this provider. |
|
113 | + * |
|
114 | + * @return string Containing only [a-zA-Z0-9] |
|
115 | + */ |
|
116 | + public function identifier() { |
|
117 | + return 'ocMailShare'; |
|
118 | + } |
|
119 | + |
|
120 | + /** |
|
121 | + * DefaultShareProvider constructor. |
|
122 | + * |
|
123 | + * @param IDBConnection $connection |
|
124 | + * @param ISecureRandom $secureRandom |
|
125 | + * @param IUserManager $userManager |
|
126 | + * @param IRootFolder $rootFolder |
|
127 | + * @param IL10N $l |
|
128 | + * @param ILogger $logger |
|
129 | + * @param IMailer $mailer |
|
130 | + * @param IURLGenerator $urlGenerator |
|
131 | + * @param IManager $activityManager |
|
132 | + * @param SettingsManager $settingsManager |
|
133 | + * @param Defaults $defaults |
|
134 | + * @param IHasher $hasher |
|
135 | + * @param CapabilitiesManager $capabilitiesManager |
|
136 | + */ |
|
137 | + public function __construct( |
|
138 | + IDBConnection $connection, |
|
139 | + ISecureRandom $secureRandom, |
|
140 | + IUserManager $userManager, |
|
141 | + IRootFolder $rootFolder, |
|
142 | + IL10N $l, |
|
143 | + ILogger $logger, |
|
144 | + IMailer $mailer, |
|
145 | + IURLGenerator $urlGenerator, |
|
146 | + IManager $activityManager, |
|
147 | + SettingsManager $settingsManager, |
|
148 | + Defaults $defaults, |
|
149 | + IHasher $hasher, |
|
150 | + CapabilitiesManager $capabilitiesManager |
|
151 | + ) { |
|
152 | + $this->dbConnection = $connection; |
|
153 | + $this->secureRandom = $secureRandom; |
|
154 | + $this->userManager = $userManager; |
|
155 | + $this->rootFolder = $rootFolder; |
|
156 | + $this->l = $l; |
|
157 | + $this->logger = $logger; |
|
158 | + $this->mailer = $mailer; |
|
159 | + $this->urlGenerator = $urlGenerator; |
|
160 | + $this->activityManager = $activityManager; |
|
161 | + $this->settingsManager = $settingsManager; |
|
162 | + $this->defaults = $defaults; |
|
163 | + $this->hasher = $hasher; |
|
164 | + $this->capabilitiesManager = $capabilitiesManager; |
|
165 | + } |
|
166 | + |
|
167 | + /** |
|
168 | + * Share a path |
|
169 | + * |
|
170 | + * @param IShare $share |
|
171 | + * @return IShare The share object |
|
172 | + * @throws ShareNotFound |
|
173 | + * @throws \Exception |
|
174 | + */ |
|
175 | + public function create(IShare $share) { |
|
176 | + $shareWith = $share->getSharedWith(); |
|
177 | + /* |
|
178 | 178 | * Check if file is not already shared with the remote user |
179 | 179 | */ |
180 | - $alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_EMAIL, $share->getNode(), 1, 0); |
|
181 | - if (!empty($alreadyShared)) { |
|
182 | - $message = 'Sharing %1$s failed, this item is already shared with %2$s'; |
|
183 | - $message_t = $this->l->t('Sharing %1$s failed, this item is already shared with %2$s', [$share->getNode()->getName(), $shareWith]); |
|
184 | - $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); |
|
185 | - throw new \Exception($message_t); |
|
186 | - } |
|
187 | - |
|
188 | - // if the admin enforces a password for all mail shares we create a |
|
189 | - // random password and send it to the recipient |
|
190 | - $password = $share->getPassword() ?: ''; |
|
191 | - $passwordEnforced = $this->settingsManager->enforcePasswordProtection(); |
|
192 | - if ($passwordEnforced && empty($password)) { |
|
193 | - $password = $this->autoGeneratePassword($share); |
|
194 | - } |
|
195 | - |
|
196 | - if (!empty($password)) { |
|
197 | - $share->setPassword($this->hasher->hash($password)); |
|
198 | - } |
|
199 | - |
|
200 | - $shareId = $this->createMailShare($share); |
|
201 | - $send = $this->sendPassword($share, $password); |
|
202 | - if ($passwordEnforced && $send === false) { |
|
203 | - $this->sendPasswordToOwner($share, $password); |
|
204 | - } |
|
205 | - |
|
206 | - $this->createShareActivity($share); |
|
207 | - $data = $this->getRawShare($shareId); |
|
208 | - |
|
209 | - return $this->createShareObject($data); |
|
210 | - } |
|
211 | - |
|
212 | - /** |
|
213 | - * auto generate password in case of password enforcement on mail shares |
|
214 | - * |
|
215 | - * @param IShare $share |
|
216 | - * @return string |
|
217 | - * @throws \Exception |
|
218 | - */ |
|
219 | - protected function autoGeneratePassword($share) { |
|
220 | - $initiatorUser = $this->userManager->get($share->getSharedBy()); |
|
221 | - $initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
222 | - $allowPasswordByMail = $this->settingsManager->sendPasswordByMail(); |
|
223 | - |
|
224 | - if ($initiatorEMailAddress === null && !$allowPasswordByMail) { |
|
225 | - throw new \Exception( |
|
226 | - $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.") |
|
227 | - ); |
|
228 | - } |
|
229 | - |
|
230 | - $passwordPolicy = $this->getPasswordPolicy(); |
|
231 | - $passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS; |
|
232 | - $passwordLength = 8; |
|
233 | - if (!empty($passwordPolicy)) { |
|
234 | - $passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength; |
|
235 | - $passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : ''; |
|
236 | - } |
|
237 | - |
|
238 | - $password = $this->secureRandom->generate($passwordLength, $passwordCharset); |
|
239 | - |
|
240 | - return $password; |
|
241 | - } |
|
242 | - |
|
243 | - /** |
|
244 | - * get password policy |
|
245 | - * |
|
246 | - * @return array |
|
247 | - */ |
|
248 | - protected function getPasswordPolicy() { |
|
249 | - $capabilities = $this->capabilitiesManager->getCapabilities(); |
|
250 | - if (isset($capabilities['password_policy'])) { |
|
251 | - return $capabilities['password_policy']; |
|
252 | - } |
|
253 | - |
|
254 | - return []; |
|
255 | - } |
|
256 | - |
|
257 | - /** |
|
258 | - * create activity if a file/folder was shared by mail |
|
259 | - * |
|
260 | - * @param IShare $share |
|
261 | - * @param string $type |
|
262 | - */ |
|
263 | - protected function createShareActivity(IShare $share, string $type = 'share') { |
|
264 | - $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
265 | - |
|
266 | - $this->publishActivity( |
|
267 | - $type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_SELF : Activity::SUBJECT_UNSHARED_EMAIL_SELF, |
|
268 | - [$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()], |
|
269 | - $share->getSharedBy(), |
|
270 | - $share->getNode()->getId(), |
|
271 | - (string) $userFolder->getRelativePath($share->getNode()->getPath()) |
|
272 | - ); |
|
273 | - |
|
274 | - if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
275 | - $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
|
276 | - $fileId = $share->getNode()->getId(); |
|
277 | - $nodes = $ownerFolder->getById($fileId); |
|
278 | - $ownerPath = $nodes[0]->getPath(); |
|
279 | - $this->publishActivity( |
|
280 | - $type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_BY : Activity::SUBJECT_UNSHARED_EMAIL_BY, |
|
281 | - [$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()], |
|
282 | - $share->getShareOwner(), |
|
283 | - $fileId, |
|
284 | - (string) $ownerFolder->getRelativePath($ownerPath) |
|
285 | - ); |
|
286 | - } |
|
287 | - } |
|
288 | - |
|
289 | - /** |
|
290 | - * create activity if a file/folder was shared by mail |
|
291 | - * |
|
292 | - * @param IShare $share |
|
293 | - * @param string $sharedWith |
|
294 | - * @param bool $sendToSelf |
|
295 | - */ |
|
296 | - protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) { |
|
297 | - $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
298 | - |
|
299 | - if ($sendToSelf) { |
|
300 | - $this->publishActivity( |
|
301 | - Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF, |
|
302 | - [$userFolder->getRelativePath($share->getNode()->getPath())], |
|
303 | - $share->getSharedBy(), |
|
304 | - $share->getNode()->getId(), |
|
305 | - (string) $userFolder->getRelativePath($share->getNode()->getPath()) |
|
306 | - ); |
|
307 | - } else { |
|
308 | - $this->publishActivity( |
|
309 | - Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND, |
|
310 | - [$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith], |
|
311 | - $share->getSharedBy(), |
|
312 | - $share->getNode()->getId(), |
|
313 | - (string) $userFolder->getRelativePath($share->getNode()->getPath()) |
|
314 | - ); |
|
315 | - } |
|
316 | - } |
|
317 | - |
|
318 | - |
|
319 | - /** |
|
320 | - * publish activity if a file/folder was shared by mail |
|
321 | - * |
|
322 | - * @param string $subject |
|
323 | - * @param array $parameters |
|
324 | - * @param string $affectedUser |
|
325 | - * @param int $fileId |
|
326 | - * @param string $filePath |
|
327 | - */ |
|
328 | - protected function publishActivity(string $subject, array $parameters, string $affectedUser, int $fileId, string $filePath) { |
|
329 | - $event = $this->activityManager->generateEvent(); |
|
330 | - $event->setApp('sharebymail') |
|
331 | - ->setType('shared') |
|
332 | - ->setSubject($subject, $parameters) |
|
333 | - ->setAffectedUser($affectedUser) |
|
334 | - ->setObject('files', $fileId, $filePath); |
|
335 | - $this->activityManager->publish($event); |
|
336 | - } |
|
337 | - |
|
338 | - /** |
|
339 | - * @param IShare $share |
|
340 | - * @return int |
|
341 | - * @throws \Exception |
|
342 | - */ |
|
343 | - protected function createMailShare(IShare $share) { |
|
344 | - $share->setToken($this->generateToken()); |
|
345 | - $shareId = $this->addShareToDB( |
|
346 | - $share->getNodeId(), |
|
347 | - $share->getNodeType(), |
|
348 | - $share->getSharedWith(), |
|
349 | - $share->getSharedBy(), |
|
350 | - $share->getShareOwner(), |
|
351 | - $share->getPermissions(), |
|
352 | - $share->getToken(), |
|
353 | - $share->getPassword(), |
|
354 | - $share->getSendPasswordByTalk(), |
|
355 | - $share->getHideDownload() |
|
356 | - ); |
|
357 | - |
|
358 | - try { |
|
359 | - $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', |
|
360 | - ['token' => $share->getToken()]); |
|
361 | - $this->sendMailNotification( |
|
362 | - $share->getNode()->getName(), |
|
363 | - $link, |
|
364 | - $share->getSharedBy(), |
|
365 | - $share->getSharedWith(), |
|
366 | - $share->getExpirationDate() |
|
367 | - ); |
|
368 | - } catch (HintException $hintException) { |
|
369 | - $this->logger->logException($hintException, [ |
|
370 | - 'message' => 'Failed to send share by mail.', |
|
371 | - 'level' => ILogger::ERROR, |
|
372 | - 'app' => 'sharebymail', |
|
373 | - ]); |
|
374 | - $this->removeShareFromTable($shareId); |
|
375 | - throw $hintException; |
|
376 | - } catch (\Exception $e) { |
|
377 | - $this->logger->logException($e, [ |
|
378 | - 'message' => 'Failed to send share by mail.', |
|
379 | - 'level' => ILogger::ERROR, |
|
380 | - 'app' => 'sharebymail', |
|
381 | - ]); |
|
382 | - $this->removeShareFromTable($shareId); |
|
383 | - throw new HintException('Failed to send share by mail', |
|
384 | - $this->l->t('Failed to send share by email')); |
|
385 | - } |
|
386 | - |
|
387 | - return $shareId; |
|
388 | - } |
|
389 | - |
|
390 | - /** |
|
391 | - * @param string $filename |
|
392 | - * @param string $link |
|
393 | - * @param string $initiator |
|
394 | - * @param string $shareWith |
|
395 | - * @param \DateTime|null $expiration |
|
396 | - * @throws \Exception If mail couldn't be sent |
|
397 | - */ |
|
398 | - protected function sendMailNotification($filename, |
|
399 | - $link, |
|
400 | - $initiator, |
|
401 | - $shareWith, |
|
402 | - \DateTime $expiration = null) { |
|
403 | - $initiatorUser = $this->userManager->get($initiator); |
|
404 | - $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
405 | - $message = $this->mailer->createMessage(); |
|
406 | - |
|
407 | - $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [ |
|
408 | - 'filename' => $filename, |
|
409 | - 'link' => $link, |
|
410 | - 'initiator' => $initiatorDisplayName, |
|
411 | - 'expiration' => $expiration, |
|
412 | - 'shareWith' => $shareWith, |
|
413 | - ]); |
|
414 | - |
|
415 | - $emailTemplate->setSubject($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename])); |
|
416 | - $emailTemplate->addHeader(); |
|
417 | - $emailTemplate->addHeading($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false); |
|
418 | - $text = $this->l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]); |
|
419 | - |
|
420 | - $emailTemplate->addBodyText( |
|
421 | - htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')), |
|
422 | - $text |
|
423 | - ); |
|
424 | - $emailTemplate->addBodyButton( |
|
425 | - $this->l->t('Open »%s«', [$filename]), |
|
426 | - $link |
|
427 | - ); |
|
428 | - |
|
429 | - $message->setTo([$shareWith]); |
|
430 | - |
|
431 | - // The "From" contains the sharers name |
|
432 | - $instanceName = $this->defaults->getName(); |
|
433 | - $senderName = $this->l->t( |
|
434 | - '%1$s via %2$s', |
|
435 | - [ |
|
436 | - $initiatorDisplayName, |
|
437 | - $instanceName |
|
438 | - ] |
|
439 | - ); |
|
440 | - $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
441 | - |
|
442 | - // The "Reply-To" is set to the sharer if an mail address is configured |
|
443 | - // also the default footer contains a "Do not reply" which needs to be adjusted. |
|
444 | - $initiatorEmail = $initiatorUser->getEMailAddress(); |
|
445 | - if ($initiatorEmail !== null) { |
|
446 | - $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]); |
|
447 | - $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')); |
|
448 | - } else { |
|
449 | - $emailTemplate->addFooter(); |
|
450 | - } |
|
451 | - |
|
452 | - $message->useTemplate($emailTemplate); |
|
453 | - $this->mailer->send($message); |
|
454 | - } |
|
455 | - |
|
456 | - /** |
|
457 | - * send password to recipient of a mail share |
|
458 | - * |
|
459 | - * @param IShare $share |
|
460 | - * @param string $password |
|
461 | - * @return bool |
|
462 | - */ |
|
463 | - protected function sendPassword(IShare $share, $password) { |
|
464 | - $filename = $share->getNode()->getName(); |
|
465 | - $initiator = $share->getSharedBy(); |
|
466 | - $shareWith = $share->getSharedWith(); |
|
467 | - |
|
468 | - if ($password === '' || $this->settingsManager->sendPasswordByMail() === false || $share->getSendPasswordByTalk()) { |
|
469 | - return false; |
|
470 | - } |
|
471 | - |
|
472 | - $initiatorUser = $this->userManager->get($initiator); |
|
473 | - $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
474 | - $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
475 | - |
|
476 | - $plainBodyPart = $this->l->t("%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]); |
|
477 | - $htmlBodyPart = $this->l->t('%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]); |
|
478 | - |
|
479 | - $message = $this->mailer->createMessage(); |
|
480 | - |
|
481 | - $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [ |
|
482 | - 'filename' => $filename, |
|
483 | - 'password' => $password, |
|
484 | - 'initiator' => $initiatorDisplayName, |
|
485 | - 'initiatorEmail' => $initiatorEmailAddress, |
|
486 | - 'shareWith' => $shareWith, |
|
487 | - ]); |
|
488 | - |
|
489 | - $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName])); |
|
490 | - $emailTemplate->addHeader(); |
|
491 | - $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false); |
|
492 | - $emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart); |
|
493 | - $emailTemplate->addBodyText($this->l->t('It is protected with the following password:')); |
|
494 | - $emailTemplate->addBodyText($password); |
|
495 | - |
|
496 | - // The "From" contains the sharers name |
|
497 | - $instanceName = $this->defaults->getName(); |
|
498 | - $senderName = $this->l->t( |
|
499 | - '%1$s via %2$s', |
|
500 | - [ |
|
501 | - $initiatorDisplayName, |
|
502 | - $instanceName |
|
503 | - ] |
|
504 | - ); |
|
505 | - $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
506 | - if ($initiatorEmailAddress !== null) { |
|
507 | - $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
|
508 | - $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
509 | - } else { |
|
510 | - $emailTemplate->addFooter(); |
|
511 | - } |
|
512 | - |
|
513 | - $message->setTo([$shareWith]); |
|
514 | - $message->useTemplate($emailTemplate); |
|
515 | - $this->mailer->send($message); |
|
516 | - |
|
517 | - $this->createPasswordSendActivity($share, $shareWith, false); |
|
518 | - |
|
519 | - return true; |
|
520 | - } |
|
521 | - |
|
522 | - protected function sendNote(IShare $share) { |
|
523 | - $recipient = $share->getSharedWith(); |
|
524 | - |
|
525 | - |
|
526 | - $filename = $share->getNode()->getName(); |
|
527 | - $initiator = $share->getSharedBy(); |
|
528 | - $note = $share->getNote(); |
|
529 | - |
|
530 | - $initiatorUser = $this->userManager->get($initiator); |
|
531 | - $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
532 | - $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
533 | - |
|
534 | - $plainHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add:', [$initiatorDisplayName, $filename]); |
|
535 | - $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add', [$initiatorDisplayName, $filename]); |
|
536 | - |
|
537 | - $message = $this->mailer->createMessage(); |
|
538 | - |
|
539 | - $emailTemplate = $this->mailer->createEMailTemplate('shareByMail.sendNote'); |
|
540 | - |
|
541 | - $emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName])); |
|
542 | - $emailTemplate->addHeader(); |
|
543 | - $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading); |
|
544 | - $emailTemplate->addBodyText(htmlspecialchars($note), $note); |
|
545 | - |
|
546 | - $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', |
|
547 | - ['token' => $share->getToken()]); |
|
548 | - $emailTemplate->addBodyButton( |
|
549 | - $this->l->t('Open »%s«', [$filename]), |
|
550 | - $link |
|
551 | - ); |
|
552 | - |
|
553 | - // The "From" contains the sharers name |
|
554 | - $instanceName = $this->defaults->getName(); |
|
555 | - $senderName = $this->l->t( |
|
556 | - '%1$s via %2$s', |
|
557 | - [ |
|
558 | - $initiatorDisplayName, |
|
559 | - $instanceName |
|
560 | - ] |
|
561 | - ); |
|
562 | - $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
563 | - if ($initiatorEmailAddress !== null) { |
|
564 | - $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
|
565 | - $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
566 | - } else { |
|
567 | - $emailTemplate->addFooter(); |
|
568 | - } |
|
569 | - |
|
570 | - $message->setTo([$recipient]); |
|
571 | - $message->useTemplate($emailTemplate); |
|
572 | - $this->mailer->send($message); |
|
573 | - } |
|
574 | - |
|
575 | - /** |
|
576 | - * send auto generated password to the owner. This happens if the admin enforces |
|
577 | - * a password for mail shares and forbid to send the password by mail to the recipient |
|
578 | - * |
|
579 | - * @param IShare $share |
|
580 | - * @param string $password |
|
581 | - * @return bool |
|
582 | - * @throws \Exception |
|
583 | - */ |
|
584 | - protected function sendPasswordToOwner(IShare $share, $password) { |
|
585 | - $filename = $share->getNode()->getName(); |
|
586 | - $initiator = $this->userManager->get($share->getSharedBy()); |
|
587 | - $initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null; |
|
588 | - $initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy(); |
|
589 | - $shareWith = $share->getSharedWith(); |
|
590 | - |
|
591 | - if ($initiatorEMailAddress === null) { |
|
592 | - throw new \Exception( |
|
593 | - $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.") |
|
594 | - ); |
|
595 | - } |
|
596 | - |
|
597 | - $bodyPart = $this->l->t('You just shared »%1$s« with %2$s. The share was already sent to the recipient. Due to the security policies defined by the administrator of %3$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()]); |
|
598 | - |
|
599 | - $message = $this->mailer->createMessage(); |
|
600 | - $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [ |
|
601 | - 'filename' => $filename, |
|
602 | - 'password' => $password, |
|
603 | - 'initiator' => $initiatorDisplayName, |
|
604 | - 'initiatorEmail' => $initiatorEMailAddress, |
|
605 | - 'shareWith' => $shareWith, |
|
606 | - ]); |
|
607 | - |
|
608 | - $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared by you with %2$s', [$filename, $shareWith])); |
|
609 | - $emailTemplate->addHeader(); |
|
610 | - $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false); |
|
611 | - $emailTemplate->addBodyText($bodyPart); |
|
612 | - $emailTemplate->addBodyText($this->l->t('This is the password:')); |
|
613 | - $emailTemplate->addBodyText($password); |
|
614 | - $emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.')); |
|
615 | - $emailTemplate->addFooter(); |
|
616 | - |
|
617 | - $instanceName = $this->defaults->getName(); |
|
618 | - $senderName = $this->l->t( |
|
619 | - '%1$s via %2$s', |
|
620 | - [ |
|
621 | - $initiatorDisplayName, |
|
622 | - $instanceName |
|
623 | - ] |
|
624 | - ); |
|
625 | - $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
626 | - $message->setTo([$initiatorEMailAddress => $initiatorDisplayName]); |
|
627 | - $message->useTemplate($emailTemplate); |
|
628 | - $this->mailer->send($message); |
|
629 | - |
|
630 | - $this->createPasswordSendActivity($share, $shareWith, true); |
|
631 | - |
|
632 | - return true; |
|
633 | - } |
|
634 | - |
|
635 | - /** |
|
636 | - * generate share token |
|
637 | - * |
|
638 | - * @return string |
|
639 | - */ |
|
640 | - protected function generateToken($size = 15) { |
|
641 | - $token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE); |
|
642 | - return $token; |
|
643 | - } |
|
644 | - |
|
645 | - /** |
|
646 | - * Get all children of this share |
|
647 | - * |
|
648 | - * @param IShare $parent |
|
649 | - * @return IShare[] |
|
650 | - */ |
|
651 | - public function getChildren(IShare $parent) { |
|
652 | - $children = []; |
|
653 | - |
|
654 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
655 | - $qb->select('*') |
|
656 | - ->from('share') |
|
657 | - ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) |
|
658 | - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
659 | - ->orderBy('id'); |
|
660 | - |
|
661 | - $cursor = $qb->execute(); |
|
662 | - while ($data = $cursor->fetch()) { |
|
663 | - $children[] = $this->createShareObject($data); |
|
664 | - } |
|
665 | - $cursor->closeCursor(); |
|
666 | - |
|
667 | - return $children; |
|
668 | - } |
|
669 | - |
|
670 | - /** |
|
671 | - * add share to the database and return the ID |
|
672 | - * |
|
673 | - * @param int $itemSource |
|
674 | - * @param string $itemType |
|
675 | - * @param string $shareWith |
|
676 | - * @param string $sharedBy |
|
677 | - * @param string $uidOwner |
|
678 | - * @param int $permissions |
|
679 | - * @param string $token |
|
680 | - * @param string $password |
|
681 | - * @param bool $sendPasswordByTalk |
|
682 | - * @param bool $hideDownload |
|
683 | - * @return int |
|
684 | - */ |
|
685 | - protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password, $sendPasswordByTalk, $hideDownload) { |
|
686 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
687 | - $qb->insert('share') |
|
688 | - ->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)) |
|
689 | - ->setValue('item_type', $qb->createNamedParameter($itemType)) |
|
690 | - ->setValue('item_source', $qb->createNamedParameter($itemSource)) |
|
691 | - ->setValue('file_source', $qb->createNamedParameter($itemSource)) |
|
692 | - ->setValue('share_with', $qb->createNamedParameter($shareWith)) |
|
693 | - ->setValue('uid_owner', $qb->createNamedParameter($uidOwner)) |
|
694 | - ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy)) |
|
695 | - ->setValue('permissions', $qb->createNamedParameter($permissions)) |
|
696 | - ->setValue('token', $qb->createNamedParameter($token)) |
|
697 | - ->setValue('password', $qb->createNamedParameter($password)) |
|
698 | - ->setValue('password_by_talk', $qb->createNamedParameter($sendPasswordByTalk, IQueryBuilder::PARAM_BOOL)) |
|
699 | - ->setValue('stime', $qb->createNamedParameter(time())) |
|
700 | - ->setValue('hide_download', $qb->createNamedParameter((int)$hideDownload, IQueryBuilder::PARAM_INT)); |
|
701 | - |
|
702 | - /* |
|
180 | + $alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_EMAIL, $share->getNode(), 1, 0); |
|
181 | + if (!empty($alreadyShared)) { |
|
182 | + $message = 'Sharing %1$s failed, this item is already shared with %2$s'; |
|
183 | + $message_t = $this->l->t('Sharing %1$s failed, this item is already shared with %2$s', [$share->getNode()->getName(), $shareWith]); |
|
184 | + $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); |
|
185 | + throw new \Exception($message_t); |
|
186 | + } |
|
187 | + |
|
188 | + // if the admin enforces a password for all mail shares we create a |
|
189 | + // random password and send it to the recipient |
|
190 | + $password = $share->getPassword() ?: ''; |
|
191 | + $passwordEnforced = $this->settingsManager->enforcePasswordProtection(); |
|
192 | + if ($passwordEnforced && empty($password)) { |
|
193 | + $password = $this->autoGeneratePassword($share); |
|
194 | + } |
|
195 | + |
|
196 | + if (!empty($password)) { |
|
197 | + $share->setPassword($this->hasher->hash($password)); |
|
198 | + } |
|
199 | + |
|
200 | + $shareId = $this->createMailShare($share); |
|
201 | + $send = $this->sendPassword($share, $password); |
|
202 | + if ($passwordEnforced && $send === false) { |
|
203 | + $this->sendPasswordToOwner($share, $password); |
|
204 | + } |
|
205 | + |
|
206 | + $this->createShareActivity($share); |
|
207 | + $data = $this->getRawShare($shareId); |
|
208 | + |
|
209 | + return $this->createShareObject($data); |
|
210 | + } |
|
211 | + |
|
212 | + /** |
|
213 | + * auto generate password in case of password enforcement on mail shares |
|
214 | + * |
|
215 | + * @param IShare $share |
|
216 | + * @return string |
|
217 | + * @throws \Exception |
|
218 | + */ |
|
219 | + protected function autoGeneratePassword($share) { |
|
220 | + $initiatorUser = $this->userManager->get($share->getSharedBy()); |
|
221 | + $initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
222 | + $allowPasswordByMail = $this->settingsManager->sendPasswordByMail(); |
|
223 | + |
|
224 | + if ($initiatorEMailAddress === null && !$allowPasswordByMail) { |
|
225 | + throw new \Exception( |
|
226 | + $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.") |
|
227 | + ); |
|
228 | + } |
|
229 | + |
|
230 | + $passwordPolicy = $this->getPasswordPolicy(); |
|
231 | + $passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS; |
|
232 | + $passwordLength = 8; |
|
233 | + if (!empty($passwordPolicy)) { |
|
234 | + $passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength; |
|
235 | + $passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : ''; |
|
236 | + } |
|
237 | + |
|
238 | + $password = $this->secureRandom->generate($passwordLength, $passwordCharset); |
|
239 | + |
|
240 | + return $password; |
|
241 | + } |
|
242 | + |
|
243 | + /** |
|
244 | + * get password policy |
|
245 | + * |
|
246 | + * @return array |
|
247 | + */ |
|
248 | + protected function getPasswordPolicy() { |
|
249 | + $capabilities = $this->capabilitiesManager->getCapabilities(); |
|
250 | + if (isset($capabilities['password_policy'])) { |
|
251 | + return $capabilities['password_policy']; |
|
252 | + } |
|
253 | + |
|
254 | + return []; |
|
255 | + } |
|
256 | + |
|
257 | + /** |
|
258 | + * create activity if a file/folder was shared by mail |
|
259 | + * |
|
260 | + * @param IShare $share |
|
261 | + * @param string $type |
|
262 | + */ |
|
263 | + protected function createShareActivity(IShare $share, string $type = 'share') { |
|
264 | + $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
265 | + |
|
266 | + $this->publishActivity( |
|
267 | + $type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_SELF : Activity::SUBJECT_UNSHARED_EMAIL_SELF, |
|
268 | + [$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()], |
|
269 | + $share->getSharedBy(), |
|
270 | + $share->getNode()->getId(), |
|
271 | + (string) $userFolder->getRelativePath($share->getNode()->getPath()) |
|
272 | + ); |
|
273 | + |
|
274 | + if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
275 | + $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
|
276 | + $fileId = $share->getNode()->getId(); |
|
277 | + $nodes = $ownerFolder->getById($fileId); |
|
278 | + $ownerPath = $nodes[0]->getPath(); |
|
279 | + $this->publishActivity( |
|
280 | + $type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_BY : Activity::SUBJECT_UNSHARED_EMAIL_BY, |
|
281 | + [$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()], |
|
282 | + $share->getShareOwner(), |
|
283 | + $fileId, |
|
284 | + (string) $ownerFolder->getRelativePath($ownerPath) |
|
285 | + ); |
|
286 | + } |
|
287 | + } |
|
288 | + |
|
289 | + /** |
|
290 | + * create activity if a file/folder was shared by mail |
|
291 | + * |
|
292 | + * @param IShare $share |
|
293 | + * @param string $sharedWith |
|
294 | + * @param bool $sendToSelf |
|
295 | + */ |
|
296 | + protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) { |
|
297 | + $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
298 | + |
|
299 | + if ($sendToSelf) { |
|
300 | + $this->publishActivity( |
|
301 | + Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF, |
|
302 | + [$userFolder->getRelativePath($share->getNode()->getPath())], |
|
303 | + $share->getSharedBy(), |
|
304 | + $share->getNode()->getId(), |
|
305 | + (string) $userFolder->getRelativePath($share->getNode()->getPath()) |
|
306 | + ); |
|
307 | + } else { |
|
308 | + $this->publishActivity( |
|
309 | + Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND, |
|
310 | + [$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith], |
|
311 | + $share->getSharedBy(), |
|
312 | + $share->getNode()->getId(), |
|
313 | + (string) $userFolder->getRelativePath($share->getNode()->getPath()) |
|
314 | + ); |
|
315 | + } |
|
316 | + } |
|
317 | + |
|
318 | + |
|
319 | + /** |
|
320 | + * publish activity if a file/folder was shared by mail |
|
321 | + * |
|
322 | + * @param string $subject |
|
323 | + * @param array $parameters |
|
324 | + * @param string $affectedUser |
|
325 | + * @param int $fileId |
|
326 | + * @param string $filePath |
|
327 | + */ |
|
328 | + protected function publishActivity(string $subject, array $parameters, string $affectedUser, int $fileId, string $filePath) { |
|
329 | + $event = $this->activityManager->generateEvent(); |
|
330 | + $event->setApp('sharebymail') |
|
331 | + ->setType('shared') |
|
332 | + ->setSubject($subject, $parameters) |
|
333 | + ->setAffectedUser($affectedUser) |
|
334 | + ->setObject('files', $fileId, $filePath); |
|
335 | + $this->activityManager->publish($event); |
|
336 | + } |
|
337 | + |
|
338 | + /** |
|
339 | + * @param IShare $share |
|
340 | + * @return int |
|
341 | + * @throws \Exception |
|
342 | + */ |
|
343 | + protected function createMailShare(IShare $share) { |
|
344 | + $share->setToken($this->generateToken()); |
|
345 | + $shareId = $this->addShareToDB( |
|
346 | + $share->getNodeId(), |
|
347 | + $share->getNodeType(), |
|
348 | + $share->getSharedWith(), |
|
349 | + $share->getSharedBy(), |
|
350 | + $share->getShareOwner(), |
|
351 | + $share->getPermissions(), |
|
352 | + $share->getToken(), |
|
353 | + $share->getPassword(), |
|
354 | + $share->getSendPasswordByTalk(), |
|
355 | + $share->getHideDownload() |
|
356 | + ); |
|
357 | + |
|
358 | + try { |
|
359 | + $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', |
|
360 | + ['token' => $share->getToken()]); |
|
361 | + $this->sendMailNotification( |
|
362 | + $share->getNode()->getName(), |
|
363 | + $link, |
|
364 | + $share->getSharedBy(), |
|
365 | + $share->getSharedWith(), |
|
366 | + $share->getExpirationDate() |
|
367 | + ); |
|
368 | + } catch (HintException $hintException) { |
|
369 | + $this->logger->logException($hintException, [ |
|
370 | + 'message' => 'Failed to send share by mail.', |
|
371 | + 'level' => ILogger::ERROR, |
|
372 | + 'app' => 'sharebymail', |
|
373 | + ]); |
|
374 | + $this->removeShareFromTable($shareId); |
|
375 | + throw $hintException; |
|
376 | + } catch (\Exception $e) { |
|
377 | + $this->logger->logException($e, [ |
|
378 | + 'message' => 'Failed to send share by mail.', |
|
379 | + 'level' => ILogger::ERROR, |
|
380 | + 'app' => 'sharebymail', |
|
381 | + ]); |
|
382 | + $this->removeShareFromTable($shareId); |
|
383 | + throw new HintException('Failed to send share by mail', |
|
384 | + $this->l->t('Failed to send share by email')); |
|
385 | + } |
|
386 | + |
|
387 | + return $shareId; |
|
388 | + } |
|
389 | + |
|
390 | + /** |
|
391 | + * @param string $filename |
|
392 | + * @param string $link |
|
393 | + * @param string $initiator |
|
394 | + * @param string $shareWith |
|
395 | + * @param \DateTime|null $expiration |
|
396 | + * @throws \Exception If mail couldn't be sent |
|
397 | + */ |
|
398 | + protected function sendMailNotification($filename, |
|
399 | + $link, |
|
400 | + $initiator, |
|
401 | + $shareWith, |
|
402 | + \DateTime $expiration = null) { |
|
403 | + $initiatorUser = $this->userManager->get($initiator); |
|
404 | + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
405 | + $message = $this->mailer->createMessage(); |
|
406 | + |
|
407 | + $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [ |
|
408 | + 'filename' => $filename, |
|
409 | + 'link' => $link, |
|
410 | + 'initiator' => $initiatorDisplayName, |
|
411 | + 'expiration' => $expiration, |
|
412 | + 'shareWith' => $shareWith, |
|
413 | + ]); |
|
414 | + |
|
415 | + $emailTemplate->setSubject($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename])); |
|
416 | + $emailTemplate->addHeader(); |
|
417 | + $emailTemplate->addHeading($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false); |
|
418 | + $text = $this->l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]); |
|
419 | + |
|
420 | + $emailTemplate->addBodyText( |
|
421 | + htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')), |
|
422 | + $text |
|
423 | + ); |
|
424 | + $emailTemplate->addBodyButton( |
|
425 | + $this->l->t('Open »%s«', [$filename]), |
|
426 | + $link |
|
427 | + ); |
|
428 | + |
|
429 | + $message->setTo([$shareWith]); |
|
430 | + |
|
431 | + // The "From" contains the sharers name |
|
432 | + $instanceName = $this->defaults->getName(); |
|
433 | + $senderName = $this->l->t( |
|
434 | + '%1$s via %2$s', |
|
435 | + [ |
|
436 | + $initiatorDisplayName, |
|
437 | + $instanceName |
|
438 | + ] |
|
439 | + ); |
|
440 | + $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
441 | + |
|
442 | + // The "Reply-To" is set to the sharer if an mail address is configured |
|
443 | + // also the default footer contains a "Do not reply" which needs to be adjusted. |
|
444 | + $initiatorEmail = $initiatorUser->getEMailAddress(); |
|
445 | + if ($initiatorEmail !== null) { |
|
446 | + $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]); |
|
447 | + $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')); |
|
448 | + } else { |
|
449 | + $emailTemplate->addFooter(); |
|
450 | + } |
|
451 | + |
|
452 | + $message->useTemplate($emailTemplate); |
|
453 | + $this->mailer->send($message); |
|
454 | + } |
|
455 | + |
|
456 | + /** |
|
457 | + * send password to recipient of a mail share |
|
458 | + * |
|
459 | + * @param IShare $share |
|
460 | + * @param string $password |
|
461 | + * @return bool |
|
462 | + */ |
|
463 | + protected function sendPassword(IShare $share, $password) { |
|
464 | + $filename = $share->getNode()->getName(); |
|
465 | + $initiator = $share->getSharedBy(); |
|
466 | + $shareWith = $share->getSharedWith(); |
|
467 | + |
|
468 | + if ($password === '' || $this->settingsManager->sendPasswordByMail() === false || $share->getSendPasswordByTalk()) { |
|
469 | + return false; |
|
470 | + } |
|
471 | + |
|
472 | + $initiatorUser = $this->userManager->get($initiator); |
|
473 | + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
474 | + $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
475 | + |
|
476 | + $plainBodyPart = $this->l->t("%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]); |
|
477 | + $htmlBodyPart = $this->l->t('%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]); |
|
478 | + |
|
479 | + $message = $this->mailer->createMessage(); |
|
480 | + |
|
481 | + $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [ |
|
482 | + 'filename' => $filename, |
|
483 | + 'password' => $password, |
|
484 | + 'initiator' => $initiatorDisplayName, |
|
485 | + 'initiatorEmail' => $initiatorEmailAddress, |
|
486 | + 'shareWith' => $shareWith, |
|
487 | + ]); |
|
488 | + |
|
489 | + $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName])); |
|
490 | + $emailTemplate->addHeader(); |
|
491 | + $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false); |
|
492 | + $emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart); |
|
493 | + $emailTemplate->addBodyText($this->l->t('It is protected with the following password:')); |
|
494 | + $emailTemplate->addBodyText($password); |
|
495 | + |
|
496 | + // The "From" contains the sharers name |
|
497 | + $instanceName = $this->defaults->getName(); |
|
498 | + $senderName = $this->l->t( |
|
499 | + '%1$s via %2$s', |
|
500 | + [ |
|
501 | + $initiatorDisplayName, |
|
502 | + $instanceName |
|
503 | + ] |
|
504 | + ); |
|
505 | + $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
506 | + if ($initiatorEmailAddress !== null) { |
|
507 | + $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
|
508 | + $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
509 | + } else { |
|
510 | + $emailTemplate->addFooter(); |
|
511 | + } |
|
512 | + |
|
513 | + $message->setTo([$shareWith]); |
|
514 | + $message->useTemplate($emailTemplate); |
|
515 | + $this->mailer->send($message); |
|
516 | + |
|
517 | + $this->createPasswordSendActivity($share, $shareWith, false); |
|
518 | + |
|
519 | + return true; |
|
520 | + } |
|
521 | + |
|
522 | + protected function sendNote(IShare $share) { |
|
523 | + $recipient = $share->getSharedWith(); |
|
524 | + |
|
525 | + |
|
526 | + $filename = $share->getNode()->getName(); |
|
527 | + $initiator = $share->getSharedBy(); |
|
528 | + $note = $share->getNote(); |
|
529 | + |
|
530 | + $initiatorUser = $this->userManager->get($initiator); |
|
531 | + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
532 | + $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
533 | + |
|
534 | + $plainHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add:', [$initiatorDisplayName, $filename]); |
|
535 | + $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add', [$initiatorDisplayName, $filename]); |
|
536 | + |
|
537 | + $message = $this->mailer->createMessage(); |
|
538 | + |
|
539 | + $emailTemplate = $this->mailer->createEMailTemplate('shareByMail.sendNote'); |
|
540 | + |
|
541 | + $emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName])); |
|
542 | + $emailTemplate->addHeader(); |
|
543 | + $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading); |
|
544 | + $emailTemplate->addBodyText(htmlspecialchars($note), $note); |
|
545 | + |
|
546 | + $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', |
|
547 | + ['token' => $share->getToken()]); |
|
548 | + $emailTemplate->addBodyButton( |
|
549 | + $this->l->t('Open »%s«', [$filename]), |
|
550 | + $link |
|
551 | + ); |
|
552 | + |
|
553 | + // The "From" contains the sharers name |
|
554 | + $instanceName = $this->defaults->getName(); |
|
555 | + $senderName = $this->l->t( |
|
556 | + '%1$s via %2$s', |
|
557 | + [ |
|
558 | + $initiatorDisplayName, |
|
559 | + $instanceName |
|
560 | + ] |
|
561 | + ); |
|
562 | + $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
563 | + if ($initiatorEmailAddress !== null) { |
|
564 | + $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
|
565 | + $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
566 | + } else { |
|
567 | + $emailTemplate->addFooter(); |
|
568 | + } |
|
569 | + |
|
570 | + $message->setTo([$recipient]); |
|
571 | + $message->useTemplate($emailTemplate); |
|
572 | + $this->mailer->send($message); |
|
573 | + } |
|
574 | + |
|
575 | + /** |
|
576 | + * send auto generated password to the owner. This happens if the admin enforces |
|
577 | + * a password for mail shares and forbid to send the password by mail to the recipient |
|
578 | + * |
|
579 | + * @param IShare $share |
|
580 | + * @param string $password |
|
581 | + * @return bool |
|
582 | + * @throws \Exception |
|
583 | + */ |
|
584 | + protected function sendPasswordToOwner(IShare $share, $password) { |
|
585 | + $filename = $share->getNode()->getName(); |
|
586 | + $initiator = $this->userManager->get($share->getSharedBy()); |
|
587 | + $initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null; |
|
588 | + $initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy(); |
|
589 | + $shareWith = $share->getSharedWith(); |
|
590 | + |
|
591 | + if ($initiatorEMailAddress === null) { |
|
592 | + throw new \Exception( |
|
593 | + $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.") |
|
594 | + ); |
|
595 | + } |
|
596 | + |
|
597 | + $bodyPart = $this->l->t('You just shared »%1$s« with %2$s. The share was already sent to the recipient. Due to the security policies defined by the administrator of %3$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()]); |
|
598 | + |
|
599 | + $message = $this->mailer->createMessage(); |
|
600 | + $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [ |
|
601 | + 'filename' => $filename, |
|
602 | + 'password' => $password, |
|
603 | + 'initiator' => $initiatorDisplayName, |
|
604 | + 'initiatorEmail' => $initiatorEMailAddress, |
|
605 | + 'shareWith' => $shareWith, |
|
606 | + ]); |
|
607 | + |
|
608 | + $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared by you with %2$s', [$filename, $shareWith])); |
|
609 | + $emailTemplate->addHeader(); |
|
610 | + $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false); |
|
611 | + $emailTemplate->addBodyText($bodyPart); |
|
612 | + $emailTemplate->addBodyText($this->l->t('This is the password:')); |
|
613 | + $emailTemplate->addBodyText($password); |
|
614 | + $emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.')); |
|
615 | + $emailTemplate->addFooter(); |
|
616 | + |
|
617 | + $instanceName = $this->defaults->getName(); |
|
618 | + $senderName = $this->l->t( |
|
619 | + '%1$s via %2$s', |
|
620 | + [ |
|
621 | + $initiatorDisplayName, |
|
622 | + $instanceName |
|
623 | + ] |
|
624 | + ); |
|
625 | + $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
626 | + $message->setTo([$initiatorEMailAddress => $initiatorDisplayName]); |
|
627 | + $message->useTemplate($emailTemplate); |
|
628 | + $this->mailer->send($message); |
|
629 | + |
|
630 | + $this->createPasswordSendActivity($share, $shareWith, true); |
|
631 | + |
|
632 | + return true; |
|
633 | + } |
|
634 | + |
|
635 | + /** |
|
636 | + * generate share token |
|
637 | + * |
|
638 | + * @return string |
|
639 | + */ |
|
640 | + protected function generateToken($size = 15) { |
|
641 | + $token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE); |
|
642 | + return $token; |
|
643 | + } |
|
644 | + |
|
645 | + /** |
|
646 | + * Get all children of this share |
|
647 | + * |
|
648 | + * @param IShare $parent |
|
649 | + * @return IShare[] |
|
650 | + */ |
|
651 | + public function getChildren(IShare $parent) { |
|
652 | + $children = []; |
|
653 | + |
|
654 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
655 | + $qb->select('*') |
|
656 | + ->from('share') |
|
657 | + ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) |
|
658 | + ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
659 | + ->orderBy('id'); |
|
660 | + |
|
661 | + $cursor = $qb->execute(); |
|
662 | + while ($data = $cursor->fetch()) { |
|
663 | + $children[] = $this->createShareObject($data); |
|
664 | + } |
|
665 | + $cursor->closeCursor(); |
|
666 | + |
|
667 | + return $children; |
|
668 | + } |
|
669 | + |
|
670 | + /** |
|
671 | + * add share to the database and return the ID |
|
672 | + * |
|
673 | + * @param int $itemSource |
|
674 | + * @param string $itemType |
|
675 | + * @param string $shareWith |
|
676 | + * @param string $sharedBy |
|
677 | + * @param string $uidOwner |
|
678 | + * @param int $permissions |
|
679 | + * @param string $token |
|
680 | + * @param string $password |
|
681 | + * @param bool $sendPasswordByTalk |
|
682 | + * @param bool $hideDownload |
|
683 | + * @return int |
|
684 | + */ |
|
685 | + protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password, $sendPasswordByTalk, $hideDownload) { |
|
686 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
687 | + $qb->insert('share') |
|
688 | + ->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)) |
|
689 | + ->setValue('item_type', $qb->createNamedParameter($itemType)) |
|
690 | + ->setValue('item_source', $qb->createNamedParameter($itemSource)) |
|
691 | + ->setValue('file_source', $qb->createNamedParameter($itemSource)) |
|
692 | + ->setValue('share_with', $qb->createNamedParameter($shareWith)) |
|
693 | + ->setValue('uid_owner', $qb->createNamedParameter($uidOwner)) |
|
694 | + ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy)) |
|
695 | + ->setValue('permissions', $qb->createNamedParameter($permissions)) |
|
696 | + ->setValue('token', $qb->createNamedParameter($token)) |
|
697 | + ->setValue('password', $qb->createNamedParameter($password)) |
|
698 | + ->setValue('password_by_talk', $qb->createNamedParameter($sendPasswordByTalk, IQueryBuilder::PARAM_BOOL)) |
|
699 | + ->setValue('stime', $qb->createNamedParameter(time())) |
|
700 | + ->setValue('hide_download', $qb->createNamedParameter((int)$hideDownload, IQueryBuilder::PARAM_INT)); |
|
701 | + |
|
702 | + /* |
|
703 | 703 | * Added to fix https://github.com/owncloud/core/issues/22215 |
704 | 704 | * Can be removed once we get rid of ajax/share.php |
705 | 705 | */ |
706 | - $qb->setValue('file_target', $qb->createNamedParameter('')); |
|
707 | - |
|
708 | - $qb->execute(); |
|
709 | - $id = $qb->getLastInsertId(); |
|
710 | - |
|
711 | - return (int)$id; |
|
712 | - } |
|
713 | - |
|
714 | - /** |
|
715 | - * Update a share |
|
716 | - * |
|
717 | - * @param IShare $share |
|
718 | - * @param string|null $plainTextPassword |
|
719 | - * @return IShare The share object |
|
720 | - */ |
|
721 | - public function update(IShare $share, $plainTextPassword = null) { |
|
722 | - $originalShare = $this->getShareById($share->getId()); |
|
723 | - |
|
724 | - // a real password was given |
|
725 | - $validPassword = $plainTextPassword !== null && $plainTextPassword !== ''; |
|
726 | - |
|
727 | - if ($validPassword && ($originalShare->getPassword() !== $share->getPassword() || |
|
728 | - ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()))) { |
|
729 | - $this->sendPassword($share, $plainTextPassword); |
|
730 | - } |
|
731 | - /* |
|
706 | + $qb->setValue('file_target', $qb->createNamedParameter('')); |
|
707 | + |
|
708 | + $qb->execute(); |
|
709 | + $id = $qb->getLastInsertId(); |
|
710 | + |
|
711 | + return (int)$id; |
|
712 | + } |
|
713 | + |
|
714 | + /** |
|
715 | + * Update a share |
|
716 | + * |
|
717 | + * @param IShare $share |
|
718 | + * @param string|null $plainTextPassword |
|
719 | + * @return IShare The share object |
|
720 | + */ |
|
721 | + public function update(IShare $share, $plainTextPassword = null) { |
|
722 | + $originalShare = $this->getShareById($share->getId()); |
|
723 | + |
|
724 | + // a real password was given |
|
725 | + $validPassword = $plainTextPassword !== null && $plainTextPassword !== ''; |
|
726 | + |
|
727 | + if ($validPassword && ($originalShare->getPassword() !== $share->getPassword() || |
|
728 | + ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()))) { |
|
729 | + $this->sendPassword($share, $plainTextPassword); |
|
730 | + } |
|
731 | + /* |
|
732 | 732 | * We allow updating the permissions and password of mail shares |
733 | 733 | */ |
734 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
735 | - $qb->update('share') |
|
736 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) |
|
737 | - ->set('permissions', $qb->createNamedParameter($share->getPermissions())) |
|
738 | - ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) |
|
739 | - ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) |
|
740 | - ->set('password', $qb->createNamedParameter($share->getPassword())) |
|
741 | - ->set('password_by_talk', $qb->createNamedParameter($share->getSendPasswordByTalk(), IQueryBuilder::PARAM_BOOL)) |
|
742 | - ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) |
|
743 | - ->set('note', $qb->createNamedParameter($share->getNote())) |
|
744 | - ->set('hide_download', $qb->createNamedParameter((int)$share->getHideDownload(), IQueryBuilder::PARAM_INT)) |
|
745 | - ->execute(); |
|
746 | - |
|
747 | - if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') { |
|
748 | - $this->sendNote($share); |
|
749 | - } |
|
750 | - |
|
751 | - return $share; |
|
752 | - } |
|
753 | - |
|
754 | - /** |
|
755 | - * @inheritdoc |
|
756 | - */ |
|
757 | - public function move(IShare $share, $recipient) { |
|
758 | - /** |
|
759 | - * nothing to do here, mail shares are only outgoing shares |
|
760 | - */ |
|
761 | - return $share; |
|
762 | - } |
|
763 | - |
|
764 | - /** |
|
765 | - * Delete a share (owner unShares the file) |
|
766 | - * |
|
767 | - * @param IShare $share |
|
768 | - */ |
|
769 | - public function delete(IShare $share) { |
|
770 | - try { |
|
771 | - $this->createShareActivity($share, 'unshare'); |
|
772 | - } catch (\Exception $e) { |
|
773 | - } |
|
774 | - |
|
775 | - $this->removeShareFromTable($share->getId()); |
|
776 | - } |
|
777 | - |
|
778 | - /** |
|
779 | - * @inheritdoc |
|
780 | - */ |
|
781 | - public function deleteFromSelf(IShare $share, $recipient) { |
|
782 | - // nothing to do here, mail shares are only outgoing shares |
|
783 | - } |
|
784 | - |
|
785 | - public function restore(IShare $share, string $recipient): IShare { |
|
786 | - throw new GenericShareException('not implemented'); |
|
787 | - } |
|
788 | - |
|
789 | - /** |
|
790 | - * @inheritdoc |
|
791 | - */ |
|
792 | - public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) { |
|
793 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
794 | - $qb->select('*') |
|
795 | - ->from('share'); |
|
796 | - |
|
797 | - $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))); |
|
798 | - |
|
799 | - /** |
|
800 | - * Reshares for this user are shares where they are the owner. |
|
801 | - */ |
|
802 | - if ($reshares === false) { |
|
803 | - //Special case for old shares created via the web UI |
|
804 | - $or1 = $qb->expr()->andX( |
|
805 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
806 | - $qb->expr()->isNull('uid_initiator') |
|
807 | - ); |
|
808 | - |
|
809 | - $qb->andWhere( |
|
810 | - $qb->expr()->orX( |
|
811 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)), |
|
812 | - $or1 |
|
813 | - ) |
|
814 | - ); |
|
815 | - } else { |
|
816 | - $qb->andWhere( |
|
817 | - $qb->expr()->orX( |
|
818 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
819 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
820 | - ) |
|
821 | - ); |
|
822 | - } |
|
823 | - |
|
824 | - if ($node !== null) { |
|
825 | - $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
826 | - } |
|
827 | - |
|
828 | - if ($limit !== -1) { |
|
829 | - $qb->setMaxResults($limit); |
|
830 | - } |
|
831 | - |
|
832 | - $qb->setFirstResult($offset); |
|
833 | - $qb->orderBy('id'); |
|
834 | - |
|
835 | - $cursor = $qb->execute(); |
|
836 | - $shares = []; |
|
837 | - while ($data = $cursor->fetch()) { |
|
838 | - $shares[] = $this->createShareObject($data); |
|
839 | - } |
|
840 | - $cursor->closeCursor(); |
|
841 | - |
|
842 | - return $shares; |
|
843 | - } |
|
844 | - |
|
845 | - /** |
|
846 | - * @inheritdoc |
|
847 | - */ |
|
848 | - public function getShareById($id, $recipientId = null) { |
|
849 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
850 | - |
|
851 | - $qb->select('*') |
|
852 | - ->from('share') |
|
853 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) |
|
854 | - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))); |
|
855 | - |
|
856 | - $cursor = $qb->execute(); |
|
857 | - $data = $cursor->fetch(); |
|
858 | - $cursor->closeCursor(); |
|
859 | - |
|
860 | - if ($data === false) { |
|
861 | - throw new ShareNotFound(); |
|
862 | - } |
|
863 | - |
|
864 | - try { |
|
865 | - $share = $this->createShareObject($data); |
|
866 | - } catch (InvalidShare $e) { |
|
867 | - throw new ShareNotFound(); |
|
868 | - } |
|
869 | - |
|
870 | - return $share; |
|
871 | - } |
|
872 | - |
|
873 | - /** |
|
874 | - * Get shares for a given path |
|
875 | - * |
|
876 | - * @param \OCP\Files\Node $path |
|
877 | - * @return IShare[] |
|
878 | - */ |
|
879 | - public function getSharesByPath(Node $path) { |
|
880 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
881 | - |
|
882 | - $cursor = $qb->select('*') |
|
883 | - ->from('share') |
|
884 | - ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) |
|
885 | - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
886 | - ->execute(); |
|
887 | - |
|
888 | - $shares = []; |
|
889 | - while ($data = $cursor->fetch()) { |
|
890 | - $shares[] = $this->createShareObject($data); |
|
891 | - } |
|
892 | - $cursor->closeCursor(); |
|
893 | - |
|
894 | - return $shares; |
|
895 | - } |
|
896 | - |
|
897 | - /** |
|
898 | - * @inheritdoc |
|
899 | - */ |
|
900 | - public function getSharedWith($userId, $shareType, $node, $limit, $offset) { |
|
901 | - /** @var IShare[] $shares */ |
|
902 | - $shares = []; |
|
903 | - |
|
904 | - //Get shares directly with this user |
|
905 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
906 | - $qb->select('*') |
|
907 | - ->from('share'); |
|
908 | - |
|
909 | - // Order by id |
|
910 | - $qb->orderBy('id'); |
|
911 | - |
|
912 | - // Set limit and offset |
|
913 | - if ($limit !== -1) { |
|
914 | - $qb->setMaxResults($limit); |
|
915 | - } |
|
916 | - $qb->setFirstResult($offset); |
|
917 | - |
|
918 | - $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))); |
|
919 | - $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); |
|
920 | - |
|
921 | - // Filter by node if provided |
|
922 | - if ($node !== null) { |
|
923 | - $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
924 | - } |
|
925 | - |
|
926 | - $cursor = $qb->execute(); |
|
927 | - |
|
928 | - while ($data = $cursor->fetch()) { |
|
929 | - $shares[] = $this->createShareObject($data); |
|
930 | - } |
|
931 | - $cursor->closeCursor(); |
|
932 | - |
|
933 | - |
|
934 | - return $shares; |
|
935 | - } |
|
936 | - |
|
937 | - /** |
|
938 | - * Get a share by token |
|
939 | - * |
|
940 | - * @param string $token |
|
941 | - * @return IShare |
|
942 | - * @throws ShareNotFound |
|
943 | - */ |
|
944 | - public function getShareByToken($token) { |
|
945 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
946 | - |
|
947 | - $cursor = $qb->select('*') |
|
948 | - ->from('share') |
|
949 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
950 | - ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) |
|
951 | - ->execute(); |
|
952 | - |
|
953 | - $data = $cursor->fetch(); |
|
954 | - |
|
955 | - if ($data === false) { |
|
956 | - throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
957 | - } |
|
958 | - |
|
959 | - try { |
|
960 | - $share = $this->createShareObject($data); |
|
961 | - } catch (InvalidShare $e) { |
|
962 | - throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
963 | - } |
|
964 | - |
|
965 | - return $share; |
|
966 | - } |
|
967 | - |
|
968 | - /** |
|
969 | - * remove share from table |
|
970 | - * |
|
971 | - * @param string $shareId |
|
972 | - */ |
|
973 | - protected function removeShareFromTable($shareId) { |
|
974 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
975 | - $qb->delete('share') |
|
976 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId))); |
|
977 | - $qb->execute(); |
|
978 | - } |
|
979 | - |
|
980 | - /** |
|
981 | - * Create a share object from an database row |
|
982 | - * |
|
983 | - * @param array $data |
|
984 | - * @return IShare |
|
985 | - * @throws InvalidShare |
|
986 | - * @throws ShareNotFound |
|
987 | - */ |
|
988 | - protected function createShareObject($data) { |
|
989 | - $share = new Share($this->rootFolder, $this->userManager); |
|
990 | - $share->setId((int)$data['id']) |
|
991 | - ->setShareType((int)$data['share_type']) |
|
992 | - ->setPermissions((int)$data['permissions']) |
|
993 | - ->setTarget($data['file_target']) |
|
994 | - ->setMailSend((bool)$data['mail_send']) |
|
995 | - ->setNote($data['note']) |
|
996 | - ->setToken($data['token']); |
|
997 | - |
|
998 | - $shareTime = new \DateTime(); |
|
999 | - $shareTime->setTimestamp((int)$data['stime']); |
|
1000 | - $share->setShareTime($shareTime); |
|
1001 | - $share->setSharedWith($data['share_with']); |
|
1002 | - $share->setPassword($data['password']); |
|
1003 | - $share->setSendPasswordByTalk((bool)$data['password_by_talk']); |
|
1004 | - $share->setHideDownload((bool)$data['hide_download']); |
|
1005 | - |
|
1006 | - if ($data['uid_initiator'] !== null) { |
|
1007 | - $share->setShareOwner($data['uid_owner']); |
|
1008 | - $share->setSharedBy($data['uid_initiator']); |
|
1009 | - } else { |
|
1010 | - //OLD SHARE |
|
1011 | - $share->setSharedBy($data['uid_owner']); |
|
1012 | - $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
1013 | - |
|
1014 | - $owner = $path->getOwner(); |
|
1015 | - $share->setShareOwner($owner->getUID()); |
|
1016 | - } |
|
1017 | - |
|
1018 | - if ($data['expiration'] !== null) { |
|
1019 | - $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']); |
|
1020 | - if ($expiration !== false) { |
|
1021 | - $share->setExpirationDate($expiration); |
|
1022 | - } |
|
1023 | - } |
|
1024 | - |
|
1025 | - $share->setNodeId((int)$data['file_source']); |
|
1026 | - $share->setNodeType($data['item_type']); |
|
1027 | - |
|
1028 | - $share->setProviderId($this->identifier()); |
|
1029 | - |
|
1030 | - return $share; |
|
1031 | - } |
|
1032 | - |
|
1033 | - /** |
|
1034 | - * Get the node with file $id for $user |
|
1035 | - * |
|
1036 | - * @param string $userId |
|
1037 | - * @param int $id |
|
1038 | - * @return \OCP\Files\File|\OCP\Files\Folder |
|
1039 | - * @throws InvalidShare |
|
1040 | - */ |
|
1041 | - private function getNode($userId, $id) { |
|
1042 | - try { |
|
1043 | - $userFolder = $this->rootFolder->getUserFolder($userId); |
|
1044 | - } catch (NoUserException $e) { |
|
1045 | - throw new InvalidShare(); |
|
1046 | - } |
|
1047 | - |
|
1048 | - $nodes = $userFolder->getById($id); |
|
1049 | - |
|
1050 | - if (empty($nodes)) { |
|
1051 | - throw new InvalidShare(); |
|
1052 | - } |
|
1053 | - |
|
1054 | - return $nodes[0]; |
|
1055 | - } |
|
1056 | - |
|
1057 | - /** |
|
1058 | - * A user is deleted from the system |
|
1059 | - * So clean up the relevant shares. |
|
1060 | - * |
|
1061 | - * @param string $uid |
|
1062 | - * @param int $shareType |
|
1063 | - */ |
|
1064 | - public function userDeleted($uid, $shareType) { |
|
1065 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1066 | - |
|
1067 | - $qb->delete('share') |
|
1068 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
1069 | - ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))) |
|
1070 | - ->execute(); |
|
1071 | - } |
|
1072 | - |
|
1073 | - /** |
|
1074 | - * This provider does not support group shares |
|
1075 | - * |
|
1076 | - * @param string $gid |
|
1077 | - */ |
|
1078 | - public function groupDeleted($gid) { |
|
1079 | - } |
|
1080 | - |
|
1081 | - /** |
|
1082 | - * This provider does not support group shares |
|
1083 | - * |
|
1084 | - * @param string $uid |
|
1085 | - * @param string $gid |
|
1086 | - */ |
|
1087 | - public function userDeletedFromGroup($uid, $gid) { |
|
1088 | - } |
|
1089 | - |
|
1090 | - /** |
|
1091 | - * get database row of a give share |
|
1092 | - * |
|
1093 | - * @param $id |
|
1094 | - * @return array |
|
1095 | - * @throws ShareNotFound |
|
1096 | - */ |
|
1097 | - protected function getRawShare($id) { |
|
1098 | - |
|
1099 | - // Now fetch the inserted share and create a complete share object |
|
1100 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1101 | - $qb->select('*') |
|
1102 | - ->from('share') |
|
1103 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); |
|
1104 | - |
|
1105 | - $cursor = $qb->execute(); |
|
1106 | - $data = $cursor->fetch(); |
|
1107 | - $cursor->closeCursor(); |
|
1108 | - |
|
1109 | - if ($data === false) { |
|
1110 | - throw new ShareNotFound; |
|
1111 | - } |
|
1112 | - |
|
1113 | - return $data; |
|
1114 | - } |
|
1115 | - |
|
1116 | - public function getSharesInFolder($userId, Folder $node, $reshares) { |
|
1117 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1118 | - $qb->select('*') |
|
1119 | - ->from('share', 's') |
|
1120 | - ->andWhere($qb->expr()->orX( |
|
1121 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1122 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1123 | - )) |
|
1124 | - ->andWhere( |
|
1125 | - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)) |
|
1126 | - ); |
|
1127 | - |
|
1128 | - /** |
|
1129 | - * Reshares for this user are shares where they are the owner. |
|
1130 | - */ |
|
1131 | - if ($reshares === false) { |
|
1132 | - $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); |
|
1133 | - } else { |
|
1134 | - $qb->andWhere( |
|
1135 | - $qb->expr()->orX( |
|
1136 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
1137 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
1138 | - ) |
|
1139 | - ); |
|
1140 | - } |
|
1141 | - |
|
1142 | - $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
1143 | - $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
|
1144 | - |
|
1145 | - $qb->orderBy('id'); |
|
1146 | - |
|
1147 | - $cursor = $qb->execute(); |
|
1148 | - $shares = []; |
|
1149 | - while ($data = $cursor->fetch()) { |
|
1150 | - $shares[$data['fileid']][] = $this->createShareObject($data); |
|
1151 | - } |
|
1152 | - $cursor->closeCursor(); |
|
1153 | - |
|
1154 | - return $shares; |
|
1155 | - } |
|
1156 | - |
|
1157 | - /** |
|
1158 | - * @inheritdoc |
|
1159 | - */ |
|
1160 | - public function getAccessList($nodes, $currentAccess) { |
|
1161 | - $ids = []; |
|
1162 | - foreach ($nodes as $node) { |
|
1163 | - $ids[] = $node->getId(); |
|
1164 | - } |
|
1165 | - |
|
1166 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1167 | - $qb->select('share_with') |
|
1168 | - ->from('share') |
|
1169 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
1170 | - ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) |
|
1171 | - ->andWhere($qb->expr()->orX( |
|
1172 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1173 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1174 | - )) |
|
1175 | - ->setMaxResults(1); |
|
1176 | - $cursor = $qb->execute(); |
|
1177 | - |
|
1178 | - $mail = $cursor->fetch() !== false; |
|
1179 | - $cursor->closeCursor(); |
|
1180 | - |
|
1181 | - return ['public' => $mail]; |
|
1182 | - } |
|
1183 | - |
|
1184 | - public function getAllShares(): iterable { |
|
1185 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1186 | - |
|
1187 | - $qb->select('*') |
|
1188 | - ->from('share') |
|
1189 | - ->where( |
|
1190 | - $qb->expr()->orX( |
|
1191 | - $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_EMAIL)) |
|
1192 | - ) |
|
1193 | - ); |
|
1194 | - |
|
1195 | - $cursor = $qb->execute(); |
|
1196 | - while ($data = $cursor->fetch()) { |
|
1197 | - try { |
|
1198 | - $share = $this->createShareObject($data); |
|
1199 | - } catch (InvalidShare $e) { |
|
1200 | - continue; |
|
1201 | - } catch (ShareNotFound $e) { |
|
1202 | - continue; |
|
1203 | - } |
|
1204 | - |
|
1205 | - yield $share; |
|
1206 | - } |
|
1207 | - $cursor->closeCursor(); |
|
1208 | - } |
|
734 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
735 | + $qb->update('share') |
|
736 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) |
|
737 | + ->set('permissions', $qb->createNamedParameter($share->getPermissions())) |
|
738 | + ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) |
|
739 | + ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) |
|
740 | + ->set('password', $qb->createNamedParameter($share->getPassword())) |
|
741 | + ->set('password_by_talk', $qb->createNamedParameter($share->getSendPasswordByTalk(), IQueryBuilder::PARAM_BOOL)) |
|
742 | + ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) |
|
743 | + ->set('note', $qb->createNamedParameter($share->getNote())) |
|
744 | + ->set('hide_download', $qb->createNamedParameter((int)$share->getHideDownload(), IQueryBuilder::PARAM_INT)) |
|
745 | + ->execute(); |
|
746 | + |
|
747 | + if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') { |
|
748 | + $this->sendNote($share); |
|
749 | + } |
|
750 | + |
|
751 | + return $share; |
|
752 | + } |
|
753 | + |
|
754 | + /** |
|
755 | + * @inheritdoc |
|
756 | + */ |
|
757 | + public function move(IShare $share, $recipient) { |
|
758 | + /** |
|
759 | + * nothing to do here, mail shares are only outgoing shares |
|
760 | + */ |
|
761 | + return $share; |
|
762 | + } |
|
763 | + |
|
764 | + /** |
|
765 | + * Delete a share (owner unShares the file) |
|
766 | + * |
|
767 | + * @param IShare $share |
|
768 | + */ |
|
769 | + public function delete(IShare $share) { |
|
770 | + try { |
|
771 | + $this->createShareActivity($share, 'unshare'); |
|
772 | + } catch (\Exception $e) { |
|
773 | + } |
|
774 | + |
|
775 | + $this->removeShareFromTable($share->getId()); |
|
776 | + } |
|
777 | + |
|
778 | + /** |
|
779 | + * @inheritdoc |
|
780 | + */ |
|
781 | + public function deleteFromSelf(IShare $share, $recipient) { |
|
782 | + // nothing to do here, mail shares are only outgoing shares |
|
783 | + } |
|
784 | + |
|
785 | + public function restore(IShare $share, string $recipient): IShare { |
|
786 | + throw new GenericShareException('not implemented'); |
|
787 | + } |
|
788 | + |
|
789 | + /** |
|
790 | + * @inheritdoc |
|
791 | + */ |
|
792 | + public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) { |
|
793 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
794 | + $qb->select('*') |
|
795 | + ->from('share'); |
|
796 | + |
|
797 | + $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))); |
|
798 | + |
|
799 | + /** |
|
800 | + * Reshares for this user are shares where they are the owner. |
|
801 | + */ |
|
802 | + if ($reshares === false) { |
|
803 | + //Special case for old shares created via the web UI |
|
804 | + $or1 = $qb->expr()->andX( |
|
805 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
806 | + $qb->expr()->isNull('uid_initiator') |
|
807 | + ); |
|
808 | + |
|
809 | + $qb->andWhere( |
|
810 | + $qb->expr()->orX( |
|
811 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)), |
|
812 | + $or1 |
|
813 | + ) |
|
814 | + ); |
|
815 | + } else { |
|
816 | + $qb->andWhere( |
|
817 | + $qb->expr()->orX( |
|
818 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
819 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
820 | + ) |
|
821 | + ); |
|
822 | + } |
|
823 | + |
|
824 | + if ($node !== null) { |
|
825 | + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
826 | + } |
|
827 | + |
|
828 | + if ($limit !== -1) { |
|
829 | + $qb->setMaxResults($limit); |
|
830 | + } |
|
831 | + |
|
832 | + $qb->setFirstResult($offset); |
|
833 | + $qb->orderBy('id'); |
|
834 | + |
|
835 | + $cursor = $qb->execute(); |
|
836 | + $shares = []; |
|
837 | + while ($data = $cursor->fetch()) { |
|
838 | + $shares[] = $this->createShareObject($data); |
|
839 | + } |
|
840 | + $cursor->closeCursor(); |
|
841 | + |
|
842 | + return $shares; |
|
843 | + } |
|
844 | + |
|
845 | + /** |
|
846 | + * @inheritdoc |
|
847 | + */ |
|
848 | + public function getShareById($id, $recipientId = null) { |
|
849 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
850 | + |
|
851 | + $qb->select('*') |
|
852 | + ->from('share') |
|
853 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) |
|
854 | + ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))); |
|
855 | + |
|
856 | + $cursor = $qb->execute(); |
|
857 | + $data = $cursor->fetch(); |
|
858 | + $cursor->closeCursor(); |
|
859 | + |
|
860 | + if ($data === false) { |
|
861 | + throw new ShareNotFound(); |
|
862 | + } |
|
863 | + |
|
864 | + try { |
|
865 | + $share = $this->createShareObject($data); |
|
866 | + } catch (InvalidShare $e) { |
|
867 | + throw new ShareNotFound(); |
|
868 | + } |
|
869 | + |
|
870 | + return $share; |
|
871 | + } |
|
872 | + |
|
873 | + /** |
|
874 | + * Get shares for a given path |
|
875 | + * |
|
876 | + * @param \OCP\Files\Node $path |
|
877 | + * @return IShare[] |
|
878 | + */ |
|
879 | + public function getSharesByPath(Node $path) { |
|
880 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
881 | + |
|
882 | + $cursor = $qb->select('*') |
|
883 | + ->from('share') |
|
884 | + ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) |
|
885 | + ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
886 | + ->execute(); |
|
887 | + |
|
888 | + $shares = []; |
|
889 | + while ($data = $cursor->fetch()) { |
|
890 | + $shares[] = $this->createShareObject($data); |
|
891 | + } |
|
892 | + $cursor->closeCursor(); |
|
893 | + |
|
894 | + return $shares; |
|
895 | + } |
|
896 | + |
|
897 | + /** |
|
898 | + * @inheritdoc |
|
899 | + */ |
|
900 | + public function getSharedWith($userId, $shareType, $node, $limit, $offset) { |
|
901 | + /** @var IShare[] $shares */ |
|
902 | + $shares = []; |
|
903 | + |
|
904 | + //Get shares directly with this user |
|
905 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
906 | + $qb->select('*') |
|
907 | + ->from('share'); |
|
908 | + |
|
909 | + // Order by id |
|
910 | + $qb->orderBy('id'); |
|
911 | + |
|
912 | + // Set limit and offset |
|
913 | + if ($limit !== -1) { |
|
914 | + $qb->setMaxResults($limit); |
|
915 | + } |
|
916 | + $qb->setFirstResult($offset); |
|
917 | + |
|
918 | + $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))); |
|
919 | + $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); |
|
920 | + |
|
921 | + // Filter by node if provided |
|
922 | + if ($node !== null) { |
|
923 | + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
924 | + } |
|
925 | + |
|
926 | + $cursor = $qb->execute(); |
|
927 | + |
|
928 | + while ($data = $cursor->fetch()) { |
|
929 | + $shares[] = $this->createShareObject($data); |
|
930 | + } |
|
931 | + $cursor->closeCursor(); |
|
932 | + |
|
933 | + |
|
934 | + return $shares; |
|
935 | + } |
|
936 | + |
|
937 | + /** |
|
938 | + * Get a share by token |
|
939 | + * |
|
940 | + * @param string $token |
|
941 | + * @return IShare |
|
942 | + * @throws ShareNotFound |
|
943 | + */ |
|
944 | + public function getShareByToken($token) { |
|
945 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
946 | + |
|
947 | + $cursor = $qb->select('*') |
|
948 | + ->from('share') |
|
949 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
950 | + ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) |
|
951 | + ->execute(); |
|
952 | + |
|
953 | + $data = $cursor->fetch(); |
|
954 | + |
|
955 | + if ($data === false) { |
|
956 | + throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
957 | + } |
|
958 | + |
|
959 | + try { |
|
960 | + $share = $this->createShareObject($data); |
|
961 | + } catch (InvalidShare $e) { |
|
962 | + throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
963 | + } |
|
964 | + |
|
965 | + return $share; |
|
966 | + } |
|
967 | + |
|
968 | + /** |
|
969 | + * remove share from table |
|
970 | + * |
|
971 | + * @param string $shareId |
|
972 | + */ |
|
973 | + protected function removeShareFromTable($shareId) { |
|
974 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
975 | + $qb->delete('share') |
|
976 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId))); |
|
977 | + $qb->execute(); |
|
978 | + } |
|
979 | + |
|
980 | + /** |
|
981 | + * Create a share object from an database row |
|
982 | + * |
|
983 | + * @param array $data |
|
984 | + * @return IShare |
|
985 | + * @throws InvalidShare |
|
986 | + * @throws ShareNotFound |
|
987 | + */ |
|
988 | + protected function createShareObject($data) { |
|
989 | + $share = new Share($this->rootFolder, $this->userManager); |
|
990 | + $share->setId((int)$data['id']) |
|
991 | + ->setShareType((int)$data['share_type']) |
|
992 | + ->setPermissions((int)$data['permissions']) |
|
993 | + ->setTarget($data['file_target']) |
|
994 | + ->setMailSend((bool)$data['mail_send']) |
|
995 | + ->setNote($data['note']) |
|
996 | + ->setToken($data['token']); |
|
997 | + |
|
998 | + $shareTime = new \DateTime(); |
|
999 | + $shareTime->setTimestamp((int)$data['stime']); |
|
1000 | + $share->setShareTime($shareTime); |
|
1001 | + $share->setSharedWith($data['share_with']); |
|
1002 | + $share->setPassword($data['password']); |
|
1003 | + $share->setSendPasswordByTalk((bool)$data['password_by_talk']); |
|
1004 | + $share->setHideDownload((bool)$data['hide_download']); |
|
1005 | + |
|
1006 | + if ($data['uid_initiator'] !== null) { |
|
1007 | + $share->setShareOwner($data['uid_owner']); |
|
1008 | + $share->setSharedBy($data['uid_initiator']); |
|
1009 | + } else { |
|
1010 | + //OLD SHARE |
|
1011 | + $share->setSharedBy($data['uid_owner']); |
|
1012 | + $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
1013 | + |
|
1014 | + $owner = $path->getOwner(); |
|
1015 | + $share->setShareOwner($owner->getUID()); |
|
1016 | + } |
|
1017 | + |
|
1018 | + if ($data['expiration'] !== null) { |
|
1019 | + $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']); |
|
1020 | + if ($expiration !== false) { |
|
1021 | + $share->setExpirationDate($expiration); |
|
1022 | + } |
|
1023 | + } |
|
1024 | + |
|
1025 | + $share->setNodeId((int)$data['file_source']); |
|
1026 | + $share->setNodeType($data['item_type']); |
|
1027 | + |
|
1028 | + $share->setProviderId($this->identifier()); |
|
1029 | + |
|
1030 | + return $share; |
|
1031 | + } |
|
1032 | + |
|
1033 | + /** |
|
1034 | + * Get the node with file $id for $user |
|
1035 | + * |
|
1036 | + * @param string $userId |
|
1037 | + * @param int $id |
|
1038 | + * @return \OCP\Files\File|\OCP\Files\Folder |
|
1039 | + * @throws InvalidShare |
|
1040 | + */ |
|
1041 | + private function getNode($userId, $id) { |
|
1042 | + try { |
|
1043 | + $userFolder = $this->rootFolder->getUserFolder($userId); |
|
1044 | + } catch (NoUserException $e) { |
|
1045 | + throw new InvalidShare(); |
|
1046 | + } |
|
1047 | + |
|
1048 | + $nodes = $userFolder->getById($id); |
|
1049 | + |
|
1050 | + if (empty($nodes)) { |
|
1051 | + throw new InvalidShare(); |
|
1052 | + } |
|
1053 | + |
|
1054 | + return $nodes[0]; |
|
1055 | + } |
|
1056 | + |
|
1057 | + /** |
|
1058 | + * A user is deleted from the system |
|
1059 | + * So clean up the relevant shares. |
|
1060 | + * |
|
1061 | + * @param string $uid |
|
1062 | + * @param int $shareType |
|
1063 | + */ |
|
1064 | + public function userDeleted($uid, $shareType) { |
|
1065 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1066 | + |
|
1067 | + $qb->delete('share') |
|
1068 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
1069 | + ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))) |
|
1070 | + ->execute(); |
|
1071 | + } |
|
1072 | + |
|
1073 | + /** |
|
1074 | + * This provider does not support group shares |
|
1075 | + * |
|
1076 | + * @param string $gid |
|
1077 | + */ |
|
1078 | + public function groupDeleted($gid) { |
|
1079 | + } |
|
1080 | + |
|
1081 | + /** |
|
1082 | + * This provider does not support group shares |
|
1083 | + * |
|
1084 | + * @param string $uid |
|
1085 | + * @param string $gid |
|
1086 | + */ |
|
1087 | + public function userDeletedFromGroup($uid, $gid) { |
|
1088 | + } |
|
1089 | + |
|
1090 | + /** |
|
1091 | + * get database row of a give share |
|
1092 | + * |
|
1093 | + * @param $id |
|
1094 | + * @return array |
|
1095 | + * @throws ShareNotFound |
|
1096 | + */ |
|
1097 | + protected function getRawShare($id) { |
|
1098 | + |
|
1099 | + // Now fetch the inserted share and create a complete share object |
|
1100 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1101 | + $qb->select('*') |
|
1102 | + ->from('share') |
|
1103 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); |
|
1104 | + |
|
1105 | + $cursor = $qb->execute(); |
|
1106 | + $data = $cursor->fetch(); |
|
1107 | + $cursor->closeCursor(); |
|
1108 | + |
|
1109 | + if ($data === false) { |
|
1110 | + throw new ShareNotFound; |
|
1111 | + } |
|
1112 | + |
|
1113 | + return $data; |
|
1114 | + } |
|
1115 | + |
|
1116 | + public function getSharesInFolder($userId, Folder $node, $reshares) { |
|
1117 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1118 | + $qb->select('*') |
|
1119 | + ->from('share', 's') |
|
1120 | + ->andWhere($qb->expr()->orX( |
|
1121 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1122 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1123 | + )) |
|
1124 | + ->andWhere( |
|
1125 | + $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)) |
|
1126 | + ); |
|
1127 | + |
|
1128 | + /** |
|
1129 | + * Reshares for this user are shares where they are the owner. |
|
1130 | + */ |
|
1131 | + if ($reshares === false) { |
|
1132 | + $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); |
|
1133 | + } else { |
|
1134 | + $qb->andWhere( |
|
1135 | + $qb->expr()->orX( |
|
1136 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
1137 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
1138 | + ) |
|
1139 | + ); |
|
1140 | + } |
|
1141 | + |
|
1142 | + $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
1143 | + $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
|
1144 | + |
|
1145 | + $qb->orderBy('id'); |
|
1146 | + |
|
1147 | + $cursor = $qb->execute(); |
|
1148 | + $shares = []; |
|
1149 | + while ($data = $cursor->fetch()) { |
|
1150 | + $shares[$data['fileid']][] = $this->createShareObject($data); |
|
1151 | + } |
|
1152 | + $cursor->closeCursor(); |
|
1153 | + |
|
1154 | + return $shares; |
|
1155 | + } |
|
1156 | + |
|
1157 | + /** |
|
1158 | + * @inheritdoc |
|
1159 | + */ |
|
1160 | + public function getAccessList($nodes, $currentAccess) { |
|
1161 | + $ids = []; |
|
1162 | + foreach ($nodes as $node) { |
|
1163 | + $ids[] = $node->getId(); |
|
1164 | + } |
|
1165 | + |
|
1166 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1167 | + $qb->select('share_with') |
|
1168 | + ->from('share') |
|
1169 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))) |
|
1170 | + ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) |
|
1171 | + ->andWhere($qb->expr()->orX( |
|
1172 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1173 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1174 | + )) |
|
1175 | + ->setMaxResults(1); |
|
1176 | + $cursor = $qb->execute(); |
|
1177 | + |
|
1178 | + $mail = $cursor->fetch() !== false; |
|
1179 | + $cursor->closeCursor(); |
|
1180 | + |
|
1181 | + return ['public' => $mail]; |
|
1182 | + } |
|
1183 | + |
|
1184 | + public function getAllShares(): iterable { |
|
1185 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1186 | + |
|
1187 | + $qb->select('*') |
|
1188 | + ->from('share') |
|
1189 | + ->where( |
|
1190 | + $qb->expr()->orX( |
|
1191 | + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_EMAIL)) |
|
1192 | + ) |
|
1193 | + ); |
|
1194 | + |
|
1195 | + $cursor = $qb->execute(); |
|
1196 | + while ($data = $cursor->fetch()) { |
|
1197 | + try { |
|
1198 | + $share = $this->createShareObject($data); |
|
1199 | + } catch (InvalidShare $e) { |
|
1200 | + continue; |
|
1201 | + } catch (ShareNotFound $e) { |
|
1202 | + continue; |
|
1203 | + } |
|
1204 | + |
|
1205 | + yield $share; |
|
1206 | + } |
|
1207 | + $cursor->closeCursor(); |
|
1208 | + } |
|
1209 | 1209 | } |
@@ -58,788 +58,788 @@ |
||
58 | 58 | |
59 | 59 | class CloudFederationProviderFiles implements ICloudFederationProvider { |
60 | 60 | |
61 | - /** @var IAppManager */ |
|
62 | - private $appManager; |
|
63 | - |
|
64 | - /** @var FederatedShareProvider */ |
|
65 | - private $federatedShareProvider; |
|
66 | - |
|
67 | - /** @var AddressHandler */ |
|
68 | - private $addressHandler; |
|
69 | - |
|
70 | - /** @var ILogger */ |
|
71 | - private $logger; |
|
72 | - |
|
73 | - /** @var IUserManager */ |
|
74 | - private $userManager; |
|
75 | - |
|
76 | - /** @var IManager */ |
|
77 | - private $shareManager; |
|
78 | - |
|
79 | - /** @var ICloudIdManager */ |
|
80 | - private $cloudIdManager; |
|
81 | - |
|
82 | - /** @var IActivityManager */ |
|
83 | - private $activityManager; |
|
84 | - |
|
85 | - /** @var INotificationManager */ |
|
86 | - private $notificationManager; |
|
87 | - |
|
88 | - /** @var IURLGenerator */ |
|
89 | - private $urlGenerator; |
|
90 | - |
|
91 | - /** @var ICloudFederationFactory */ |
|
92 | - private $cloudFederationFactory; |
|
93 | - |
|
94 | - /** @var ICloudFederationProviderManager */ |
|
95 | - private $cloudFederationProviderManager; |
|
96 | - |
|
97 | - /** @var IDBConnection */ |
|
98 | - private $connection; |
|
99 | - |
|
100 | - /** @var IGroupManager */ |
|
101 | - private $groupManager; |
|
102 | - |
|
103 | - /** |
|
104 | - * CloudFederationProvider constructor. |
|
105 | - * |
|
106 | - * @param IAppManager $appManager |
|
107 | - * @param FederatedShareProvider $federatedShareProvider |
|
108 | - * @param AddressHandler $addressHandler |
|
109 | - * @param ILogger $logger |
|
110 | - * @param IUserManager $userManager |
|
111 | - * @param IManager $shareManager |
|
112 | - * @param ICloudIdManager $cloudIdManager |
|
113 | - * @param IActivityManager $activityManager |
|
114 | - * @param INotificationManager $notificationManager |
|
115 | - * @param IURLGenerator $urlGenerator |
|
116 | - * @param ICloudFederationFactory $cloudFederationFactory |
|
117 | - * @param ICloudFederationProviderManager $cloudFederationProviderManager |
|
118 | - * @param IDBConnection $connection |
|
119 | - * @param IGroupManager $groupManager |
|
120 | - */ |
|
121 | - public function __construct(IAppManager $appManager, |
|
122 | - FederatedShareProvider $federatedShareProvider, |
|
123 | - AddressHandler $addressHandler, |
|
124 | - ILogger $logger, |
|
125 | - IUserManager $userManager, |
|
126 | - IManager $shareManager, |
|
127 | - ICloudIdManager $cloudIdManager, |
|
128 | - IActivityManager $activityManager, |
|
129 | - INotificationManager $notificationManager, |
|
130 | - IURLGenerator $urlGenerator, |
|
131 | - ICloudFederationFactory $cloudFederationFactory, |
|
132 | - ICloudFederationProviderManager $cloudFederationProviderManager, |
|
133 | - IDBConnection $connection, |
|
134 | - IGroupManager $groupManager |
|
135 | - ) { |
|
136 | - $this->appManager = $appManager; |
|
137 | - $this->federatedShareProvider = $federatedShareProvider; |
|
138 | - $this->addressHandler = $addressHandler; |
|
139 | - $this->logger = $logger; |
|
140 | - $this->userManager = $userManager; |
|
141 | - $this->shareManager = $shareManager; |
|
142 | - $this->cloudIdManager = $cloudIdManager; |
|
143 | - $this->activityManager = $activityManager; |
|
144 | - $this->notificationManager = $notificationManager; |
|
145 | - $this->urlGenerator = $urlGenerator; |
|
146 | - $this->cloudFederationFactory = $cloudFederationFactory; |
|
147 | - $this->cloudFederationProviderManager = $cloudFederationProviderManager; |
|
148 | - $this->connection = $connection; |
|
149 | - $this->groupManager = $groupManager; |
|
150 | - } |
|
151 | - |
|
152 | - |
|
153 | - |
|
154 | - /** |
|
155 | - * @return string |
|
156 | - */ |
|
157 | - public function getShareType() { |
|
158 | - return 'file'; |
|
159 | - } |
|
160 | - |
|
161 | - /** |
|
162 | - * share received from another server |
|
163 | - * |
|
164 | - * @param ICloudFederationShare $share |
|
165 | - * @return string provider specific unique ID of the share |
|
166 | - * |
|
167 | - * @throws ProviderCouldNotAddShareException |
|
168 | - * @throws \OCP\AppFramework\QueryException |
|
169 | - * @throws \OC\HintException |
|
170 | - * @since 14.0.0 |
|
171 | - */ |
|
172 | - public function shareReceived(ICloudFederationShare $share) { |
|
173 | - if (!$this->isS2SEnabled(true)) { |
|
174 | - throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE); |
|
175 | - } |
|
176 | - |
|
177 | - $protocol = $share->getProtocol(); |
|
178 | - if ($protocol['name'] !== 'webdav') { |
|
179 | - throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED); |
|
180 | - } |
|
181 | - |
|
182 | - list($ownerUid, $remote) = $this->addressHandler->splitUserRemote($share->getOwner()); |
|
183 | - // for backward compatibility make sure that the remote url stored in the |
|
184 | - // database ends with a trailing slash |
|
185 | - if (substr($remote, -1) !== '/') { |
|
186 | - $remote = $remote . '/'; |
|
187 | - } |
|
188 | - |
|
189 | - $token = $share->getShareSecret(); |
|
190 | - $name = $share->getResourceName(); |
|
191 | - $owner = $share->getOwnerDisplayName(); |
|
192 | - $sharedBy = $share->getSharedByDisplayName(); |
|
193 | - $shareWith = $share->getShareWith(); |
|
194 | - $remoteId = $share->getProviderId(); |
|
195 | - $sharedByFederatedId = $share->getSharedBy(); |
|
196 | - $ownerFederatedId = $share->getOwner(); |
|
197 | - $shareType = $this->mapShareTypeToNextcloud($share->getShareType()); |
|
198 | - |
|
199 | - // if no explicit information about the person who created the share was send |
|
200 | - // we assume that the share comes from the owner |
|
201 | - if ($sharedByFederatedId === null) { |
|
202 | - $sharedBy = $owner; |
|
203 | - $sharedByFederatedId = $ownerFederatedId; |
|
204 | - } |
|
205 | - |
|
206 | - if ($remote && $token && $name && $owner && $remoteId && $shareWith) { |
|
207 | - if (!Util::isValidFileName($name)) { |
|
208 | - throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST); |
|
209 | - } |
|
210 | - |
|
211 | - // FIXME this should be a method in the user management instead |
|
212 | - if ($shareType === IShare::TYPE_USER) { |
|
213 | - $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']); |
|
214 | - Util::emitHook( |
|
215 | - '\OCA\Files_Sharing\API\Server2Server', |
|
216 | - 'preLoginNameUsedAsUserName', |
|
217 | - ['uid' => &$shareWith] |
|
218 | - ); |
|
219 | - $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']); |
|
220 | - |
|
221 | - if (!$this->userManager->userExists($shareWith)) { |
|
222 | - throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST); |
|
223 | - } |
|
224 | - |
|
225 | - \OC_Util::setupFS($shareWith); |
|
226 | - } |
|
227 | - |
|
228 | - if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) { |
|
229 | - throw new ProviderCouldNotAddShareException('Group does not exists', '',Http::STATUS_BAD_REQUEST); |
|
230 | - } |
|
231 | - |
|
232 | - $externalManager = new \OCA\Files_Sharing\External\Manager( |
|
233 | - \OC::$server->getDatabaseConnection(), |
|
234 | - Filesystem::getMountManager(), |
|
235 | - Filesystem::getLoader(), |
|
236 | - \OC::$server->getHTTPClientService(), |
|
237 | - \OC::$server->getNotificationManager(), |
|
238 | - \OC::$server->query(\OCP\OCS\IDiscoveryService::class), |
|
239 | - \OC::$server->getCloudFederationProviderManager(), |
|
240 | - \OC::$server->getCloudFederationFactory(), |
|
241 | - \OC::$server->getGroupManager(), |
|
242 | - \OC::$server->getUserManager(), |
|
243 | - $shareWith |
|
244 | - ); |
|
245 | - |
|
246 | - try { |
|
247 | - $externalManager->addShare($remote, $token, '', $name, $owner, $shareType,false, $shareWith, $remoteId); |
|
248 | - $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external'); |
|
249 | - |
|
250 | - if ($shareType === IShare::TYPE_USER) { |
|
251 | - $event = $this->activityManager->generateEvent(); |
|
252 | - $event->setApp('files_sharing') |
|
253 | - ->setType('remote_share') |
|
254 | - ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')]) |
|
255 | - ->setAffectedUser($shareWith) |
|
256 | - ->setObject('remote_share', (int)$shareId, $name); |
|
257 | - \OC::$server->getActivityManager()->publish($event); |
|
258 | - $this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $sharedBy, $owner); |
|
259 | - } else { |
|
260 | - $groupMembers = $this->groupManager->get($shareWith)->getUsers(); |
|
261 | - foreach ($groupMembers as $user) { |
|
262 | - $event = $this->activityManager->generateEvent(); |
|
263 | - $event->setApp('files_sharing') |
|
264 | - ->setType('remote_share') |
|
265 | - ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')]) |
|
266 | - ->setAffectedUser($user->getUID()) |
|
267 | - ->setObject('remote_share', (int)$shareId, $name); |
|
268 | - \OC::$server->getActivityManager()->publish($event); |
|
269 | - $this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $sharedBy, $owner); |
|
270 | - } |
|
271 | - } |
|
272 | - return $shareId; |
|
273 | - } catch (\Exception $e) { |
|
274 | - $this->logger->logException($e, [ |
|
275 | - 'message' => 'Server can not add remote share.', |
|
276 | - 'level' => ILogger::ERROR, |
|
277 | - 'app' => 'files_sharing' |
|
278 | - ]); |
|
279 | - throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR); |
|
280 | - } |
|
281 | - } |
|
282 | - |
|
283 | - throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST); |
|
284 | - } |
|
285 | - |
|
286 | - /** |
|
287 | - * notification received from another server |
|
288 | - * |
|
289 | - * @param string $notificationType (e.g. SHARE_ACCEPTED) |
|
290 | - * @param string $providerId id of the share |
|
291 | - * @param array $notification payload of the notification |
|
292 | - * @return array data send back to the sender |
|
293 | - * |
|
294 | - * @throws ActionNotSupportedException |
|
295 | - * @throws AuthenticationFailedException |
|
296 | - * @throws BadRequestException |
|
297 | - * @throws \OC\HintException |
|
298 | - * @since 14.0.0 |
|
299 | - */ |
|
300 | - public function notificationReceived($notificationType, $providerId, array $notification) { |
|
301 | - switch ($notificationType) { |
|
302 | - case 'SHARE_ACCEPTED': |
|
303 | - return $this->shareAccepted($providerId, $notification); |
|
304 | - case 'SHARE_DECLINED': |
|
305 | - return $this->shareDeclined($providerId, $notification); |
|
306 | - case 'SHARE_UNSHARED': |
|
307 | - return $this->unshare($providerId, $notification); |
|
308 | - case 'REQUEST_RESHARE': |
|
309 | - return $this->reshareRequested($providerId, $notification); |
|
310 | - case 'RESHARE_UNDO': |
|
311 | - return $this->undoReshare($providerId, $notification); |
|
312 | - case 'RESHARE_CHANGE_PERMISSION': |
|
313 | - return $this->updateResharePermissions($providerId, $notification); |
|
314 | - } |
|
315 | - |
|
316 | - |
|
317 | - throw new BadRequestException([$notificationType]); |
|
318 | - } |
|
319 | - |
|
320 | - /** |
|
321 | - * map OCM share type (strings) to Nextcloud internal share types (integer) |
|
322 | - * |
|
323 | - * @param string $shareType |
|
324 | - * @return int |
|
325 | - */ |
|
326 | - private function mapShareTypeToNextcloud($shareType) { |
|
327 | - $result = IShare::TYPE_USER; |
|
328 | - if ($shareType === 'group') { |
|
329 | - $result = IShare::TYPE_GROUP; |
|
330 | - } |
|
331 | - |
|
332 | - return $result; |
|
333 | - } |
|
334 | - |
|
335 | - /** |
|
336 | - * notify user about new federated share |
|
337 | - * |
|
338 | - * @param $shareWith |
|
339 | - * @param $shareId |
|
340 | - * @param $ownerFederatedId |
|
341 | - * @param $sharedByFederatedId |
|
342 | - * @param $name |
|
343 | - */ |
|
344 | - private function notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $sharedBy, $owner) { |
|
345 | - $notification = $this->notificationManager->createNotification(); |
|
346 | - $notification->setApp('files_sharing') |
|
347 | - ->setUser($shareWith) |
|
348 | - ->setDateTime(new \DateTime()) |
|
349 | - ->setObject('remote_share', $shareId) |
|
350 | - ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/'), $sharedBy, $owner]); |
|
351 | - |
|
352 | - $declineAction = $notification->createAction(); |
|
353 | - $declineAction->setLabel('decline') |
|
354 | - ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE'); |
|
355 | - $notification->addAction($declineAction); |
|
356 | - |
|
357 | - $acceptAction = $notification->createAction(); |
|
358 | - $acceptAction->setLabel('accept') |
|
359 | - ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST'); |
|
360 | - $notification->addAction($acceptAction); |
|
361 | - |
|
362 | - $this->notificationManager->notify($notification); |
|
363 | - } |
|
364 | - |
|
365 | - /** |
|
366 | - * process notification that the recipient accepted a share |
|
367 | - * |
|
368 | - * @param string $id |
|
369 | - * @param array $notification |
|
370 | - * @return array |
|
371 | - * @throws ActionNotSupportedException |
|
372 | - * @throws AuthenticationFailedException |
|
373 | - * @throws BadRequestException |
|
374 | - * @throws \OC\HintException |
|
375 | - */ |
|
376 | - private function shareAccepted($id, array $notification) { |
|
377 | - if (!$this->isS2SEnabled()) { |
|
378 | - throw new ActionNotSupportedException('Server does not support federated cloud sharing'); |
|
379 | - } |
|
380 | - |
|
381 | - if (!isset($notification['sharedSecret'])) { |
|
382 | - throw new BadRequestException(['sharedSecret']); |
|
383 | - } |
|
384 | - |
|
385 | - $token = $notification['sharedSecret']; |
|
386 | - |
|
387 | - $share = $this->federatedShareProvider->getShareById($id); |
|
388 | - |
|
389 | - $this->verifyShare($share, $token); |
|
390 | - $this->executeAcceptShare($share); |
|
391 | - if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
392 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
393 | - $remoteId = $this->federatedShareProvider->getRemoteId($share); |
|
394 | - $notification = $this->cloudFederationFactory->getCloudFederationNotification(); |
|
395 | - $notification->setMessage( |
|
396 | - 'SHARE_ACCEPTED', |
|
397 | - 'file', |
|
398 | - $remoteId, |
|
399 | - [ |
|
400 | - 'sharedSecret' => $token, |
|
401 | - 'message' => 'Recipient accepted the re-share' |
|
402 | - ] |
|
403 | - |
|
404 | - ); |
|
405 | - $this->cloudFederationProviderManager->sendNotification($remote, $notification); |
|
406 | - } |
|
407 | - |
|
408 | - return []; |
|
409 | - } |
|
410 | - |
|
411 | - /** |
|
412 | - * @param IShare $share |
|
413 | - * @throws ShareNotFound |
|
414 | - */ |
|
415 | - protected function executeAcceptShare(IShare $share) { |
|
416 | - try { |
|
417 | - $fileId = (int)$share->getNode()->getId(); |
|
418 | - list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId); |
|
419 | - } catch (\Exception $e) { |
|
420 | - throw new ShareNotFound(); |
|
421 | - } |
|
422 | - |
|
423 | - $event = $this->activityManager->generateEvent(); |
|
424 | - $event->setApp('files_sharing') |
|
425 | - ->setType('remote_share') |
|
426 | - ->setAffectedUser($this->getCorrectUid($share)) |
|
427 | - ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]]) |
|
428 | - ->setObject('files', $fileId, $file) |
|
429 | - ->setLink($link); |
|
430 | - $this->activityManager->publish($event); |
|
431 | - } |
|
432 | - |
|
433 | - /** |
|
434 | - * process notification that the recipient declined a share |
|
435 | - * |
|
436 | - * @param string $id |
|
437 | - * @param array $notification |
|
438 | - * @return array |
|
439 | - * @throws ActionNotSupportedException |
|
440 | - * @throws AuthenticationFailedException |
|
441 | - * @throws BadRequestException |
|
442 | - * @throws ShareNotFound |
|
443 | - * @throws \OC\HintException |
|
444 | - * |
|
445 | - */ |
|
446 | - protected function shareDeclined($id, array $notification) { |
|
447 | - if (!$this->isS2SEnabled()) { |
|
448 | - throw new ActionNotSupportedException('Server does not support federated cloud sharing'); |
|
449 | - } |
|
450 | - |
|
451 | - if (!isset($notification['sharedSecret'])) { |
|
452 | - throw new BadRequestException(['sharedSecret']); |
|
453 | - } |
|
454 | - |
|
455 | - $token = $notification['sharedSecret']; |
|
456 | - |
|
457 | - $share = $this->federatedShareProvider->getShareById($id); |
|
458 | - |
|
459 | - $this->verifyShare($share, $token); |
|
460 | - |
|
461 | - if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
462 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
463 | - $remoteId = $this->federatedShareProvider->getRemoteId($share); |
|
464 | - $notification = $this->cloudFederationFactory->getCloudFederationNotification(); |
|
465 | - $notification->setMessage( |
|
466 | - 'SHARE_DECLINED', |
|
467 | - 'file', |
|
468 | - $remoteId, |
|
469 | - [ |
|
470 | - 'sharedSecret' => $token, |
|
471 | - 'message' => 'Recipient declined the re-share' |
|
472 | - ] |
|
473 | - |
|
474 | - ); |
|
475 | - $this->cloudFederationProviderManager->sendNotification($remote, $notification); |
|
476 | - } |
|
477 | - |
|
478 | - $this->executeDeclineShare($share); |
|
479 | - |
|
480 | - return []; |
|
481 | - } |
|
482 | - |
|
483 | - /** |
|
484 | - * delete declined share and create a activity |
|
485 | - * |
|
486 | - * @param IShare $share |
|
487 | - * @throws ShareNotFound |
|
488 | - */ |
|
489 | - protected function executeDeclineShare(IShare $share) { |
|
490 | - $this->federatedShareProvider->removeShareFromTable($share); |
|
491 | - |
|
492 | - try { |
|
493 | - $fileId = (int)$share->getNode()->getId(); |
|
494 | - list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId); |
|
495 | - } catch (\Exception $e) { |
|
496 | - throw new ShareNotFound(); |
|
497 | - } |
|
498 | - |
|
499 | - $event = $this->activityManager->generateEvent(); |
|
500 | - $event->setApp('files_sharing') |
|
501 | - ->setType('remote_share') |
|
502 | - ->setAffectedUser($this->getCorrectUid($share)) |
|
503 | - ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]]) |
|
504 | - ->setObject('files', $fileId, $file) |
|
505 | - ->setLink($link); |
|
506 | - $this->activityManager->publish($event); |
|
507 | - } |
|
508 | - |
|
509 | - /** |
|
510 | - * received the notification that the owner unshared a file from you |
|
511 | - * |
|
512 | - * @param string $id |
|
513 | - * @param array $notification |
|
514 | - * @return array |
|
515 | - * @throws AuthenticationFailedException |
|
516 | - * @throws BadRequestException |
|
517 | - */ |
|
518 | - private function undoReshare($id, array $notification) { |
|
519 | - if (!isset($notification['sharedSecret'])) { |
|
520 | - throw new BadRequestException(['sharedSecret']); |
|
521 | - } |
|
522 | - $token = $notification['sharedSecret']; |
|
523 | - |
|
524 | - $share = $this->federatedShareProvider->getShareById($id); |
|
525 | - |
|
526 | - $this->verifyShare($share, $token); |
|
527 | - $this->federatedShareProvider->removeShareFromTable($share); |
|
528 | - return []; |
|
529 | - } |
|
530 | - |
|
531 | - /** |
|
532 | - * unshare file from self |
|
533 | - * |
|
534 | - * @param string $id |
|
535 | - * @param array $notification |
|
536 | - * @return array |
|
537 | - * @throws ActionNotSupportedException |
|
538 | - * @throws BadRequestException |
|
539 | - */ |
|
540 | - private function unshare($id, array $notification) { |
|
541 | - if (!$this->isS2SEnabled(true)) { |
|
542 | - throw new ActionNotSupportedException("incoming shares disabled!"); |
|
543 | - } |
|
544 | - |
|
545 | - if (!isset($notification['sharedSecret'])) { |
|
546 | - throw new BadRequestException(['sharedSecret']); |
|
547 | - } |
|
548 | - $token = $notification['sharedSecret']; |
|
549 | - |
|
550 | - $qb = $this->connection->getQueryBuilder(); |
|
551 | - $qb->select('*') |
|
552 | - ->from('share_external') |
|
553 | - ->where( |
|
554 | - $qb->expr()->andX( |
|
555 | - $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)), |
|
556 | - $qb->expr()->eq('share_token', $qb->createNamedParameter($token)) |
|
557 | - ) |
|
558 | - ); |
|
559 | - |
|
560 | - $result = $qb->execute(); |
|
561 | - $share = $result->fetch(); |
|
562 | - $result->closeCursor(); |
|
563 | - |
|
564 | - if ($token && $id && !empty($share)) { |
|
565 | - $remote = $this->cleanupRemote($share['remote']); |
|
566 | - |
|
567 | - $owner = $this->cloudIdManager->getCloudId($share['owner'], $remote); |
|
568 | - $mountpoint = $share['mountpoint']; |
|
569 | - $user = $share['user']; |
|
570 | - |
|
571 | - $qb = $this->connection->getQueryBuilder(); |
|
572 | - $qb->delete('share_external') |
|
573 | - ->where( |
|
574 | - $qb->expr()->andX( |
|
575 | - $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)), |
|
576 | - $qb->expr()->eq('share_token', $qb->createNamedParameter($token)) |
|
577 | - ) |
|
578 | - ); |
|
579 | - |
|
580 | - $qb->execute(); |
|
581 | - |
|
582 | - // delete all child in case of a group share |
|
583 | - $qb = $this->connection->getQueryBuilder(); |
|
584 | - $qb->delete('share_external') |
|
585 | - ->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id']))); |
|
586 | - $qb->execute(); |
|
587 | - |
|
588 | - if ((int)$share['share_type'] === IShare::TYPE_USER) { |
|
589 | - if ($share['accepted']) { |
|
590 | - $path = trim($mountpoint, '/'); |
|
591 | - } else { |
|
592 | - $path = trim($share['name'], '/'); |
|
593 | - } |
|
594 | - $notification = $this->notificationManager->createNotification(); |
|
595 | - $notification->setApp('files_sharing') |
|
596 | - ->setUser($share['user']) |
|
597 | - ->setObject('remote_share', (int)$share['id']); |
|
598 | - $this->notificationManager->markProcessed($notification); |
|
599 | - |
|
600 | - $event = $this->activityManager->generateEvent(); |
|
601 | - $event->setApp('files_sharing') |
|
602 | - ->setType('remote_share') |
|
603 | - ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path]) |
|
604 | - ->setAffectedUser($user) |
|
605 | - ->setObject('remote_share', (int)$share['id'], $path); |
|
606 | - \OC::$server->getActivityManager()->publish($event); |
|
607 | - } |
|
608 | - } |
|
609 | - |
|
610 | - return []; |
|
611 | - } |
|
612 | - |
|
613 | - private function cleanupRemote($remote) { |
|
614 | - $remote = substr($remote, strpos($remote, '://') + 3); |
|
615 | - |
|
616 | - return rtrim($remote, '/'); |
|
617 | - } |
|
618 | - |
|
619 | - /** |
|
620 | - * recipient of a share request to re-share the file with another user |
|
621 | - * |
|
622 | - * @param string $id |
|
623 | - * @param array $notification |
|
624 | - * @return array |
|
625 | - * @throws AuthenticationFailedException |
|
626 | - * @throws BadRequestException |
|
627 | - * @throws ProviderCouldNotAddShareException |
|
628 | - * @throws ShareNotFound |
|
629 | - */ |
|
630 | - protected function reshareRequested($id, array $notification) { |
|
631 | - if (!isset($notification['sharedSecret'])) { |
|
632 | - throw new BadRequestException(['sharedSecret']); |
|
633 | - } |
|
634 | - $token = $notification['sharedSecret']; |
|
635 | - |
|
636 | - if (!isset($notification['shareWith'])) { |
|
637 | - throw new BadRequestException(['shareWith']); |
|
638 | - } |
|
639 | - $shareWith = $notification['shareWith']; |
|
640 | - |
|
641 | - if (!isset($notification['senderId'])) { |
|
642 | - throw new BadRequestException(['senderId']); |
|
643 | - } |
|
644 | - $senderId = $notification['senderId']; |
|
645 | - |
|
646 | - $share = $this->federatedShareProvider->getShareById($id); |
|
647 | - // don't allow to share a file back to the owner |
|
648 | - try { |
|
649 | - list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); |
|
650 | - $owner = $share->getShareOwner(); |
|
651 | - $currentServer = $this->addressHandler->generateRemoteURL(); |
|
652 | - if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) { |
|
653 | - throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id); |
|
654 | - } |
|
655 | - } catch (\Exception $e) { |
|
656 | - throw new ProviderCouldNotAddShareException($e->getMessage()); |
|
657 | - } |
|
658 | - |
|
659 | - $this->verifyShare($share, $token); |
|
660 | - |
|
661 | - // check if re-sharing is allowed |
|
662 | - if ($share->getPermissions() & Constants::PERMISSION_SHARE) { |
|
663 | - // the recipient of the initial share is now the initiator for the re-share |
|
664 | - $share->setSharedBy($share->getSharedWith()); |
|
665 | - $share->setSharedWith($shareWith); |
|
666 | - $result = $this->federatedShareProvider->create($share); |
|
667 | - $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId); |
|
668 | - return ['token' => $result->getToken(), 'providerId' => $result->getId()]; |
|
669 | - } else { |
|
670 | - throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id); |
|
671 | - } |
|
672 | - } |
|
673 | - |
|
674 | - /** |
|
675 | - * update permission of a re-share so that the share dialog shows the right |
|
676 | - * permission if the owner or the sender changes the permission |
|
677 | - * |
|
678 | - * @param string $id |
|
679 | - * @param array $notification |
|
680 | - * @return array |
|
681 | - * @throws AuthenticationFailedException |
|
682 | - * @throws BadRequestException |
|
683 | - */ |
|
684 | - protected function updateResharePermissions($id, array $notification) { |
|
685 | - if (!isset($notification['sharedSecret'])) { |
|
686 | - throw new BadRequestException(['sharedSecret']); |
|
687 | - } |
|
688 | - $token = $notification['sharedSecret']; |
|
689 | - |
|
690 | - if (!isset($notification['permission'])) { |
|
691 | - throw new BadRequestException(['permission']); |
|
692 | - } |
|
693 | - $ocmPermissions = $notification['permission']; |
|
694 | - |
|
695 | - $share = $this->federatedShareProvider->getShareById($id); |
|
696 | - |
|
697 | - $ncPermission = $this->ocmPermissions2ncPermissions($ocmPermissions); |
|
698 | - |
|
699 | - $this->verifyShare($share, $token); |
|
700 | - $this->updatePermissionsInDatabase($share, $ncPermission); |
|
701 | - |
|
702 | - return []; |
|
703 | - } |
|
704 | - |
|
705 | - /** |
|
706 | - * translate OCM Permissions to Nextcloud permissions |
|
707 | - * |
|
708 | - * @param array $ocmPermissions |
|
709 | - * @return int |
|
710 | - * @throws BadRequestException |
|
711 | - */ |
|
712 | - protected function ocmPermissions2ncPermissions(array $ocmPermissions) { |
|
713 | - $ncPermissions = 0; |
|
714 | - foreach ($ocmPermissions as $permission) { |
|
715 | - switch (strtolower($permission)) { |
|
716 | - case 'read': |
|
717 | - $ncPermissions += Constants::PERMISSION_READ; |
|
718 | - break; |
|
719 | - case 'write': |
|
720 | - $ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE; |
|
721 | - break; |
|
722 | - case 'share': |
|
723 | - $ncPermissions += Constants::PERMISSION_SHARE; |
|
724 | - break; |
|
725 | - default: |
|
726 | - throw new BadRequestException(['permission']); |
|
727 | - } |
|
728 | - } |
|
729 | - |
|
730 | - return $ncPermissions; |
|
731 | - } |
|
732 | - |
|
733 | - /** |
|
734 | - * update permissions in database |
|
735 | - * |
|
736 | - * @param IShare $share |
|
737 | - * @param int $permissions |
|
738 | - */ |
|
739 | - protected function updatePermissionsInDatabase(IShare $share, $permissions) { |
|
740 | - $query = $this->connection->getQueryBuilder(); |
|
741 | - $query->update('share') |
|
742 | - ->where($query->expr()->eq('id', $query->createNamedParameter($share->getId()))) |
|
743 | - ->set('permissions', $query->createNamedParameter($permissions)) |
|
744 | - ->execute(); |
|
745 | - } |
|
746 | - |
|
747 | - |
|
748 | - /** |
|
749 | - * get file |
|
750 | - * |
|
751 | - * @param string $user |
|
752 | - * @param int $fileSource |
|
753 | - * @return array with internal path of the file and a absolute link to it |
|
754 | - */ |
|
755 | - private function getFile($user, $fileSource) { |
|
756 | - \OC_Util::setupFS($user); |
|
757 | - |
|
758 | - try { |
|
759 | - $file = Filesystem::getPath($fileSource); |
|
760 | - } catch (NotFoundException $e) { |
|
761 | - $file = null; |
|
762 | - } |
|
763 | - $args = Filesystem::is_dir($file) ? ['dir' => $file] : ['dir' => dirname($file), 'scrollto' => $file]; |
|
764 | - $link = Util::linkToAbsolute('files', 'index.php', $args); |
|
765 | - |
|
766 | - return [$file, $link]; |
|
767 | - } |
|
768 | - |
|
769 | - /** |
|
770 | - * check if we are the initiator or the owner of a re-share and return the correct UID |
|
771 | - * |
|
772 | - * @param IShare $share |
|
773 | - * @return string |
|
774 | - */ |
|
775 | - protected function getCorrectUid(IShare $share) { |
|
776 | - if ($this->userManager->userExists($share->getShareOwner())) { |
|
777 | - return $share->getShareOwner(); |
|
778 | - } |
|
779 | - |
|
780 | - return $share->getSharedBy(); |
|
781 | - } |
|
782 | - |
|
783 | - |
|
784 | - |
|
785 | - /** |
|
786 | - * check if we got the right share |
|
787 | - * |
|
788 | - * @param IShare $share |
|
789 | - * @param string $token |
|
790 | - * @return bool |
|
791 | - * @throws AuthenticationFailedException |
|
792 | - */ |
|
793 | - protected function verifyShare(IShare $share, $token) { |
|
794 | - if ( |
|
795 | - $share->getShareType() === IShare::TYPE_REMOTE && |
|
796 | - $share->getToken() === $token |
|
797 | - ) { |
|
798 | - return true; |
|
799 | - } |
|
800 | - |
|
801 | - if ($share->getShareType() === IShare::TYPE_CIRCLE) { |
|
802 | - try { |
|
803 | - $knownShare = $this->shareManager->getShareByToken($token); |
|
804 | - if ($knownShare->getId() === $share->getId()) { |
|
805 | - return true; |
|
806 | - } |
|
807 | - } catch (ShareNotFound $e) { |
|
808 | - } |
|
809 | - } |
|
810 | - |
|
811 | - throw new AuthenticationFailedException(); |
|
812 | - } |
|
813 | - |
|
814 | - |
|
815 | - |
|
816 | - /** |
|
817 | - * check if server-to-server sharing is enabled |
|
818 | - * |
|
819 | - * @param bool $incoming |
|
820 | - * @return bool |
|
821 | - */ |
|
822 | - private function isS2SEnabled($incoming = false) { |
|
823 | - $result = $this->appManager->isEnabledForUser('files_sharing'); |
|
824 | - |
|
825 | - if ($incoming) { |
|
826 | - $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled(); |
|
827 | - } else { |
|
828 | - $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled(); |
|
829 | - } |
|
830 | - |
|
831 | - return $result; |
|
832 | - } |
|
833 | - |
|
834 | - |
|
835 | - /** |
|
836 | - * get the supported share types, e.g. "user", "group", etc. |
|
837 | - * |
|
838 | - * @return array |
|
839 | - * |
|
840 | - * @since 14.0.0 |
|
841 | - */ |
|
842 | - public function getSupportedShareTypes() { |
|
843 | - return ['user', 'group']; |
|
844 | - } |
|
61 | + /** @var IAppManager */ |
|
62 | + private $appManager; |
|
63 | + |
|
64 | + /** @var FederatedShareProvider */ |
|
65 | + private $federatedShareProvider; |
|
66 | + |
|
67 | + /** @var AddressHandler */ |
|
68 | + private $addressHandler; |
|
69 | + |
|
70 | + /** @var ILogger */ |
|
71 | + private $logger; |
|
72 | + |
|
73 | + /** @var IUserManager */ |
|
74 | + private $userManager; |
|
75 | + |
|
76 | + /** @var IManager */ |
|
77 | + private $shareManager; |
|
78 | + |
|
79 | + /** @var ICloudIdManager */ |
|
80 | + private $cloudIdManager; |
|
81 | + |
|
82 | + /** @var IActivityManager */ |
|
83 | + private $activityManager; |
|
84 | + |
|
85 | + /** @var INotificationManager */ |
|
86 | + private $notificationManager; |
|
87 | + |
|
88 | + /** @var IURLGenerator */ |
|
89 | + private $urlGenerator; |
|
90 | + |
|
91 | + /** @var ICloudFederationFactory */ |
|
92 | + private $cloudFederationFactory; |
|
93 | + |
|
94 | + /** @var ICloudFederationProviderManager */ |
|
95 | + private $cloudFederationProviderManager; |
|
96 | + |
|
97 | + /** @var IDBConnection */ |
|
98 | + private $connection; |
|
99 | + |
|
100 | + /** @var IGroupManager */ |
|
101 | + private $groupManager; |
|
102 | + |
|
103 | + /** |
|
104 | + * CloudFederationProvider constructor. |
|
105 | + * |
|
106 | + * @param IAppManager $appManager |
|
107 | + * @param FederatedShareProvider $federatedShareProvider |
|
108 | + * @param AddressHandler $addressHandler |
|
109 | + * @param ILogger $logger |
|
110 | + * @param IUserManager $userManager |
|
111 | + * @param IManager $shareManager |
|
112 | + * @param ICloudIdManager $cloudIdManager |
|
113 | + * @param IActivityManager $activityManager |
|
114 | + * @param INotificationManager $notificationManager |
|
115 | + * @param IURLGenerator $urlGenerator |
|
116 | + * @param ICloudFederationFactory $cloudFederationFactory |
|
117 | + * @param ICloudFederationProviderManager $cloudFederationProviderManager |
|
118 | + * @param IDBConnection $connection |
|
119 | + * @param IGroupManager $groupManager |
|
120 | + */ |
|
121 | + public function __construct(IAppManager $appManager, |
|
122 | + FederatedShareProvider $federatedShareProvider, |
|
123 | + AddressHandler $addressHandler, |
|
124 | + ILogger $logger, |
|
125 | + IUserManager $userManager, |
|
126 | + IManager $shareManager, |
|
127 | + ICloudIdManager $cloudIdManager, |
|
128 | + IActivityManager $activityManager, |
|
129 | + INotificationManager $notificationManager, |
|
130 | + IURLGenerator $urlGenerator, |
|
131 | + ICloudFederationFactory $cloudFederationFactory, |
|
132 | + ICloudFederationProviderManager $cloudFederationProviderManager, |
|
133 | + IDBConnection $connection, |
|
134 | + IGroupManager $groupManager |
|
135 | + ) { |
|
136 | + $this->appManager = $appManager; |
|
137 | + $this->federatedShareProvider = $federatedShareProvider; |
|
138 | + $this->addressHandler = $addressHandler; |
|
139 | + $this->logger = $logger; |
|
140 | + $this->userManager = $userManager; |
|
141 | + $this->shareManager = $shareManager; |
|
142 | + $this->cloudIdManager = $cloudIdManager; |
|
143 | + $this->activityManager = $activityManager; |
|
144 | + $this->notificationManager = $notificationManager; |
|
145 | + $this->urlGenerator = $urlGenerator; |
|
146 | + $this->cloudFederationFactory = $cloudFederationFactory; |
|
147 | + $this->cloudFederationProviderManager = $cloudFederationProviderManager; |
|
148 | + $this->connection = $connection; |
|
149 | + $this->groupManager = $groupManager; |
|
150 | + } |
|
151 | + |
|
152 | + |
|
153 | + |
|
154 | + /** |
|
155 | + * @return string |
|
156 | + */ |
|
157 | + public function getShareType() { |
|
158 | + return 'file'; |
|
159 | + } |
|
160 | + |
|
161 | + /** |
|
162 | + * share received from another server |
|
163 | + * |
|
164 | + * @param ICloudFederationShare $share |
|
165 | + * @return string provider specific unique ID of the share |
|
166 | + * |
|
167 | + * @throws ProviderCouldNotAddShareException |
|
168 | + * @throws \OCP\AppFramework\QueryException |
|
169 | + * @throws \OC\HintException |
|
170 | + * @since 14.0.0 |
|
171 | + */ |
|
172 | + public function shareReceived(ICloudFederationShare $share) { |
|
173 | + if (!$this->isS2SEnabled(true)) { |
|
174 | + throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE); |
|
175 | + } |
|
176 | + |
|
177 | + $protocol = $share->getProtocol(); |
|
178 | + if ($protocol['name'] !== 'webdav') { |
|
179 | + throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED); |
|
180 | + } |
|
181 | + |
|
182 | + list($ownerUid, $remote) = $this->addressHandler->splitUserRemote($share->getOwner()); |
|
183 | + // for backward compatibility make sure that the remote url stored in the |
|
184 | + // database ends with a trailing slash |
|
185 | + if (substr($remote, -1) !== '/') { |
|
186 | + $remote = $remote . '/'; |
|
187 | + } |
|
188 | + |
|
189 | + $token = $share->getShareSecret(); |
|
190 | + $name = $share->getResourceName(); |
|
191 | + $owner = $share->getOwnerDisplayName(); |
|
192 | + $sharedBy = $share->getSharedByDisplayName(); |
|
193 | + $shareWith = $share->getShareWith(); |
|
194 | + $remoteId = $share->getProviderId(); |
|
195 | + $sharedByFederatedId = $share->getSharedBy(); |
|
196 | + $ownerFederatedId = $share->getOwner(); |
|
197 | + $shareType = $this->mapShareTypeToNextcloud($share->getShareType()); |
|
198 | + |
|
199 | + // if no explicit information about the person who created the share was send |
|
200 | + // we assume that the share comes from the owner |
|
201 | + if ($sharedByFederatedId === null) { |
|
202 | + $sharedBy = $owner; |
|
203 | + $sharedByFederatedId = $ownerFederatedId; |
|
204 | + } |
|
205 | + |
|
206 | + if ($remote && $token && $name && $owner && $remoteId && $shareWith) { |
|
207 | + if (!Util::isValidFileName($name)) { |
|
208 | + throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST); |
|
209 | + } |
|
210 | + |
|
211 | + // FIXME this should be a method in the user management instead |
|
212 | + if ($shareType === IShare::TYPE_USER) { |
|
213 | + $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']); |
|
214 | + Util::emitHook( |
|
215 | + '\OCA\Files_Sharing\API\Server2Server', |
|
216 | + 'preLoginNameUsedAsUserName', |
|
217 | + ['uid' => &$shareWith] |
|
218 | + ); |
|
219 | + $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']); |
|
220 | + |
|
221 | + if (!$this->userManager->userExists($shareWith)) { |
|
222 | + throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST); |
|
223 | + } |
|
224 | + |
|
225 | + \OC_Util::setupFS($shareWith); |
|
226 | + } |
|
227 | + |
|
228 | + if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) { |
|
229 | + throw new ProviderCouldNotAddShareException('Group does not exists', '',Http::STATUS_BAD_REQUEST); |
|
230 | + } |
|
231 | + |
|
232 | + $externalManager = new \OCA\Files_Sharing\External\Manager( |
|
233 | + \OC::$server->getDatabaseConnection(), |
|
234 | + Filesystem::getMountManager(), |
|
235 | + Filesystem::getLoader(), |
|
236 | + \OC::$server->getHTTPClientService(), |
|
237 | + \OC::$server->getNotificationManager(), |
|
238 | + \OC::$server->query(\OCP\OCS\IDiscoveryService::class), |
|
239 | + \OC::$server->getCloudFederationProviderManager(), |
|
240 | + \OC::$server->getCloudFederationFactory(), |
|
241 | + \OC::$server->getGroupManager(), |
|
242 | + \OC::$server->getUserManager(), |
|
243 | + $shareWith |
|
244 | + ); |
|
245 | + |
|
246 | + try { |
|
247 | + $externalManager->addShare($remote, $token, '', $name, $owner, $shareType,false, $shareWith, $remoteId); |
|
248 | + $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external'); |
|
249 | + |
|
250 | + if ($shareType === IShare::TYPE_USER) { |
|
251 | + $event = $this->activityManager->generateEvent(); |
|
252 | + $event->setApp('files_sharing') |
|
253 | + ->setType('remote_share') |
|
254 | + ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')]) |
|
255 | + ->setAffectedUser($shareWith) |
|
256 | + ->setObject('remote_share', (int)$shareId, $name); |
|
257 | + \OC::$server->getActivityManager()->publish($event); |
|
258 | + $this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $sharedBy, $owner); |
|
259 | + } else { |
|
260 | + $groupMembers = $this->groupManager->get($shareWith)->getUsers(); |
|
261 | + foreach ($groupMembers as $user) { |
|
262 | + $event = $this->activityManager->generateEvent(); |
|
263 | + $event->setApp('files_sharing') |
|
264 | + ->setType('remote_share') |
|
265 | + ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')]) |
|
266 | + ->setAffectedUser($user->getUID()) |
|
267 | + ->setObject('remote_share', (int)$shareId, $name); |
|
268 | + \OC::$server->getActivityManager()->publish($event); |
|
269 | + $this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $sharedBy, $owner); |
|
270 | + } |
|
271 | + } |
|
272 | + return $shareId; |
|
273 | + } catch (\Exception $e) { |
|
274 | + $this->logger->logException($e, [ |
|
275 | + 'message' => 'Server can not add remote share.', |
|
276 | + 'level' => ILogger::ERROR, |
|
277 | + 'app' => 'files_sharing' |
|
278 | + ]); |
|
279 | + throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR); |
|
280 | + } |
|
281 | + } |
|
282 | + |
|
283 | + throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST); |
|
284 | + } |
|
285 | + |
|
286 | + /** |
|
287 | + * notification received from another server |
|
288 | + * |
|
289 | + * @param string $notificationType (e.g. SHARE_ACCEPTED) |
|
290 | + * @param string $providerId id of the share |
|
291 | + * @param array $notification payload of the notification |
|
292 | + * @return array data send back to the sender |
|
293 | + * |
|
294 | + * @throws ActionNotSupportedException |
|
295 | + * @throws AuthenticationFailedException |
|
296 | + * @throws BadRequestException |
|
297 | + * @throws \OC\HintException |
|
298 | + * @since 14.0.0 |
|
299 | + */ |
|
300 | + public function notificationReceived($notificationType, $providerId, array $notification) { |
|
301 | + switch ($notificationType) { |
|
302 | + case 'SHARE_ACCEPTED': |
|
303 | + return $this->shareAccepted($providerId, $notification); |
|
304 | + case 'SHARE_DECLINED': |
|
305 | + return $this->shareDeclined($providerId, $notification); |
|
306 | + case 'SHARE_UNSHARED': |
|
307 | + return $this->unshare($providerId, $notification); |
|
308 | + case 'REQUEST_RESHARE': |
|
309 | + return $this->reshareRequested($providerId, $notification); |
|
310 | + case 'RESHARE_UNDO': |
|
311 | + return $this->undoReshare($providerId, $notification); |
|
312 | + case 'RESHARE_CHANGE_PERMISSION': |
|
313 | + return $this->updateResharePermissions($providerId, $notification); |
|
314 | + } |
|
315 | + |
|
316 | + |
|
317 | + throw new BadRequestException([$notificationType]); |
|
318 | + } |
|
319 | + |
|
320 | + /** |
|
321 | + * map OCM share type (strings) to Nextcloud internal share types (integer) |
|
322 | + * |
|
323 | + * @param string $shareType |
|
324 | + * @return int |
|
325 | + */ |
|
326 | + private function mapShareTypeToNextcloud($shareType) { |
|
327 | + $result = IShare::TYPE_USER; |
|
328 | + if ($shareType === 'group') { |
|
329 | + $result = IShare::TYPE_GROUP; |
|
330 | + } |
|
331 | + |
|
332 | + return $result; |
|
333 | + } |
|
334 | + |
|
335 | + /** |
|
336 | + * notify user about new federated share |
|
337 | + * |
|
338 | + * @param $shareWith |
|
339 | + * @param $shareId |
|
340 | + * @param $ownerFederatedId |
|
341 | + * @param $sharedByFederatedId |
|
342 | + * @param $name |
|
343 | + */ |
|
344 | + private function notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $sharedBy, $owner) { |
|
345 | + $notification = $this->notificationManager->createNotification(); |
|
346 | + $notification->setApp('files_sharing') |
|
347 | + ->setUser($shareWith) |
|
348 | + ->setDateTime(new \DateTime()) |
|
349 | + ->setObject('remote_share', $shareId) |
|
350 | + ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/'), $sharedBy, $owner]); |
|
351 | + |
|
352 | + $declineAction = $notification->createAction(); |
|
353 | + $declineAction->setLabel('decline') |
|
354 | + ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE'); |
|
355 | + $notification->addAction($declineAction); |
|
356 | + |
|
357 | + $acceptAction = $notification->createAction(); |
|
358 | + $acceptAction->setLabel('accept') |
|
359 | + ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST'); |
|
360 | + $notification->addAction($acceptAction); |
|
361 | + |
|
362 | + $this->notificationManager->notify($notification); |
|
363 | + } |
|
364 | + |
|
365 | + /** |
|
366 | + * process notification that the recipient accepted a share |
|
367 | + * |
|
368 | + * @param string $id |
|
369 | + * @param array $notification |
|
370 | + * @return array |
|
371 | + * @throws ActionNotSupportedException |
|
372 | + * @throws AuthenticationFailedException |
|
373 | + * @throws BadRequestException |
|
374 | + * @throws \OC\HintException |
|
375 | + */ |
|
376 | + private function shareAccepted($id, array $notification) { |
|
377 | + if (!$this->isS2SEnabled()) { |
|
378 | + throw new ActionNotSupportedException('Server does not support federated cloud sharing'); |
|
379 | + } |
|
380 | + |
|
381 | + if (!isset($notification['sharedSecret'])) { |
|
382 | + throw new BadRequestException(['sharedSecret']); |
|
383 | + } |
|
384 | + |
|
385 | + $token = $notification['sharedSecret']; |
|
386 | + |
|
387 | + $share = $this->federatedShareProvider->getShareById($id); |
|
388 | + |
|
389 | + $this->verifyShare($share, $token); |
|
390 | + $this->executeAcceptShare($share); |
|
391 | + if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
392 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
393 | + $remoteId = $this->federatedShareProvider->getRemoteId($share); |
|
394 | + $notification = $this->cloudFederationFactory->getCloudFederationNotification(); |
|
395 | + $notification->setMessage( |
|
396 | + 'SHARE_ACCEPTED', |
|
397 | + 'file', |
|
398 | + $remoteId, |
|
399 | + [ |
|
400 | + 'sharedSecret' => $token, |
|
401 | + 'message' => 'Recipient accepted the re-share' |
|
402 | + ] |
|
403 | + |
|
404 | + ); |
|
405 | + $this->cloudFederationProviderManager->sendNotification($remote, $notification); |
|
406 | + } |
|
407 | + |
|
408 | + return []; |
|
409 | + } |
|
410 | + |
|
411 | + /** |
|
412 | + * @param IShare $share |
|
413 | + * @throws ShareNotFound |
|
414 | + */ |
|
415 | + protected function executeAcceptShare(IShare $share) { |
|
416 | + try { |
|
417 | + $fileId = (int)$share->getNode()->getId(); |
|
418 | + list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId); |
|
419 | + } catch (\Exception $e) { |
|
420 | + throw new ShareNotFound(); |
|
421 | + } |
|
422 | + |
|
423 | + $event = $this->activityManager->generateEvent(); |
|
424 | + $event->setApp('files_sharing') |
|
425 | + ->setType('remote_share') |
|
426 | + ->setAffectedUser($this->getCorrectUid($share)) |
|
427 | + ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]]) |
|
428 | + ->setObject('files', $fileId, $file) |
|
429 | + ->setLink($link); |
|
430 | + $this->activityManager->publish($event); |
|
431 | + } |
|
432 | + |
|
433 | + /** |
|
434 | + * process notification that the recipient declined a share |
|
435 | + * |
|
436 | + * @param string $id |
|
437 | + * @param array $notification |
|
438 | + * @return array |
|
439 | + * @throws ActionNotSupportedException |
|
440 | + * @throws AuthenticationFailedException |
|
441 | + * @throws BadRequestException |
|
442 | + * @throws ShareNotFound |
|
443 | + * @throws \OC\HintException |
|
444 | + * |
|
445 | + */ |
|
446 | + protected function shareDeclined($id, array $notification) { |
|
447 | + if (!$this->isS2SEnabled()) { |
|
448 | + throw new ActionNotSupportedException('Server does not support federated cloud sharing'); |
|
449 | + } |
|
450 | + |
|
451 | + if (!isset($notification['sharedSecret'])) { |
|
452 | + throw new BadRequestException(['sharedSecret']); |
|
453 | + } |
|
454 | + |
|
455 | + $token = $notification['sharedSecret']; |
|
456 | + |
|
457 | + $share = $this->federatedShareProvider->getShareById($id); |
|
458 | + |
|
459 | + $this->verifyShare($share, $token); |
|
460 | + |
|
461 | + if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
462 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
463 | + $remoteId = $this->federatedShareProvider->getRemoteId($share); |
|
464 | + $notification = $this->cloudFederationFactory->getCloudFederationNotification(); |
|
465 | + $notification->setMessage( |
|
466 | + 'SHARE_DECLINED', |
|
467 | + 'file', |
|
468 | + $remoteId, |
|
469 | + [ |
|
470 | + 'sharedSecret' => $token, |
|
471 | + 'message' => 'Recipient declined the re-share' |
|
472 | + ] |
|
473 | + |
|
474 | + ); |
|
475 | + $this->cloudFederationProviderManager->sendNotification($remote, $notification); |
|
476 | + } |
|
477 | + |
|
478 | + $this->executeDeclineShare($share); |
|
479 | + |
|
480 | + return []; |
|
481 | + } |
|
482 | + |
|
483 | + /** |
|
484 | + * delete declined share and create a activity |
|
485 | + * |
|
486 | + * @param IShare $share |
|
487 | + * @throws ShareNotFound |
|
488 | + */ |
|
489 | + protected function executeDeclineShare(IShare $share) { |
|
490 | + $this->federatedShareProvider->removeShareFromTable($share); |
|
491 | + |
|
492 | + try { |
|
493 | + $fileId = (int)$share->getNode()->getId(); |
|
494 | + list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId); |
|
495 | + } catch (\Exception $e) { |
|
496 | + throw new ShareNotFound(); |
|
497 | + } |
|
498 | + |
|
499 | + $event = $this->activityManager->generateEvent(); |
|
500 | + $event->setApp('files_sharing') |
|
501 | + ->setType('remote_share') |
|
502 | + ->setAffectedUser($this->getCorrectUid($share)) |
|
503 | + ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]]) |
|
504 | + ->setObject('files', $fileId, $file) |
|
505 | + ->setLink($link); |
|
506 | + $this->activityManager->publish($event); |
|
507 | + } |
|
508 | + |
|
509 | + /** |
|
510 | + * received the notification that the owner unshared a file from you |
|
511 | + * |
|
512 | + * @param string $id |
|
513 | + * @param array $notification |
|
514 | + * @return array |
|
515 | + * @throws AuthenticationFailedException |
|
516 | + * @throws BadRequestException |
|
517 | + */ |
|
518 | + private function undoReshare($id, array $notification) { |
|
519 | + if (!isset($notification['sharedSecret'])) { |
|
520 | + throw new BadRequestException(['sharedSecret']); |
|
521 | + } |
|
522 | + $token = $notification['sharedSecret']; |
|
523 | + |
|
524 | + $share = $this->federatedShareProvider->getShareById($id); |
|
525 | + |
|
526 | + $this->verifyShare($share, $token); |
|
527 | + $this->federatedShareProvider->removeShareFromTable($share); |
|
528 | + return []; |
|
529 | + } |
|
530 | + |
|
531 | + /** |
|
532 | + * unshare file from self |
|
533 | + * |
|
534 | + * @param string $id |
|
535 | + * @param array $notification |
|
536 | + * @return array |
|
537 | + * @throws ActionNotSupportedException |
|
538 | + * @throws BadRequestException |
|
539 | + */ |
|
540 | + private function unshare($id, array $notification) { |
|
541 | + if (!$this->isS2SEnabled(true)) { |
|
542 | + throw new ActionNotSupportedException("incoming shares disabled!"); |
|
543 | + } |
|
544 | + |
|
545 | + if (!isset($notification['sharedSecret'])) { |
|
546 | + throw new BadRequestException(['sharedSecret']); |
|
547 | + } |
|
548 | + $token = $notification['sharedSecret']; |
|
549 | + |
|
550 | + $qb = $this->connection->getQueryBuilder(); |
|
551 | + $qb->select('*') |
|
552 | + ->from('share_external') |
|
553 | + ->where( |
|
554 | + $qb->expr()->andX( |
|
555 | + $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)), |
|
556 | + $qb->expr()->eq('share_token', $qb->createNamedParameter($token)) |
|
557 | + ) |
|
558 | + ); |
|
559 | + |
|
560 | + $result = $qb->execute(); |
|
561 | + $share = $result->fetch(); |
|
562 | + $result->closeCursor(); |
|
563 | + |
|
564 | + if ($token && $id && !empty($share)) { |
|
565 | + $remote = $this->cleanupRemote($share['remote']); |
|
566 | + |
|
567 | + $owner = $this->cloudIdManager->getCloudId($share['owner'], $remote); |
|
568 | + $mountpoint = $share['mountpoint']; |
|
569 | + $user = $share['user']; |
|
570 | + |
|
571 | + $qb = $this->connection->getQueryBuilder(); |
|
572 | + $qb->delete('share_external') |
|
573 | + ->where( |
|
574 | + $qb->expr()->andX( |
|
575 | + $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)), |
|
576 | + $qb->expr()->eq('share_token', $qb->createNamedParameter($token)) |
|
577 | + ) |
|
578 | + ); |
|
579 | + |
|
580 | + $qb->execute(); |
|
581 | + |
|
582 | + // delete all child in case of a group share |
|
583 | + $qb = $this->connection->getQueryBuilder(); |
|
584 | + $qb->delete('share_external') |
|
585 | + ->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id']))); |
|
586 | + $qb->execute(); |
|
587 | + |
|
588 | + if ((int)$share['share_type'] === IShare::TYPE_USER) { |
|
589 | + if ($share['accepted']) { |
|
590 | + $path = trim($mountpoint, '/'); |
|
591 | + } else { |
|
592 | + $path = trim($share['name'], '/'); |
|
593 | + } |
|
594 | + $notification = $this->notificationManager->createNotification(); |
|
595 | + $notification->setApp('files_sharing') |
|
596 | + ->setUser($share['user']) |
|
597 | + ->setObject('remote_share', (int)$share['id']); |
|
598 | + $this->notificationManager->markProcessed($notification); |
|
599 | + |
|
600 | + $event = $this->activityManager->generateEvent(); |
|
601 | + $event->setApp('files_sharing') |
|
602 | + ->setType('remote_share') |
|
603 | + ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path]) |
|
604 | + ->setAffectedUser($user) |
|
605 | + ->setObject('remote_share', (int)$share['id'], $path); |
|
606 | + \OC::$server->getActivityManager()->publish($event); |
|
607 | + } |
|
608 | + } |
|
609 | + |
|
610 | + return []; |
|
611 | + } |
|
612 | + |
|
613 | + private function cleanupRemote($remote) { |
|
614 | + $remote = substr($remote, strpos($remote, '://') + 3); |
|
615 | + |
|
616 | + return rtrim($remote, '/'); |
|
617 | + } |
|
618 | + |
|
619 | + /** |
|
620 | + * recipient of a share request to re-share the file with another user |
|
621 | + * |
|
622 | + * @param string $id |
|
623 | + * @param array $notification |
|
624 | + * @return array |
|
625 | + * @throws AuthenticationFailedException |
|
626 | + * @throws BadRequestException |
|
627 | + * @throws ProviderCouldNotAddShareException |
|
628 | + * @throws ShareNotFound |
|
629 | + */ |
|
630 | + protected function reshareRequested($id, array $notification) { |
|
631 | + if (!isset($notification['sharedSecret'])) { |
|
632 | + throw new BadRequestException(['sharedSecret']); |
|
633 | + } |
|
634 | + $token = $notification['sharedSecret']; |
|
635 | + |
|
636 | + if (!isset($notification['shareWith'])) { |
|
637 | + throw new BadRequestException(['shareWith']); |
|
638 | + } |
|
639 | + $shareWith = $notification['shareWith']; |
|
640 | + |
|
641 | + if (!isset($notification['senderId'])) { |
|
642 | + throw new BadRequestException(['senderId']); |
|
643 | + } |
|
644 | + $senderId = $notification['senderId']; |
|
645 | + |
|
646 | + $share = $this->federatedShareProvider->getShareById($id); |
|
647 | + // don't allow to share a file back to the owner |
|
648 | + try { |
|
649 | + list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); |
|
650 | + $owner = $share->getShareOwner(); |
|
651 | + $currentServer = $this->addressHandler->generateRemoteURL(); |
|
652 | + if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) { |
|
653 | + throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id); |
|
654 | + } |
|
655 | + } catch (\Exception $e) { |
|
656 | + throw new ProviderCouldNotAddShareException($e->getMessage()); |
|
657 | + } |
|
658 | + |
|
659 | + $this->verifyShare($share, $token); |
|
660 | + |
|
661 | + // check if re-sharing is allowed |
|
662 | + if ($share->getPermissions() & Constants::PERMISSION_SHARE) { |
|
663 | + // the recipient of the initial share is now the initiator for the re-share |
|
664 | + $share->setSharedBy($share->getSharedWith()); |
|
665 | + $share->setSharedWith($shareWith); |
|
666 | + $result = $this->federatedShareProvider->create($share); |
|
667 | + $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId); |
|
668 | + return ['token' => $result->getToken(), 'providerId' => $result->getId()]; |
|
669 | + } else { |
|
670 | + throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id); |
|
671 | + } |
|
672 | + } |
|
673 | + |
|
674 | + /** |
|
675 | + * update permission of a re-share so that the share dialog shows the right |
|
676 | + * permission if the owner or the sender changes the permission |
|
677 | + * |
|
678 | + * @param string $id |
|
679 | + * @param array $notification |
|
680 | + * @return array |
|
681 | + * @throws AuthenticationFailedException |
|
682 | + * @throws BadRequestException |
|
683 | + */ |
|
684 | + protected function updateResharePermissions($id, array $notification) { |
|
685 | + if (!isset($notification['sharedSecret'])) { |
|
686 | + throw new BadRequestException(['sharedSecret']); |
|
687 | + } |
|
688 | + $token = $notification['sharedSecret']; |
|
689 | + |
|
690 | + if (!isset($notification['permission'])) { |
|
691 | + throw new BadRequestException(['permission']); |
|
692 | + } |
|
693 | + $ocmPermissions = $notification['permission']; |
|
694 | + |
|
695 | + $share = $this->federatedShareProvider->getShareById($id); |
|
696 | + |
|
697 | + $ncPermission = $this->ocmPermissions2ncPermissions($ocmPermissions); |
|
698 | + |
|
699 | + $this->verifyShare($share, $token); |
|
700 | + $this->updatePermissionsInDatabase($share, $ncPermission); |
|
701 | + |
|
702 | + return []; |
|
703 | + } |
|
704 | + |
|
705 | + /** |
|
706 | + * translate OCM Permissions to Nextcloud permissions |
|
707 | + * |
|
708 | + * @param array $ocmPermissions |
|
709 | + * @return int |
|
710 | + * @throws BadRequestException |
|
711 | + */ |
|
712 | + protected function ocmPermissions2ncPermissions(array $ocmPermissions) { |
|
713 | + $ncPermissions = 0; |
|
714 | + foreach ($ocmPermissions as $permission) { |
|
715 | + switch (strtolower($permission)) { |
|
716 | + case 'read': |
|
717 | + $ncPermissions += Constants::PERMISSION_READ; |
|
718 | + break; |
|
719 | + case 'write': |
|
720 | + $ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE; |
|
721 | + break; |
|
722 | + case 'share': |
|
723 | + $ncPermissions += Constants::PERMISSION_SHARE; |
|
724 | + break; |
|
725 | + default: |
|
726 | + throw new BadRequestException(['permission']); |
|
727 | + } |
|
728 | + } |
|
729 | + |
|
730 | + return $ncPermissions; |
|
731 | + } |
|
732 | + |
|
733 | + /** |
|
734 | + * update permissions in database |
|
735 | + * |
|
736 | + * @param IShare $share |
|
737 | + * @param int $permissions |
|
738 | + */ |
|
739 | + protected function updatePermissionsInDatabase(IShare $share, $permissions) { |
|
740 | + $query = $this->connection->getQueryBuilder(); |
|
741 | + $query->update('share') |
|
742 | + ->where($query->expr()->eq('id', $query->createNamedParameter($share->getId()))) |
|
743 | + ->set('permissions', $query->createNamedParameter($permissions)) |
|
744 | + ->execute(); |
|
745 | + } |
|
746 | + |
|
747 | + |
|
748 | + /** |
|
749 | + * get file |
|
750 | + * |
|
751 | + * @param string $user |
|
752 | + * @param int $fileSource |
|
753 | + * @return array with internal path of the file and a absolute link to it |
|
754 | + */ |
|
755 | + private function getFile($user, $fileSource) { |
|
756 | + \OC_Util::setupFS($user); |
|
757 | + |
|
758 | + try { |
|
759 | + $file = Filesystem::getPath($fileSource); |
|
760 | + } catch (NotFoundException $e) { |
|
761 | + $file = null; |
|
762 | + } |
|
763 | + $args = Filesystem::is_dir($file) ? ['dir' => $file] : ['dir' => dirname($file), 'scrollto' => $file]; |
|
764 | + $link = Util::linkToAbsolute('files', 'index.php', $args); |
|
765 | + |
|
766 | + return [$file, $link]; |
|
767 | + } |
|
768 | + |
|
769 | + /** |
|
770 | + * check if we are the initiator or the owner of a re-share and return the correct UID |
|
771 | + * |
|
772 | + * @param IShare $share |
|
773 | + * @return string |
|
774 | + */ |
|
775 | + protected function getCorrectUid(IShare $share) { |
|
776 | + if ($this->userManager->userExists($share->getShareOwner())) { |
|
777 | + return $share->getShareOwner(); |
|
778 | + } |
|
779 | + |
|
780 | + return $share->getSharedBy(); |
|
781 | + } |
|
782 | + |
|
783 | + |
|
784 | + |
|
785 | + /** |
|
786 | + * check if we got the right share |
|
787 | + * |
|
788 | + * @param IShare $share |
|
789 | + * @param string $token |
|
790 | + * @return bool |
|
791 | + * @throws AuthenticationFailedException |
|
792 | + */ |
|
793 | + protected function verifyShare(IShare $share, $token) { |
|
794 | + if ( |
|
795 | + $share->getShareType() === IShare::TYPE_REMOTE && |
|
796 | + $share->getToken() === $token |
|
797 | + ) { |
|
798 | + return true; |
|
799 | + } |
|
800 | + |
|
801 | + if ($share->getShareType() === IShare::TYPE_CIRCLE) { |
|
802 | + try { |
|
803 | + $knownShare = $this->shareManager->getShareByToken($token); |
|
804 | + if ($knownShare->getId() === $share->getId()) { |
|
805 | + return true; |
|
806 | + } |
|
807 | + } catch (ShareNotFound $e) { |
|
808 | + } |
|
809 | + } |
|
810 | + |
|
811 | + throw new AuthenticationFailedException(); |
|
812 | + } |
|
813 | + |
|
814 | + |
|
815 | + |
|
816 | + /** |
|
817 | + * check if server-to-server sharing is enabled |
|
818 | + * |
|
819 | + * @param bool $incoming |
|
820 | + * @return bool |
|
821 | + */ |
|
822 | + private function isS2SEnabled($incoming = false) { |
|
823 | + $result = $this->appManager->isEnabledForUser('files_sharing'); |
|
824 | + |
|
825 | + if ($incoming) { |
|
826 | + $result = $result && $this->federatedShareProvider->isIncomingServer2serverShareEnabled(); |
|
827 | + } else { |
|
828 | + $result = $result && $this->federatedShareProvider->isOutgoingServer2serverShareEnabled(); |
|
829 | + } |
|
830 | + |
|
831 | + return $result; |
|
832 | + } |
|
833 | + |
|
834 | + |
|
835 | + /** |
|
836 | + * get the supported share types, e.g. "user", "group", etc. |
|
837 | + * |
|
838 | + * @return array |
|
839 | + * |
|
840 | + * @since 14.0.0 |
|
841 | + */ |
|
842 | + public function getSupportedShareTypes() { |
|
843 | + return ['user', 'group']; |
|
844 | + } |
|
845 | 845 | } |
@@ -183,7 +183,7 @@ discard block |
||
183 | 183 | // for backward compatibility make sure that the remote url stored in the |
184 | 184 | // database ends with a trailing slash |
185 | 185 | if (substr($remote, -1) !== '/') { |
186 | - $remote = $remote . '/'; |
|
186 | + $remote = $remote.'/'; |
|
187 | 187 | } |
188 | 188 | |
189 | 189 | $token = $share->getShareSecret(); |
@@ -210,23 +210,23 @@ discard block |
||
210 | 210 | |
211 | 211 | // FIXME this should be a method in the user management instead |
212 | 212 | if ($shareType === IShare::TYPE_USER) { |
213 | - $this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']); |
|
213 | + $this->logger->debug('shareWith before, '.$shareWith, ['app' => 'files_sharing']); |
|
214 | 214 | Util::emitHook( |
215 | 215 | '\OCA\Files_Sharing\API\Server2Server', |
216 | 216 | 'preLoginNameUsedAsUserName', |
217 | 217 | ['uid' => &$shareWith] |
218 | 218 | ); |
219 | - $this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']); |
|
219 | + $this->logger->debug('shareWith after, '.$shareWith, ['app' => 'files_sharing']); |
|
220 | 220 | |
221 | 221 | if (!$this->userManager->userExists($shareWith)) { |
222 | - throw new ProviderCouldNotAddShareException('User does not exists', '',Http::STATUS_BAD_REQUEST); |
|
222 | + throw new ProviderCouldNotAddShareException('User does not exists', '', Http::STATUS_BAD_REQUEST); |
|
223 | 223 | } |
224 | 224 | |
225 | 225 | \OC_Util::setupFS($shareWith); |
226 | 226 | } |
227 | 227 | |
228 | 228 | if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) { |
229 | - throw new ProviderCouldNotAddShareException('Group does not exists', '',Http::STATUS_BAD_REQUEST); |
|
229 | + throw new ProviderCouldNotAddShareException('Group does not exists', '', Http::STATUS_BAD_REQUEST); |
|
230 | 230 | } |
231 | 231 | |
232 | 232 | $externalManager = new \OCA\Files_Sharing\External\Manager( |
@@ -244,7 +244,7 @@ discard block |
||
244 | 244 | ); |
245 | 245 | |
246 | 246 | try { |
247 | - $externalManager->addShare($remote, $token, '', $name, $owner, $shareType,false, $shareWith, $remoteId); |
|
247 | + $externalManager->addShare($remote, $token, '', $name, $owner, $shareType, false, $shareWith, $remoteId); |
|
248 | 248 | $shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external'); |
249 | 249 | |
250 | 250 | if ($shareType === IShare::TYPE_USER) { |
@@ -253,7 +253,7 @@ discard block |
||
253 | 253 | ->setType('remote_share') |
254 | 254 | ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')]) |
255 | 255 | ->setAffectedUser($shareWith) |
256 | - ->setObject('remote_share', (int)$shareId, $name); |
|
256 | + ->setObject('remote_share', (int) $shareId, $name); |
|
257 | 257 | \OC::$server->getActivityManager()->publish($event); |
258 | 258 | $this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $sharedBy, $owner); |
259 | 259 | } else { |
@@ -264,7 +264,7 @@ discard block |
||
264 | 264 | ->setType('remote_share') |
265 | 265 | ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/')]) |
266 | 266 | ->setAffectedUser($user->getUID()) |
267 | - ->setObject('remote_share', (int)$shareId, $name); |
|
267 | + ->setObject('remote_share', (int) $shareId, $name); |
|
268 | 268 | \OC::$server->getActivityManager()->publish($event); |
269 | 269 | $this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $sharedBy, $owner); |
270 | 270 | } |
@@ -276,7 +276,7 @@ discard block |
||
276 | 276 | 'level' => ILogger::ERROR, |
277 | 277 | 'app' => 'files_sharing' |
278 | 278 | ]); |
279 | - throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from ' . $remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR); |
|
279 | + throw new ProviderCouldNotAddShareException('internal server error, was not able to add share from '.$remote, '', HTTP::STATUS_INTERNAL_SERVER_ERROR); |
|
280 | 280 | } |
281 | 281 | } |
282 | 282 | |
@@ -351,12 +351,12 @@ discard block |
||
351 | 351 | |
352 | 352 | $declineAction = $notification->createAction(); |
353 | 353 | $declineAction->setLabel('decline') |
354 | - ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'DELETE'); |
|
354 | + ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/'.$shareId)), 'DELETE'); |
|
355 | 355 | $notification->addAction($declineAction); |
356 | 356 | |
357 | 357 | $acceptAction = $notification->createAction(); |
358 | 358 | $acceptAction->setLabel('accept') |
359 | - ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/' . $shareId)), 'POST'); |
|
359 | + ->setLink($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'ocs/v2.php/apps/files_sharing/api/v1/remote_shares/pending/'.$shareId)), 'POST'); |
|
360 | 360 | $notification->addAction($acceptAction); |
361 | 361 | |
362 | 362 | $this->notificationManager->notify($notification); |
@@ -414,7 +414,7 @@ discard block |
||
414 | 414 | */ |
415 | 415 | protected function executeAcceptShare(IShare $share) { |
416 | 416 | try { |
417 | - $fileId = (int)$share->getNode()->getId(); |
|
417 | + $fileId = (int) $share->getNode()->getId(); |
|
418 | 418 | list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId); |
419 | 419 | } catch (\Exception $e) { |
420 | 420 | throw new ShareNotFound(); |
@@ -490,7 +490,7 @@ discard block |
||
490 | 490 | $this->federatedShareProvider->removeShareFromTable($share); |
491 | 491 | |
492 | 492 | try { |
493 | - $fileId = (int)$share->getNode()->getId(); |
|
493 | + $fileId = (int) $share->getNode()->getId(); |
|
494 | 494 | list($file, $link) = $this->getFile($this->getCorrectUid($share), $fileId); |
495 | 495 | } catch (\Exception $e) { |
496 | 496 | throw new ShareNotFound(); |
@@ -582,10 +582,10 @@ discard block |
||
582 | 582 | // delete all child in case of a group share |
583 | 583 | $qb = $this->connection->getQueryBuilder(); |
584 | 584 | $qb->delete('share_external') |
585 | - ->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id']))); |
|
585 | + ->where($qb->expr()->eq('parent', $qb->createNamedParameter((int) $share['id']))); |
|
586 | 586 | $qb->execute(); |
587 | 587 | |
588 | - if ((int)$share['share_type'] === IShare::TYPE_USER) { |
|
588 | + if ((int) $share['share_type'] === IShare::TYPE_USER) { |
|
589 | 589 | if ($share['accepted']) { |
590 | 590 | $path = trim($mountpoint, '/'); |
591 | 591 | } else { |
@@ -594,7 +594,7 @@ discard block |
||
594 | 594 | $notification = $this->notificationManager->createNotification(); |
595 | 595 | $notification->setApp('files_sharing') |
596 | 596 | ->setUser($share['user']) |
597 | - ->setObject('remote_share', (int)$share['id']); |
|
597 | + ->setObject('remote_share', (int) $share['id']); |
|
598 | 598 | $this->notificationManager->markProcessed($notification); |
599 | 599 | |
600 | 600 | $event = $this->activityManager->generateEvent(); |
@@ -602,7 +602,7 @@ discard block |
||
602 | 602 | ->setType('remote_share') |
603 | 603 | ->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path]) |
604 | 604 | ->setAffectedUser($user) |
605 | - ->setObject('remote_share', (int)$share['id'], $path); |
|
605 | + ->setObject('remote_share', (int) $share['id'], $path); |
|
606 | 606 | \OC::$server->getActivityManager()->publish($event); |
607 | 607 | } |
608 | 608 | } |
@@ -650,7 +650,7 @@ discard block |
||
650 | 650 | $owner = $share->getShareOwner(); |
651 | 651 | $currentServer = $this->addressHandler->generateRemoteURL(); |
652 | 652 | if ($this->addressHandler->compareAddresses($user, $remote, $owner, $currentServer)) { |
653 | - throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: ' . $id); |
|
653 | + throw new ProviderCouldNotAddShareException('Resharing back to the owner is not allowed: '.$id); |
|
654 | 654 | } |
655 | 655 | } catch (\Exception $e) { |
656 | 656 | throw new ProviderCouldNotAddShareException($e->getMessage()); |
@@ -664,10 +664,10 @@ discard block |
||
664 | 664 | $share->setSharedBy($share->getSharedWith()); |
665 | 665 | $share->setSharedWith($shareWith); |
666 | 666 | $result = $this->federatedShareProvider->create($share); |
667 | - $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId); |
|
667 | + $this->federatedShareProvider->storeRemoteId((int) $result->getId(), $senderId); |
|
668 | 668 | return ['token' => $result->getToken(), 'providerId' => $result->getId()]; |
669 | 669 | } else { |
670 | - throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id); |
|
670 | + throw new ProviderCouldNotAddShareException('resharing not allowed for share: '.$id); |
|
671 | 671 | } |
672 | 672 | } |
673 | 673 |
@@ -58,1071 +58,1071 @@ |
||
58 | 58 | * @package OCA\FederatedFileSharing |
59 | 59 | */ |
60 | 60 | class FederatedShareProvider implements IShareProvider { |
61 | - public const SHARE_TYPE_REMOTE = 6; |
|
62 | - |
|
63 | - /** @var IDBConnection */ |
|
64 | - private $dbConnection; |
|
65 | - |
|
66 | - /** @var AddressHandler */ |
|
67 | - private $addressHandler; |
|
68 | - |
|
69 | - /** @var Notifications */ |
|
70 | - private $notifications; |
|
71 | - |
|
72 | - /** @var TokenHandler */ |
|
73 | - private $tokenHandler; |
|
74 | - |
|
75 | - /** @var IL10N */ |
|
76 | - private $l; |
|
77 | - |
|
78 | - /** @var ILogger */ |
|
79 | - private $logger; |
|
80 | - |
|
81 | - /** @var IRootFolder */ |
|
82 | - private $rootFolder; |
|
83 | - |
|
84 | - /** @var IConfig */ |
|
85 | - private $config; |
|
86 | - |
|
87 | - /** @var string */ |
|
88 | - private $externalShareTable = 'share_external'; |
|
89 | - |
|
90 | - /** @var IUserManager */ |
|
91 | - private $userManager; |
|
92 | - |
|
93 | - /** @var ICloudIdManager */ |
|
94 | - private $cloudIdManager; |
|
95 | - |
|
96 | - /** @var \OCP\GlobalScale\IConfig */ |
|
97 | - private $gsConfig; |
|
98 | - |
|
99 | - /** @var ICloudFederationProviderManager */ |
|
100 | - private $cloudFederationProviderManager; |
|
101 | - |
|
102 | - /** @var array list of supported share types */ |
|
103 | - private $supportedShareType = [IShare::TYPE_REMOTE_GROUP, IShare::TYPE_REMOTE, IShare::TYPE_CIRCLE]; |
|
104 | - |
|
105 | - /** |
|
106 | - * DefaultShareProvider constructor. |
|
107 | - * |
|
108 | - * @param IDBConnection $connection |
|
109 | - * @param AddressHandler $addressHandler |
|
110 | - * @param Notifications $notifications |
|
111 | - * @param TokenHandler $tokenHandler |
|
112 | - * @param IL10N $l10n |
|
113 | - * @param ILogger $logger |
|
114 | - * @param IRootFolder $rootFolder |
|
115 | - * @param IConfig $config |
|
116 | - * @param IUserManager $userManager |
|
117 | - * @param ICloudIdManager $cloudIdManager |
|
118 | - * @param \OCP\GlobalScale\IConfig $globalScaleConfig |
|
119 | - * @param ICloudFederationProviderManager $cloudFederationProviderManager |
|
120 | - */ |
|
121 | - public function __construct( |
|
122 | - IDBConnection $connection, |
|
123 | - AddressHandler $addressHandler, |
|
124 | - Notifications $notifications, |
|
125 | - TokenHandler $tokenHandler, |
|
126 | - IL10N $l10n, |
|
127 | - ILogger $logger, |
|
128 | - IRootFolder $rootFolder, |
|
129 | - IConfig $config, |
|
130 | - IUserManager $userManager, |
|
131 | - ICloudIdManager $cloudIdManager, |
|
132 | - \OCP\GlobalScale\IConfig $globalScaleConfig, |
|
133 | - ICloudFederationProviderManager $cloudFederationProviderManager |
|
134 | - ) { |
|
135 | - $this->dbConnection = $connection; |
|
136 | - $this->addressHandler = $addressHandler; |
|
137 | - $this->notifications = $notifications; |
|
138 | - $this->tokenHandler = $tokenHandler; |
|
139 | - $this->l = $l10n; |
|
140 | - $this->logger = $logger; |
|
141 | - $this->rootFolder = $rootFolder; |
|
142 | - $this->config = $config; |
|
143 | - $this->userManager = $userManager; |
|
144 | - $this->cloudIdManager = $cloudIdManager; |
|
145 | - $this->gsConfig = $globalScaleConfig; |
|
146 | - $this->cloudFederationProviderManager = $cloudFederationProviderManager; |
|
147 | - } |
|
148 | - |
|
149 | - /** |
|
150 | - * Return the identifier of this provider. |
|
151 | - * |
|
152 | - * @return string Containing only [a-zA-Z0-9] |
|
153 | - */ |
|
154 | - public function identifier() { |
|
155 | - return 'ocFederatedSharing'; |
|
156 | - } |
|
157 | - |
|
158 | - /** |
|
159 | - * Share a path |
|
160 | - * |
|
161 | - * @param IShare $share |
|
162 | - * @return IShare The share object |
|
163 | - * @throws ShareNotFound |
|
164 | - * @throws \Exception |
|
165 | - */ |
|
166 | - public function create(IShare $share) { |
|
167 | - $shareWith = $share->getSharedWith(); |
|
168 | - $itemSource = $share->getNodeId(); |
|
169 | - $itemType = $share->getNodeType(); |
|
170 | - $permissions = $share->getPermissions(); |
|
171 | - $sharedBy = $share->getSharedBy(); |
|
172 | - $shareType = $share->getShareType(); |
|
173 | - |
|
174 | - if ($shareType === IShare::TYPE_REMOTE_GROUP && |
|
175 | - !$this->isOutgoingServer2serverGroupShareEnabled() |
|
176 | - ) { |
|
177 | - $message = 'It is not allowed to send federated group shares from this server.'; |
|
178 | - $message_t = $this->l->t('It is not allowed to send federated group shares from this server.'); |
|
179 | - $this->logger->debug($message, ['app' => 'Federated File Sharing']); |
|
180 | - throw new \Exception($message_t); |
|
181 | - } |
|
182 | - |
|
183 | - /* |
|
61 | + public const SHARE_TYPE_REMOTE = 6; |
|
62 | + |
|
63 | + /** @var IDBConnection */ |
|
64 | + private $dbConnection; |
|
65 | + |
|
66 | + /** @var AddressHandler */ |
|
67 | + private $addressHandler; |
|
68 | + |
|
69 | + /** @var Notifications */ |
|
70 | + private $notifications; |
|
71 | + |
|
72 | + /** @var TokenHandler */ |
|
73 | + private $tokenHandler; |
|
74 | + |
|
75 | + /** @var IL10N */ |
|
76 | + private $l; |
|
77 | + |
|
78 | + /** @var ILogger */ |
|
79 | + private $logger; |
|
80 | + |
|
81 | + /** @var IRootFolder */ |
|
82 | + private $rootFolder; |
|
83 | + |
|
84 | + /** @var IConfig */ |
|
85 | + private $config; |
|
86 | + |
|
87 | + /** @var string */ |
|
88 | + private $externalShareTable = 'share_external'; |
|
89 | + |
|
90 | + /** @var IUserManager */ |
|
91 | + private $userManager; |
|
92 | + |
|
93 | + /** @var ICloudIdManager */ |
|
94 | + private $cloudIdManager; |
|
95 | + |
|
96 | + /** @var \OCP\GlobalScale\IConfig */ |
|
97 | + private $gsConfig; |
|
98 | + |
|
99 | + /** @var ICloudFederationProviderManager */ |
|
100 | + private $cloudFederationProviderManager; |
|
101 | + |
|
102 | + /** @var array list of supported share types */ |
|
103 | + private $supportedShareType = [IShare::TYPE_REMOTE_GROUP, IShare::TYPE_REMOTE, IShare::TYPE_CIRCLE]; |
|
104 | + |
|
105 | + /** |
|
106 | + * DefaultShareProvider constructor. |
|
107 | + * |
|
108 | + * @param IDBConnection $connection |
|
109 | + * @param AddressHandler $addressHandler |
|
110 | + * @param Notifications $notifications |
|
111 | + * @param TokenHandler $tokenHandler |
|
112 | + * @param IL10N $l10n |
|
113 | + * @param ILogger $logger |
|
114 | + * @param IRootFolder $rootFolder |
|
115 | + * @param IConfig $config |
|
116 | + * @param IUserManager $userManager |
|
117 | + * @param ICloudIdManager $cloudIdManager |
|
118 | + * @param \OCP\GlobalScale\IConfig $globalScaleConfig |
|
119 | + * @param ICloudFederationProviderManager $cloudFederationProviderManager |
|
120 | + */ |
|
121 | + public function __construct( |
|
122 | + IDBConnection $connection, |
|
123 | + AddressHandler $addressHandler, |
|
124 | + Notifications $notifications, |
|
125 | + TokenHandler $tokenHandler, |
|
126 | + IL10N $l10n, |
|
127 | + ILogger $logger, |
|
128 | + IRootFolder $rootFolder, |
|
129 | + IConfig $config, |
|
130 | + IUserManager $userManager, |
|
131 | + ICloudIdManager $cloudIdManager, |
|
132 | + \OCP\GlobalScale\IConfig $globalScaleConfig, |
|
133 | + ICloudFederationProviderManager $cloudFederationProviderManager |
|
134 | + ) { |
|
135 | + $this->dbConnection = $connection; |
|
136 | + $this->addressHandler = $addressHandler; |
|
137 | + $this->notifications = $notifications; |
|
138 | + $this->tokenHandler = $tokenHandler; |
|
139 | + $this->l = $l10n; |
|
140 | + $this->logger = $logger; |
|
141 | + $this->rootFolder = $rootFolder; |
|
142 | + $this->config = $config; |
|
143 | + $this->userManager = $userManager; |
|
144 | + $this->cloudIdManager = $cloudIdManager; |
|
145 | + $this->gsConfig = $globalScaleConfig; |
|
146 | + $this->cloudFederationProviderManager = $cloudFederationProviderManager; |
|
147 | + } |
|
148 | + |
|
149 | + /** |
|
150 | + * Return the identifier of this provider. |
|
151 | + * |
|
152 | + * @return string Containing only [a-zA-Z0-9] |
|
153 | + */ |
|
154 | + public function identifier() { |
|
155 | + return 'ocFederatedSharing'; |
|
156 | + } |
|
157 | + |
|
158 | + /** |
|
159 | + * Share a path |
|
160 | + * |
|
161 | + * @param IShare $share |
|
162 | + * @return IShare The share object |
|
163 | + * @throws ShareNotFound |
|
164 | + * @throws \Exception |
|
165 | + */ |
|
166 | + public function create(IShare $share) { |
|
167 | + $shareWith = $share->getSharedWith(); |
|
168 | + $itemSource = $share->getNodeId(); |
|
169 | + $itemType = $share->getNodeType(); |
|
170 | + $permissions = $share->getPermissions(); |
|
171 | + $sharedBy = $share->getSharedBy(); |
|
172 | + $shareType = $share->getShareType(); |
|
173 | + |
|
174 | + if ($shareType === IShare::TYPE_REMOTE_GROUP && |
|
175 | + !$this->isOutgoingServer2serverGroupShareEnabled() |
|
176 | + ) { |
|
177 | + $message = 'It is not allowed to send federated group shares from this server.'; |
|
178 | + $message_t = $this->l->t('It is not allowed to send federated group shares from this server.'); |
|
179 | + $this->logger->debug($message, ['app' => 'Federated File Sharing']); |
|
180 | + throw new \Exception($message_t); |
|
181 | + } |
|
182 | + |
|
183 | + /* |
|
184 | 184 | * Check if file is not already shared with the remote user |
185 | 185 | */ |
186 | - $alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE, $share->getNode(), 1, 0); |
|
187 | - $alreadySharedGroup = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE_GROUP, $share->getNode(), 1, 0); |
|
188 | - if (!empty($alreadyShared) || !empty($alreadySharedGroup)) { |
|
189 | - $message = 'Sharing %1$s failed, because this item is already shared with %2$s'; |
|
190 | - $message_t = $this->l->t('Sharing %1$s failed, because this item is already shared with %2$s', [$share->getNode()->getName(), $shareWith]); |
|
191 | - $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); |
|
192 | - throw new \Exception($message_t); |
|
193 | - } |
|
194 | - |
|
195 | - |
|
196 | - // don't allow federated shares if source and target server are the same |
|
197 | - $cloudId = $this->cloudIdManager->resolveCloudId($shareWith); |
|
198 | - $currentServer = $this->addressHandler->generateRemoteURL(); |
|
199 | - $currentUser = $sharedBy; |
|
200 | - if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) { |
|
201 | - $message = 'Not allowed to create a federated share with the same user.'; |
|
202 | - $message_t = $this->l->t('Not allowed to create a federated share with the same user'); |
|
203 | - $this->logger->debug($message, ['app' => 'Federated File Sharing']); |
|
204 | - throw new \Exception($message_t); |
|
205 | - } |
|
206 | - |
|
207 | - |
|
208 | - $share->setSharedWith($cloudId->getId()); |
|
209 | - |
|
210 | - try { |
|
211 | - $remoteShare = $this->getShareFromExternalShareTable($share); |
|
212 | - } catch (ShareNotFound $e) { |
|
213 | - $remoteShare = null; |
|
214 | - } |
|
215 | - |
|
216 | - if ($remoteShare) { |
|
217 | - try { |
|
218 | - $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']); |
|
219 | - $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType); |
|
220 | - $share->setId($shareId); |
|
221 | - list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId); |
|
222 | - // remote share was create successfully if we get a valid token as return |
|
223 | - $send = is_string($token) && $token !== ''; |
|
224 | - } catch (\Exception $e) { |
|
225 | - // fall back to old re-share behavior if the remote server |
|
226 | - // doesn't support flat re-shares (was introduced with Nextcloud 9.1) |
|
227 | - $this->removeShareFromTable($share); |
|
228 | - $shareId = $this->createFederatedShare($share); |
|
229 | - } |
|
230 | - if ($send) { |
|
231 | - $this->updateSuccessfulReshare($shareId, $token); |
|
232 | - $this->storeRemoteId($shareId, $remoteId); |
|
233 | - } else { |
|
234 | - $this->removeShareFromTable($share); |
|
235 | - $message_t = $this->l->t('File is already shared with %s', [$shareWith]); |
|
236 | - throw new \Exception($message_t); |
|
237 | - } |
|
238 | - } else { |
|
239 | - $shareId = $this->createFederatedShare($share); |
|
240 | - } |
|
241 | - |
|
242 | - $data = $this->getRawShare($shareId); |
|
243 | - return $this->createShareObject($data); |
|
244 | - } |
|
245 | - |
|
246 | - /** |
|
247 | - * create federated share and inform the recipient |
|
248 | - * |
|
249 | - * @param IShare $share |
|
250 | - * @return int |
|
251 | - * @throws ShareNotFound |
|
252 | - * @throws \Exception |
|
253 | - */ |
|
254 | - protected function createFederatedShare(IShare $share) { |
|
255 | - $token = $this->tokenHandler->generateToken(); |
|
256 | - $shareId = $this->addShareToDB( |
|
257 | - $share->getNodeId(), |
|
258 | - $share->getNodeType(), |
|
259 | - $share->getSharedWith(), |
|
260 | - $share->getSharedBy(), |
|
261 | - $share->getShareOwner(), |
|
262 | - $share->getPermissions(), |
|
263 | - $token, |
|
264 | - $share->getShareType() |
|
265 | - ); |
|
266 | - |
|
267 | - $failure = false; |
|
268 | - |
|
269 | - try { |
|
270 | - $sharedByFederatedId = $share->getSharedBy(); |
|
271 | - if ($this->userManager->userExists($sharedByFederatedId)) { |
|
272 | - $cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL()); |
|
273 | - $sharedByFederatedId = $cloudId->getId(); |
|
274 | - } |
|
275 | - $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL()); |
|
276 | - $send = $this->notifications->sendRemoteShare( |
|
277 | - $token, |
|
278 | - $share->getSharedWith(), |
|
279 | - $share->getNode()->getName(), |
|
280 | - $shareId, |
|
281 | - $share->getShareOwner(), |
|
282 | - $ownerCloudId->getId(), |
|
283 | - $share->getSharedBy(), |
|
284 | - $sharedByFederatedId, |
|
285 | - $share->getShareType() |
|
286 | - ); |
|
287 | - |
|
288 | - if ($send === false) { |
|
289 | - $failure = true; |
|
290 | - } |
|
291 | - } catch (\Exception $e) { |
|
292 | - $this->logger->logException($e, [ |
|
293 | - 'message' => 'Failed to notify remote server of federated share, removing share.', |
|
294 | - 'level' => ILogger::ERROR, |
|
295 | - 'app' => 'federatedfilesharing', |
|
296 | - ]); |
|
297 | - $failure = true; |
|
298 | - } |
|
299 | - |
|
300 | - if ($failure) { |
|
301 | - $this->removeShareFromTableById($shareId); |
|
302 | - $message_t = $this->l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable or uses a self-signed certificate.', |
|
303 | - [$share->getNode()->getName(), $share->getSharedWith()]); |
|
304 | - throw new \Exception($message_t); |
|
305 | - } |
|
306 | - |
|
307 | - return $shareId; |
|
308 | - } |
|
309 | - |
|
310 | - /** |
|
311 | - * @param string $shareWith |
|
312 | - * @param IShare $share |
|
313 | - * @param string $shareId internal share Id |
|
314 | - * @return array |
|
315 | - * @throws \Exception |
|
316 | - */ |
|
317 | - protected function askOwnerToReShare($shareWith, IShare $share, $shareId) { |
|
318 | - $remoteShare = $this->getShareFromExternalShareTable($share); |
|
319 | - $token = $remoteShare['share_token']; |
|
320 | - $remoteId = $remoteShare['remote_id']; |
|
321 | - $remote = $remoteShare['remote']; |
|
322 | - |
|
323 | - list($token, $remoteId) = $this->notifications->requestReShare( |
|
324 | - $token, |
|
325 | - $remoteId, |
|
326 | - $shareId, |
|
327 | - $remote, |
|
328 | - $shareWith, |
|
329 | - $share->getPermissions(), |
|
330 | - $share->getNode()->getName() |
|
331 | - ); |
|
332 | - |
|
333 | - return [$token, $remoteId]; |
|
334 | - } |
|
335 | - |
|
336 | - /** |
|
337 | - * get federated share from the share_external table but exclude mounted link shares |
|
338 | - * |
|
339 | - * @param IShare $share |
|
340 | - * @return array |
|
341 | - * @throws ShareNotFound |
|
342 | - */ |
|
343 | - protected function getShareFromExternalShareTable(IShare $share) { |
|
344 | - $query = $this->dbConnection->getQueryBuilder(); |
|
345 | - $query->select('*')->from($this->externalShareTable) |
|
346 | - ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner()))) |
|
347 | - ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget()))); |
|
348 | - $result = $query->execute()->fetchAll(); |
|
349 | - |
|
350 | - if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) { |
|
351 | - return $result[0]; |
|
352 | - } |
|
353 | - |
|
354 | - throw new ShareNotFound('share not found in share_external table'); |
|
355 | - } |
|
356 | - |
|
357 | - /** |
|
358 | - * add share to the database and return the ID |
|
359 | - * |
|
360 | - * @param int $itemSource |
|
361 | - * @param string $itemType |
|
362 | - * @param string $shareWith |
|
363 | - * @param string $sharedBy |
|
364 | - * @param string $uidOwner |
|
365 | - * @param int $permissions |
|
366 | - * @param string $token |
|
367 | - * @param int $shareType |
|
368 | - * @return int |
|
369 | - */ |
|
370 | - private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType) { |
|
371 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
372 | - $qb->insert('share') |
|
373 | - ->setValue('share_type', $qb->createNamedParameter($shareType)) |
|
374 | - ->setValue('item_type', $qb->createNamedParameter($itemType)) |
|
375 | - ->setValue('item_source', $qb->createNamedParameter($itemSource)) |
|
376 | - ->setValue('file_source', $qb->createNamedParameter($itemSource)) |
|
377 | - ->setValue('share_with', $qb->createNamedParameter($shareWith)) |
|
378 | - ->setValue('uid_owner', $qb->createNamedParameter($uidOwner)) |
|
379 | - ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy)) |
|
380 | - ->setValue('permissions', $qb->createNamedParameter($permissions)) |
|
381 | - ->setValue('token', $qb->createNamedParameter($token)) |
|
382 | - ->setValue('stime', $qb->createNamedParameter(time())); |
|
383 | - |
|
384 | - /* |
|
186 | + $alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE, $share->getNode(), 1, 0); |
|
187 | + $alreadySharedGroup = $this->getSharedWith($shareWith, IShare::TYPE_REMOTE_GROUP, $share->getNode(), 1, 0); |
|
188 | + if (!empty($alreadyShared) || !empty($alreadySharedGroup)) { |
|
189 | + $message = 'Sharing %1$s failed, because this item is already shared with %2$s'; |
|
190 | + $message_t = $this->l->t('Sharing %1$s failed, because this item is already shared with %2$s', [$share->getNode()->getName(), $shareWith]); |
|
191 | + $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); |
|
192 | + throw new \Exception($message_t); |
|
193 | + } |
|
194 | + |
|
195 | + |
|
196 | + // don't allow federated shares if source and target server are the same |
|
197 | + $cloudId = $this->cloudIdManager->resolveCloudId($shareWith); |
|
198 | + $currentServer = $this->addressHandler->generateRemoteURL(); |
|
199 | + $currentUser = $sharedBy; |
|
200 | + if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) { |
|
201 | + $message = 'Not allowed to create a federated share with the same user.'; |
|
202 | + $message_t = $this->l->t('Not allowed to create a federated share with the same user'); |
|
203 | + $this->logger->debug($message, ['app' => 'Federated File Sharing']); |
|
204 | + throw new \Exception($message_t); |
|
205 | + } |
|
206 | + |
|
207 | + |
|
208 | + $share->setSharedWith($cloudId->getId()); |
|
209 | + |
|
210 | + try { |
|
211 | + $remoteShare = $this->getShareFromExternalShareTable($share); |
|
212 | + } catch (ShareNotFound $e) { |
|
213 | + $remoteShare = null; |
|
214 | + } |
|
215 | + |
|
216 | + if ($remoteShare) { |
|
217 | + try { |
|
218 | + $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']); |
|
219 | + $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType); |
|
220 | + $share->setId($shareId); |
|
221 | + list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId); |
|
222 | + // remote share was create successfully if we get a valid token as return |
|
223 | + $send = is_string($token) && $token !== ''; |
|
224 | + } catch (\Exception $e) { |
|
225 | + // fall back to old re-share behavior if the remote server |
|
226 | + // doesn't support flat re-shares (was introduced with Nextcloud 9.1) |
|
227 | + $this->removeShareFromTable($share); |
|
228 | + $shareId = $this->createFederatedShare($share); |
|
229 | + } |
|
230 | + if ($send) { |
|
231 | + $this->updateSuccessfulReshare($shareId, $token); |
|
232 | + $this->storeRemoteId($shareId, $remoteId); |
|
233 | + } else { |
|
234 | + $this->removeShareFromTable($share); |
|
235 | + $message_t = $this->l->t('File is already shared with %s', [$shareWith]); |
|
236 | + throw new \Exception($message_t); |
|
237 | + } |
|
238 | + } else { |
|
239 | + $shareId = $this->createFederatedShare($share); |
|
240 | + } |
|
241 | + |
|
242 | + $data = $this->getRawShare($shareId); |
|
243 | + return $this->createShareObject($data); |
|
244 | + } |
|
245 | + |
|
246 | + /** |
|
247 | + * create federated share and inform the recipient |
|
248 | + * |
|
249 | + * @param IShare $share |
|
250 | + * @return int |
|
251 | + * @throws ShareNotFound |
|
252 | + * @throws \Exception |
|
253 | + */ |
|
254 | + protected function createFederatedShare(IShare $share) { |
|
255 | + $token = $this->tokenHandler->generateToken(); |
|
256 | + $shareId = $this->addShareToDB( |
|
257 | + $share->getNodeId(), |
|
258 | + $share->getNodeType(), |
|
259 | + $share->getSharedWith(), |
|
260 | + $share->getSharedBy(), |
|
261 | + $share->getShareOwner(), |
|
262 | + $share->getPermissions(), |
|
263 | + $token, |
|
264 | + $share->getShareType() |
|
265 | + ); |
|
266 | + |
|
267 | + $failure = false; |
|
268 | + |
|
269 | + try { |
|
270 | + $sharedByFederatedId = $share->getSharedBy(); |
|
271 | + if ($this->userManager->userExists($sharedByFederatedId)) { |
|
272 | + $cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL()); |
|
273 | + $sharedByFederatedId = $cloudId->getId(); |
|
274 | + } |
|
275 | + $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL()); |
|
276 | + $send = $this->notifications->sendRemoteShare( |
|
277 | + $token, |
|
278 | + $share->getSharedWith(), |
|
279 | + $share->getNode()->getName(), |
|
280 | + $shareId, |
|
281 | + $share->getShareOwner(), |
|
282 | + $ownerCloudId->getId(), |
|
283 | + $share->getSharedBy(), |
|
284 | + $sharedByFederatedId, |
|
285 | + $share->getShareType() |
|
286 | + ); |
|
287 | + |
|
288 | + if ($send === false) { |
|
289 | + $failure = true; |
|
290 | + } |
|
291 | + } catch (\Exception $e) { |
|
292 | + $this->logger->logException($e, [ |
|
293 | + 'message' => 'Failed to notify remote server of federated share, removing share.', |
|
294 | + 'level' => ILogger::ERROR, |
|
295 | + 'app' => 'federatedfilesharing', |
|
296 | + ]); |
|
297 | + $failure = true; |
|
298 | + } |
|
299 | + |
|
300 | + if ($failure) { |
|
301 | + $this->removeShareFromTableById($shareId); |
|
302 | + $message_t = $this->l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable or uses a self-signed certificate.', |
|
303 | + [$share->getNode()->getName(), $share->getSharedWith()]); |
|
304 | + throw new \Exception($message_t); |
|
305 | + } |
|
306 | + |
|
307 | + return $shareId; |
|
308 | + } |
|
309 | + |
|
310 | + /** |
|
311 | + * @param string $shareWith |
|
312 | + * @param IShare $share |
|
313 | + * @param string $shareId internal share Id |
|
314 | + * @return array |
|
315 | + * @throws \Exception |
|
316 | + */ |
|
317 | + protected function askOwnerToReShare($shareWith, IShare $share, $shareId) { |
|
318 | + $remoteShare = $this->getShareFromExternalShareTable($share); |
|
319 | + $token = $remoteShare['share_token']; |
|
320 | + $remoteId = $remoteShare['remote_id']; |
|
321 | + $remote = $remoteShare['remote']; |
|
322 | + |
|
323 | + list($token, $remoteId) = $this->notifications->requestReShare( |
|
324 | + $token, |
|
325 | + $remoteId, |
|
326 | + $shareId, |
|
327 | + $remote, |
|
328 | + $shareWith, |
|
329 | + $share->getPermissions(), |
|
330 | + $share->getNode()->getName() |
|
331 | + ); |
|
332 | + |
|
333 | + return [$token, $remoteId]; |
|
334 | + } |
|
335 | + |
|
336 | + /** |
|
337 | + * get federated share from the share_external table but exclude mounted link shares |
|
338 | + * |
|
339 | + * @param IShare $share |
|
340 | + * @return array |
|
341 | + * @throws ShareNotFound |
|
342 | + */ |
|
343 | + protected function getShareFromExternalShareTable(IShare $share) { |
|
344 | + $query = $this->dbConnection->getQueryBuilder(); |
|
345 | + $query->select('*')->from($this->externalShareTable) |
|
346 | + ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner()))) |
|
347 | + ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget()))); |
|
348 | + $result = $query->execute()->fetchAll(); |
|
349 | + |
|
350 | + if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) { |
|
351 | + return $result[0]; |
|
352 | + } |
|
353 | + |
|
354 | + throw new ShareNotFound('share not found in share_external table'); |
|
355 | + } |
|
356 | + |
|
357 | + /** |
|
358 | + * add share to the database and return the ID |
|
359 | + * |
|
360 | + * @param int $itemSource |
|
361 | + * @param string $itemType |
|
362 | + * @param string $shareWith |
|
363 | + * @param string $sharedBy |
|
364 | + * @param string $uidOwner |
|
365 | + * @param int $permissions |
|
366 | + * @param string $token |
|
367 | + * @param int $shareType |
|
368 | + * @return int |
|
369 | + */ |
|
370 | + private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType) { |
|
371 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
372 | + $qb->insert('share') |
|
373 | + ->setValue('share_type', $qb->createNamedParameter($shareType)) |
|
374 | + ->setValue('item_type', $qb->createNamedParameter($itemType)) |
|
375 | + ->setValue('item_source', $qb->createNamedParameter($itemSource)) |
|
376 | + ->setValue('file_source', $qb->createNamedParameter($itemSource)) |
|
377 | + ->setValue('share_with', $qb->createNamedParameter($shareWith)) |
|
378 | + ->setValue('uid_owner', $qb->createNamedParameter($uidOwner)) |
|
379 | + ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy)) |
|
380 | + ->setValue('permissions', $qb->createNamedParameter($permissions)) |
|
381 | + ->setValue('token', $qb->createNamedParameter($token)) |
|
382 | + ->setValue('stime', $qb->createNamedParameter(time())); |
|
383 | + |
|
384 | + /* |
|
385 | 385 | * Added to fix https://github.com/owncloud/core/issues/22215 |
386 | 386 | * Can be removed once we get rid of ajax/share.php |
387 | 387 | */ |
388 | - $qb->setValue('file_target', $qb->createNamedParameter('')); |
|
389 | - |
|
390 | - $qb->execute(); |
|
391 | - $id = $qb->getLastInsertId(); |
|
392 | - |
|
393 | - return (int)$id; |
|
394 | - } |
|
395 | - |
|
396 | - /** |
|
397 | - * Update a share |
|
398 | - * |
|
399 | - * @param IShare $share |
|
400 | - * @return IShare The share object |
|
401 | - */ |
|
402 | - public function update(IShare $share) { |
|
403 | - /* |
|
388 | + $qb->setValue('file_target', $qb->createNamedParameter('')); |
|
389 | + |
|
390 | + $qb->execute(); |
|
391 | + $id = $qb->getLastInsertId(); |
|
392 | + |
|
393 | + return (int)$id; |
|
394 | + } |
|
395 | + |
|
396 | + /** |
|
397 | + * Update a share |
|
398 | + * |
|
399 | + * @param IShare $share |
|
400 | + * @return IShare The share object |
|
401 | + */ |
|
402 | + public function update(IShare $share) { |
|
403 | + /* |
|
404 | 404 | * We allow updating the permissions of federated shares |
405 | 405 | */ |
406 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
407 | - $qb->update('share') |
|
408 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) |
|
409 | - ->set('permissions', $qb->createNamedParameter($share->getPermissions())) |
|
410 | - ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) |
|
411 | - ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) |
|
412 | - ->execute(); |
|
413 | - |
|
414 | - // send the updated permission to the owner/initiator, if they are not the same |
|
415 | - if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
416 | - $this->sendPermissionUpdate($share); |
|
417 | - } |
|
418 | - |
|
419 | - return $share; |
|
420 | - } |
|
421 | - |
|
422 | - /** |
|
423 | - * send the updated permission to the owner/initiator, if they are not the same |
|
424 | - * |
|
425 | - * @param IShare $share |
|
426 | - * @throws ShareNotFound |
|
427 | - * @throws \OC\HintException |
|
428 | - */ |
|
429 | - protected function sendPermissionUpdate(IShare $share) { |
|
430 | - $remoteId = $this->getRemoteId($share); |
|
431 | - // if the local user is the owner we send the permission change to the initiator |
|
432 | - if ($this->userManager->userExists($share->getShareOwner())) { |
|
433 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
434 | - } else { // ... if not we send the permission change to the owner |
|
435 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); |
|
436 | - } |
|
437 | - $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions()); |
|
438 | - } |
|
439 | - |
|
440 | - |
|
441 | - /** |
|
442 | - * update successful reShare with the correct token |
|
443 | - * |
|
444 | - * @param int $shareId |
|
445 | - * @param string $token |
|
446 | - */ |
|
447 | - protected function updateSuccessfulReShare($shareId, $token) { |
|
448 | - $query = $this->dbConnection->getQueryBuilder(); |
|
449 | - $query->update('share') |
|
450 | - ->where($query->expr()->eq('id', $query->createNamedParameter($shareId))) |
|
451 | - ->set('token', $query->createNamedParameter($token)) |
|
452 | - ->execute(); |
|
453 | - } |
|
454 | - |
|
455 | - /** |
|
456 | - * store remote ID in federated reShare table |
|
457 | - * |
|
458 | - * @param $shareId |
|
459 | - * @param $remoteId |
|
460 | - */ |
|
461 | - public function storeRemoteId($shareId, $remoteId) { |
|
462 | - $query = $this->dbConnection->getQueryBuilder(); |
|
463 | - $query->insert('federated_reshares') |
|
464 | - ->values( |
|
465 | - [ |
|
466 | - 'share_id' => $query->createNamedParameter($shareId), |
|
467 | - 'remote_id' => $query->createNamedParameter($remoteId), |
|
468 | - ] |
|
469 | - ); |
|
470 | - $query->execute(); |
|
471 | - } |
|
472 | - |
|
473 | - /** |
|
474 | - * get share ID on remote server for federated re-shares |
|
475 | - * |
|
476 | - * @param IShare $share |
|
477 | - * @return int |
|
478 | - * @throws ShareNotFound |
|
479 | - */ |
|
480 | - public function getRemoteId(IShare $share) { |
|
481 | - $query = $this->dbConnection->getQueryBuilder(); |
|
482 | - $query->select('remote_id')->from('federated_reshares') |
|
483 | - ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId()))); |
|
484 | - $data = $query->execute()->fetch(); |
|
485 | - |
|
486 | - if (!is_array($data) || !isset($data['remote_id'])) { |
|
487 | - throw new ShareNotFound(); |
|
488 | - } |
|
489 | - |
|
490 | - return (int)$data['remote_id']; |
|
491 | - } |
|
492 | - |
|
493 | - /** |
|
494 | - * @inheritdoc |
|
495 | - */ |
|
496 | - public function move(IShare $share, $recipient) { |
|
497 | - /* |
|
406 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
407 | + $qb->update('share') |
|
408 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) |
|
409 | + ->set('permissions', $qb->createNamedParameter($share->getPermissions())) |
|
410 | + ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) |
|
411 | + ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) |
|
412 | + ->execute(); |
|
413 | + |
|
414 | + // send the updated permission to the owner/initiator, if they are not the same |
|
415 | + if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
416 | + $this->sendPermissionUpdate($share); |
|
417 | + } |
|
418 | + |
|
419 | + return $share; |
|
420 | + } |
|
421 | + |
|
422 | + /** |
|
423 | + * send the updated permission to the owner/initiator, if they are not the same |
|
424 | + * |
|
425 | + * @param IShare $share |
|
426 | + * @throws ShareNotFound |
|
427 | + * @throws \OC\HintException |
|
428 | + */ |
|
429 | + protected function sendPermissionUpdate(IShare $share) { |
|
430 | + $remoteId = $this->getRemoteId($share); |
|
431 | + // if the local user is the owner we send the permission change to the initiator |
|
432 | + if ($this->userManager->userExists($share->getShareOwner())) { |
|
433 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
434 | + } else { // ... if not we send the permission change to the owner |
|
435 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); |
|
436 | + } |
|
437 | + $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions()); |
|
438 | + } |
|
439 | + |
|
440 | + |
|
441 | + /** |
|
442 | + * update successful reShare with the correct token |
|
443 | + * |
|
444 | + * @param int $shareId |
|
445 | + * @param string $token |
|
446 | + */ |
|
447 | + protected function updateSuccessfulReShare($shareId, $token) { |
|
448 | + $query = $this->dbConnection->getQueryBuilder(); |
|
449 | + $query->update('share') |
|
450 | + ->where($query->expr()->eq('id', $query->createNamedParameter($shareId))) |
|
451 | + ->set('token', $query->createNamedParameter($token)) |
|
452 | + ->execute(); |
|
453 | + } |
|
454 | + |
|
455 | + /** |
|
456 | + * store remote ID in federated reShare table |
|
457 | + * |
|
458 | + * @param $shareId |
|
459 | + * @param $remoteId |
|
460 | + */ |
|
461 | + public function storeRemoteId($shareId, $remoteId) { |
|
462 | + $query = $this->dbConnection->getQueryBuilder(); |
|
463 | + $query->insert('federated_reshares') |
|
464 | + ->values( |
|
465 | + [ |
|
466 | + 'share_id' => $query->createNamedParameter($shareId), |
|
467 | + 'remote_id' => $query->createNamedParameter($remoteId), |
|
468 | + ] |
|
469 | + ); |
|
470 | + $query->execute(); |
|
471 | + } |
|
472 | + |
|
473 | + /** |
|
474 | + * get share ID on remote server for federated re-shares |
|
475 | + * |
|
476 | + * @param IShare $share |
|
477 | + * @return int |
|
478 | + * @throws ShareNotFound |
|
479 | + */ |
|
480 | + public function getRemoteId(IShare $share) { |
|
481 | + $query = $this->dbConnection->getQueryBuilder(); |
|
482 | + $query->select('remote_id')->from('federated_reshares') |
|
483 | + ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId()))); |
|
484 | + $data = $query->execute()->fetch(); |
|
485 | + |
|
486 | + if (!is_array($data) || !isset($data['remote_id'])) { |
|
487 | + throw new ShareNotFound(); |
|
488 | + } |
|
489 | + |
|
490 | + return (int)$data['remote_id']; |
|
491 | + } |
|
492 | + |
|
493 | + /** |
|
494 | + * @inheritdoc |
|
495 | + */ |
|
496 | + public function move(IShare $share, $recipient) { |
|
497 | + /* |
|
498 | 498 | * This function does nothing yet as it is just for outgoing |
499 | 499 | * federated shares. |
500 | 500 | */ |
501 | - return $share; |
|
502 | - } |
|
503 | - |
|
504 | - /** |
|
505 | - * Get all children of this share |
|
506 | - * |
|
507 | - * @param IShare $parent |
|
508 | - * @return IShare[] |
|
509 | - */ |
|
510 | - public function getChildren(IShare $parent) { |
|
511 | - $children = []; |
|
512 | - |
|
513 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
514 | - $qb->select('*') |
|
515 | - ->from('share') |
|
516 | - ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) |
|
517 | - ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
518 | - ->orderBy('id'); |
|
519 | - |
|
520 | - $cursor = $qb->execute(); |
|
521 | - while ($data = $cursor->fetch()) { |
|
522 | - $children[] = $this->createShareObject($data); |
|
523 | - } |
|
524 | - $cursor->closeCursor(); |
|
525 | - |
|
526 | - return $children; |
|
527 | - } |
|
528 | - |
|
529 | - /** |
|
530 | - * Delete a share (owner unShares the file) |
|
531 | - * |
|
532 | - * @param IShare $share |
|
533 | - * @throws ShareNotFound |
|
534 | - * @throws \OC\HintException |
|
535 | - */ |
|
536 | - public function delete(IShare $share) { |
|
537 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith()); |
|
538 | - |
|
539 | - // if the local user is the owner we can send the unShare request directly... |
|
540 | - if ($this->userManager->userExists($share->getShareOwner())) { |
|
541 | - $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken()); |
|
542 | - $this->revokeShare($share, true); |
|
543 | - } else { // ... if not we need to correct ID for the unShare request |
|
544 | - $remoteId = $this->getRemoteId($share); |
|
545 | - $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken()); |
|
546 | - $this->revokeShare($share, false); |
|
547 | - } |
|
548 | - |
|
549 | - // only remove the share when all messages are send to not lose information |
|
550 | - // about the share to early |
|
551 | - $this->removeShareFromTable($share); |
|
552 | - } |
|
553 | - |
|
554 | - /** |
|
555 | - * in case of a re-share we need to send the other use (initiator or owner) |
|
556 | - * a message that the file was unshared |
|
557 | - * |
|
558 | - * @param IShare $share |
|
559 | - * @param bool $isOwner the user can either be the owner or the user who re-sahred it |
|
560 | - * @throws ShareNotFound |
|
561 | - * @throws \OC\HintException |
|
562 | - */ |
|
563 | - protected function revokeShare($share, $isOwner) { |
|
564 | - if ($this->userManager->userExists($share->getShareOwner() && $this->userManager->userExists($share->getSharedBy()))) { |
|
565 | - // If both the owner and the initiator of the share are local users we don't have to notify anybody else |
|
566 | - return; |
|
567 | - } |
|
568 | - |
|
569 | - // also send a unShare request to the initiator, if this is a different user than the owner |
|
570 | - if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
571 | - if ($isOwner) { |
|
572 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
573 | - } else { |
|
574 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); |
|
575 | - } |
|
576 | - $remoteId = $this->getRemoteId($share); |
|
577 | - $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken()); |
|
578 | - } |
|
579 | - } |
|
580 | - |
|
581 | - /** |
|
582 | - * remove share from table |
|
583 | - * |
|
584 | - * @param IShare $share |
|
585 | - */ |
|
586 | - public function removeShareFromTable(IShare $share) { |
|
587 | - $this->removeShareFromTableById($share->getId()); |
|
588 | - } |
|
589 | - |
|
590 | - /** |
|
591 | - * remove share from table |
|
592 | - * |
|
593 | - * @param string $shareId |
|
594 | - */ |
|
595 | - private function removeShareFromTableById($shareId) { |
|
596 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
597 | - $qb->delete('share') |
|
598 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId))) |
|
599 | - ->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(IShare::TYPE_CIRCLE))); |
|
600 | - $qb->execute(); |
|
601 | - |
|
602 | - $qb->delete('federated_reshares') |
|
603 | - ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId))); |
|
604 | - $qb->execute(); |
|
605 | - } |
|
606 | - |
|
607 | - /** |
|
608 | - * @inheritdoc |
|
609 | - */ |
|
610 | - public function deleteFromSelf(IShare $share, $recipient) { |
|
611 | - // nothing to do here. Technically deleteFromSelf in the context of federated |
|
612 | - // shares is a umount of a external storage. This is handled here |
|
613 | - // apps/files_sharing/lib/external/manager.php |
|
614 | - // TODO move this code over to this app |
|
615 | - } |
|
616 | - |
|
617 | - public function restore(IShare $share, string $recipient): IShare { |
|
618 | - throw new GenericShareException('not implemented'); |
|
619 | - } |
|
620 | - |
|
621 | - |
|
622 | - public function getSharesInFolder($userId, Folder $node, $reshares) { |
|
623 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
624 | - $qb->select('*') |
|
625 | - ->from('share', 's') |
|
626 | - ->andWhere($qb->expr()->orX( |
|
627 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
628 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
629 | - )) |
|
630 | - ->andWhere( |
|
631 | - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)) |
|
632 | - ); |
|
633 | - |
|
634 | - /** |
|
635 | - * Reshares for this user are shares where they are the owner. |
|
636 | - */ |
|
637 | - if ($reshares === false) { |
|
638 | - $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); |
|
639 | - } else { |
|
640 | - $qb->andWhere( |
|
641 | - $qb->expr()->orX( |
|
642 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
643 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
644 | - ) |
|
645 | - ); |
|
646 | - } |
|
647 | - |
|
648 | - $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
649 | - $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
|
650 | - |
|
651 | - $qb->orderBy('id'); |
|
652 | - |
|
653 | - $cursor = $qb->execute(); |
|
654 | - $shares = []; |
|
655 | - while ($data = $cursor->fetch()) { |
|
656 | - $shares[$data['fileid']][] = $this->createShareObject($data); |
|
657 | - } |
|
658 | - $cursor->closeCursor(); |
|
659 | - |
|
660 | - return $shares; |
|
661 | - } |
|
662 | - |
|
663 | - /** |
|
664 | - * @inheritdoc |
|
665 | - */ |
|
666 | - public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) { |
|
667 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
668 | - $qb->select('*') |
|
669 | - ->from('share'); |
|
670 | - |
|
671 | - $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType))); |
|
672 | - |
|
673 | - /** |
|
674 | - * Reshares for this user are shares where they are the owner. |
|
675 | - */ |
|
676 | - if ($reshares === false) { |
|
677 | - //Special case for old shares created via the web UI |
|
678 | - $or1 = $qb->expr()->andX( |
|
679 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
680 | - $qb->expr()->isNull('uid_initiator') |
|
681 | - ); |
|
682 | - |
|
683 | - $qb->andWhere( |
|
684 | - $qb->expr()->orX( |
|
685 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)), |
|
686 | - $or1 |
|
687 | - ) |
|
688 | - ); |
|
689 | - } else { |
|
690 | - $qb->andWhere( |
|
691 | - $qb->expr()->orX( |
|
692 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
693 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
694 | - ) |
|
695 | - ); |
|
696 | - } |
|
697 | - |
|
698 | - if ($node !== null) { |
|
699 | - $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
700 | - } |
|
701 | - |
|
702 | - if ($limit !== -1) { |
|
703 | - $qb->setMaxResults($limit); |
|
704 | - } |
|
705 | - |
|
706 | - $qb->setFirstResult($offset); |
|
707 | - $qb->orderBy('id'); |
|
708 | - |
|
709 | - $cursor = $qb->execute(); |
|
710 | - $shares = []; |
|
711 | - while ($data = $cursor->fetch()) { |
|
712 | - $shares[] = $this->createShareObject($data); |
|
713 | - } |
|
714 | - $cursor->closeCursor(); |
|
715 | - |
|
716 | - return $shares; |
|
717 | - } |
|
718 | - |
|
719 | - /** |
|
720 | - * @inheritdoc |
|
721 | - */ |
|
722 | - public function getShareById($id, $recipientId = null) { |
|
723 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
724 | - |
|
725 | - $qb->select('*') |
|
726 | - ->from('share') |
|
727 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) |
|
728 | - ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); |
|
729 | - |
|
730 | - $cursor = $qb->execute(); |
|
731 | - $data = $cursor->fetch(); |
|
732 | - $cursor->closeCursor(); |
|
733 | - |
|
734 | - if ($data === false) { |
|
735 | - throw new ShareNotFound('Can not find share with ID: ' . $id); |
|
736 | - } |
|
737 | - |
|
738 | - try { |
|
739 | - $share = $this->createShareObject($data); |
|
740 | - } catch (InvalidShare $e) { |
|
741 | - throw new ShareNotFound(); |
|
742 | - } |
|
743 | - |
|
744 | - return $share; |
|
745 | - } |
|
746 | - |
|
747 | - /** |
|
748 | - * Get shares for a given path |
|
749 | - * |
|
750 | - * @param \OCP\Files\Node $path |
|
751 | - * @return IShare[] |
|
752 | - */ |
|
753 | - public function getSharesByPath(Node $path) { |
|
754 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
755 | - |
|
756 | - // get federated user shares |
|
757 | - $cursor = $qb->select('*') |
|
758 | - ->from('share') |
|
759 | - ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) |
|
760 | - ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
761 | - ->execute(); |
|
762 | - |
|
763 | - $shares = []; |
|
764 | - while ($data = $cursor->fetch()) { |
|
765 | - $shares[] = $this->createShareObject($data); |
|
766 | - } |
|
767 | - $cursor->closeCursor(); |
|
768 | - |
|
769 | - return $shares; |
|
770 | - } |
|
771 | - |
|
772 | - /** |
|
773 | - * @inheritdoc |
|
774 | - */ |
|
775 | - public function getSharedWith($userId, $shareType, $node, $limit, $offset) { |
|
776 | - /** @var IShare[] $shares */ |
|
777 | - $shares = []; |
|
778 | - |
|
779 | - //Get shares directly with this user |
|
780 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
781 | - $qb->select('*') |
|
782 | - ->from('share'); |
|
783 | - |
|
784 | - // Order by id |
|
785 | - $qb->orderBy('id'); |
|
786 | - |
|
787 | - // Set limit and offset |
|
788 | - if ($limit !== -1) { |
|
789 | - $qb->setMaxResults($limit); |
|
790 | - } |
|
791 | - $qb->setFirstResult($offset); |
|
792 | - |
|
793 | - $qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); |
|
794 | - $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); |
|
795 | - |
|
796 | - // Filter by node if provided |
|
797 | - if ($node !== null) { |
|
798 | - $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
799 | - } |
|
800 | - |
|
801 | - $cursor = $qb->execute(); |
|
802 | - |
|
803 | - while ($data = $cursor->fetch()) { |
|
804 | - $shares[] = $this->createShareObject($data); |
|
805 | - } |
|
806 | - $cursor->closeCursor(); |
|
807 | - |
|
808 | - |
|
809 | - return $shares; |
|
810 | - } |
|
811 | - |
|
812 | - /** |
|
813 | - * Get a share by token |
|
814 | - * |
|
815 | - * @param string $token |
|
816 | - * @return IShare |
|
817 | - * @throws ShareNotFound |
|
818 | - */ |
|
819 | - public function getShareByToken($token) { |
|
820 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
821 | - |
|
822 | - $cursor = $qb->select('*') |
|
823 | - ->from('share') |
|
824 | - ->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
825 | - ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) |
|
826 | - ->execute(); |
|
827 | - |
|
828 | - $data = $cursor->fetch(); |
|
829 | - |
|
830 | - if ($data === false) { |
|
831 | - throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
832 | - } |
|
833 | - |
|
834 | - try { |
|
835 | - $share = $this->createShareObject($data); |
|
836 | - } catch (InvalidShare $e) { |
|
837 | - throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
838 | - } |
|
839 | - |
|
840 | - return $share; |
|
841 | - } |
|
842 | - |
|
843 | - /** |
|
844 | - * get database row of a give share |
|
845 | - * |
|
846 | - * @param $id |
|
847 | - * @return array |
|
848 | - * @throws ShareNotFound |
|
849 | - */ |
|
850 | - private function getRawShare($id) { |
|
851 | - |
|
852 | - // Now fetch the inserted share and create a complete share object |
|
853 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
854 | - $qb->select('*') |
|
855 | - ->from('share') |
|
856 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); |
|
857 | - |
|
858 | - $cursor = $qb->execute(); |
|
859 | - $data = $cursor->fetch(); |
|
860 | - $cursor->closeCursor(); |
|
861 | - |
|
862 | - if ($data === false) { |
|
863 | - throw new ShareNotFound; |
|
864 | - } |
|
865 | - |
|
866 | - return $data; |
|
867 | - } |
|
868 | - |
|
869 | - /** |
|
870 | - * Create a share object from an database row |
|
871 | - * |
|
872 | - * @param array $data |
|
873 | - * @return IShare |
|
874 | - * @throws InvalidShare |
|
875 | - * @throws ShareNotFound |
|
876 | - */ |
|
877 | - private function createShareObject($data) { |
|
878 | - $share = new Share($this->rootFolder, $this->userManager); |
|
879 | - $share->setId((int)$data['id']) |
|
880 | - ->setShareType((int)$data['share_type']) |
|
881 | - ->setPermissions((int)$data['permissions']) |
|
882 | - ->setTarget($data['file_target']) |
|
883 | - ->setMailSend((bool)$data['mail_send']) |
|
884 | - ->setToken($data['token']); |
|
885 | - |
|
886 | - $shareTime = new \DateTime(); |
|
887 | - $shareTime->setTimestamp((int)$data['stime']); |
|
888 | - $share->setShareTime($shareTime); |
|
889 | - $share->setSharedWith($data['share_with']); |
|
890 | - |
|
891 | - if ($data['uid_initiator'] !== null) { |
|
892 | - $share->setShareOwner($data['uid_owner']); |
|
893 | - $share->setSharedBy($data['uid_initiator']); |
|
894 | - } else { |
|
895 | - //OLD SHARE |
|
896 | - $share->setSharedBy($data['uid_owner']); |
|
897 | - $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
898 | - |
|
899 | - $owner = $path->getOwner(); |
|
900 | - $share->setShareOwner($owner->getUID()); |
|
901 | - } |
|
902 | - |
|
903 | - $share->setNodeId((int)$data['file_source']); |
|
904 | - $share->setNodeType($data['item_type']); |
|
905 | - |
|
906 | - $share->setProviderId($this->identifier()); |
|
907 | - |
|
908 | - return $share; |
|
909 | - } |
|
910 | - |
|
911 | - /** |
|
912 | - * Get the node with file $id for $user |
|
913 | - * |
|
914 | - * @param string $userId |
|
915 | - * @param int $id |
|
916 | - * @return \OCP\Files\File|\OCP\Files\Folder |
|
917 | - * @throws InvalidShare |
|
918 | - */ |
|
919 | - private function getNode($userId, $id) { |
|
920 | - try { |
|
921 | - $userFolder = $this->rootFolder->getUserFolder($userId); |
|
922 | - } catch (NotFoundException $e) { |
|
923 | - throw new InvalidShare(); |
|
924 | - } |
|
925 | - |
|
926 | - $nodes = $userFolder->getById($id); |
|
927 | - |
|
928 | - if (empty($nodes)) { |
|
929 | - throw new InvalidShare(); |
|
930 | - } |
|
931 | - |
|
932 | - return $nodes[0]; |
|
933 | - } |
|
934 | - |
|
935 | - /** |
|
936 | - * A user is deleted from the system |
|
937 | - * So clean up the relevant shares. |
|
938 | - * |
|
939 | - * @param string $uid |
|
940 | - * @param int $shareType |
|
941 | - */ |
|
942 | - public function userDeleted($uid, $shareType) { |
|
943 | - //TODO: probabaly a good idea to send unshare info to remote servers |
|
944 | - |
|
945 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
946 | - |
|
947 | - $qb->delete('share') |
|
948 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))) |
|
949 | - ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))) |
|
950 | - ->execute(); |
|
951 | - } |
|
952 | - |
|
953 | - /** |
|
954 | - * This provider does not handle groups |
|
955 | - * |
|
956 | - * @param string $gid |
|
957 | - */ |
|
958 | - public function groupDeleted($gid) { |
|
959 | - // We don't handle groups here |
|
960 | - } |
|
961 | - |
|
962 | - /** |
|
963 | - * This provider does not handle groups |
|
964 | - * |
|
965 | - * @param string $uid |
|
966 | - * @param string $gid |
|
967 | - */ |
|
968 | - public function userDeletedFromGroup($uid, $gid) { |
|
969 | - // We don't handle groups here |
|
970 | - } |
|
971 | - |
|
972 | - /** |
|
973 | - * check if users from other Nextcloud instances are allowed to mount public links share by this instance |
|
974 | - * |
|
975 | - * @return bool |
|
976 | - */ |
|
977 | - public function isOutgoingServer2serverShareEnabled() { |
|
978 | - if ($this->gsConfig->onlyInternalFederation()) { |
|
979 | - return false; |
|
980 | - } |
|
981 | - $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes'); |
|
982 | - return ($result === 'yes'); |
|
983 | - } |
|
984 | - |
|
985 | - /** |
|
986 | - * check if users are allowed to mount public links from other Nextclouds |
|
987 | - * |
|
988 | - * @return bool |
|
989 | - */ |
|
990 | - public function isIncomingServer2serverShareEnabled() { |
|
991 | - if ($this->gsConfig->onlyInternalFederation()) { |
|
992 | - return false; |
|
993 | - } |
|
994 | - $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes'); |
|
995 | - return ($result === 'yes'); |
|
996 | - } |
|
997 | - |
|
998 | - |
|
999 | - /** |
|
1000 | - * check if users from other Nextcloud instances are allowed to send federated group shares |
|
1001 | - * |
|
1002 | - * @return bool |
|
1003 | - */ |
|
1004 | - public function isOutgoingServer2serverGroupShareEnabled() { |
|
1005 | - if ($this->gsConfig->onlyInternalFederation()) { |
|
1006 | - return false; |
|
1007 | - } |
|
1008 | - $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no'); |
|
1009 | - return ($result === 'yes'); |
|
1010 | - } |
|
1011 | - |
|
1012 | - /** |
|
1013 | - * check if users are allowed to receive federated group shares |
|
1014 | - * |
|
1015 | - * @return bool |
|
1016 | - */ |
|
1017 | - public function isIncomingServer2serverGroupShareEnabled() { |
|
1018 | - if ($this->gsConfig->onlyInternalFederation()) { |
|
1019 | - return false; |
|
1020 | - } |
|
1021 | - $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no'); |
|
1022 | - return ($result === 'yes'); |
|
1023 | - } |
|
1024 | - |
|
1025 | - /** |
|
1026 | - * check if federated group sharing is supported, therefore the OCM API need to be enabled |
|
1027 | - * |
|
1028 | - * @return bool |
|
1029 | - */ |
|
1030 | - public function isFederatedGroupSharingSupported() { |
|
1031 | - return $this->cloudFederationProviderManager->isReady(); |
|
1032 | - } |
|
1033 | - |
|
1034 | - /** |
|
1035 | - * Check if querying sharees on the lookup server is enabled |
|
1036 | - * |
|
1037 | - * @return bool |
|
1038 | - */ |
|
1039 | - public function isLookupServerQueriesEnabled() { |
|
1040 | - // in a global scale setup we should always query the lookup server |
|
1041 | - if ($this->gsConfig->isGlobalScaleEnabled()) { |
|
1042 | - return true; |
|
1043 | - } |
|
1044 | - $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes'); |
|
1045 | - return ($result === 'yes'); |
|
1046 | - } |
|
1047 | - |
|
1048 | - |
|
1049 | - /** |
|
1050 | - * Check if it is allowed to publish user specific data to the lookup server |
|
1051 | - * |
|
1052 | - * @return bool |
|
1053 | - */ |
|
1054 | - public function isLookupServerUploadEnabled() { |
|
1055 | - // in a global scale setup the admin is responsible to keep the lookup server up-to-date |
|
1056 | - if ($this->gsConfig->isGlobalScaleEnabled()) { |
|
1057 | - return false; |
|
1058 | - } |
|
1059 | - $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes'); |
|
1060 | - return ($result === 'yes'); |
|
1061 | - } |
|
1062 | - |
|
1063 | - /** |
|
1064 | - * @inheritdoc |
|
1065 | - */ |
|
1066 | - public function getAccessList($nodes, $currentAccess) { |
|
1067 | - $ids = []; |
|
1068 | - foreach ($nodes as $node) { |
|
1069 | - $ids[] = $node->getId(); |
|
1070 | - } |
|
1071 | - |
|
1072 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1073 | - $qb->select('share_with', 'token', 'file_source') |
|
1074 | - ->from('share') |
|
1075 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))) |
|
1076 | - ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) |
|
1077 | - ->andWhere($qb->expr()->orX( |
|
1078 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1079 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1080 | - )); |
|
1081 | - $cursor = $qb->execute(); |
|
1082 | - |
|
1083 | - if ($currentAccess === false) { |
|
1084 | - $remote = $cursor->fetch() !== false; |
|
1085 | - $cursor->closeCursor(); |
|
1086 | - |
|
1087 | - return ['remote' => $remote]; |
|
1088 | - } |
|
1089 | - |
|
1090 | - $remote = []; |
|
1091 | - while ($row = $cursor->fetch()) { |
|
1092 | - $remote[$row['share_with']] = [ |
|
1093 | - 'node_id' => $row['file_source'], |
|
1094 | - 'token' => $row['token'], |
|
1095 | - ]; |
|
1096 | - } |
|
1097 | - $cursor->closeCursor(); |
|
1098 | - |
|
1099 | - return ['remote' => $remote]; |
|
1100 | - } |
|
1101 | - |
|
1102 | - public function getAllShares(): iterable { |
|
1103 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1104 | - |
|
1105 | - $qb->select('*') |
|
1106 | - ->from('share') |
|
1107 | - ->where( |
|
1108 | - $qb->expr()->orX( |
|
1109 | - $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE)), |
|
1110 | - $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE_GROUP)) |
|
1111 | - ) |
|
1112 | - ); |
|
1113 | - |
|
1114 | - $cursor = $qb->execute(); |
|
1115 | - while ($data = $cursor->fetch()) { |
|
1116 | - try { |
|
1117 | - $share = $this->createShareObject($data); |
|
1118 | - } catch (InvalidShare $e) { |
|
1119 | - continue; |
|
1120 | - } catch (ShareNotFound $e) { |
|
1121 | - continue; |
|
1122 | - } |
|
1123 | - |
|
1124 | - yield $share; |
|
1125 | - } |
|
1126 | - $cursor->closeCursor(); |
|
1127 | - } |
|
501 | + return $share; |
|
502 | + } |
|
503 | + |
|
504 | + /** |
|
505 | + * Get all children of this share |
|
506 | + * |
|
507 | + * @param IShare $parent |
|
508 | + * @return IShare[] |
|
509 | + */ |
|
510 | + public function getChildren(IShare $parent) { |
|
511 | + $children = []; |
|
512 | + |
|
513 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
514 | + $qb->select('*') |
|
515 | + ->from('share') |
|
516 | + ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) |
|
517 | + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
518 | + ->orderBy('id'); |
|
519 | + |
|
520 | + $cursor = $qb->execute(); |
|
521 | + while ($data = $cursor->fetch()) { |
|
522 | + $children[] = $this->createShareObject($data); |
|
523 | + } |
|
524 | + $cursor->closeCursor(); |
|
525 | + |
|
526 | + return $children; |
|
527 | + } |
|
528 | + |
|
529 | + /** |
|
530 | + * Delete a share (owner unShares the file) |
|
531 | + * |
|
532 | + * @param IShare $share |
|
533 | + * @throws ShareNotFound |
|
534 | + * @throws \OC\HintException |
|
535 | + */ |
|
536 | + public function delete(IShare $share) { |
|
537 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith()); |
|
538 | + |
|
539 | + // if the local user is the owner we can send the unShare request directly... |
|
540 | + if ($this->userManager->userExists($share->getShareOwner())) { |
|
541 | + $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken()); |
|
542 | + $this->revokeShare($share, true); |
|
543 | + } else { // ... if not we need to correct ID for the unShare request |
|
544 | + $remoteId = $this->getRemoteId($share); |
|
545 | + $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken()); |
|
546 | + $this->revokeShare($share, false); |
|
547 | + } |
|
548 | + |
|
549 | + // only remove the share when all messages are send to not lose information |
|
550 | + // about the share to early |
|
551 | + $this->removeShareFromTable($share); |
|
552 | + } |
|
553 | + |
|
554 | + /** |
|
555 | + * in case of a re-share we need to send the other use (initiator or owner) |
|
556 | + * a message that the file was unshared |
|
557 | + * |
|
558 | + * @param IShare $share |
|
559 | + * @param bool $isOwner the user can either be the owner or the user who re-sahred it |
|
560 | + * @throws ShareNotFound |
|
561 | + * @throws \OC\HintException |
|
562 | + */ |
|
563 | + protected function revokeShare($share, $isOwner) { |
|
564 | + if ($this->userManager->userExists($share->getShareOwner() && $this->userManager->userExists($share->getSharedBy()))) { |
|
565 | + // If both the owner and the initiator of the share are local users we don't have to notify anybody else |
|
566 | + return; |
|
567 | + } |
|
568 | + |
|
569 | + // also send a unShare request to the initiator, if this is a different user than the owner |
|
570 | + if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
571 | + if ($isOwner) { |
|
572 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
573 | + } else { |
|
574 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); |
|
575 | + } |
|
576 | + $remoteId = $this->getRemoteId($share); |
|
577 | + $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken()); |
|
578 | + } |
|
579 | + } |
|
580 | + |
|
581 | + /** |
|
582 | + * remove share from table |
|
583 | + * |
|
584 | + * @param IShare $share |
|
585 | + */ |
|
586 | + public function removeShareFromTable(IShare $share) { |
|
587 | + $this->removeShareFromTableById($share->getId()); |
|
588 | + } |
|
589 | + |
|
590 | + /** |
|
591 | + * remove share from table |
|
592 | + * |
|
593 | + * @param string $shareId |
|
594 | + */ |
|
595 | + private function removeShareFromTableById($shareId) { |
|
596 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
597 | + $qb->delete('share') |
|
598 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId))) |
|
599 | + ->andWhere($qb->expr()->neq('share_type', $qb->createNamedParameter(IShare::TYPE_CIRCLE))); |
|
600 | + $qb->execute(); |
|
601 | + |
|
602 | + $qb->delete('federated_reshares') |
|
603 | + ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId))); |
|
604 | + $qb->execute(); |
|
605 | + } |
|
606 | + |
|
607 | + /** |
|
608 | + * @inheritdoc |
|
609 | + */ |
|
610 | + public function deleteFromSelf(IShare $share, $recipient) { |
|
611 | + // nothing to do here. Technically deleteFromSelf in the context of federated |
|
612 | + // shares is a umount of a external storage. This is handled here |
|
613 | + // apps/files_sharing/lib/external/manager.php |
|
614 | + // TODO move this code over to this app |
|
615 | + } |
|
616 | + |
|
617 | + public function restore(IShare $share, string $recipient): IShare { |
|
618 | + throw new GenericShareException('not implemented'); |
|
619 | + } |
|
620 | + |
|
621 | + |
|
622 | + public function getSharesInFolder($userId, Folder $node, $reshares) { |
|
623 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
624 | + $qb->select('*') |
|
625 | + ->from('share', 's') |
|
626 | + ->andWhere($qb->expr()->orX( |
|
627 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
628 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
629 | + )) |
|
630 | + ->andWhere( |
|
631 | + $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)) |
|
632 | + ); |
|
633 | + |
|
634 | + /** |
|
635 | + * Reshares for this user are shares where they are the owner. |
|
636 | + */ |
|
637 | + if ($reshares === false) { |
|
638 | + $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); |
|
639 | + } else { |
|
640 | + $qb->andWhere( |
|
641 | + $qb->expr()->orX( |
|
642 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
643 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
644 | + ) |
|
645 | + ); |
|
646 | + } |
|
647 | + |
|
648 | + $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
649 | + $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
|
650 | + |
|
651 | + $qb->orderBy('id'); |
|
652 | + |
|
653 | + $cursor = $qb->execute(); |
|
654 | + $shares = []; |
|
655 | + while ($data = $cursor->fetch()) { |
|
656 | + $shares[$data['fileid']][] = $this->createShareObject($data); |
|
657 | + } |
|
658 | + $cursor->closeCursor(); |
|
659 | + |
|
660 | + return $shares; |
|
661 | + } |
|
662 | + |
|
663 | + /** |
|
664 | + * @inheritdoc |
|
665 | + */ |
|
666 | + public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) { |
|
667 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
668 | + $qb->select('*') |
|
669 | + ->from('share'); |
|
670 | + |
|
671 | + $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType))); |
|
672 | + |
|
673 | + /** |
|
674 | + * Reshares for this user are shares where they are the owner. |
|
675 | + */ |
|
676 | + if ($reshares === false) { |
|
677 | + //Special case for old shares created via the web UI |
|
678 | + $or1 = $qb->expr()->andX( |
|
679 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
680 | + $qb->expr()->isNull('uid_initiator') |
|
681 | + ); |
|
682 | + |
|
683 | + $qb->andWhere( |
|
684 | + $qb->expr()->orX( |
|
685 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)), |
|
686 | + $or1 |
|
687 | + ) |
|
688 | + ); |
|
689 | + } else { |
|
690 | + $qb->andWhere( |
|
691 | + $qb->expr()->orX( |
|
692 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
693 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
694 | + ) |
|
695 | + ); |
|
696 | + } |
|
697 | + |
|
698 | + if ($node !== null) { |
|
699 | + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
700 | + } |
|
701 | + |
|
702 | + if ($limit !== -1) { |
|
703 | + $qb->setMaxResults($limit); |
|
704 | + } |
|
705 | + |
|
706 | + $qb->setFirstResult($offset); |
|
707 | + $qb->orderBy('id'); |
|
708 | + |
|
709 | + $cursor = $qb->execute(); |
|
710 | + $shares = []; |
|
711 | + while ($data = $cursor->fetch()) { |
|
712 | + $shares[] = $this->createShareObject($data); |
|
713 | + } |
|
714 | + $cursor->closeCursor(); |
|
715 | + |
|
716 | + return $shares; |
|
717 | + } |
|
718 | + |
|
719 | + /** |
|
720 | + * @inheritdoc |
|
721 | + */ |
|
722 | + public function getShareById($id, $recipientId = null) { |
|
723 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
724 | + |
|
725 | + $qb->select('*') |
|
726 | + ->from('share') |
|
727 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) |
|
728 | + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); |
|
729 | + |
|
730 | + $cursor = $qb->execute(); |
|
731 | + $data = $cursor->fetch(); |
|
732 | + $cursor->closeCursor(); |
|
733 | + |
|
734 | + if ($data === false) { |
|
735 | + throw new ShareNotFound('Can not find share with ID: ' . $id); |
|
736 | + } |
|
737 | + |
|
738 | + try { |
|
739 | + $share = $this->createShareObject($data); |
|
740 | + } catch (InvalidShare $e) { |
|
741 | + throw new ShareNotFound(); |
|
742 | + } |
|
743 | + |
|
744 | + return $share; |
|
745 | + } |
|
746 | + |
|
747 | + /** |
|
748 | + * Get shares for a given path |
|
749 | + * |
|
750 | + * @param \OCP\Files\Node $path |
|
751 | + * @return IShare[] |
|
752 | + */ |
|
753 | + public function getSharesByPath(Node $path) { |
|
754 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
755 | + |
|
756 | + // get federated user shares |
|
757 | + $cursor = $qb->select('*') |
|
758 | + ->from('share') |
|
759 | + ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) |
|
760 | + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
761 | + ->execute(); |
|
762 | + |
|
763 | + $shares = []; |
|
764 | + while ($data = $cursor->fetch()) { |
|
765 | + $shares[] = $this->createShareObject($data); |
|
766 | + } |
|
767 | + $cursor->closeCursor(); |
|
768 | + |
|
769 | + return $shares; |
|
770 | + } |
|
771 | + |
|
772 | + /** |
|
773 | + * @inheritdoc |
|
774 | + */ |
|
775 | + public function getSharedWith($userId, $shareType, $node, $limit, $offset) { |
|
776 | + /** @var IShare[] $shares */ |
|
777 | + $shares = []; |
|
778 | + |
|
779 | + //Get shares directly with this user |
|
780 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
781 | + $qb->select('*') |
|
782 | + ->from('share'); |
|
783 | + |
|
784 | + // Order by id |
|
785 | + $qb->orderBy('id'); |
|
786 | + |
|
787 | + // Set limit and offset |
|
788 | + if ($limit !== -1) { |
|
789 | + $qb->setMaxResults($limit); |
|
790 | + } |
|
791 | + $qb->setFirstResult($offset); |
|
792 | + |
|
793 | + $qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); |
|
794 | + $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); |
|
795 | + |
|
796 | + // Filter by node if provided |
|
797 | + if ($node !== null) { |
|
798 | + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
799 | + } |
|
800 | + |
|
801 | + $cursor = $qb->execute(); |
|
802 | + |
|
803 | + while ($data = $cursor->fetch()) { |
|
804 | + $shares[] = $this->createShareObject($data); |
|
805 | + } |
|
806 | + $cursor->closeCursor(); |
|
807 | + |
|
808 | + |
|
809 | + return $shares; |
|
810 | + } |
|
811 | + |
|
812 | + /** |
|
813 | + * Get a share by token |
|
814 | + * |
|
815 | + * @param string $token |
|
816 | + * @return IShare |
|
817 | + * @throws ShareNotFound |
|
818 | + */ |
|
819 | + public function getShareByToken($token) { |
|
820 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
821 | + |
|
822 | + $cursor = $qb->select('*') |
|
823 | + ->from('share') |
|
824 | + ->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
825 | + ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) |
|
826 | + ->execute(); |
|
827 | + |
|
828 | + $data = $cursor->fetch(); |
|
829 | + |
|
830 | + if ($data === false) { |
|
831 | + throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
832 | + } |
|
833 | + |
|
834 | + try { |
|
835 | + $share = $this->createShareObject($data); |
|
836 | + } catch (InvalidShare $e) { |
|
837 | + throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
838 | + } |
|
839 | + |
|
840 | + return $share; |
|
841 | + } |
|
842 | + |
|
843 | + /** |
|
844 | + * get database row of a give share |
|
845 | + * |
|
846 | + * @param $id |
|
847 | + * @return array |
|
848 | + * @throws ShareNotFound |
|
849 | + */ |
|
850 | + private function getRawShare($id) { |
|
851 | + |
|
852 | + // Now fetch the inserted share and create a complete share object |
|
853 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
854 | + $qb->select('*') |
|
855 | + ->from('share') |
|
856 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); |
|
857 | + |
|
858 | + $cursor = $qb->execute(); |
|
859 | + $data = $cursor->fetch(); |
|
860 | + $cursor->closeCursor(); |
|
861 | + |
|
862 | + if ($data === false) { |
|
863 | + throw new ShareNotFound; |
|
864 | + } |
|
865 | + |
|
866 | + return $data; |
|
867 | + } |
|
868 | + |
|
869 | + /** |
|
870 | + * Create a share object from an database row |
|
871 | + * |
|
872 | + * @param array $data |
|
873 | + * @return IShare |
|
874 | + * @throws InvalidShare |
|
875 | + * @throws ShareNotFound |
|
876 | + */ |
|
877 | + private function createShareObject($data) { |
|
878 | + $share = new Share($this->rootFolder, $this->userManager); |
|
879 | + $share->setId((int)$data['id']) |
|
880 | + ->setShareType((int)$data['share_type']) |
|
881 | + ->setPermissions((int)$data['permissions']) |
|
882 | + ->setTarget($data['file_target']) |
|
883 | + ->setMailSend((bool)$data['mail_send']) |
|
884 | + ->setToken($data['token']); |
|
885 | + |
|
886 | + $shareTime = new \DateTime(); |
|
887 | + $shareTime->setTimestamp((int)$data['stime']); |
|
888 | + $share->setShareTime($shareTime); |
|
889 | + $share->setSharedWith($data['share_with']); |
|
890 | + |
|
891 | + if ($data['uid_initiator'] !== null) { |
|
892 | + $share->setShareOwner($data['uid_owner']); |
|
893 | + $share->setSharedBy($data['uid_initiator']); |
|
894 | + } else { |
|
895 | + //OLD SHARE |
|
896 | + $share->setSharedBy($data['uid_owner']); |
|
897 | + $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
898 | + |
|
899 | + $owner = $path->getOwner(); |
|
900 | + $share->setShareOwner($owner->getUID()); |
|
901 | + } |
|
902 | + |
|
903 | + $share->setNodeId((int)$data['file_source']); |
|
904 | + $share->setNodeType($data['item_type']); |
|
905 | + |
|
906 | + $share->setProviderId($this->identifier()); |
|
907 | + |
|
908 | + return $share; |
|
909 | + } |
|
910 | + |
|
911 | + /** |
|
912 | + * Get the node with file $id for $user |
|
913 | + * |
|
914 | + * @param string $userId |
|
915 | + * @param int $id |
|
916 | + * @return \OCP\Files\File|\OCP\Files\Folder |
|
917 | + * @throws InvalidShare |
|
918 | + */ |
|
919 | + private function getNode($userId, $id) { |
|
920 | + try { |
|
921 | + $userFolder = $this->rootFolder->getUserFolder($userId); |
|
922 | + } catch (NotFoundException $e) { |
|
923 | + throw new InvalidShare(); |
|
924 | + } |
|
925 | + |
|
926 | + $nodes = $userFolder->getById($id); |
|
927 | + |
|
928 | + if (empty($nodes)) { |
|
929 | + throw new InvalidShare(); |
|
930 | + } |
|
931 | + |
|
932 | + return $nodes[0]; |
|
933 | + } |
|
934 | + |
|
935 | + /** |
|
936 | + * A user is deleted from the system |
|
937 | + * So clean up the relevant shares. |
|
938 | + * |
|
939 | + * @param string $uid |
|
940 | + * @param int $shareType |
|
941 | + */ |
|
942 | + public function userDeleted($uid, $shareType) { |
|
943 | + //TODO: probabaly a good idea to send unshare info to remote servers |
|
944 | + |
|
945 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
946 | + |
|
947 | + $qb->delete('share') |
|
948 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))) |
|
949 | + ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))) |
|
950 | + ->execute(); |
|
951 | + } |
|
952 | + |
|
953 | + /** |
|
954 | + * This provider does not handle groups |
|
955 | + * |
|
956 | + * @param string $gid |
|
957 | + */ |
|
958 | + public function groupDeleted($gid) { |
|
959 | + // We don't handle groups here |
|
960 | + } |
|
961 | + |
|
962 | + /** |
|
963 | + * This provider does not handle groups |
|
964 | + * |
|
965 | + * @param string $uid |
|
966 | + * @param string $gid |
|
967 | + */ |
|
968 | + public function userDeletedFromGroup($uid, $gid) { |
|
969 | + // We don't handle groups here |
|
970 | + } |
|
971 | + |
|
972 | + /** |
|
973 | + * check if users from other Nextcloud instances are allowed to mount public links share by this instance |
|
974 | + * |
|
975 | + * @return bool |
|
976 | + */ |
|
977 | + public function isOutgoingServer2serverShareEnabled() { |
|
978 | + if ($this->gsConfig->onlyInternalFederation()) { |
|
979 | + return false; |
|
980 | + } |
|
981 | + $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes'); |
|
982 | + return ($result === 'yes'); |
|
983 | + } |
|
984 | + |
|
985 | + /** |
|
986 | + * check if users are allowed to mount public links from other Nextclouds |
|
987 | + * |
|
988 | + * @return bool |
|
989 | + */ |
|
990 | + public function isIncomingServer2serverShareEnabled() { |
|
991 | + if ($this->gsConfig->onlyInternalFederation()) { |
|
992 | + return false; |
|
993 | + } |
|
994 | + $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes'); |
|
995 | + return ($result === 'yes'); |
|
996 | + } |
|
997 | + |
|
998 | + |
|
999 | + /** |
|
1000 | + * check if users from other Nextcloud instances are allowed to send federated group shares |
|
1001 | + * |
|
1002 | + * @return bool |
|
1003 | + */ |
|
1004 | + public function isOutgoingServer2serverGroupShareEnabled() { |
|
1005 | + if ($this->gsConfig->onlyInternalFederation()) { |
|
1006 | + return false; |
|
1007 | + } |
|
1008 | + $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no'); |
|
1009 | + return ($result === 'yes'); |
|
1010 | + } |
|
1011 | + |
|
1012 | + /** |
|
1013 | + * check if users are allowed to receive federated group shares |
|
1014 | + * |
|
1015 | + * @return bool |
|
1016 | + */ |
|
1017 | + public function isIncomingServer2serverGroupShareEnabled() { |
|
1018 | + if ($this->gsConfig->onlyInternalFederation()) { |
|
1019 | + return false; |
|
1020 | + } |
|
1021 | + $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no'); |
|
1022 | + return ($result === 'yes'); |
|
1023 | + } |
|
1024 | + |
|
1025 | + /** |
|
1026 | + * check if federated group sharing is supported, therefore the OCM API need to be enabled |
|
1027 | + * |
|
1028 | + * @return bool |
|
1029 | + */ |
|
1030 | + public function isFederatedGroupSharingSupported() { |
|
1031 | + return $this->cloudFederationProviderManager->isReady(); |
|
1032 | + } |
|
1033 | + |
|
1034 | + /** |
|
1035 | + * Check if querying sharees on the lookup server is enabled |
|
1036 | + * |
|
1037 | + * @return bool |
|
1038 | + */ |
|
1039 | + public function isLookupServerQueriesEnabled() { |
|
1040 | + // in a global scale setup we should always query the lookup server |
|
1041 | + if ($this->gsConfig->isGlobalScaleEnabled()) { |
|
1042 | + return true; |
|
1043 | + } |
|
1044 | + $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes'); |
|
1045 | + return ($result === 'yes'); |
|
1046 | + } |
|
1047 | + |
|
1048 | + |
|
1049 | + /** |
|
1050 | + * Check if it is allowed to publish user specific data to the lookup server |
|
1051 | + * |
|
1052 | + * @return bool |
|
1053 | + */ |
|
1054 | + public function isLookupServerUploadEnabled() { |
|
1055 | + // in a global scale setup the admin is responsible to keep the lookup server up-to-date |
|
1056 | + if ($this->gsConfig->isGlobalScaleEnabled()) { |
|
1057 | + return false; |
|
1058 | + } |
|
1059 | + $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes'); |
|
1060 | + return ($result === 'yes'); |
|
1061 | + } |
|
1062 | + |
|
1063 | + /** |
|
1064 | + * @inheritdoc |
|
1065 | + */ |
|
1066 | + public function getAccessList($nodes, $currentAccess) { |
|
1067 | + $ids = []; |
|
1068 | + foreach ($nodes as $node) { |
|
1069 | + $ids[] = $node->getId(); |
|
1070 | + } |
|
1071 | + |
|
1072 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1073 | + $qb->select('share_with', 'token', 'file_source') |
|
1074 | + ->from('share') |
|
1075 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))) |
|
1076 | + ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) |
|
1077 | + ->andWhere($qb->expr()->orX( |
|
1078 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1079 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1080 | + )); |
|
1081 | + $cursor = $qb->execute(); |
|
1082 | + |
|
1083 | + if ($currentAccess === false) { |
|
1084 | + $remote = $cursor->fetch() !== false; |
|
1085 | + $cursor->closeCursor(); |
|
1086 | + |
|
1087 | + return ['remote' => $remote]; |
|
1088 | + } |
|
1089 | + |
|
1090 | + $remote = []; |
|
1091 | + while ($row = $cursor->fetch()) { |
|
1092 | + $remote[$row['share_with']] = [ |
|
1093 | + 'node_id' => $row['file_source'], |
|
1094 | + 'token' => $row['token'], |
|
1095 | + ]; |
|
1096 | + } |
|
1097 | + $cursor->closeCursor(); |
|
1098 | + |
|
1099 | + return ['remote' => $remote]; |
|
1100 | + } |
|
1101 | + |
|
1102 | + public function getAllShares(): iterable { |
|
1103 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1104 | + |
|
1105 | + $qb->select('*') |
|
1106 | + ->from('share') |
|
1107 | + ->where( |
|
1108 | + $qb->expr()->orX( |
|
1109 | + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE)), |
|
1110 | + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_REMOTE_GROUP)) |
|
1111 | + ) |
|
1112 | + ); |
|
1113 | + |
|
1114 | + $cursor = $qb->execute(); |
|
1115 | + while ($data = $cursor->fetch()) { |
|
1116 | + try { |
|
1117 | + $share = $this->createShareObject($data); |
|
1118 | + } catch (InvalidShare $e) { |
|
1119 | + continue; |
|
1120 | + } catch (ShareNotFound $e) { |
|
1121 | + continue; |
|
1122 | + } |
|
1123 | + |
|
1124 | + yield $share; |
|
1125 | + } |
|
1126 | + $cursor->closeCursor(); |
|
1127 | + } |
|
1128 | 1128 | } |