This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | /** |
||
6 | * Teampass - a collaborative passwords manager. |
||
7 | * --- |
||
8 | * This file is part of the TeamPass project. |
||
9 | * |
||
10 | * TeamPass is free software: you can redistribute it and/or modify it |
||
11 | * under the terms of the GNU General Public License as published by |
||
12 | * the Free Software Foundation, version 3 of the License. |
||
13 | * |
||
14 | * TeamPass is distributed in the hope that it will be useful, |
||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
17 | * GNU General Public License for more details. |
||
18 | * |
||
19 | * You should have received a copy of the GNU General Public License |
||
20 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
||
21 | * |
||
22 | * Certain components of this file may be under different licenses. For |
||
23 | * details, see the `licenses` directory or individual file headers. |
||
24 | * --- |
||
25 | * @file folders.queries.php |
||
26 | * @author Nils Laumaillé ([email protected]) |
||
27 | * @copyright 2009-2025 Teampass.net |
||
28 | * @license GPL-3.0 |
||
29 | * @see https://www.teampass.net |
||
30 | */ |
||
31 | |||
32 | use TeampassClasses\NestedTree\NestedTree; |
||
33 | use TeampassClasses\SessionManager\SessionManager; |
||
34 | use Symfony\Component\HttpFoundation\Request as SymfonyRequest; |
||
35 | use TeampassClasses\Language\Language; |
||
36 | use TeampassClasses\PerformChecks\PerformChecks; |
||
37 | use TeampassClasses\ConfigManager\ConfigManager; |
||
38 | |||
39 | // Load functions |
||
40 | require_once 'main.functions.php'; |
||
41 | |||
42 | // init |
||
43 | loadClasses('DB'); |
||
44 | $session = SessionManager::getSession(); |
||
45 | $request = SymfonyRequest::createFromGlobals(); |
||
46 | $lang = new Language($session->get('user-language') ?? 'english'); |
||
47 | |||
48 | // Load config |
||
49 | $configManager = new ConfigManager(); |
||
50 | $SETTINGS = $configManager->getAllSettings(); |
||
51 | |||
52 | // Do checks |
||
53 | // Instantiate the class with posted data |
||
54 | $checkUserAccess = new PerformChecks( |
||
55 | dataSanitizer( |
||
56 | [ |
||
57 | 'type' => htmlspecialchars($request->request->get('type', ''), ENT_QUOTES, 'UTF-8'), |
||
58 | ], |
||
59 | [ |
||
60 | 'type' => 'trim|escape', |
||
61 | ], |
||
62 | ), |
||
63 | [ |
||
64 | 'user_id' => returnIfSet($session->get('user-id'), null), |
||
65 | 'user_key' => returnIfSet($session->get('key'), null), |
||
66 | ] |
||
67 | ); |
||
68 | |||
69 | // Define Timezone |
||
70 | date_default_timezone_set($SETTINGS['timezone'] ?? 'UTC'); |
||
71 | |||
72 | // Set header properties |
||
73 | header('Content-type: text/html; charset=utf-8'); |
||
74 | header('Cache-Control: no-cache, no-store, must-revalidate'); |
||
75 | |||
76 | // --------------------------------- // |
||
77 | |||
78 | |||
79 | // Load tree |
||
80 | $tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title'); |
||
81 | |||
82 | // Prepare post variables |
||
83 | $post_key = filter_input(INPUT_POST, 'key', FILTER_SANITIZE_FULL_SPECIAL_CHARS); |
||
84 | $post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_FULL_SPECIAL_CHARS); |
||
85 | $post_data = filter_input(INPUT_POST, 'data', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES); |
||
86 | |||
87 | // Ensure Complexity levels are translated |
||
88 | if (defined('TP_PW_COMPLEXITY') === false) { |
||
89 | define( |
||
90 | 'TP_PW_COMPLEXITY', |
||
91 | array( |
||
92 | TP_PW_STRENGTH_1 => array(TP_PW_STRENGTH_1, $lang->get('complex_level1'), 'fas fa-thermometer-empty text-danger'), |
||
93 | TP_PW_STRENGTH_2 => array(TP_PW_STRENGTH_2, $lang->get('complex_level2'), 'fas fa-thermometer-quarter text-warning'), |
||
94 | TP_PW_STRENGTH_3 => array(TP_PW_STRENGTH_3, $lang->get('complex_level3'), 'fas fa-thermometer-half text-warning'), |
||
95 | TP_PW_STRENGTH_4 => array(TP_PW_STRENGTH_4, $lang->get('complex_level4'), 'fas fa-thermometer-three-quarters text-success'), |
||
96 | TP_PW_STRENGTH_5 => array(TP_PW_STRENGTH_5, $lang->get('complex_level5'), 'fas fa-thermometer-full text-success'), |
||
97 | ) |
||
98 | ); |
||
99 | } |
||
100 | |||
101 | if (null !== $post_type) { |
||
102 | switch ($post_type) { |
||
103 | /* |
||
104 | * BUILD liste of folders |
||
105 | */ |
||
106 | case 'build_matrix': |
||
107 | // Check KEY |
||
108 | if ($post_key !== $session->get('key')) { |
||
109 | echo prepareExchangedData( |
||
110 | array( |
||
111 | 'error' => true, |
||
112 | 'message' => $lang->get('key_is_not_correct'), |
||
113 | ), |
||
114 | 'encode' |
||
115 | ); |
||
116 | break; |
||
117 | } elseif ($session->get('user-read_only') === 1) { |
||
118 | echo prepareExchangedData( |
||
119 | array( |
||
120 | 'error' => true, |
||
121 | 'message' => $lang->get('error_not_allowed_to'), |
||
122 | ), |
||
123 | 'encode' |
||
124 | ); |
||
125 | break; |
||
126 | } |
||
127 | |||
128 | // Prepare variables |
||
129 | $arrData = array(); |
||
130 | |||
131 | $treeDesc = $tree->getDescendants(); |
||
132 | |||
133 | foreach ($treeDesc as $t) { |
||
134 | if ( |
||
135 | in_array($t->id, $session->get('user-accessible_folders')) === true |
||
136 | && in_array($t->id, $session->get('user-personal_visible_folders')) === false |
||
137 | && $t->personal_folder == 0 |
||
138 | ) { |
||
139 | // get $t->parent_id |
||
140 | $data = DB::queryFirstRow('SELECT title FROM ' . prefixTable('nested_tree') . ' WHERE id = %i', $t->parent_id); |
||
141 | if ($t->nlevel == 1) { |
||
142 | $data['title'] = $lang->get('root'); |
||
143 | } |
||
144 | |||
145 | // get rights on this folder |
||
146 | $arrayRights = array(); |
||
147 | $rows = DB::query('SELECT fonction_id FROM ' . prefixTable('rights') . ' WHERE authorized=%i AND tree_id = %i', 1, $t->id); |
||
148 | foreach ($rows as $record) { |
||
149 | array_push($arrayRights, $record['fonction_id']); |
||
150 | } |
||
151 | |||
152 | $arbo = $tree->getPath($t->id, false); |
||
153 | $arrayPath = array(); |
||
154 | $arrayParents = array(); |
||
155 | foreach ($arbo as $elem) { |
||
156 | array_push($arrayPath, $elem->title); |
||
157 | array_push($arrayParents, $elem->id); |
||
158 | } |
||
159 | |||
160 | // Get some elements from DB concerning this node |
||
161 | $node_data = DB::queryFirstRow( |
||
162 | 'SELECT m.valeur AS valeur, n.renewal_period AS renewal_period, |
||
163 | n.bloquer_creation AS bloquer_creation, n.bloquer_modification AS bloquer_modification, |
||
164 | n.fa_icon AS fa_icon, n.fa_icon_selected AS fa_icon_selected |
||
165 | FROM ' . prefixTable('misc') . ' AS m, |
||
166 | ' . prefixTable('nested_tree') . ' AS n |
||
167 | WHERE m.type=%s AND m.intitule = n.id AND m.intitule = %i', |
||
168 | 'complex', |
||
169 | $t->id |
||
170 | ); |
||
171 | |||
172 | // Preapre array of columns |
||
173 | $arrayColumns = array(); |
||
174 | |||
175 | $arrayColumns['id'] = (int) $t->id; |
||
176 | $arrayColumns['numOfChildren'] = (int) $tree->numDescendants($t->id); |
||
177 | $arrayColumns['level'] = (int) $t->nlevel; |
||
178 | $arrayColumns['parentId'] = (int) $t->parent_id; |
||
179 | $arrayColumns['title'] = $t->title; |
||
180 | $arrayColumns['nbItems'] = (int) DB::count(); |
||
181 | $arrayColumns['path'] = $arrayPath; |
||
182 | $arrayColumns['parents'] = $arrayParents; |
||
183 | |||
184 | if (is_null($node_data) === false && isset(TP_PW_COMPLEXITY[$node_data['valeur']][1]) === true) { |
||
185 | $arrayColumns['folderComplexity'] = array( |
||
186 | 'text' => TP_PW_COMPLEXITY[$node_data['valeur']][1], |
||
187 | 'value' => TP_PW_COMPLEXITY[$node_data['valeur']][0], |
||
188 | 'class' => TP_PW_COMPLEXITY[$node_data['valeur']][2], |
||
189 | ); |
||
190 | } else { |
||
191 | $arrayColumns['folderComplexity'] = ''; |
||
192 | } |
||
193 | |||
194 | if (is_null($node_data)=== false) { |
||
195 | $arrayColumns['renewalPeriod'] = (int) $node_data['renewal_period']; |
||
196 | } else { |
||
197 | $arrayColumns['renewalPeriod']=0; |
||
198 | } |
||
199 | |||
200 | //col7 |
||
201 | $data7 = DB::queryFirstRow( |
||
202 | 'SELECT bloquer_creation,bloquer_modification |
||
203 | FROM ' . prefixTable('nested_tree') . ' |
||
204 | WHERE id = %i', |
||
205 | intval($t->id) |
||
206 | ); |
||
207 | $arrayColumns['add_is_blocked'] = (int) $data7['bloquer_creation']; |
||
208 | $arrayColumns['edit_is_blocked'] = (int) $data7['bloquer_modification']; |
||
209 | $arrayColumns['icon'] = (string) !is_null($node_data) ? $node_data['fa_icon'] : ''; |
||
210 | $arrayColumns['iconSelected'] = (string) !is_null($node_data) ? $node_data['fa_icon_selected'] : ''; |
||
211 | |||
212 | array_push($arrData, $arrayColumns); |
||
213 | } |
||
214 | } |
||
215 | |||
216 | // Send the complexity levels |
||
217 | $complexity = array( |
||
218 | array('value' => TP_PW_STRENGTH_1, 'text' => $lang->get('complex_level1')), |
||
219 | array('value' => TP_PW_STRENGTH_2, 'text' => $lang->get('complex_level2')), |
||
220 | array('value' => TP_PW_STRENGTH_3, 'text' => $lang->get('complex_level3')), |
||
221 | array('value' => TP_PW_STRENGTH_4, 'text' => $lang->get('complex_level4')), |
||
222 | array('value' => TP_PW_STRENGTH_5, 'text' => $lang->get('complex_level5')), |
||
223 | ); |
||
224 | |||
225 | echo prepareExchangedData( |
||
226 | array( |
||
227 | 'error' => false, |
||
228 | 'message' => '', |
||
229 | 'matrix' => $arrData, |
||
230 | 'userIsAdmin' => $session->get('user-admin'), |
||
231 | 'userCanCreateRootFolder' => (int) $session->get('user-can_create_root_folder'), |
||
232 | 'fullComplexity' => $complexity, |
||
233 | ), |
||
234 | 'encode' |
||
235 | ); |
||
236 | |||
237 | break; |
||
238 | |||
239 | // CASE where selecting/deselecting sub-folders |
||
240 | case 'select_sub_folders': |
||
241 | // Check KEY |
||
242 | if ($post_key !== $session->get('key')) { |
||
243 | echo prepareExchangedData( |
||
244 | array( |
||
245 | 'error' => true, |
||
246 | 'message' => $lang->get('key_is_not_correct'), |
||
247 | ), |
||
248 | 'encode' |
||
249 | ); |
||
250 | break; |
||
251 | } elseif ($session->get('user-read_only') === 1) { |
||
252 | echo prepareExchangedData( |
||
253 | array( |
||
254 | 'error' => true, |
||
255 | 'message' => $lang->get('error_not_allowed_to'), |
||
256 | ), |
||
257 | 'encode' |
||
258 | ); |
||
259 | break; |
||
260 | } |
||
261 | |||
262 | $post_id = filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT); |
||
263 | |||
264 | // get sub folders |
||
265 | $subfolders = array(); |
||
266 | |||
267 | // Get through each subfolder |
||
268 | $folders = $tree->getDescendants($post_id, false); |
||
269 | foreach ($folders as $folder) { |
||
270 | array_push($subfolders, (int) $folder->id); |
||
271 | } |
||
272 | |||
273 | echo prepareExchangedData( |
||
274 | array( |
||
275 | 'error' => false, |
||
276 | 'subfolders' => json_encode($subfolders), |
||
277 | ), |
||
278 | 'encode' |
||
279 | ); |
||
280 | |||
281 | break; |
||
282 | |||
283 | //CASE where UPDATING a new group |
||
284 | case 'update_folder': |
||
285 | // Check KEY |
||
286 | if ($post_key !== $session->get('key')) { |
||
287 | echo prepareExchangedData( |
||
288 | array( |
||
289 | 'error' => true, |
||
290 | 'message' => $lang->get('key_is_not_correct'), |
||
291 | ), |
||
292 | 'encode' |
||
293 | ); |
||
294 | break; |
||
295 | } elseif ($session->get('user-read_only') === 1) { |
||
296 | echo prepareExchangedData( |
||
297 | array( |
||
298 | 'error' => true, |
||
299 | 'message' => $lang->get('error_not_allowed_to'), |
||
300 | ), |
||
301 | 'encode' |
||
302 | ); |
||
303 | break; |
||
304 | } |
||
305 | |||
306 | // decrypt and retrieve data in JSON format |
||
307 | $dataReceived = prepareExchangedData( |
||
308 | $post_data, |
||
309 | 'decode' |
||
310 | ); |
||
311 | |||
312 | // prepare variables |
||
313 | $data = [ |
||
314 | 'id' => isset($dataReceived['id']) === true ? $dataReceived['id'] : -1, |
||
315 | 'title' => isset($dataReceived['title']) === true ? $dataReceived['title'] : '', |
||
316 | 'parentId' => isset($dataReceived['parentId']) === true ? $dataReceived['parentId'] : 0, |
||
317 | 'complexity' => isset($dataReceived['complexity']) === true ? $dataReceived['complexity'] : '', |
||
318 | 'duration' => isset($dataReceived['renewalPeriod']) === true ? $dataReceived['renewalPeriod'] : 0, |
||
319 | 'create_auth_without' => isset($dataReceived['addRestriction']) === true ? $dataReceived['addRestriction'] : 0, |
||
320 | 'edit_auth_without' => isset($dataReceived['editRestriction']) === true ? $dataReceived['editRestriction'] : 0, |
||
321 | 'icon' => isset($dataReceived['icon']) === true ? $dataReceived['icon'] : '', |
||
322 | 'icon_selected' => isset($dataReceived['iconSelected']) === true ? $dataReceived['iconSelected'] : '', |
||
323 | 'access_rights' => isset($dataReceived['accessRight']) === true ? $dataReceived['accessRight'] : 'W', |
||
324 | ]; |
||
325 | $filters = [ |
||
326 | 'id' => 'cast:integer', |
||
327 | 'title' => 'trim|escape', |
||
328 | 'parentId' => 'cast:integer', |
||
329 | 'complexity' => 'cast:integer', |
||
330 | 'duration' => 'cast:integer', |
||
331 | 'create_auth_without' => 'cast:integer', |
||
332 | 'edit_auth_without' => 'cast:integer', |
||
333 | 'icon' => 'trim|escape', |
||
334 | 'icon_selected' => 'trim|escape', |
||
335 | 'access_rights' => 'trim|escape', |
||
336 | ]; |
||
337 | $inputData = dataSanitizer( |
||
338 | $data, |
||
339 | $filters |
||
340 | ); |
||
341 | |||
342 | // Init |
||
343 | $error = false; |
||
344 | $errorMessage = ''; |
||
345 | |||
346 | // check if title is numeric |
||
347 | if (is_numeric($inputData['title']) === true) { |
||
348 | echo prepareExchangedData( |
||
349 | array( |
||
350 | 'error' => true, |
||
351 | 'message' => $lang->get('error_only_numbers_in_folder_name'), |
||
352 | ), |
||
353 | 'encode' |
||
354 | ); |
||
355 | break; |
||
356 | } |
||
357 | |||
358 | // Get info about this folder |
||
359 | $dataFolder = DB::queryFirstRow( |
||
360 | 'SELECT * |
||
361 | FROM ' . prefixTable('nested_tree') . ' |
||
362 | WHERE id = %i', |
||
363 | $inputData['id'] |
||
364 | ); |
||
365 | |||
366 | //Check if duplicate folders name are allowed |
||
367 | if ( |
||
368 | isset($SETTINGS['duplicate_folder']) === true |
||
369 | && (int) $SETTINGS['duplicate_folder'] === 0 |
||
370 | ) { |
||
371 | if ( |
||
372 | empty($dataFolder['id']) === false |
||
373 | && intval($dataReceived['id']) !== intval($dataFolder['id']) |
||
374 | && $inputData['title'] !== $dataFolder['title'] |
||
375 | ) { |
||
376 | echo prepareExchangedData( |
||
377 | array( |
||
378 | 'error' => true, |
||
379 | 'message' => $lang->get('error_group_exist'), |
||
380 | ), |
||
381 | 'encode' |
||
382 | ); |
||
383 | break; |
||
384 | } |
||
385 | } |
||
386 | |||
387 | // Is the parent folder changed? |
||
388 | if ((int) $dataFolder['parent_id'] === (int) $inputData['parentId']) { |
||
389 | $parentChanged = false; |
||
390 | } else { |
||
391 | $parentChanged = true; |
||
392 | } |
||
393 | |||
394 | //check if parent folder is personal |
||
395 | $dataParent = DB::queryFirstRow( |
||
396 | 'SELECT personal_folder, bloquer_creation, bloquer_modification |
||
397 | FROM ' . prefixTable('nested_tree') . ' |
||
398 | WHERE id = %i', |
||
399 | $inputData['parentId'] |
||
400 | ); |
||
401 | |||
402 | // inherit from parent the specific settings it has |
||
403 | if (DB::count() > 0) { |
||
404 | $parentBloquerCreation = $dataParent['bloquer_creation']; |
||
405 | $parentBloquerModification = $dataParent['bloquer_modification']; |
||
406 | } else { |
||
407 | $parentBloquerCreation = 0; |
||
408 | $parentBloquerModification = 0; |
||
409 | } |
||
410 | |||
411 | if (isset($dataParent['personal_folder']) === true && (int) $dataParent['personal_folder'] === 1) { |
||
412 | $isPersonal = 1; |
||
413 | } else { |
||
414 | $isPersonal = 0; |
||
415 | |||
416 | // check if complexity level is good |
||
417 | // if manager or admin don't care |
||
418 | if ( |
||
419 | (int) $session->get('user-admin') !== 1 |
||
420 | && ((int) $session->get('user-manager') !== 1 |
||
421 | || (int) $session->get('user-can_manage_all_users') !== 1) |
||
422 | ) { |
||
423 | // get complexity level for this folder |
||
424 | $data = DB::queryFirstRow( |
||
425 | 'SELECT valeur |
||
426 | FROM ' . prefixTable('misc') . ' |
||
427 | WHERE intitule = %i AND type = %s', |
||
428 | $inputData['parentId'], |
||
429 | 'complex' |
||
430 | ); |
||
431 | |||
432 | if (isset($data['valeur']) === true && (int) $inputData['complexity'] < (int) $data['valeur']) { |
||
433 | echo prepareExchangedData( |
||
434 | array( |
||
435 | 'error' => true, |
||
436 | 'message' => $lang->get('error_folder_complexity_lower_than_top_folder') |
||
437 | . ' [<b>' . TP_PW_COMPLEXITY[$data['valeur']][1] . '</b>]', |
||
438 | ), |
||
439 | 'encode' |
||
440 | ); |
||
441 | break; |
||
442 | } |
||
443 | } |
||
444 | } |
||
445 | |||
446 | // Check if user is allowed |
||
447 | if ( |
||
448 | !( |
||
449 | (int) $isPersonal === 1 |
||
450 | || (int) $session->get('user-admin') === 1 |
||
451 | || (int) $session->get('user-manager') === 1 |
||
452 | || (int) $session->get('user-can_manage_all_users') === 1 |
||
453 | || (isset($SETTINGS['enable_user_can_create_folders']) === true |
||
454 | && (int) $SETTINGS['enable_user_can_create_folders'] == 1) |
||
455 | || (int) $session->get('user-can_create_root_folder') === 1 |
||
456 | ) |
||
457 | ) { |
||
458 | echo prepareExchangedData( |
||
459 | array( |
||
460 | 'error' => true, |
||
461 | 'message' => $lang->get('error_not_allowed_to'), |
||
462 | ), |
||
463 | 'encode' |
||
464 | ); |
||
465 | break; |
||
466 | } |
||
467 | |||
468 | // Prepare update parameters |
||
469 | $folderParameters = array( |
||
470 | 'parent_id' => $inputData['parentId'], |
||
471 | 'title' => $inputData['title'], |
||
472 | 'personal_folder' => $isPersonal, |
||
473 | 'fa_icon' => empty($inputData['icon']) === true ? TP_DEFAULT_ICON : $inputData['icon'], |
||
474 | 'fa_icon_selected' => empty($inputData['icon_selected']) === true ? TP_DEFAULT_ICON_SELECTED : $inputData['icon_selected'], |
||
475 | ); |
||
476 | |||
477 | if ($inputData['duration'] !== -1 && $dataFolder['renewal_period'] !== $inputData['duration']) { |
||
478 | $folderParameters['renewal_period'] = $inputData['duration']; |
||
479 | } |
||
480 | if ($inputData['create_auth_without'] !== -1 && $dataFolder['bloquer_creation'] !== $inputData['create_auth_without']) { |
||
481 | $folderParameters['bloquer_creation'] = $inputData['create_auth_without']; |
||
482 | } |
||
483 | if ($inputData['edit_auth_without'] !== -1 && $dataFolder['bloquer_modification'] !== $inputData['edit_auth_without']) { |
||
484 | $folderParameters['bloquer_modification'] = $inputData['edit_auth_without']; |
||
485 | } |
||
486 | |||
487 | // Now update |
||
488 | DB::update( |
||
489 | prefixTable('nested_tree'), |
||
490 | $folderParameters, |
||
491 | 'id=%i', |
||
492 | $dataFolder['id'] |
||
493 | ); |
||
494 | |||
495 | // Update timestamp |
||
496 | DB::update( |
||
497 | prefixTable('misc'), |
||
498 | array( |
||
499 | 'valeur' => time(), |
||
500 | 'updated_at' => time(), |
||
501 | ), |
||
502 | 'type = %s AND intitule = %s', |
||
503 | 'timestamp', |
||
504 | 'last_folder_change' |
||
505 | ); |
||
506 | |||
507 | //Add complexity |
||
508 | DB::update( |
||
509 | prefixTable('misc'), |
||
510 | array( |
||
511 | 'valeur' => $inputData['complexity'], |
||
512 | 'updated_at' => time(), |
||
513 | ), |
||
514 | 'intitule = %s AND type = %s', |
||
515 | $dataFolder['id'], |
||
516 | 'complex' |
||
517 | ); |
||
518 | |||
519 | // ensure categories are set |
||
520 | handleFoldersCategories( |
||
521 | [$dataFolder['id']] |
||
522 | ); |
||
523 | |||
524 | $tree->rebuild(); |
||
525 | |||
526 | echo prepareExchangedData( |
||
527 | array( |
||
528 | 'error' => $error, |
||
529 | 'message' => $errorMessage, |
||
530 | 'info_parent_changed' => $parentChanged, |
||
531 | ), |
||
532 | 'encode' |
||
533 | ); |
||
534 | |||
535 | break; |
||
536 | |||
537 | //CASE where ADDING a new group |
||
538 | case 'add_folder': |
||
539 | // Check KEY |
||
540 | if ($post_key !== $session->get('key')) { |
||
541 | echo prepareExchangedData( |
||
542 | array( |
||
543 | 'error' => true, |
||
544 | 'message' => $lang->get('key_is_not_correct'), |
||
545 | ), |
||
546 | 'encode' |
||
547 | ); |
||
548 | break; |
||
549 | } elseif ($session->get('user-read_only') === 1) { |
||
550 | echo prepareExchangedData( |
||
551 | array( |
||
552 | 'error' => true, |
||
553 | 'message' => $lang->get('error_not_allowed_to'), |
||
554 | ), |
||
555 | 'encode' |
||
556 | ); |
||
557 | break; |
||
558 | } |
||
559 | |||
560 | // decrypt and retrieve data in JSON format |
||
561 | $dataReceived = prepareExchangedData( |
||
562 | $post_data, |
||
563 | 'decode' |
||
564 | ); |
||
565 | |||
566 | // prepare variables |
||
567 | $data = [ |
||
568 | 'title' => isset($dataReceived['title']) === true ? $dataReceived['title'] : '', |
||
569 | 'parentId' => isset($dataReceived['parentId']) === true ? $dataReceived['parentId'] : 0, |
||
570 | 'complexity' => isset($dataReceived['complexity']) === true ? $dataReceived['complexity'] : '', |
||
571 | 'duration' => isset($dataReceived['renewalPeriod']) === true ? $dataReceived['renewalPeriod'] : 0, |
||
572 | 'create_auth_without' => isset($dataReceived['addRestriction']) === true ? $dataReceived['addRestriction'] : 0, |
||
573 | 'edit_auth_without' => isset($dataReceived['editRestriction']) === true ? $dataReceived['editRestriction'] : 0, |
||
574 | 'icon' => isset($dataReceived['icon']) === true ? $dataReceived['icon'] : '', |
||
575 | 'icon_selected' => isset($dataReceived['iconSelected']) === true ? $dataReceived['iconSelected'] : '', |
||
576 | 'access_rights' => isset($dataReceived['accessRight']) === true ? $dataReceived['accessRight'] : 'W', |
||
577 | ]; |
||
578 | $filters = [ |
||
579 | 'title' => 'trim|escape', |
||
580 | 'parentId' => 'cast:integer', |
||
581 | 'complexity' => 'cast:integer', |
||
582 | 'duration' => 'cast:integer', |
||
583 | 'create_auth_without' => 'cast:integer', |
||
584 | 'edit_auth_without' => 'cast:integer', |
||
585 | 'icon' => 'trim|escape', |
||
586 | 'icon_selected' => 'trim|escape', |
||
587 | 'access_rights' => 'trim|escape', |
||
588 | ]; |
||
589 | $inputData = dataSanitizer( |
||
590 | $data, |
||
591 | $filters |
||
592 | ); |
||
593 | |||
594 | // Check if parent folder is personal |
||
595 | $dataParent = DB::queryFirstRow( |
||
596 | 'SELECT personal_folder |
||
597 | FROM ' . prefixTable('nested_tree') . ' |
||
598 | WHERE id = %i', |
||
599 | $inputData['parentId'] |
||
600 | ); |
||
601 | |||
602 | $isPersonal = (isset($dataParent['personal_folder']) === true && (int) $dataParent['personal_folder'] == 1) ? 1 : 0; |
||
603 | |||
604 | // Create folder |
||
605 | require_once 'folders.class.php'; |
||
606 | $folderManager = new FolderManager($lang); |
||
0 ignored issues
–
show
|
|||
607 | $params = [ |
||
608 | 'title' => (string) $inputData['title'], |
||
609 | 'parent_id' => (int) $inputData['parentId'], |
||
610 | 'personal_folder' => (int) $isPersonal, |
||
611 | 'complexity' => (int) $inputData['complexity'], |
||
612 | 'duration' => (int) $inputData['duration'], |
||
613 | 'create_auth_without' => (int) $inputData['create_auth_without'], |
||
614 | 'edit_auth_without' => (int) $inputData['edit_auth_without'], |
||
615 | 'icon' => (string) $inputData['icon'], |
||
616 | 'icon_selected' => (string) $inputData['icon_selected'], |
||
617 | 'access_rights' => (string) $inputData['access_rights'], |
||
618 | 'user_is_admin' => (int) $session->get('user-admin'), |
||
619 | 'user_accessible_folders' => (array) $session->get('user-accessible_folders'), |
||
620 | 'user_is_manager' => (int) $session->get('user-manager'), |
||
621 | 'user_can_create_root_folder' => (int) $session->get('user-can_create_root_folder'), |
||
622 | 'user_can_manage_all_users' => (int) $session->get('user-can_manage_all_users'), |
||
623 | 'user_id' => (int) $session->get('user-id'), |
||
624 | 'user_roles' => (string) $session->get('user-roles') |
||
625 | ]; |
||
626 | $options = [ |
||
627 | 'rebuildFolderTree' => true, |
||
628 | 'setFolderCategories' => false, |
||
629 | 'manageFolderPermissions' => true, |
||
630 | 'copyCustomFieldsCategories' => false, |
||
631 | 'refreshCacheForUsersWithSimilarRoles' => true, |
||
632 | ]; |
||
633 | $creationStatus = $folderManager->createNewFolder($params, $options); |
||
634 | |||
635 | // User created the folder |
||
636 | // Add new ID to list of visible ones |
||
637 | if ((int) $session->get('user-admin') === 0 && $creationStatus['error'] === false && $creationStatus['newId'] !== 0) { |
||
638 | SessionManager::addRemoveFromSessionArray('user-accessible_folders', [$creationStatus['newId']], 'add'); |
||
639 | } |
||
640 | |||
641 | echo prepareExchangedData( |
||
642 | array( |
||
643 | 'error' => $creationStatus['error'], |
||
644 | 'message' => $creationStatus['error'] === true ? $lang->get('error_not_allowed_to') : $lang->get('folder_created') , |
||
645 | 'newId' => $creationStatus['newId'], |
||
646 | ), |
||
647 | 'encode' |
||
648 | ); |
||
649 | |||
650 | break; |
||
651 | |||
652 | // CASE where DELETING multiple groups |
||
653 | case 'delete_folders': |
||
654 | // Check KEY |
||
655 | if ($post_key !== $session->get('key')) { |
||
656 | echo prepareExchangedData( |
||
657 | array( |
||
658 | 'error' => true, |
||
659 | 'message' => $lang->get('key_is_not_correct'), |
||
660 | ), |
||
661 | 'encode' |
||
662 | ); |
||
663 | break; |
||
664 | } elseif ($session->get('user-read_only') === 1) { |
||
665 | echo prepareExchangedData( |
||
666 | array( |
||
667 | 'error' => true, |
||
668 | 'message' => $lang->get('error_not_allowed_to'), |
||
669 | ), |
||
670 | 'encode' |
||
671 | ); |
||
672 | break; |
||
673 | } |
||
674 | |||
675 | // decrypt and retrieve data in JSON format |
||
676 | $dataReceived = prepareExchangedData( |
||
677 | $post_data, |
||
678 | 'decode' |
||
679 | ); |
||
680 | |||
681 | // prepare variables |
||
682 | $post_folders = filter_var_array( |
||
683 | $dataReceived['selectedFolders'], |
||
684 | FILTER_SANITIZE_FULL_SPECIAL_CHARS |
||
685 | ); |
||
686 | |||
687 | // Ensure that the root folder is not part of the list |
||
688 | if (in_array(0, $post_folders, true)) { |
||
689 | echo prepareExchangedData( |
||
690 | array( |
||
691 | 'error' => true, |
||
692 | 'message' => $lang->get('error_not_allowed_to'). " (You can't delete the root folder)", |
||
693 | ), |
||
694 | 'encode' |
||
695 | ); |
||
696 | break; |
||
697 | } |
||
698 | |||
699 | // Ensure that user has access to all folders |
||
700 | $foldersAccessible = DB::query( |
||
701 | 'SELECT id |
||
702 | FROM ' . prefixTable('nested_tree') . ' |
||
703 | WHERE id IN %li AND id IN %li', |
||
704 | $post_folders, |
||
705 | $session->get('user-accessible_folders') |
||
706 | ); |
||
707 | // Extract found folder IDs |
||
708 | $accessibleIds = array_column($foldersAccessible, 'id'); |
||
709 | // Identify those that are not existing in DB or not visible by user |
||
710 | $missingFolders = array_diff($post_folders, $accessibleIds); |
||
711 | if (!empty($missingFolders)) { |
||
712 | // There is some issues |
||
713 | echo prepareExchangedData( |
||
714 | array( |
||
715 | 'error' => true, |
||
716 | 'message' => $lang->get('error_not_allowed_to') . ' (The following folders are not accessible or do not exist: ' . implode(', ', $missingFolders) . ')', |
||
717 | ), |
||
718 | 'encode' |
||
719 | ); |
||
720 | break; |
||
721 | } |
||
722 | |||
723 | //decrypt and retreive data in JSON format |
||
724 | $folderForDel = array(); |
||
725 | |||
726 | // Start transaction |
||
727 | DB::startTransaction(); |
||
728 | |||
729 | foreach ($post_folders as $folderId) { |
||
730 | // Check if parent folder is personal |
||
731 | $dataParent = DB::queryFirstRow( |
||
732 | 'SELECT personal_folder |
||
733 | FROM ' . prefixTable('nested_tree') . ' |
||
734 | WHERE id = %i', |
||
735 | $folderId |
||
736 | ); |
||
737 | |||
738 | $isPersonal = (isset($dataParent['personal_folder']) === true && (int) $dataParent['personal_folder'] === 1) ? 1 : 0; |
||
739 | |||
740 | // Check if user is allowed |
||
741 | if ( |
||
742 | !( |
||
743 | (int) $isPersonal === 1 |
||
744 | || (int) $session->get('user-admin') === 1 |
||
745 | || (int) $session->get('user-manager') === 1 |
||
746 | || (int) $session->get('user-can_manage_all_users') === 1 |
||
747 | || (isset($SETTINGS['enable_user_can_create_folders']) === true |
||
748 | && (int) $SETTINGS['enable_user_can_create_folders'] == 1) |
||
749 | || (int) $session->get('user-can_create_root_folder') === 1 |
||
750 | ) |
||
751 | ) { |
||
752 | echo prepareExchangedData( |
||
753 | array( |
||
754 | 'error' => true, |
||
755 | 'message' => $lang->get('error_not_allowed_to'), |
||
756 | ), |
||
757 | 'encode' |
||
758 | ); |
||
759 | |||
760 | // Rollback transaction if error |
||
761 | DB::rollback(); |
||
762 | |||
763 | exit; |
||
764 | } |
||
765 | |||
766 | // Exclude a folder with id already in the list |
||
767 | if (in_array($folderId, $folderForDel) === false) { |
||
768 | // Get through each subfolder |
||
769 | $subFolders = $tree->getDescendants($folderId, true); |
||
770 | foreach ($subFolders as $thisSubFolders) { |
||
771 | if ($thisSubFolders->parent_id >= 0 |
||
772 | && $thisSubFolders->title !== $session->get('user-id') |
||
773 | ) { |
||
774 | //Store the deleted folder (recycled bin) |
||
775 | DB::insert( |
||
776 | prefixTable('misc'), |
||
777 | array( |
||
778 | 'type' => 'folder_deleted', |
||
779 | 'intitule' => 'f' . $thisSubFolders->id, |
||
780 | 'valeur' => $thisSubFolders->id . ', ' . $thisSubFolders->parent_id . ', ' . |
||
781 | $thisSubFolders->title . ', ' . $thisSubFolders->nleft . ', ' . $thisSubFolders->nright . ', ' . |
||
782 | $thisSubFolders->nlevel . ', 0, 0, 0, 0', |
||
783 | 'created_at' => time(), |
||
784 | ) |
||
785 | ); |
||
786 | //array for delete folder |
||
787 | $folderForDel[] = $thisSubFolders->id; |
||
788 | |||
789 | //delete items & logs |
||
790 | $itemsInSubFolder = DB::query( |
||
791 | 'SELECT id FROM ' . prefixTable('items') . ' |
||
792 | WHERE id_tree=%i', |
||
793 | $thisSubFolders->id |
||
794 | ); |
||
795 | foreach ($itemsInSubFolder as $item) { |
||
796 | DB::update( |
||
797 | prefixTable('items'), |
||
798 | array( |
||
799 | 'inactif' => '1', |
||
800 | ), |
||
801 | 'id = %i', |
||
802 | $item['id'] |
||
803 | ); |
||
804 | |||
805 | // log |
||
806 | logItems( |
||
807 | $SETTINGS, |
||
808 | (int) $item['id'], |
||
809 | '', |
||
810 | $session->get('user-id'), |
||
811 | 'at_delete', |
||
812 | $session->get('user-login') |
||
813 | ); |
||
814 | |||
815 | // delete folder from SESSION |
||
816 | if (array_search($item['id'], $session->get('user-accessible_folders')) !== false) { |
||
817 | SessionManager::addRemoveFromSessionArray('user-accessible_folders', [$item['id']], 'remove'); |
||
818 | } |
||
819 | |||
820 | //Update CACHE table |
||
821 | updateCacheTable('delete_value',(int) $item['id']); |
||
822 | } |
||
823 | |||
824 | //Actualize the variable |
||
825 | $session->set('user-nb_folders', $session->get('user-nb_folders') - 1); |
||
826 | } |
||
827 | } |
||
828 | } |
||
829 | } |
||
830 | |||
831 | // Add new task for building user cache tree |
||
832 | if ((int) $session->get('user-admin') !== 1) { |
||
833 | DB::insert( |
||
834 | prefixTable('background_tasks'), |
||
835 | array( |
||
836 | 'created_at' => time(), |
||
837 | 'process_type' => 'user_build_cache_tree', |
||
838 | 'arguments' => json_encode([ |
||
839 | 'user_id' => (int) $session->get('user-id'), |
||
840 | ], JSON_HEX_QUOT | JSON_HEX_TAG), |
||
841 | 'updated_at' => null, |
||
842 | 'finished_at' => null, |
||
843 | 'output' => null, |
||
844 | ) |
||
845 | ); |
||
846 | } |
||
847 | |||
848 | // delete folders |
||
849 | $folderForDel = array_unique($folderForDel); |
||
850 | foreach ($folderForDel as $fol) { |
||
851 | DB::delete(prefixTable('nested_tree'), 'id = %i', $fol); |
||
852 | } |
||
853 | |||
854 | // Update timestamp |
||
855 | DB::update( |
||
856 | prefixTable('misc'), |
||
857 | array( |
||
858 | 'valeur' => time(), |
||
859 | 'updated_at' => time(), |
||
860 | ), |
||
861 | 'type = %s AND intitule = %s', |
||
862 | 'timestamp', |
||
863 | 'last_folder_change' |
||
864 | ); |
||
865 | |||
866 | // Commit transaction |
||
867 | DB::commit(); |
||
868 | |||
869 | //rebuild tree |
||
870 | $tree->rebuild(); |
||
871 | |||
872 | echo prepareExchangedData( |
||
873 | array( |
||
874 | 'error' => false, |
||
875 | 'message' => '', |
||
876 | ), |
||
877 | 'encode' |
||
878 | ); |
||
879 | |||
880 | break; |
||
881 | |||
882 | case 'copy_folder': |
||
883 | // Check KEY |
||
884 | if ($post_key !== $session->get('key')) { |
||
885 | echo prepareExchangedData( |
||
886 | array( |
||
887 | 'error' => true, |
||
888 | 'message' => $lang->get('key_is_not_correct'), |
||
889 | ), |
||
890 | 'encode' |
||
891 | ); |
||
892 | break; |
||
893 | } elseif ($session->get('user-read_only') === 1) { |
||
894 | echo prepareExchangedData( |
||
895 | array( |
||
896 | 'error' => true, |
||
897 | 'message' => $lang->get('error_not_allowed_to'), |
||
898 | ), |
||
899 | 'encode' |
||
900 | ); |
||
901 | break; |
||
902 | } |
||
903 | |||
904 | // decrypt and retrieve data in JSON format |
||
905 | $dataReceived = prepareExchangedData( |
||
906 | $post_data, |
||
907 | 'decode' |
||
908 | ); |
||
909 | |||
910 | // Init post variables |
||
911 | $post_source_folder_id = filter_var($dataReceived['source_folder_id'], FILTER_SANITIZE_NUMBER_INT); |
||
912 | $post_target_folder_id = filter_var($dataReceived['target_folder_id'], FILTER_SANITIZE_NUMBER_INT); |
||
913 | $post_folder_label = filter_var($dataReceived['folder_label'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); |
||
914 | |||
915 | // Test if target folder is Read-only |
||
916 | // If it is then stop |
||
917 | if (in_array($post_target_folder_id, $session->get('user-read_only_folders')) === true) { |
||
918 | echo prepareExchangedData( |
||
919 | array( |
||
920 | 'error' => true, |
||
921 | 'message' => $lang->get('error_not_allowed_to'), |
||
922 | ), |
||
923 | 'encode' |
||
924 | ); |
||
925 | break; |
||
926 | } |
||
927 | |||
928 | // Check if target parent folder is personal |
||
929 | $dataParent = DB::queryFirstRow( |
||
930 | 'SELECT personal_folder |
||
931 | FROM ' . prefixTable('nested_tree') . ' |
||
932 | WHERE id = %i', |
||
933 | $post_target_folder_id |
||
934 | ); |
||
935 | |||
936 | $isPersonal = (isset($dataParent['personal_folder']) === true && (int) $dataParent['personal_folder'] === 1) ? 1 : 0; |
||
937 | |||
938 | // Check if user is allowed |
||
939 | if ( |
||
940 | !( |
||
941 | (int) $isPersonal === 1 |
||
942 | || (int) $session->get('user-admin') === 1 |
||
943 | || (int) $session->get('user-manager') === 1 |
||
944 | || (int) $session->get('user-can_manage_all_users') === 1 |
||
945 | || (isset($SETTINGS['enable_user_can_create_folders']) === true |
||
946 | && (int) $SETTINGS['enable_user_can_create_folders'] == 1) |
||
947 | || (int) $session->get('user-can_create_root_folder') === 1 |
||
948 | ) |
||
949 | ) { |
||
950 | echo prepareExchangedData( |
||
951 | array( |
||
952 | 'error' => true, |
||
953 | 'message' => $lang->get('error_not_allowed_to'), |
||
954 | ), |
||
955 | 'encode' |
||
956 | ); |
||
957 | break; |
||
958 | } |
||
959 | |||
960 | // Get all allowed folders |
||
961 | $array_all_visible_folders = array_merge( |
||
962 | $session->get('user-accessible_folders'), |
||
963 | $session->get('user-read_only_folders'), |
||
964 | $session->get('user-personal_visible_folders') |
||
965 | ); |
||
966 | |||
967 | // get list of all folders |
||
968 | $nodeDescendants = $tree->getDescendants($post_source_folder_id, true, false, false); |
||
969 | $parentId = ''; |
||
970 | $tabNodes = []; |
||
971 | foreach ($nodeDescendants as $node) { |
||
972 | // step1 - copy folder |
||
973 | |||
974 | // Can user access this subfolder? |
||
975 | if (in_array($node->id, $array_all_visible_folders) === false) { |
||
976 | continue; |
||
977 | } |
||
978 | |||
979 | // get info about current node |
||
980 | $nodeInfo = $tree->getNode($node->id); |
||
981 | |||
982 | // get complexity of current node |
||
983 | $nodeComplexity = DB::queryFirstRow( |
||
984 | 'SELECT valeur |
||
985 | FROM ' . prefixTable('misc') . ' |
||
986 | WHERE intitule = %i AND type= %s', |
||
987 | $nodeInfo->id, |
||
988 | 'complex' |
||
989 | ); |
||
990 | |||
991 | // prepare parent Id |
||
992 | if (empty($parentId) === true) { |
||
993 | $parentId = $post_target_folder_id; |
||
994 | } else { |
||
995 | $parentId = $tabNodes[$nodeInfo->parent_id]; |
||
996 | } |
||
997 | |||
998 | //create folder |
||
999 | DB::insert( |
||
1000 | prefixTable('nested_tree'), |
||
1001 | array( |
||
1002 | 'parent_id' => $parentId, |
||
1003 | 'title' => count($tabNodes) === 0 ? $post_folder_label : $nodeInfo->title, |
||
1004 | 'personal_folder' => $nodeInfo->personal_folder, |
||
1005 | 'renewal_period' => $nodeInfo->renewal_period, |
||
1006 | 'bloquer_creation' => $nodeInfo->bloquer_creation, |
||
1007 | 'bloquer_modification' => $nodeInfo->bloquer_modification, |
||
1008 | 'categories' => '', |
||
1009 | ) |
||
1010 | ); |
||
1011 | $newFolderId = DB::insertId(); |
||
1012 | |||
1013 | // add to correspondance matrix |
||
1014 | $tabNodes[$nodeInfo->id] = $newFolderId; |
||
1015 | |||
1016 | //Add complexity |
||
1017 | DB::insert( |
||
1018 | prefixTable('misc'), |
||
1019 | array( |
||
1020 | 'type' => 'complex', |
||
1021 | 'intitule' => $newFolderId, |
||
1022 | 'valeur' => is_null($nodeComplexity['valeur']) === false ? $nodeComplexity['valeur'] : 0, |
||
1023 | 'created_at' => time(), |
||
1024 | ) |
||
1025 | ); |
||
1026 | |||
1027 | // add new folder id in SESSION |
||
1028 | $session->set('user-accessible_folders', array_unique(array_merge($session->get('user-accessible_folders'), [$newFolderId]), SORT_NUMERIC)); |
||
1029 | if ((int) $nodeInfo->personal_folder === 1) { |
||
1030 | SessionManager::addRemoveFromSessionArray('user-personal_folders', [$newFolderId], 'add'); |
||
1031 | SessionManager::addRemoveFromSessionArray('user-personal_visible_folders', [$newFolderId], 'add'); |
||
1032 | } |
||
1033 | |||
1034 | // If new folder should not heritate of parent rights |
||
1035 | // Then use the creator ones |
||
1036 | if ( |
||
1037 | (int) $nodeInfo->personal_folder !== 1 |
||
1038 | && isset($SETTINGS['subfolder_rights_as_parent']) === true |
||
1039 | && (int) $SETTINGS['subfolder_rights_as_parent'] === 1 |
||
1040 | && (int) $session->get('user-admin') === 0 |
||
1041 | ) { |
||
1042 | //add access to this new folder |
||
1043 | foreach (explode(';', $session->get('user-roles')) as $role) { |
||
1044 | if (empty($role) === false) { |
||
1045 | DB::insertUpdate( |
||
1046 | prefixTable('roles_values'), |
||
1047 | array( |
||
1048 | 'role_id' => $role, |
||
1049 | 'folder_id' => $newFolderId, |
||
1050 | 'type' => 'W', |
||
1051 | ) |
||
1052 | ); |
||
1053 | } |
||
1054 | } |
||
1055 | } |
||
1056 | |||
1057 | // If it is a subfolder, then give access to it for all roles that allows the parent folder |
||
1058 | $rows = DB::query( |
||
1059 | 'SELECT role_id, type |
||
1060 | FROM ' . prefixTable('roles_values') . ' |
||
1061 | WHERE folder_id = %i', |
||
1062 | $parentId |
||
1063 | ); |
||
1064 | foreach ($rows as $record) { |
||
1065 | // Add access to this subfolder |
||
1066 | DB::insertUpdate( |
||
1067 | prefixTable('roles_values'), |
||
1068 | array( |
||
1069 | 'role_id' => $record['role_id'], |
||
1070 | 'folder_id' => $newFolderId, |
||
1071 | 'type' => $record['type'], |
||
1072 | ) |
||
1073 | ); |
||
1074 | } |
||
1075 | |||
1076 | // if parent folder has Custom Fields Categories then add to this child one too |
||
1077 | $rows = DB::query( |
||
1078 | 'SELECT id_category |
||
1079 | FROM ' . prefixTable('categories_folders') . ' |
||
1080 | WHERE id_folder = %i', |
||
1081 | $nodeInfo->id |
||
1082 | ); |
||
1083 | foreach ($rows as $record) { |
||
1084 | //add CF Category to this subfolder |
||
1085 | DB::insert( |
||
1086 | prefixTable('categories_folders'), |
||
1087 | array( |
||
1088 | 'id_category' => $record['id_category'], |
||
1089 | 'id_folder' => $newFolderId, |
||
1090 | ) |
||
1091 | ); |
||
1092 | } |
||
1093 | |||
1094 | // step2 - copy items |
||
1095 | |||
1096 | $rows = DB::query( |
||
1097 | 'SELECT * |
||
1098 | FROM ' . prefixTable('items') . ' |
||
1099 | WHERE id_tree = %i', |
||
1100 | $nodeInfo->id |
||
1101 | ); |
||
1102 | foreach ($rows as $record) { |
||
1103 | // check if item is deleted |
||
1104 | // if it is then don't copy it |
||
1105 | $item_deleted = DB::queryFirstRow( |
||
1106 | 'SELECT * |
||
1107 | FROM ' . prefixTable('log_items') . ' |
||
1108 | WHERE id_item = %i AND action = %s |
||
1109 | ORDER BY date DESC |
||
1110 | LIMIT 0, 1', |
||
1111 | $record['id'], |
||
1112 | 'at_delete' |
||
1113 | ); |
||
1114 | $dataDeleted = DB::count(); |
||
1115 | |||
1116 | $item_restored = DB::queryFirstRow( |
||
1117 | 'SELECT * |
||
1118 | FROM ' . prefixTable('log_items') . ' |
||
1119 | WHERE id_item = %i AND action = %s |
||
1120 | ORDER BY date DESC |
||
1121 | LIMIT 0, 1', |
||
1122 | $record['id'], |
||
1123 | 'at_restored' |
||
1124 | ); |
||
1125 | |||
1126 | if ( |
||
1127 | (int) $dataDeleted !== 1 |
||
1128 | || (isset($item_restored['date']) === true && (int) $item_deleted['date'] < (int) $item_restored['date']) |
||
1129 | ) { |
||
1130 | // Get the ITEM object key for the user |
||
1131 | $userKey = DB::queryFirstRow( |
||
1132 | 'SELECT share_key |
||
1133 | FROM ' . prefixTable('sharekeys_items') . ' |
||
1134 | WHERE user_id = %i AND object_id = %i', |
||
1135 | $session->get('user-id'), |
||
1136 | $record['id'] |
||
1137 | ); |
||
1138 | if (DB::count() === 0) { |
||
1139 | // ERROR - No sharekey found for this item and user |
||
1140 | echo prepareExchangedData( |
||
1141 | array( |
||
1142 | 'error' => true, |
||
1143 | 'message' => $lang->get('error_not_allowed_to'), |
||
1144 | ), |
||
1145 | 'encode' |
||
1146 | ); |
||
1147 | break; |
||
1148 | } |
||
1149 | |||
1150 | |||
1151 | // Decrypt / Encrypt the password |
||
1152 | $cryptedStuff = doDataEncryption( |
||
1153 | base64_decode( |
||
1154 | doDataDecryption( |
||
1155 | $record['pw'], |
||
1156 | decryptUserObjectKey( |
||
1157 | $userKey['share_key'], |
||
1158 | $session->get('user-private_key') |
||
1159 | ) |
||
1160 | ) |
||
1161 | ) |
||
1162 | ); |
||
1163 | |||
1164 | // Insert the new record and get the new auto_increment id |
||
1165 | DB::insert( |
||
1166 | prefixTable('items'), |
||
1167 | array( |
||
1168 | 'label' => substr($record['label'], 0, 500), |
||
1169 | 'description' => empty($record['description']) === true ? '' : $record['description'], |
||
1170 | 'id_tree' => $newFolderId, |
||
1171 | 'pw' => $cryptedStuff['encrypted'], |
||
1172 | 'pw_iv' => '', |
||
1173 | 'url' => empty($record['url']) === true ? '' : substr($record['url'], 0, 500), |
||
1174 | 'login' => empty($record['login']) === true ? '' : substr($record['login'], 0, 200), |
||
1175 | 'viewed_no' => 0, |
||
1176 | 'encryption_type' => 'teampass_aes', |
||
1177 | 'item_key' => uniqidReal(50), |
||
1178 | 'created_at' => time(), |
||
1179 | ) |
||
1180 | ); |
||
1181 | $newItemId = DB::insertId(); |
||
1182 | |||
1183 | // Create task for the new item |
||
1184 | storeTask( |
||
1185 | 'item_copy', |
||
1186 | $session->get('user-id'), |
||
1187 | (int) $nodeInfo->personal_folder, |
||
1188 | (int) $newFolderId, |
||
1189 | (int) $newItemId, |
||
1190 | $cryptedStuff['objectKey'], |
||
1191 | ); |
||
1192 | |||
1193 | // Add this duplicate in logs |
||
1194 | logItems( |
||
1195 | $SETTINGS, |
||
1196 | (int) $newItemId, |
||
1197 | $record['label'], |
||
1198 | $session->get('user-id'), |
||
1199 | 'at_creation', |
||
1200 | $session->get('user-login') |
||
1201 | ); |
||
1202 | // Add the fact that item has been copied in logs |
||
1203 | logItems( |
||
1204 | $SETTINGS, |
||
1205 | (int) $newItemId, |
||
1206 | $record['label'], |
||
1207 | $session->get('user-id'), |
||
1208 | 'at_copy', |
||
1209 | $session->get('user-login') |
||
1210 | ); |
||
1211 | |||
1212 | // Add item to cache table |
||
1213 | updateCacheTable('add_value', (int) $newItemId); |
||
1214 | } |
||
1215 | } |
||
1216 | } |
||
1217 | |||
1218 | // rebuild tree |
||
1219 | $tree->rebuild(); |
||
1220 | |||
1221 | // Update timestamp |
||
1222 | DB::update( |
||
1223 | prefixTable('misc'), |
||
1224 | array( |
||
1225 | 'valeur' => time(), |
||
1226 | 'updated_at' => time(), |
||
1227 | ), |
||
1228 | 'type = %s AND intitule = %s', |
||
1229 | 'timestamp', |
||
1230 | 'last_folder_change' |
||
1231 | ); |
||
1232 | |||
1233 | $data = array( |
||
1234 | 'error' => '', |
||
1235 | ); |
||
1236 | |||
1237 | // send data |
||
1238 | echo prepareExchangedData( |
||
1239 | $data, |
||
1240 | 'encode' |
||
1241 | ); |
||
1242 | |||
1243 | break; |
||
1244 | |||
1245 | // CASE where selecting/deselecting sub-folders |
||
1246 | case 'refresh_folders_list': |
||
1247 | // Check KEY |
||
1248 | if ($post_key !== $session->get('key')) { |
||
1249 | echo prepareExchangedData( |
||
1250 | array( |
||
1251 | 'error' => true, |
||
1252 | 'message' => $lang->get('key_is_not_correct'), |
||
1253 | ), |
||
1254 | 'encode' |
||
1255 | ); |
||
1256 | break; |
||
1257 | } elseif ($session->get('user-read_only') === 1) { |
||
1258 | echo prepareExchangedData( |
||
1259 | array( |
||
1260 | 'error' => true, |
||
1261 | 'message' => $lang->get('error_not_allowed_to'), |
||
1262 | ), |
||
1263 | 'encode' |
||
1264 | ); |
||
1265 | break; |
||
1266 | } |
||
1267 | |||
1268 | $subfolders = array(); |
||
1269 | |||
1270 | if ((int) $session->get('user-admin') === 1 || (int) $session->get('user-manager') === 1 || (int) $session->get('user-can_create_root_folder') === 1) { |
||
1271 | array_push( |
||
1272 | $subfolders, |
||
1273 | array( |
||
1274 | 'id' => 0, |
||
1275 | 'label' => $lang->get('root'), |
||
1276 | 'level' => 0, |
||
1277 | 'path' => '' |
||
1278 | ) |
||
1279 | ); |
||
1280 | } |
||
1281 | |||
1282 | // get sub folders |
||
1283 | |||
1284 | // Get through each subfolder |
||
1285 | $folders = $tree->getDescendants(0, false); |
||
1286 | |||
1287 | foreach ($folders as $folder) { |
||
1288 | if ( |
||
1289 | in_array($folder->id, $session->get('user-accessible_folders')) === true |
||
1290 | && in_array($folder->id, $session->get('user-personal_visible_folders')) === false |
||
1291 | ) { |
||
1292 | // Get path |
||
1293 | $text = ''; |
||
1294 | foreach ($tree->getPath($folder->id, false) as $fld) { |
||
1295 | $text .= empty($text) === true ? ' [<i>' . $fld->title : ' > ' . $fld->title; |
||
1296 | } |
||
1297 | |||
1298 | // Save array |
||
1299 | array_push( |
||
1300 | $subfolders, |
||
1301 | array( |
||
1302 | 'id' => (int) $folder->id, |
||
1303 | 'label' => $folder->title, |
||
1304 | 'level' => $folder->nlevel, |
||
1305 | 'path' => empty($text) === true ? '' : $text . '</i>]' |
||
1306 | ) |
||
1307 | ); |
||
1308 | } |
||
1309 | } |
||
1310 | |||
1311 | echo prepareExchangedData( |
||
1312 | array( |
||
1313 | 'error' => false, |
||
1314 | 'subfolders' => ($subfolders), |
||
1315 | ), |
||
1316 | 'encode' |
||
1317 | ); |
||
1318 | |||
1319 | break; |
||
1320 | } |
||
1321 | } |
||
1322 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths