1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @author Björn Schießle <[email protected]> |
4
|
|
|
* @author Joas Schilling <[email protected]> |
5
|
|
|
* @author Miguel Prokop <[email protected]> |
6
|
|
|
* @author Morris Jobke <[email protected]> |
7
|
|
|
* @author Robin Appelman <[email protected]> |
8
|
|
|
* @author Robin McCorkell <[email protected]> |
9
|
|
|
* @author Thomas Müller <[email protected]> |
10
|
|
|
* @author Vincent Petry <[email protected]> |
11
|
|
|
* |
12
|
|
|
* @copyright Copyright (c) 2018, ownCloud GmbH |
13
|
|
|
* @license AGPL-3.0 |
14
|
|
|
* |
15
|
|
|
* This code is free software: you can redistribute it and/or modify |
16
|
|
|
* it under the terms of the GNU Affero General Public License, version 3, |
17
|
|
|
* as published by the Free Software Foundation. |
18
|
|
|
* |
19
|
|
|
* This program is distributed in the hope that it will be useful, |
20
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
21
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22
|
|
|
* GNU Affero General Public License for more details. |
23
|
|
|
* |
24
|
|
|
* You should have received a copy of the GNU Affero General Public License, version 3, |
25
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/> |
26
|
|
|
* |
27
|
|
|
*/ |
28
|
|
|
|
29
|
|
|
namespace OC\Share; |
30
|
|
|
|
31
|
|
|
use OC\HintException; |
32
|
|
|
|
33
|
|
|
class Helper extends \OC\Share\Constants { |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Delete all reshares and group share children of an item |
37
|
|
|
* @param int $parent Id of item to delete |
38
|
|
|
* @param bool $excludeParent If true, exclude the parent from the delete (optional) |
39
|
|
|
* @param string $uidOwner The user that the parent was shared with (optional) |
40
|
|
|
* @param int $newParent new parent for the childrens |
41
|
|
|
* @param bool $excludeGroupChildren exclude group children elements |
42
|
|
|
* @return array of deleted items |
43
|
|
|
*/ |
44
|
|
|
public static function delete($parent, $excludeParent = false, $uidOwner = null, $newParent = null, $excludeGroupChildren = false) { |
45
|
|
|
$ids = [$parent]; |
46
|
|
|
$deletedItems = []; |
47
|
|
|
$changeParent = []; |
48
|
|
|
$parents = [$parent]; |
49
|
|
|
while (!empty($parents)) { |
50
|
|
|
$parents = "'".\implode("','", $parents)."'"; |
51
|
|
|
// Check the owner on the first search of reshares, useful for |
52
|
|
|
// finding and deleting the reshares by a single user of a group share |
53
|
|
|
$params = []; |
54
|
|
|
if (\count($ids) == 1 && isset($uidOwner)) { |
55
|
|
|
// FIXME: don't concat $parents, use Docrine's PARAM_INT_ARRAY approach |
56
|
|
|
$queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' . |
57
|
|
|
'`item_target`, `file_target`, `parent` ' . |
58
|
|
|
'FROM `*PREFIX*share` ' . |
59
|
|
|
'WHERE `parent` IN ('.$parents.') AND `uid_owner` = ? '; |
60
|
|
|
$params[] = $uidOwner; |
61
|
|
|
} else { |
62
|
|
|
$queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' . |
63
|
|
|
'`item_target`, `file_target`, `parent`, `uid_owner` ' . |
64
|
|
|
'FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') '; |
65
|
|
|
} |
66
|
|
|
if ($excludeGroupChildren) { |
67
|
|
|
$queryString .= ' AND `share_type` != ?'; |
68
|
|
|
$params[] = self::$shareTypeGroupUserUnique; |
69
|
|
|
} |
70
|
|
|
$query = \OC_DB::prepare($queryString); |
71
|
|
|
$result = $query->execute($params); |
72
|
|
|
// Reset parents array, only go through loop again if items are found |
73
|
|
|
$parents = []; |
74
|
|
|
while ($item = $result->fetchRow()) { |
75
|
|
|
$tmpItem = [ |
76
|
|
|
'id' => $item['id'], |
77
|
|
|
'shareWith' => $item['share_with'], |
78
|
|
|
'itemTarget' => $item['item_target'], |
79
|
|
|
'itemType' => $item['item_type'], |
80
|
|
|
'shareType' => (int)$item['share_type'], |
81
|
|
|
]; |
82
|
|
|
if (isset($item['file_target'])) { |
83
|
|
|
$tmpItem['fileTarget'] = $item['file_target']; |
84
|
|
|
} |
85
|
|
|
// if we have a new parent for the child we remember the child |
86
|
|
|
// to update the parent, if not we add it to the list of items |
87
|
|
|
// which should be deleted |
88
|
|
|
if ($newParent !== null) { |
89
|
|
|
$changeParent[] = $item['id']; |
90
|
|
|
} else { |
91
|
|
|
$deletedItems[] = $tmpItem; |
92
|
|
|
$ids[] = $item['id']; |
93
|
|
|
$parents[] = $item['id']; |
94
|
|
|
} |
95
|
|
|
} |
96
|
|
|
} |
97
|
|
|
if ($excludeParent) { |
98
|
|
|
unset($ids[0]); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
View Code Duplication |
if (!empty($changeParent)) { |
|
|
|
|
102
|
|
|
$idList = "'".\implode("','", $changeParent)."'"; |
103
|
|
|
$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` IN ('.$idList.')'); |
104
|
|
|
$query->execute([$newParent]); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
View Code Duplication |
if (!empty($ids)) { |
|
|
|
|
108
|
|
|
$idList = "'".\implode("','", $ids)."'"; |
109
|
|
|
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$idList.')'); |
110
|
|
|
$query->execute(); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
return $deletedItems; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* get default expire settings defined by the admin |
118
|
|
|
* @return array contains 'defaultExpireDateSet', 'enforceExpireDate', 'expireAfterDays' |
119
|
|
|
*/ |
120
|
|
|
public static function getDefaultExpireSetting() { |
121
|
|
|
$config = \OC::$server->getConfig(); |
122
|
|
|
|
123
|
|
|
$defaultExpireSettings = ['defaultExpireDateSet' => false]; |
124
|
|
|
|
125
|
|
|
// get default expire settings |
126
|
|
|
$defaultExpireDate = $config->getAppValue('core', 'shareapi_default_expire_date', 'no'); |
127
|
|
|
if ($defaultExpireDate === 'yes') { |
128
|
|
|
$enforceExpireDate = $config->getAppValue('core', 'shareapi_enforce_expire_date', 'no'); |
129
|
|
|
$defaultExpireSettings['defaultExpireDateSet'] = true; |
130
|
|
|
$defaultExpireSettings['expireAfterDays'] = (int)($config->getAppValue('core', 'shareapi_expire_after_n_days', '7')); |
131
|
|
|
$defaultExpireSettings['enforceExpireDate'] = $enforceExpireDate === 'yes' ? true : false; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
return $defaultExpireSettings; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* calculate expire date |
139
|
|
|
* @param array $defaultExpireSettings contains 'defaultExpireDateSet', 'enforceExpireDate', 'expireAfterDays' |
140
|
|
|
* @param int $creationTime timestamp when the share was created |
141
|
|
|
* @param int $userExpireDate expire timestamp set by the user |
142
|
|
|
* @return mixed integer timestamp or False |
143
|
|
|
*/ |
144
|
|
|
public static function calculateExpireDate($defaultExpireSettings, $creationTime, $userExpireDate = null) { |
145
|
|
|
$expires = false; |
146
|
|
|
$defaultExpires = null; |
147
|
|
|
|
148
|
|
|
if (!empty($defaultExpireSettings['defaultExpireDateSet'])) { |
149
|
|
|
$defaultExpires = $creationTime + $defaultExpireSettings['expireAfterDays'] * 86400; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
if (isset($userExpireDate)) { |
153
|
|
|
// if the admin decided to enforce the default expire date then we only take |
154
|
|
|
// the user defined expire date of it is before the default expire date |
155
|
|
|
if ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) { |
156
|
|
|
$expires = \min($userExpireDate, $defaultExpires); |
157
|
|
|
} else { |
158
|
|
|
$expires = $userExpireDate; |
159
|
|
|
} |
160
|
|
|
} elseif ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) { |
161
|
|
|
$expires = $defaultExpires; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
return $expires; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Strips away a potential file names and trailing slashes: |
169
|
|
|
* - http://localhost |
170
|
|
|
* - http://localhost/ |
171
|
|
|
* - http://localhost/index.php |
172
|
|
|
* - http://localhost/index.php/s/{shareToken} |
173
|
|
|
* |
174
|
|
|
* all return: http://localhost |
175
|
|
|
* |
176
|
|
|
* @param string $remote |
177
|
|
|
* @return string |
178
|
|
|
*/ |
179
|
|
View Code Duplication |
protected static function fixRemoteURL($remote) { |
180
|
|
|
$remote = \str_replace('\\', '/', $remote); |
181
|
|
|
if ($fileNamePosition = \strpos($remote, '/index.php')) { |
182
|
|
|
$remote = \substr($remote, 0, $fileNamePosition); |
183
|
|
|
} |
184
|
|
|
$remote = \rtrim($remote, '/'); |
185
|
|
|
|
186
|
|
|
return $remote; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* split user and remote from federated cloud id |
191
|
|
|
* |
192
|
|
|
* @param string $id |
193
|
|
|
* @return string[] |
194
|
|
|
* @throws HintException |
195
|
|
|
*/ |
196
|
|
|
public static function splitUserRemote($id) { |
197
|
|
|
if (\strpos($id, '@') === false) { |
198
|
|
|
$l = \OC::$server->getL10N('core'); |
199
|
|
|
$hint = $l->t('Invalid Federated Cloud ID'); |
200
|
|
|
throw new HintException('Invalid Federated Cloud ID', $hint); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
// Find the first character that is not allowed in user names |
204
|
|
|
$id = \str_replace('\\', '/', $id); |
205
|
|
|
$posSlash = \strpos($id, '/'); |
206
|
|
|
$posColon = \strpos($id, ':'); |
207
|
|
|
|
208
|
|
View Code Duplication |
if ($posSlash === false && $posColon === false) { |
|
|
|
|
209
|
|
|
$invalidPos = \strlen($id); |
210
|
|
|
} elseif ($posSlash === false) { |
211
|
|
|
$invalidPos = $posColon; |
212
|
|
|
} elseif ($posColon === false) { |
213
|
|
|
$invalidPos = $posSlash; |
214
|
|
|
} else { |
215
|
|
|
$invalidPos = \min($posSlash, $posColon); |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
// Find the last @ before $invalidPos |
219
|
|
|
$pos = $lastAtPos = 0; |
220
|
|
View Code Duplication |
while ($lastAtPos !== false && $lastAtPos <= $invalidPos) { |
|
|
|
|
221
|
|
|
$pos = $lastAtPos; |
222
|
|
|
$lastAtPos = \strpos($id, '@', $pos + 1); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
View Code Duplication |
if ($pos !== false) { |
|
|
|
|
226
|
|
|
$user = \substr($id, 0, $pos); |
227
|
|
|
$remote = \substr($id, $pos + 1); |
228
|
|
|
$remote = self::fixRemoteURL($remote); |
229
|
|
|
if (!empty($user) && !empty($remote)) { |
230
|
|
|
return [$user, $remote]; |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
$l = \OC::$server->getL10N('core'); |
235
|
|
|
$hint = $l->t('Invalid Federated Cloud ID'); |
236
|
|
|
throw new HintException('Invalid Fededrated Cloud ID', $hint); |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* check if two federated cloud IDs refer to the same user |
241
|
|
|
* |
242
|
|
|
* @param string $user1 |
243
|
|
|
* @param string $server1 |
244
|
|
|
* @param string $user2 |
245
|
|
|
* @param string $server2 |
246
|
|
|
* @return bool true if both users and servers are the same |
247
|
|
|
*/ |
248
|
|
|
public static function isSameUserOnSameServer($user1, $server1, $user2, $server2) { |
249
|
|
|
$normalizedServer1 = \strtolower(\OC\Share\Share::removeProtocolFromUrl($server1)); |
250
|
|
|
$normalizedServer2 = \strtolower(\OC\Share\Share::removeProtocolFromUrl($server2)); |
251
|
|
|
|
252
|
|
View Code Duplication |
if (\rtrim($normalizedServer1, '/') === \rtrim($normalizedServer2, '/')) { |
|
|
|
|
253
|
|
|
// FIXME this should be a method in the user management instead |
254
|
|
|
\OCP\Util::emitHook( |
255
|
|
|
'\OCA\Files_Sharing\API\Server2Server', |
256
|
|
|
'preLoginNameUsedAsUserName', |
257
|
|
|
['uid' => &$user1] |
258
|
|
|
); |
259
|
|
|
\OCP\Util::emitHook( |
260
|
|
|
'\OCA\Files_Sharing\API\Server2Server', |
261
|
|
|
'preLoginNameUsedAsUserName', |
262
|
|
|
['uid' => &$user2] |
263
|
|
|
); |
264
|
|
|
|
265
|
|
|
if ($user1 === $user2) { |
266
|
|
|
return true; |
267
|
|
|
} |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
return false; |
271
|
|
|
} |
272
|
|
|
} |
273
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.