Passed
Pull Request — master (#4439)
by Nils
06:07
created

getCurrentAccessRights()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 36
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 7
eloc 14
c 2
b 0
f 0
nc 7
nop 3
dl 0
loc 36
rs 8.8333
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      items.queries.php
26
 * @author    Nils Laumaillé ([email protected])
27
 * @copyright 2009-2024 Teampass.net
28
 * @license   GPL-3.0
29
 * @see       https://www.teampass.net
30
 */
31
32
33
use voku\helper\AntiXSS;
34
use TeampassClasses\NestedTree\NestedTree;
35
use TeampassClasses\SessionManager\SessionManager;
36
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
37
use TeampassClasses\Language\Language;
38
use EZimuel\PHPSecureSession;
39
use TeampassClasses\PerformChecks\PerformChecks;
40
use TeampassClasses\ConfigManager\ConfigManager;
41
use OTPHP\TOTP;
42
use TeampassClasses\EmailService\EmailService;
43
use TeampassClasses\EmailService\EmailSettings;
44
45
// Load functions
46
require_once 'main.functions.php';
47
48
// init
49
loadClasses('DB');
50
$session = SessionManager::getSession();
51
$request = SymfonyRequest::createFromGlobals();
52
$lang = new Language($session->get('user-language') ?? 'english');
53
54
// Load config
55
$configManager = new ConfigManager();
56
$SETTINGS = $configManager->getAllSettings();
57
58
// Do checks
59
// Instantiate the class with posted data
60
$checkUserAccess = new PerformChecks(
61
    dataSanitizer(
62
        [
63
            'type' => null !== $request->request->get('type') ? htmlspecialchars($request->request->get('type')) : '',
64
        ],
65
        [
66
            'type' => 'trim|escape',
67
        ],
68
    ),
69
    [
70
        'user_id' => returnIfSet($session->get('user-id'), null),
71
        'user_key' => returnIfSet($session->get('key', 'SESSION'), null),
72
    ]
73
);
74
// Handle the case
75
echo $checkUserAccess->caseHandler();
76
if (
77
    $checkUserAccess->userAccessPage('items') === false ||
78
    $checkUserAccess->checkSession() === false
79
) {
80
    // Not allowed page
81
    $session->set('system-error_code', ERR_NOT_ALLOWED);
82
    include $SETTINGS['cpassman_dir'] . '/error.php';
83
    exit;
84
}
85
86
// Define Timezone
87
date_default_timezone_set(isset($SETTINGS['timezone']) === true ? $SETTINGS['timezone'] : 'UTC');
88
89
// Set header properties
90
header('Content-type: text/html; charset=utf-8');
91
header('Cache-Control: no-cache, no-store, must-revalidate');
92
error_reporting(E_ERROR);
93
set_time_limit(0);
94
95
// --------------------------------- //
96
97
98
/*
99
 * Define Timezone
100
*/
101
if (isset($SETTINGS['timezone']) === true) {
102
    date_default_timezone_set($SETTINGS['timezone']);
103
} else {
104
    date_default_timezone_set('UTC');
105
}
106
107
require_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $session->get('user-language') . '.php';
108
header('Content-type: text/html; charset=utf-8');
109
header('Cache-Control: no-cache, must-revalidate');
110
111
112
// Prepare nestedTree
113
$tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
114
115
// Load AntiXSS
116
$antiXss = new AntiXSS();
117
118
// Ensure Complexity levels are translated
119
if (defined('TP_PW_COMPLEXITY') === false) {
120
    define(
121
        'TP_PW_COMPLEXITY',
122
        array(
123
            TP_PW_STRENGTH_1 => array(TP_PW_STRENGTH_1, $lang->get('complex_level1'), 'fas fa-thermometer-empty text-danger'),
124
            TP_PW_STRENGTH_2 => array(TP_PW_STRENGTH_2, $lang->get('complex_level2'), 'fas fa-thermometer-quarter text-warning'),
125
            TP_PW_STRENGTH_3 => array(TP_PW_STRENGTH_3, $lang->get('complex_level3'), 'fas fa-thermometer-half text-warning'),
126
            TP_PW_STRENGTH_4 => array(TP_PW_STRENGTH_4, $lang->get('complex_level4'), 'fas fa-thermometer-three-quarters text-success'),
127
            TP_PW_STRENGTH_5 => array(TP_PW_STRENGTH_5, $lang->get('complex_level5'), 'fas fa-thermometer-full text-success'),
128
        )
129
    );
130
}
131
132
// Prepare POST variables
133
$data = [
134
    'type' => $request->request->filter('type', '', FILTER_SANITIZE_SPECIAL_CHARS),
135
    'data' => $request->request->filter('data', '', FILTER_SANITIZE_SPECIAL_CHARS),
136
    'key' => $request->request->filter('key', '', FILTER_SANITIZE_SPECIAL_CHARS),
137
    'label' => $request->request->filter('label', '', FILTER_SANITIZE_SPECIAL_CHARS),
138
    'status' => $request->request->filter('status', '', FILTER_SANITIZE_SPECIAL_CHARS),
139
    'cat' => $request->request->filter('cat', '', FILTER_SANITIZE_SPECIAL_CHARS),
140
    'receipt' => $request->request->filter('receipt', '', FILTER_SANITIZE_SPECIAL_CHARS),
141
    'itemId' => $request->request->filter('item_id', '', FILTER_SANITIZE_SPECIAL_CHARS),
142
    'folderId' => $request->request->filter('folder_id', '', FILTER_SANITIZE_SPECIAL_CHARS),
143
    'id' => $request->request->filter('id', '', FILTER_SANITIZE_SPECIAL_CHARS),
144
    'destination' => $request->request->filter('destination', '', FILTER_SANITIZE_SPECIAL_CHARS),
145
    'source' => $request->request->filter('source', '', FILTER_SANITIZE_SPECIAL_CHARS),
146
    'userId' => $request->request->filter('user_id', '', FILTER_SANITIZE_SPECIAL_CHARS),
147
    'getType' => $request->query->get('type', ''),
148
    'getTerm' => $request->query->get('term', ''),
149
    'option' => $request->request->filter('option', '', FILTER_SANITIZE_SPECIAL_CHARS),
150
    'fileSuffix' => $request->request->filter('file_suffix', '', FILTER_SANITIZE_SPECIAL_CHARS),
151
    'context' => $request->request->filter('context', '', FILTER_SANITIZE_SPECIAL_CHARS),
152
    'notifyType' => $request->request->filter('notify_type', '', FILTER_SANITIZE_SPECIAL_CHARS),
153
    'timestamp' => $request->request->filter('timestamp', '', FILTER_SANITIZE_SPECIAL_CHARS),
154
    'itemKey' => $request->request->filter('item_key', '', FILTER_SANITIZE_SPECIAL_CHARS),
155
];
156
157
$filters = [
158
    'type' => 'trim|escape',
159
    'data' => 'trim|escape',
160
    'key' => 'trim|escape',
161
    'label' => 'trim|escape',
162
    'status' => 'trim|escape',
163
    'cat' => 'trim|escape',
164
    'receipt' => 'trim|escape',
165
    'itemId' => 'cast:integer',
166
    'folderId' => 'cast:integer',
167
    'id' => 'cast:integer',
168
    'destination' => 'cast:integer',
169
    'source' => 'cast:integer',
170
    'userId' => 'cast:integer',
171
    'getType' => 'trim|escape',
172
    'getTerm' => 'trim|escape',
173
    'option' => 'trim|escape',
174
    'fileSuffix' => 'trim|escape',
175
    'context' => 'trim|escape',
176
    'notifyType' => 'trim|escape',
177
    'timestamp' => 'cast:integer',
178
    'itemKey' => 'trim|escape',
179
];
180
181
$inputData = dataSanitizer(
182
    $data,
183
    $filters
184
);
185
186
// Do asked action
187
switch ($inputData['type']) {
188
    /*
189
    * CASE
190
    * creating a new ITEM
191
    */
192
    case 'new_item':
193
        // Check KEY and rights
194
        if ($inputData['key'] !== $session->get('key')) {
195
            echo (string) prepareExchangedData(
196
                array(
197
                    'error' => true,
198
                    'message' => $lang->get('key_is_not_correct'),
199
                ),
200
                'encode'
201
            );
202
            break;
203
        }
204
        if ($session->get('user-read_only') === 1) {
205
            echo (string) prepareExchangedData(
206
                array(
207
                    'error' => true,
208
                    'message' => $lang->get('error_not_allowed_to'),
209
                ),
210
                'encode'
211
            );
212
            break;
213
        }
214
215
        // init
216
        $returnValues = array();
217
        // decrypt and retreive data in JSON format
218
        $dataReceived = prepareExchangedData(
219
            $inputData['data'],
220
            'decode'
221
        );
222
223
        if (is_array($dataReceived) === true && count($dataReceived) > 0) {
224
            // Prepare variables
225
            $post_anyone_can_modify = filter_var($dataReceived['anyone_can_modify'], FILTER_SANITIZE_NUMBER_INT);
226
            $post_complexity_level = filter_var($dataReceived['complexity_level'], FILTER_SANITIZE_NUMBER_INT);
227
            $post_description = $antiXss->xss_clean($dataReceived['description']);
228
            $post_diffusion_list = filter_var_array(
229
                $dataReceived['diffusion_list'],
230
                FILTER_SANITIZE_FULL_SPECIAL_CHARS
231
            );
232
            $post_diffusion_list_names = filter_var_array(
233
                $dataReceived['diffusion_list_names'],
234
                FILTER_SANITIZE_FULL_SPECIAL_CHARS
235
            );
236
            $post_email = filter_var(htmlspecialchars_decode($dataReceived['email']), FILTER_SANITIZE_EMAIL);
237
            $post_fields = filter_var_array(
238
                $dataReceived['fields'],
239
                FILTER_SANITIZE_FULL_SPECIAL_CHARS
240
            );
241
            $inputData['folderId'] = filter_var($dataReceived['folder'], FILTER_SANITIZE_NUMBER_INT);
242
            $post_folder_is_personal = filter_var($dataReceived['folder_is_personal'], FILTER_SANITIZE_NUMBER_INT);
243
            $inputData['label'] = filter_var($dataReceived['label'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
244
            $post_login = filter_var($dataReceived['login'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
245
            $post_password = htmlspecialchars_decode($dataReceived['pw']);
246
            $post_restricted_to = filter_var(
247
                $dataReceived['restricted_to'],
248
                FILTER_SANITIZE_FULL_SPECIAL_CHARS
249
            );
250
            $post_restricted_to = $post_restricted_to !== false ? json_decode($post_restricted_to) : '';
251
            $post_restricted_to_roles = filter_var(
252
                $dataReceived['restricted_to_roles'],
253
                FILTER_SANITIZE_FULL_SPECIAL_CHARS
254
            );
255
            $post_restricted_to_roles = $post_restricted_to_roles !== false ? json_decode($post_restricted_to_roles) : '';
256
            $post_tags = htmlspecialchars_decode($dataReceived['tags']);
257
            $post_template_id = filter_var($dataReceived['template_id'], FILTER_SANITIZE_NUMBER_INT);
258
            $post_url = filter_var(htmlspecialchars_decode($dataReceived['url']), FILTER_SANITIZE_URL);
259
            $post_uploaded_file_id = filter_var($dataReceived['uploaded_file_id'], FILTER_SANITIZE_NUMBER_INT);
260
            $inputData['userId'] = filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
261
            $post_to_be_deleted_after_date = isset($dataReceived['to_be_deleted_after_date']) === true ? filter_var($dataReceived['to_be_deleted_after_date'], FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
262
            $post_to_be_deleted_after_x_views = filter_var($dataReceived['to_be_deleted_after_x_views'], FILTER_SANITIZE_NUMBER_INT);
263
            $post_fa_icon = isset($dataReceived['fa_icon']) === true ? filter_var($dataReceived['fa_icon'], FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
264
265
            //-> DO A SET OF CHECKS
266
            // Perform a check in case of Read-Only user creating an item in his PF
267
            if ($session->get('user-read_only') === 1
268
                && (in_array($inputData['folderId'], $session->get('user-personal_folders')) === false
269
                || $post_folder_is_personal !== 1)
270
            ) {
271
                echo (string) prepareExchangedData(
272
                    array(
273
                        'error' => true,
274
                        'message' => $lang->get('error_not_allowed_to_access_this_folder'),
275
                    ),
276
                    'encode'
277
                );
278
                break;
279
            }
280
281
            // Is author authorized to create in this folder
282
            if (count($session->get('user-list_folders_limited')) > 0) {
283
                if (in_array($inputData['folderId'], array_keys($session->get('user-list_folders_limited'))) === false
284
                    && in_array($inputData['folderId'], $session->get('user-accessible_folders')) === false
285
                    && in_array($inputData['folderId'], $session->get('user-personal_folders')) === false
286
                ) {
287
                    echo (string) prepareExchangedData(
288
                        array(
289
                            'error' => true,
290
                            'message' => $lang->get('error_not_allowed_to_access_this_folder'),
291
                        ),
292
                        'encode'
293
                    );
294
                    break;
295
                }
296
            } else {
297
                if (in_array($inputData['folderId'], $session->get('user-accessible_folders')) === false) {
298
                    echo (string) prepareExchangedData(
299
                        array(
300
                            'error' => true,
301
                            'message' => $lang->get('error_not_allowed_to_access_this_folder'),
302
                        ),
303
                        'encode'
304
                    );
305
                    break;
306
                }
307
            }
308
309
            // perform a check in case of Read-Only user creating an item in his PF
310
            if (
311
                $session->get('user-read_only') === 1
312
                && in_array($inputData['folderId'], $session->get('user-personal_folders')) === false
313
            ) {
314
                echo (string) prepareExchangedData(
315
                    array(
316
                        'error' => true,
317
                        'message' => $lang->get('error_not_allowed_to_access_this_folder'),
318
                    ),
319
                    'encode'
320
                );
321
                break;
322
            }
323
324
            // is pwd empty?
325
            if (
326
                empty($post_password) === true
327
                && $session->has('user-create_item_without_password') && null !== $session->get('user-create_item_without_password')
328
                && (int) $session->get('user-create_item_without_password') !== 1
329
            ) {
330
                echo (string) prepareExchangedData(
331
                    array(
332
                        'error' => true,
333
                        'message' => $lang->get('password_cannot_be_empty'),
334
                    ),
335
                    'encode'
336
                );
337
                break;
338
            }
339
340
            // Check length
341
            $strlen_post_password = strlen($post_password);
342
            if ($strlen_post_password > $SETTINGS['pwd_maximum_length']) {
343
                echo (string) prepareExchangedData(
344
                    array(
345
                        'error' => true,
346
                        'message' => $lang->get('password_too_long'),
347
                    ),
348
                    'encode'
349
                );
350
                break;
351
            }
352
353
            // Need info in DB
354
            // About special settings
355
            $dataFolderSettings = DB::queryFirstRow(
356
                'SELECT bloquer_creation, bloquer_modification, personal_folder
357
                FROM ' . prefixTable('nested_tree') . ' 
358
                WHERE id = %i',
359
                $inputData['folderId']
360
            );
361
            $itemInfos = [];
362
            $itemInfos['personal_folder'] = $dataFolderSettings['personal_folder'];
363
            if ((int) $itemInfos['personal_folder'] === 1) {
364
                $itemInfos['no_complex_check_on_modification'] = 1;
365
                $itemInfos['no_complex_check_on_creation'] = 1;
366
            } else {
367
                $itemInfos['no_complex_check_on_modification'] = (int) $dataFolderSettings['bloquer_modification'];
368
                $itemInfos['no_complex_check_on_creation'] = (int) $dataFolderSettings['bloquer_creation'];
369
            }
370
371
            // Get folder complexity
372
            $folderComplexity = DB::queryfirstrow(
373
                'SELECT valeur
374
                FROM ' . prefixTable('misc') . '
375
                WHERE type = %s AND intitule = %i',
376
                'complex',
377
                $inputData['folderId']
378
            );
379
            $itemInfos['requested_folder_complexity'] = $folderComplexity !== null ? (int) $folderComplexity['valeur'] : 0;
380
381
            // Check COMPLEXITY
382
            if ($post_complexity_level < $itemInfos['requested_folder_complexity'] && $itemInfos['no_complex_check_on_creation'] === 0) {
383
                echo (string) prepareExchangedData(
384
                    array(
385
                        'error' => true,
386
                        'message' => $lang->get('error_security_level_not_reached'),
387
                    ),
388
                    'encode'
389
                );
390
                break;
391
            }
392
393
            // ./ END
394
395
            // check if element doesn't already exist
396
            $itemExists = 0;
397
            $newID = '';
398
            $data = DB::queryfirstrow(
399
                'SELECT * FROM ' . prefixTable('items') . '
400
                WHERE label = %s AND inactif = %i',
401
                $inputData['label'],
402
                0
403
            );
404
            $counter = DB::count();
405
            if ($counter > 0) {
406
                $itemExists = 1;
407
            } else {
408
                $itemExists = 0;
409
            }
410
411
            // Manage case where item is personal.
412
            // In this case, duplication is allowed
413
            if (
414
                isset($SETTINGS['duplicate_item']) === true
415
                && (int) $SETTINGS['duplicate_item'] === 0
416
                && (int) $post_folder_is_personal === 1
417
                && isset($post_folder_is_personal) === true
418
            ) {
419
                $itemExists = 0;
420
            }
421
422
            if ((isset($SETTINGS['duplicate_item']) === true
423
                    && (int) $SETTINGS['duplicate_item'] === 0
424
                    && (int) $itemExists === 0)
425
                || (isset($SETTINGS['duplicate_item']) === true
426
                    && (int) $SETTINGS['duplicate_item'] === 1)
427
            ) {
428
                // Handle case where pw is empty
429
                // if not allowed then warn user
430
                if (($session->has('user-create_item_without_password') && $session->has('user-create_item_without_password') && null !== $session->get('user-create_item_without_password')
431
                        && (int) $session->get('user-create_item_without_password') !== 1) ||
432
                    empty($post_password) === false ||
433
                    (int) $post_folder_is_personal === 1
434
                ) {
435
                    // NEW ENCRYPTION
436
                    $cryptedStuff = doDataEncryption($post_password);
437
                } else {
438
                    $cryptedStuff['encrypted'] = '';
439
                    $cryptedStuff['objectKey'] = '';
440
                }
441
442
                $post_password = $cryptedStuff['encrypted'];
443
                $post_password_key = $cryptedStuff['objectKey'];
444
                $itemFilesForTasks = [];
445
                $itemFieldsForTasks = [];
446
                
447
                // ADD item
448
                DB::insert(
449
                    prefixTable('items'),
450
                    array(
451
                        'label' => $inputData['label'],
452
                        'description' => $post_description,
453
                        'pw' => $post_password,
454
                        'pw_iv' => '',
455
                        'pw_len' => $strlen_post_password,
456
                        'email' => $post_email,
457
                        'url' => $post_url,
458
                        'id_tree' => $inputData['folderId'],
459
                        'login' => $post_login,
460
                        'inactif' => 0,
461
                        'restricted_to' => empty($post_restricted_to) === true ?
462
                            '' : (is_array($post_restricted_to) === true ? implode(';', $post_restricted_to) : $post_restricted_to),
463
                        'perso' => (isset($post_folder_is_personal) === true && (int) $post_folder_is_personal === 1) ?
464
                            1 : 0,
465
                        'anyone_can_modify' => (isset($post_anyone_can_modify) === true
466
                            && $post_anyone_can_modify === 'on') ? 1 : 0,
467
                        'complexity_level' => $post_complexity_level,
468
                        'encryption_type' => 'teampass_aes',
469
                        'fa_icon' => $post_fa_icon,
470
                        'item_key' => uniqidReal(50),
471
                        'created_at' => time(),
472
                    )
473
                );
474
                $newID = DB::insertId();
475
476
                // Create sharekeys for the user itself
477
                storeUsersShareKey(
478
                    prefixTable('sharekeys_items'),
479
                    (int) $post_folder_is_personal,
480
                    (int) $inputData['folderId'],
481
                    (int) $newID,
482
                    $cryptedStuff['objectKey'],
483
                    true,   // only for the item creator
484
                    false,  // no delete all
485
                );
486
487
                // update fields
488
                if (
489
                    isset($SETTINGS['item_extra_fields']) === true
490
                    && (int) $SETTINGS['item_extra_fields'] === 1
491
                ) {
492
                    foreach ($post_fields as $field) {
493
                        if (empty($field['value']) === false) {
494
                            // should we encrypt the data
495
                            $dataTmp = DB::queryFirstRow(
496
                                'SELECT encrypted_data
497
                                FROM ' . prefixTable('categories') . '
498
                                WHERE id = %i',
499
                                $field['id']
500
                            );
501
502
                            // Should we encrypt the data
503
                            if ((int) $dataTmp['encrypted_data'] === 1) {
504
                                // Create sharekeys for users
505
                                $cryptedStuff = doDataEncryption($field['value']);
506
507
                                // Store value
508
                                DB::insert(
509
                                    prefixTable('categories_items'),
510
                                    array(
511
                                        'item_id' => $newID,
512
                                        'field_id' => $field['id'],
513
                                        'data' => $cryptedStuff['encrypted'],
514
                                        'data_iv' => '',
515
                                        'encryption_type' => TP_ENCRYPTION_NAME,
516
                                    )
517
                                );
518
                                $newObjectId = DB::insertId();
519
            
520
                                // Create sharekeys for user
521
                                storeUsersShareKey(
522
                                    prefixTable('sharekeys_fields'),
523
                                    (int) $post_folder_is_personal,
524
                                    (int) $inputData['folderId'],
525
                                    (int) $newObjectId,
526
                                    $cryptedStuff['objectKey'],
527
                                    true,   // only for the item creator
528
                                    false,  // no delete all
529
                                );
530
531
                                array_push(
532
                                    $itemFieldsForTasks,
533
                                    [
534
                                        'object_id' => $newObjectId,
535
                                        'object_key' => $cryptedStuff['objectKey'],
536
                                    ]
537
                                );
538
                                
539
                            } else {
540
                                // update value
541
                                DB::insert(
542
                                    prefixTable('categories_items'),
543
                                    array(
544
                                        'item_id' => $newID,
545
                                        'field_id' => $field['id'],
546
                                        'data' => $field['value'],
547
                                        'data_iv' => '',
548
                                        'encryption_type' => 'not_set',
549
                                    )
550
                                );
551
                            }
552
                        }
553
                    }
554
                }
555
556
                // If template enable, is there a main one selected?
557
                if (
558
                    isset($SETTINGS['item_creation_templates']) === true
559
                    && (int) $SETTINGS['item_creation_templates'] === 1
560
                    && isset($post_template_id) === true
561
                    && empty($post_template_id) === false
562
                ) {
563
                    DB::queryFirstRow(
564
                        'SELECT *
565
                        FROM ' . prefixTable('templates') . '
566
                        WHERE item_id = %i',
567
                        $newID
568
                    );
569
                    if (DB::count() === 0) {
570
                        // store field text
571
                        DB::insert(
572
                            prefixTable('templates'),
573
                            array(
574
                                'item_id' => $newID,
575
                                'category_id' => $post_template_id,
576
                            )
577
                        );
578
                    } else {
579
                        // Delete if empty
580
                        if (empty($post_template_id) === true) {
581
                            DB::delete(
582
                                prefixTable('templates'),
583
                                'item_id = %i',
584
                                $newID
585
                            );
586
                        } else {
587
                            // Update value
588
                            DB::update(
589
                                prefixTable('templates'),
590
                                array(
591
                                    'category_id' => $post_template_id,
592
                                ),
593
                                'item_id = %i',
594
                                $newID
595
                            );
596
                        }
597
                    }
598
                }
599
600
                // If automatic deletion asked
601
                if (
602
                    isset($SETTINGS['enable_delete_after_consultation']) === true
603
                    && (int) $SETTINGS['enable_delete_after_consultation'] === 1
604
                    && is_null($post_to_be_deleted_after_x_views) === false
605
                    && is_null($post_to_be_deleted_after_date) === false
606
                ) {
607
                    if (
608
                        empty($post_to_be_deleted_after_date) === false
609
                        || $post_to_be_deleted_after_x_views > 0
610
                    ) {
611
                        // Automatic deletion to be added
612
                        DB::insert(
613
                            prefixTable('automatic_del'),
614
                            array(
615
                                'item_id' => $newID,
616
                                'del_enabled' => 1,
617
                                'del_type' => $post_to_be_deleted_after_x_views > 0 ? 1 : 2, //1 = numeric : 2 = date
618
                                'del_value' => $post_to_be_deleted_after_x_views > 0 ? $post_to_be_deleted_after_x_views : dateToStamp($post_to_be_deleted_after_date, $SETTINGS['date_format']),
619
                            )
620
                        );
621
                    }
622
                }
623
624
                // Get readable list of restriction
625
                $listOfRestricted = $oldRestrictionList = '';
626
                if (
627
                    is_array($post_restricted_to) === true
628
                    && count($post_restricted_to) > 0
629
                    && isset($SETTINGS['restricted_to']) === true
630
                    && (int) $SETTINGS['restricted_to'] === 1
631
                ) {
632
                    foreach ($post_restricted_to as $userRest) {
633
                        if (empty($userRest) === false) {
634
                            $dataTmp = DB::queryfirstrow('SELECT login FROM ' . prefixTable('users') . ' WHERE id= %i', $userRest);
635
                            if (empty($listOfRestricted)) {
636
                                $listOfRestricted = $dataTmp['login'];
637
                            } else {
638
                                $listOfRestricted .= ';' . $dataTmp['login'];
639
                            }
640
                        }
641
                    }
642
                }
643
                if (
644
                    $post_restricted_to !== null
645
                    && $data !== null
646
                    && $data['restricted_to'] !== $post_restricted_to
647
                    && (int) $SETTINGS['restricted_to'] === 1
648
                ) {
649
                    if (empty($data['restricted_to']) === false) {
650
                        foreach (explode(';', $data['restricted_to']) as $userRest) {
651
                            if (empty($userRest) === false) {
652
                                $dataTmp = DB::queryfirstrow('SELECT login FROM ' . prefixTable('users') . ' WHERE id= ' . $userRest);
653
                                if (empty($oldRestrictionList) === true) {
654
                                    $oldRestrictionList = $dataTmp['login'];
655
                                } else {
656
                                    $oldRestrictionList .= ';' . $dataTmp['login'];
657
                                }
658
                            }
659
                        }
660
                    }
661
                }
662
                // Manage retriction_to_roles
663
                if (
664
                    is_array($post_restricted_to_roles) === true
665
                    && count($post_restricted_to_roles) > 0
666
                    && isset($SETTINGS['restricted_to_roles']) === true
667
                    && (int) $SETTINGS['restricted_to_roles'] === 1
668
                ) {
669
                    // add roles for item
670
                    if (
671
                        is_array($post_restricted_to_roles) === true
672
                        && count($post_restricted_to_roles) > 0
673
                    ) {
674
                        foreach ($post_restricted_to_roles as $role) {
675
                            if (count($role) > 1) {
676
                                $role = $role[1];
677
                            } else {
678
                                $role = $role[0];
679
                            }
680
                            DB::insert(
681
                                prefixTable('restriction_to_roles'),
682
                                array(
683
                                    'role_id' => $role,
684
                                    'item_id' => $inputData['itemId'],
685
                                )
686
                            );
687
                        }
688
                    }
689
                }
690
691
                // log
692
                logItems(
693
                    $SETTINGS,
694
                    (int) $newID,
695
                    $inputData['label'],
696
                    $session->get('user-id'),
697
                    'at_creation',
698
                    $session->get('user-login')
699
                );
700
701
                // Add tags
702
                $tags = explode(' ', $post_tags);
703
                foreach ($tags as $tag) {
704
                    if (empty($tag) === false) {
705
                        DB::insert(
706
                            prefixTable('tags'),
707
                            array(
708
                                'item_id' => $newID,
709
                                'tag' => strtolower($tag),
710
                            )
711
                        );
712
                    }
713
                }
714
715
                // Check if any files have been added
716
                if (empty($post_uploaded_file_id) === false) {
717
                    $rows = DB::query(
718
                        'SELECT id
719
                        FROM ' . prefixTable('files') . '
720
                        WHERE id_item = %s',
721
                        $post_uploaded_file_id
722
                    );
723
                    foreach ($rows as $record) {
724
                        // update item_id in files table
725
                        DB::update(
726
                            prefixTable('files'),
727
                            array(
728
                                'id_item' => $newID,
729
                                'confirmed' => 1,
730
                            ),
731
                            'id=%i',
732
                            $record['id']
733
                        );
734
                    }
735
                }
736
737
                // Create new task for the new item
738
                // If it is not a personnal one
739
                if ((int) $post_folder_is_personal === 0) {
740
                    storeTask(
741
                        'new_item',
742
                        $session->get('user-id'),
743
                        0,
744
                        (int) $inputData['folderId'],
745
                        (int) $newID,
746
                        $post_password_key,
747
                        $itemFieldsForTasks,
748
                        $itemFilesForTasks,
749
                    );
750
                }
751
752
                // Announce by email?
753
                if (empty($post_diffusion_list) === false) {
754
                    // get links url
755
                    if (empty($SETTINGS['email_server_url'])) {
756
                        $SETTINGS['email_server_url'] = $SETTINGS['cpassman_url'];
757
                    }
758
759
                    // Get path
760
                    $path = geItemReadablePath(
761
                        (int) $inputData['folderId'],
762
                        $inputData['label'],
763
                        $SETTINGS
764
                    );
765
766
                    // send email
767
                    if (is_array($post_diffusion_list) === true && count($post_diffusion_list) > 0) {
768
                        $cpt = 0;
769
                        foreach ($post_diffusion_list as $emailAddress) {
770
                            if (empty($emailAddress) === false) {
771
                                prepareSendingEmail(
772
                                    $lang->get('email_subject_item_updated'),
773
                                    str_replace(
774
                                        array('#label', '#link'),
775
                                            array($path, $SETTINGS['email_server_url'] . '/index.php?page=items&group=' . $inputData['folderId'] . '&id=' . $newID . $txt['email_body3']),
776
                                            $lang->get('new_item_email_body')
777
                                    ),
778
                                    $emailAddress,
779
                                    $post_diffusion_list_names[$cpt]
780
                                );
781
                            }
782
                            $cpt++;
783
                        }
784
                    }
785
                }
786
            } elseif (
787
                isset($SETTINGS['duplicate_item']) === true
788
                && (int) $SETTINGS['duplicate_item'] === 0
789
                && (int) $itemExists === 1
790
            ) {
791
                // Encrypt data to return
792
                echo (string) prepareExchangedData(
793
                    array(
794
                        'error' => true,
795
                        'message' => $lang->get('error_item_exists'),
796
                    ),
797
                    'encode'
798
                );
799
                break;
800
            }
801
802
            // Add item to CACHE table if new item has been created
803
            if (isset($newID) === true) {
804
                updateCacheTable('add_value', (int) $newID);
805
            }
806
807
            $arrData = array(
808
                'error' => false,
809
                'item_id' => $newID,
810
            );
811
        } else {
812
            // an error appears on JSON format
813
            echo (string) prepareExchangedData(
814
                array(
815
                    'error' => true,
816
                    'message' => $lang->get('json_error_format'),
817
                ),
818
                'encode'
819
            );
820
        }
821
822
        // Encrypt data to return
823
        echo (string) prepareExchangedData(
824
            $arrData,
825
            'encode'
826
        );
827
        break;
828
829
        /*
830
    * CASE
831
    * update an ITEM
832
    */
833
    case 'update_item':
834
        // Check KEY and rights
835
        if ($inputData['key'] !== $session->get('key')) {
836
            echo (string) prepareExchangedData(
837
                array(
838
                    'error' => true,
839
                    'message' => $lang->get('key_is_not_correct'),
840
                ),
841
                'encode'
842
            );
843
            break;
844
        }
845
        if ($session->get('user-read_only') === 1) {
846
            echo (string) prepareExchangedData(
847
                array(
848
                    'error' => true,
849
                    'message' => $lang->get('error_not_allowed_to'),
850
                ),
851
                'encode'
852
            );
853
            break;
854
        }
855
856
        // init
857
        $returnValues = array();
858
        // decrypt and retreive data in JSON format
859
        $dataReceived = prepareExchangedData(
860
            $inputData['data'],
861
            'decode'
862
        );
863
864
        // Error if not expected data
865
        if (is_array($dataReceived) === false || count($dataReceived) === 0) {
866
            echo (string) prepareExchangedData(
867
                array(
868
                    'error' => true,
869
                    'message' => $lang->get('json_error_format'),
870
                ),
871
                'encode'
872
            );
873
            break;
874
        }
875
876
        // Prepare variables
877
        $itemInfos = array();
878
        $inputData['label'] = isset($dataReceived['label']) && is_string($dataReceived['label']) ? filter_var($dataReceived['label'], FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
879
        $post_url = isset($dataReceived['url'])=== true ? filter_var(htmlspecialchars_decode($dataReceived['url']), FILTER_SANITIZE_URL) : '';
880
        $post_password = $original_pw = isset($dataReceived['pw']) && is_string($dataReceived['pw']) ? htmlspecialchars_decode($dataReceived['pw']) : '';
881
        $post_login = isset($dataReceived['login']) && is_string($dataReceived['login']) ? filter_var(htmlspecialchars_decode($dataReceived['login']), FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
882
        $post_tags = isset($dataReceived['tags'])=== true ? htmlspecialchars_decode($dataReceived['tags']) : '';
883
        $post_email = isset($dataReceived['email'])=== true ? filter_var(htmlspecialchars_decode($dataReceived['email']), FILTER_SANITIZE_EMAIL) : '';
884
        $post_template_id = (int) filter_var($dataReceived['template_id'], FILTER_SANITIZE_NUMBER_INT);
885
        $inputData['itemId'] = (int) filter_var($dataReceived['id'], FILTER_SANITIZE_NUMBER_INT);
886
        $post_anyone_can_modify = (int) filter_var($dataReceived['anyone_can_modify'], FILTER_SANITIZE_NUMBER_INT);
887
        $post_complexity_level = (int) filter_var($dataReceived['complexity_level'], FILTER_SANITIZE_NUMBER_INT);
888
        $inputData['folderId'] = (int) filter_var($dataReceived['folder'], FILTER_SANITIZE_NUMBER_INT);
889
        $post_folder_is_personal = (int) filter_var($dataReceived['folder_is_personal'], FILTER_SANITIZE_NUMBER_INT);
890
        $post_restricted_to = filter_var_array(
891
            $dataReceived['restricted_to'],
892
            FILTER_SANITIZE_FULL_SPECIAL_CHARS
893
        );
894
        $post_restricted_to_roles = filter_var_array(
895
            $dataReceived['restricted_to_roles'],
896
            FILTER_SANITIZE_FULL_SPECIAL_CHARS
897
        );
898
        $post_diffusion_list = filter_var_array(
899
            $dataReceived['diffusion_list'],
900
            FILTER_SANITIZE_FULL_SPECIAL_CHARS
901
        );
902
        $post_diffusion_list_names = filter_var_array(
903
            $dataReceived['diffusion_list_names'],
904
            FILTER_SANITIZE_FULL_SPECIAL_CHARS
905
        );
906
        //$post_diffusion_list_names = $post_diffusion_list_names !== false ? json_decode($post_diffusion_list_names) : '';
907
        $post_to_be_deleted_after_x_views = filter_var(
908
            $dataReceived['to_be_deleted_after_x_views'],
909
            FILTER_SANITIZE_NUMBER_INT
910
        );
911
        $post_to_be_deleted_after_date = isset($dataReceived['to_be_deleted_after_date']) === true ? filter_var(
912
                $dataReceived['to_be_deleted_after_date'],
913
                FILTER_SANITIZE_FULL_SPECIAL_CHARS
914
            ) :
915
            '';
916
        $post_fields = (filter_var_array(
917
            $dataReceived['fields'],
918
            FILTER_SANITIZE_FULL_SPECIAL_CHARS
919
        ));
920
        $post_description = $antiXss->xss_clean($dataReceived['description']);
921
        $post_fa_icon = isset($dataReceived['fa_icon']) === true ? filter_var(($dataReceived['fa_icon']), FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
922
        $post_otp_is_enabled = (int) filter_var($dataReceived['otp_is_enabled'], FILTER_SANITIZE_NUMBER_INT);
923
        $post_otp_phone_number = (int) filter_var($dataReceived['otp_phone_number'], FILTER_SANITIZE_NUMBER_INT);
924
        $post_otp_secret = isset($dataReceived['otp_secret']) === true ? filter_var(($dataReceived['otp_secret']), FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
925
926
        //-> DO A SET OF CHECKS
927
        // Perform a check in case of Read-Only user creating an item in his PF
928
        if (
929
            $session->get('user-read_only') === 1
930
            && (in_array($inputData['folderId'], $session->get('user-personal_folders')) === false
931
                || $post_folder_is_personal !== 1)
932
        ) {
933
            echo (string) prepareExchangedData(
934
                array(
935
                    'error' => true,
936
                    'message' => $lang->get('error_not_allowed_to_access_this_folder'),
937
                ),
938
                'encode'
939
            );
940
            break;
941
        }
942
943
        $dataCheck = validateDataFields(prefixTable('items'), $dataReceived);
944
        if ($dataCheck['state'] !== true) {
945
            echo (string) prepareExchangedData(
946
                array(
947
                    'error' => true,
948
                    'message' => $lang->get('error_data_not_valid').' - '.$lang->get('field').' '.strtoupper($dataCheck['field']).' '.$lang->get('exceeds_maximum_length_of').' '.$dataCheck['maxLength'].' ('.$dataCheck['currentLength'].')',
949
                ),
950
                'encode'
951
            );
952
            break;
953
        }
954
955
        // Check PWD EMPTY
956
        if (
957
            empty($pw) === true
958
            && $session->has('user-create_item_without_password') && $session->has('user-create_item_without_password') && null !== $session->get('user-create_item_without_password')
959
            && (int) $session->get('user-create_item_without_password') !== 1
960
        ) {
961
            echo (string) prepareExchangedData(
962
                array(
963
                    'error' => true,
964
                    'message' => $lang->get('error_pw'),
965
                ),
966
                'encode'
967
            );
968
            break;
969
        }
970
971
        // Need info in DB
972
        // About special settings
973
        $dataFolderSettings = DB::queryFirstRow(
974
            'SELECT bloquer_creation, bloquer_modification, personal_folder, title
975
            FROM ' . prefixTable('nested_tree') . ' 
976
            WHERE id = %i',
977
            $inputData['folderId']
978
        );
979
        $itemInfos['personal_folder'] = (int) $dataFolderSettings['personal_folder'];
980
        if ((int) $itemInfos['personal_folder'] === 1) {
981
            $itemInfos['no_complex_check_on_modification'] = 1;
982
            $itemInfos['no_complex_check_on_creation'] = 1;
983
        } else {
984
            $itemInfos['no_complex_check_on_modification'] = (int) $dataFolderSettings['bloquer_modification'];
985
            $itemInfos['no_complex_check_on_creation'] = (int) $dataFolderSettings['bloquer_creation'];
986
        }
987
988
        // Get folder complexity
989
        $folderComplexity = DB::queryfirstrow(
990
            'SELECT valeur
991
            FROM ' . prefixTable('misc') . '
992
            WHERE type = %s AND intitule = %i',
993
            'complex',
994
            $inputData['folderId']
995
        );
996
        $itemInfos['requested_folder_complexity'] = is_null($folderComplexity) === false ? (int) $folderComplexity['valeur'] : 0;
997
        // Check COMPLEXITY
998
        if ($post_complexity_level < $itemInfos['requested_folder_complexity'] && $itemInfos['no_complex_check_on_modification'] === 0) {
999
            echo (string) prepareExchangedData(
1000
                array(
1001
                    'error' => true,
1002
                    'message' => $lang->get('error_security_level_not_reached'),
1003
                ),
1004
                'encode'
1005
            );
1006
            break;
1007
        }
1008
1009
        // Check password length
1010
        $strlen_post_password = strlen($post_password);
1011
        if ($strlen_post_password > $SETTINGS['pwd_maximum_length']) {
1012
            echo (string) prepareExchangedData(
1013
                array(
1014
                    'error' => true,
1015
                    'message' => $lang->get('error_pw_too_long'),
1016
                ),
1017
                'encode'
1018
            );
1019
            break;
1020
        }
1021
1022
        // ./ END
1023
1024
        // Init
1025
        $arrayOfChanges = array();
1026
        $encryptionTaskIsRequested = false;
1027
        $itemFilesForTasks = [];
1028
        $itemFieldsForTasks = [];
1029
        $tasksToBePerformed = [];
1030
        $encrypted_password = '';
1031
        $encrypted_password_key = '';
1032
1033
        // Get all informations for this item
1034
        $dataItem = DB::queryfirstrow(
1035
            'SELECT *
1036
            FROM ' . prefixTable('items') . ' as i
1037
            INNER JOIN ' . prefixTable('log_items') . ' as l ON (l.id_item = i.id)
1038
            WHERE i.id=%i AND l.action = %s',
1039
            $inputData['itemId'],
1040
            'at_creation'
1041
        );
1042
1043
        // If source and destination folder are different -> move item
1044
        if ((int) $dataItem['id_tree'] !== $inputData['folderId']) {
1045
            // Check that user can delete on old folder
1046
            $checkRights = getCurrentAccessRights(
1047
                $session->get('user-id'),
1048
                $inputData['itemId'],
1049
                (int) $dataItem['id_tree'],
1050
            );
1051
1052
            if ($checkRights['error'] || !$checkRights['delete']) {
1053
                echo (string) prepareExchangedData(
1054
                    array(
1055
                        'error' => true,
1056
                        'message' => $lang->get('error_not_allowed_to'),
1057
                    ),
1058
                    'encode'
1059
                );
1060
                break;
1061
            }
1062
        }
1063
1064
        // Always check that user can write on requested folder
1065
        $checkRights = getCurrentAccessRights(
1066
            $session->get('user-id'),
1067
            $inputData['itemId'],
1068
            $inputData['folderId'],
1069
        );
1070
1071
        if ($checkRights['error'] || !$checkRights['edit']) {
1072
            echo (string) prepareExchangedData(
1073
                array(
1074
                    'error' => true,
1075
                    'message' => $lang->get('error_not_allowed_to'),
1076
                ),
1077
                'encode'
1078
            );
1079
            break;
1080
        }
1081
1082
        // Does the user has the sharekey
1083
        //db::debugmode(true);
1084
        DB::query(
1085
            'SELECT *
1086
            FROM ' . prefixTable('sharekeys_items') . '
1087
            WHERE object_id = %i AND user_id = %s',
1088
            $inputData['itemId'],
1089
            $session->get('user-id')
1090
        );
1091
        if (DB::count() === 0) {
1092
            if (defined('LOG_TO_SERVER') && LOG_TO_SERVER === true) {
1093
                error_log('TEAMPASS | user '.$session->get('user-id').' has no sharekey for item '.$inputData['itemId']);
1094
            }
1095
            echo (string) prepareExchangedData(
1096
                array(
1097
                    'error' => true,
1098
                    'message' => $lang->get('error_not_allowed_to'),
1099
                ),
1100
                'encode'
1101
            );
1102
            break;
1103
        }
1104
1105
        // check that actual user can access this item
1106
        $restrictionActive = true;
1107
        $restrictedTo = is_null($dataItem['restricted_to']) === false ? array_filter(explode(';', $dataItem['restricted_to'])) : [];
1108
        if (in_array($session->get('user-id'), $restrictedTo) === true) {
1109
            $restrictionActive = false;
1110
        }
1111
        if (empty($dataItem['restricted_to']) === true) {
1112
            $restrictionActive = false;
1113
        }
1114
1115
        $session__list_restricted_folders_for_items = $session->get('system-list_restricted_folders_for_items') ?? [];
1116
        if ((in_array($dataItem['id_tree'], $session->get('user-accessible_folders')) === true
1117
                && ((int) $dataItem['perso'] === 0
1118
                    || ((int) $dataItem['perso'] === 1
1119
                        //&& (int) $session->get('user-id') === (int) $dataItem['id_user']))
1120
                    ))
1121
                && $restrictionActive === false)
1122
            || (isset($SETTINGS['anyone_can_modify']) === true
1123
                && (int) $SETTINGS['anyone_can_modify'] === 1
1124
                && (int) $dataItem['anyone_can_modify'] === 1
1125
                && (in_array($dataItem['id_tree'], $session->get('user-accessible_folders')) === true
1126
                    || (int) $session->get('user-admin') === 1)
1127
                && $restrictionActive === false)
1128
            || (null !== $inputData['folderId']
1129
                && count($session__list_restricted_folders_for_items) > 0
1130
                && in_array($inputData['id'], $session__list_restricted_folders_for_items[$inputData['folderId']]) === true
1131
                && $restrictionActive === false)
1132
        ) {
1133
            // Get existing values
1134
            $data = DB::queryfirstrow(
1135
                'SELECT i.id as id, i.label as label, i.description as description, i.pw as pw, i.url as url, i.id_tree as id_tree, i.perso as perso, i.login as login, 
1136
                i.inactif as inactif, i.restricted_to as restricted_to, i.anyone_can_modify as anyone_can_modify, i.email as email, i.notification as notification,
1137
                u.login as user_login, u.email as user_email
1138
                FROM ' . prefixTable('items') . ' as i
1139
                INNER JOIN ' . prefixTable('log_items') . ' as l ON (i.id=l.id_item)
1140
                INNER JOIN ' . prefixTable('users') . ' as u ON (u.id=l.id_user)
1141
                WHERE i.id=%i',
1142
                $inputData['itemId']
1143
            );
1144
1145
            // Should we log a password change?
1146
            $userKey = DB::queryFirstRow(
1147
                'SELECT share_key
1148
                FROM ' . prefixTable('sharekeys_items') . '
1149
                WHERE user_id = %i AND object_id = %i',
1150
                $session->get('user-id'),
1151
                $inputData['itemId']
1152
            );
1153
            if (DB::count() === 0 || empty($data['pw']) === true) {
1154
                // No share key found
1155
                $pw = '';
1156
            } else {
1157
                $pw = base64_decode(doDataDecryption(
1158
                    $data['pw'],
1159
                    decryptUserObjectKey(
1160
                        $userKey['share_key'],
1161
                        $session->get('user-private_key')
1162
                    )
1163
                ));
1164
            }
1165
1166
            if ($post_password !== $pw) {
1167
                // Encrypt previous pw
1168
                $previousValue = cryption(
1169
                    $pw,
1170
                    '',
1171
                    'encrypt'
1172
                );
1173
1174
                // log the change of PW
1175
                logItems(
1176
                    $SETTINGS,
1177
                    (int) $inputData['itemId'],
1178
                    $inputData['label'],
1179
                    $session->get('user-id'),
1180
                    'at_modification',
1181
                    $session->get('user-login'),
1182
                    'at_pw',
1183
                    TP_ENCRYPTION_NAME,
1184
                    NULL,
1185
                    isset($previousValue['string']) === true ? $previousValue['string'] : '',
1186
                );
1187
            }
1188
1189
            // encrypt PW on if it has changed, or if it is empty
1190
            if ((($session->has('user-create_item_without_password') && $session->has('user-create_item_without_password') && null !== $session->get('user-create_item_without_password')
1191
                    && (int) $session->get('user-create_item_without_password') !== 1)
1192
                || empty($post_password) === false)
1193
                && $post_password !== $pw
1194
            ) {
1195
                //-----
1196
                // NEW ENCRYPTION
1197
                $cryptedStuff = doDataEncryption($post_password);
1198
                $encrypted_password = $cryptedStuff['encrypted'];
1199
                $encrypted_password_key = $cryptedStuff['objectKey'];
1200
1201
                // Create sharekeys for users
1202
                storeUsersShareKey(
1203
                    prefixTable('sharekeys_items'),
1204
                    (int) $post_folder_is_personal,
1205
                    (int) $inputData['folderId'],
1206
                    (int) $inputData['itemId'],
1207
                    $encrypted_password_key,
1208
                    true,   // only for the item creator
1209
                    true,   // delete all
1210
                );
1211
1212
                // Create a task to create sharekeys for users
1213
                if (WIP=== true) error_log('createTaskForItem - new password for this item - '.$post_password ." -- ". $pw);
1214
                $tasksToBePerformed = ['item_password'];
1215
                /*createTaskForItem(
1216
                    'item_update_create_keys',
1217
                    'item_password',
1218
                    (int) $inputData['itemId'],
1219
                    (int) $session->get('user-id'),
1220
                    $cryptedStuff['objectKey'],
1221
                    (int) $inputData['itemId'],
1222
                );*/
1223
                $encryptionTaskIsRequested = true;
1224
            } else {
1225
                $encrypted_password = $data['pw'];
1226
            }
1227
1228
            // ---Manage tags
1229
            // Get list of tags
1230
            $itemTags = DB::queryFirstColumn(
1231
                'SELECT tag
1232
                FROM ' . prefixTable('tags') . '
1233
                WHERE item_id = %i',
1234
                $inputData['itemId']
1235
            );
1236
1237
            // deleting existing tags for this item
1238
            DB::delete(
1239
                prefixTable('tags'),
1240
                'item_id = %i',
1241
                $inputData['itemId']
1242
            );
1243
1244
            // Add new tags
1245
            $postArrayTags = [];
1246
            if (empty($post_tags) === false) {
1247
                $postArrayTags = explode(' ', $post_tags);
1248
                foreach ($postArrayTags as $tag) {
1249
                    if (empty($tag) === false) {
1250
                    // save in DB
1251
                        DB::insert(
1252
                            prefixTable('tags'),
1253
                            array(
1254
                                'item_id' => $inputData['itemId'],
1255
                                'tag' => strtolower($tag),
1256
                            )
1257
                        );
1258
                    }
1259
                }
1260
            }
1261
1262
            // Store LOG
1263
            if (count(array_diff($postArrayTags, $itemTags)) > 0) {
1264
                // Store updates performed
1265
                array_push(
1266
                    $arrayOfChanges,
1267
                    'tags'
1268
                );
1269
1270
                // update LOG
1271
                logItems(
1272
                    $SETTINGS,
1273
                    (int) $inputData['itemId'],
1274
                    $inputData['label'],
1275
                    $session->get('user-id'),
1276
                    'at_modification',
1277
                    $session->get('user-login'),
1278
                    'at_tag : ' . implode(' ', $itemTags) . ' => ' . $post_tags
1279
                );
1280
            }
1281
1282
            // update item
1283
            DB::update(
1284
                prefixTable('items'),
1285
                array(
1286
                    'label' => $inputData['label'],
1287
                    'description' => $post_description,
1288
                    'pw' => $encrypted_password,
1289
                    'pw_len' => $strlen_post_password,
1290
                    'email' => $post_email,
1291
                    'login' => $post_login,
1292
                    'url' => $post_url,
1293
                    'id_tree' => $inputData['folderId'],
1294
                    'restricted_to' => empty($post_restricted_to) === true || count($post_restricted_to) === 0 ? '' : implode(';', $post_restricted_to),
1295
                    'anyone_can_modify' => (int) $post_anyone_can_modify,
1296
                    'complexity_level' => (int) $post_complexity_level,
1297
                    'encryption_type' => TP_ENCRYPTION_NAME,
1298
                    'perso' => in_array($inputData['folderId'], $session->get('user-personal_folders')) === true ? 1 : 0,
1299
                    'fa_icon' => $post_fa_icon,
1300
                    'updated_at' => time(),
1301
                ),
1302
                'id=%i',
1303
                $inputData['itemId']
1304
            );
1305
1306
            // update fields
1307
            if (
1308
                isset($SETTINGS['item_extra_fields']) === true
1309
                && (int) $SETTINGS['item_extra_fields'] === 1
1310
                && empty($post_fields) === false
1311
            ) {                
1312
                foreach ($post_fields as $field) {
1313
                    if (empty($field['value']) === false) {
1314
                        $dataTmpCat = DB::queryFirstRow(
1315
                            'SELECT c.id AS id, c.title AS title, i.data AS data, i.data_iv AS data_iv,
1316
                            i.encryption_type AS encryption_type, c.encrypted_data AS encrypted_data,
1317
                            c.masked AS masked, i.id AS field_item_id
1318
                            FROM ' . prefixTable('categories_items') . ' AS i
1319
                            INNER JOIN ' . prefixTable('categories') . ' AS c ON (i.field_id=c.id)
1320
                            WHERE i.field_id = %i AND i.item_id = %i',
1321
                            $field['id'],
1322
                            $inputData['itemId']
1323
                        );
1324
                        $cryptedStuff = [];
1325
                        $encryptedFieldIsChanged = false;
1326
1327
                        // store Field text in DB
1328
                        if (DB::count() === 0) {
1329
                            // The data for this field doesn't exist
1330
                            // It has to be added
1331
1332
                            // Perform new query
1333
                            $dataTmpCat = DB::queryFirstRow(
1334
                                'SELECT id, title, encrypted_data, masked
1335
                                FROM ' . prefixTable('categories') . '
1336
                                WHERE id = %i',
1337
                                $field['id']
1338
                            );
1339
1340
                            // store field text
1341
                            DB::insert(
1342
                                prefixTable('categories_items'),
1343
                                array(
1344
                                    'item_id' => $inputData['itemId'],
1345
                                    'field_id' => $field['id'],
1346
                                    'data' => $field['value'],
1347
                                    'data_iv' => '',
1348
                                    'encryption_type' => 'not_set',
1349
                                )
1350
                            );
1351
1352
                            $newId = DB::insertId();
1353
                            $dataTmpCat['field_item_id'] = $newId;
1354
1355
                            // Should we encrypt the data
1356
                            if ((int) $dataTmpCat['encrypted_data'] === 1) {
1357
                                $cryptedStuff = doDataEncryption($field['value']);
1358
1359
                                // Create sharekeys for users
1360
                                storeUsersShareKey(
1361
                                    prefixTable('sharekeys_fields'),
1362
                                    (int) $post_folder_is_personal,
1363
                                    (int) $inputData['folderId'],
1364
                                    (int) $newId,
1365
                                    $cryptedStuff['objectKey'],
1366
                                    true,   // only for the item creator
1367
                                    true,   // delete all
1368
                                );
1369
1370
                                // update value
1371
                                DB::update(
1372
                                    prefixTable('categories_items'),
1373
                                    array(
1374
                                        'data' => $cryptedStuff['encrypted'],
1375
                                        'data_iv' => '',
1376
                                        'encryption_type' => TP_ENCRYPTION_NAME,
1377
                                    ),
1378
                                    'id = %i',
1379
                                    $newId
1380
                                );
1381
1382
                                array_push(
1383
                                    $tasksToBePerformed,
1384
                                    'item_field'
1385
                                );
1386
                                $encryptedFieldIsChanged = true;
1387
                            } else {
1388
                                // update value
1389
                                DB::update(
1390
                                    prefixTable('categories_items'),
1391
                                    array(
1392
                                        'data' => $field['value'],
1393
                                        'data_iv' => '',
1394
                                        'encryption_type' => 'not_set',
1395
                                    ),
1396
                                    'id = %i',
1397
                                    $newId
1398
                                );
1399
                            }
1400
1401
                            // Store updates performed
1402
                            array_push(
1403
                                $arrayOfChanges,
1404
                                $dataTmpCat['title']
1405
                            );
1406
1407
                            // update LOG
1408
                            logItems(
1409
                                $SETTINGS,
1410
                                (int) $inputData['itemId'],
1411
                                $inputData['label'],
1412
                                $session->get('user-id'),
1413
                                'at_modification',
1414
                                $session->get('user-login'),
1415
                                'at_field : ' . $dataTmpCat['title'] . ' : ' . $field['value']
1416
                            );
1417
                        } else {
1418
                            // Case where the field already exists
1419
                            // compare the old and new value
1420
                            if ($dataTmpCat['encryption_type'] !== 'not_set') {
1421
                                // Get user sharekey for this field
1422
                                $userKey = DB::queryFirstRow(
1423
                                    'SELECT share_key
1424
                                    FROM ' . prefixTable('sharekeys_fields') . '
1425
                                    WHERE user_id = %i AND object_id = %i',
1426
                                    $session->get('user-id'),
1427
                                    $dataTmpCat['field_item_id']
1428
                                );
1429
1430
                                // Decrypt the current value
1431
                                if (DB::count() > 0) {
1432
                                    $oldVal = base64_decode(doDataDecryption(
1433
                                        $dataTmpCat['data'],
1434
                                        decryptUserObjectKey(
1435
                                            $userKey['share_key'],
1436
                                            $session->get('user-private_key')
1437
                                        )
1438
                                    ));
1439
                                } else {
1440
                                    $oldVal = '';
1441
                                }
1442
                            } else {
1443
                                $oldVal = $dataTmpCat['data'];
1444
                            }
1445
1446
                            // Compare both values to see if any change was done
1447
                            if ($field['value'] !== $oldVal) {
1448
                                // The strings are different
1449
                                $encrypt = [];
1450
                                
1451
                                // Should we encrypt the data
1452
                                if ((int) $dataTmpCat['encrypted_data'] === 1) {
1453
                                    $cryptedStuff = doDataEncryption($field['value']);
1454
                                    $encrypt['string'] = $cryptedStuff['encrypted'];
1455
                                    $encrypt['type'] = TP_ENCRYPTION_NAME;
1456
1457
                                    // Create sharekeys for users
1458
                                    storeUsersShareKey(
1459
                                        prefixTable('sharekeys_fields'),
1460
                                        (int) $post_folder_is_personal,
1461
                                        (int) $inputData['folderId'],
1462
                                        (int) $dataTmpCat['field_item_id'],
1463
                                        $cryptedStuff['objectKey'],
1464
                                        true,   // only for the item creator
1465
                                        true,   // delete all
1466
                                    );
1467
1468
                                    array_push(
1469
                                        $tasksToBePerformed,
1470
                                        'item_field'
1471
                                    );
1472
                                    $encryptedFieldIsChanged = true;
1473
                                } else {
1474
                                    $encrypt['string'] = $field['value'];
1475
                                    $encrypt['type'] = 'not_set';
1476
                                }
1477
1478
                                // update value
1479
                                DB::update(
1480
                                    prefixTable('categories_items'),
1481
                                    array(
1482
                                        'data' => $encrypt['string'],
1483
                                        'data_iv' => '',
1484
                                        'encryption_type' => $encrypt['type'],
1485
                                    ),
1486
                                    'item_id = %i AND field_id = %i',
1487
                                    $inputData['itemId'],
1488
                                    $field['id']
1489
                                );
1490
1491
                                // Store updates performed
1492
                                array_push(
1493
                                    $arrayOfChanges,
1494
                                    $dataTmpCat['title']
1495
                                );
1496
1497
                                // update LOG
1498
                                logItems(
1499
                                    $SETTINGS,
1500
                                    (int) $inputData['itemId'],
1501
                                    $inputData['label'],
1502
                                    $session->get('user-id'),
1503
                                    'at_modification',
1504
                                    $session->get('user-login'),
1505
                                    'at_field : ' . $dataTmpCat['title'] . ' => ' . $oldVal
1506
                                );
1507
                            }
1508
                        }
1509
1510
                        // Create a task to create sharekeys for this field for users
1511
                        // If this field is encrypted
1512
                        if ((int) $dataTmpCat['encrypted_data'] === 1 && $encryptedFieldIsChanged === true) {
1513
                            array_push(
1514
                                $itemFieldsForTasks,
1515
                                [
1516
                                    'object_id' => $dataTmpCat['field_item_id'],
1517
                                    'object_key' => $cryptedStuff['objectKey'],
1518
                                ]
1519
                            );
1520
                            $encryptionTaskIsRequested = true;
1521
                        }
1522
                    } else {
1523
                        // Case where field new value is empty
1524
                        // then delete field
1525
                        if (empty($field_data[1]) === true) {
1526
                            DB::delete(
1527
                                prefixTable('categories_items'),
1528
                                'item_id = %i AND field_id = %s',
1529
                                $inputData['itemId'],
1530
                                $field['id']
1531
                            );
1532
                        }
1533
                    }
1534
                }
1535
            }
1536
1537
            // create a task for all fields updated
1538
            if ($encryptionTaskIsRequested === true) {
1539
                if (WIP === true) error_log('createTaskForItem - '.print_r($tasksToBePerformed, true));
1540
                createTaskForItem(
1541
                    'item_update_create_keys',
1542
                    $tasksToBePerformed,
1543
                    (int) $inputData['itemId'],
1544
                    (int) $session->get('user-id'),
1545
                    $encrypted_password_key,
1546
                    (int) $inputData['itemId'],
1547
                    $itemFieldsForTasks,
1548
                    []
1549
                );
1550
            }
1551
1552
            // If template enable, is there a main one selected?
1553
            if (
1554
                isset($SETTINGS['item_creation_templates']) === true
1555
                && (int) $SETTINGS['item_creation_templates'] === 1
1556
                && isset($post_template_id) === true
1557
            ) {
1558
                DB::queryFirstRow(
1559
                    'SELECT *
1560
                    FROM ' . prefixTable('templates') . '
1561
                    WHERE item_id = %i',
1562
                    $inputData['itemId']
1563
                );
1564
                if (DB::count() === 0 && empty($post_template_id) === false) {
1565
                    // store field text
1566
                    DB::insert(
1567
                        prefixTable('templates'),
1568
                        array(
1569
                            'item_id' => $inputData['itemId'],
1570
                            'category_id' => $post_template_id,
1571
                        )
1572
                    );
1573
                } else {
1574
                    // Delete if empty
1575
                    if (empty($post_template_id) === true) {
1576
                        DB::delete(
1577
                            prefixTable('templates'),
1578
                            'item_id = %i',
1579
                            $inputData['itemId']
1580
                        );
1581
                    } else {
1582
                        // Update value
1583
                        DB::update(
1584
                            prefixTable('templates'),
1585
                            array(
1586
                                'category_id' => $post_template_id,
1587
                            ),
1588
                            'item_id = %i',
1589
                            $inputData['itemId']
1590
                        );
1591
                    }
1592
                }
1593
            }
1594
1595
            // Update automatic deletion - Only by the creator of the Item
1596
            if (
1597
                isset($SETTINGS['enable_delete_after_consultation']) === true
1598
                && (int) $SETTINGS['enable_delete_after_consultation'] === 1
1599
            ) {
1600
                // check if elem exists in Table. If not add it or update it.
1601
                DB::query(
1602
                    'SELECT *
1603
                    FROM ' . prefixTable('automatic_del') . '
1604
                    WHERE item_id = %i',
1605
                    $inputData['itemId']
1606
                );
1607
1608
                if (DB::count() === 0) {
1609
                    // No automatic deletion for this item
1610
                    if (
1611
                        empty($post_to_be_deleted_after_date) === false
1612
                        || (int) $post_to_be_deleted_after_x_views > 0
1613
                    ) {
1614
                        // Automatic deletion to be added
1615
                        DB::insert(
1616
                            prefixTable('automatic_del'),
1617
                            array(
1618
                                'item_id' => $inputData['itemId'],
1619
                                'del_enabled' => 1,
1620
                                'del_type' => empty($post_to_be_deleted_after_x_views) === false ?
1621
                                    1 : 2, //1 = numeric : 2 = date
1622
                                'del_value' => empty($post_to_be_deleted_after_x_views) === false ?
1623
                                    (int) $post_to_be_deleted_after_x_views : dateToStamp($post_to_be_deleted_after_date, $SETTINGS['date_format']),
1624
                            )
1625
                        );
1626
1627
                        // Store updates performed
1628
                        array_push(
1629
                            $arrayOfChanges,
1630
                            $lang->get('automatic_deletion_engaged') . ': ' . $lang->get('enabled')
1631
                        );
1632
1633
                        // update LOG
1634
                        logItems(
1635
                            $SETTINGS,
1636
                            (int) $inputData['itemId'],
1637
                            $inputData['label'],
1638
                            $session->get('user-id'),
1639
                            'at_modification',
1640
                            $session->get('user-login'),
1641
                            'at_automatic_del : enabled'
1642
                        );
1643
                    }
1644
                } else {
1645
                    // Automatic deletion exists for this item
1646
                    if (
1647
                        empty($post_to_be_deleted_after_date) === false
1648
                        || (int) $post_to_be_deleted_after_x_views > 0
1649
                    ) {
1650
                        // Update automatic deletion
1651
                        DB::update(
1652
                            prefixTable('automatic_del'),
1653
                            array(
1654
                                'del_type' => empty($post_to_be_deleted_after_x_views) === false ?
1655
                                    1 : 2, //1 = numeric : 2 = date
1656
                                'del_value' => empty($post_to_be_deleted_after_x_views) === false ?
1657
                                    $post_to_be_deleted_after_x_views : dateToStamp($post_to_be_deleted_after_date, $SETTINGS['date_format']),
1658
                            ),
1659
                            'item_id = %i',
1660
                            $inputData['itemId']
1661
                        );
1662
                    } else {
1663
                        // delete automatic deleteion for this item
1664
                        DB::delete(
1665
                            prefixTable('automatic_del'),
1666
                            'item_id = %i',
1667
                            $inputData['itemId']
1668
                        );
1669
1670
                        // Store updates performed
1671
                        array_push(
1672
                            $arrayOfChanges,
1673
                            $lang->get('automatic_deletion_engaged') . ': ' . $lang->get('disabled')
1674
                        );
1675
1676
                        // update LOG
1677
                        logItems(
1678
                            $SETTINGS,
1679
                            (int) $inputData['itemId'],
1680
                            $inputData['label'],
1681
                            $session->get('user-id'),
1682
                            'at_modification',
1683
                            $session->get('user-login'),
1684
                            'at_automatic_del : disabled'
1685
                        );
1686
                    }
1687
                }
1688
            }
1689
1690
            // get readable list of restriction
1691
            $listOfRestricted = $oldRestrictionList = '';
1692
            $arrayOfUsersRestriction = array();
1693
            $arrayOfUsersIdRestriction = array();
1694
            $diffUsersRestiction = array();
1695
            $diffRolesRestiction = array();
1696
            if (
1697
                is_array($post_restricted_to) === true
1698
                && count($post_restricted_to) > 0
1699
                && isset($SETTINGS['restricted_to']) === true
1700
                && (int) $SETTINGS['restricted_to'] === 1
1701
            ) {
1702
                foreach ($post_restricted_to as $userId) {
1703
                    if (empty($userId) === false) {
1704
                        $dataTmp = DB::queryfirstrow(
1705
                            'SELECT id, name, lastname
1706
                            FROM ' . prefixTable('users') . '
1707
                            WHERE id= %i',
1708
                            $userId
1709
                        );
1710
1711
                        // Add to array
1712
                        array_push(
1713
                            $arrayOfUsersRestriction,
1714
                            $dataTmp['name'] . ' ' . $dataTmp['lastname']
1715
                        );
1716
                        array_push(
1717
                            $arrayOfUsersIdRestriction,
1718
                            $dataTmp['id']
1719
                        );
1720
                    }
1721
                }
1722
            }
1723
            if ((int) $SETTINGS['restricted_to'] === 1) {
1724
                $diffUsersRestiction = array_diff(
1725
                    empty($data['restricted_to']) === false ?
1726
                        explode(';', $data['restricted_to']) : array(),
1727
                    $arrayOfUsersIdRestriction
1728
                );
1729
            }
1730
1731
            // Manage retriction_to_roles
1732
            if (
1733
                is_array($post_restricted_to_roles) === true
1734
                && count($post_restricted_to_roles) > 0
1735
                && isset($SETTINGS['restricted_to_roles']) === true
1736
                && (int) $SETTINGS['restricted_to_roles'] === 1
1737
            ) {
1738
                // Init
1739
                $arrayOfRestrictionRolesOld = array();
1740
                $arrayOfRestrictionRoles = array();
1741
1742
                // get values before deleting them
1743
                $rows = DB::query(
1744
                    'SELECT t.title, t.id AS id
1745
                    FROM ' . prefixTable('roles_title') . ' as t
1746
                    INNER JOIN ' . prefixTable('restriction_to_roles') . ' as r ON (t.id=r.role_id)
1747
                    WHERE r.item_id = %i
1748
                    ORDER BY t.title ASC',
1749
                    $inputData['itemId']
1750
                );
1751
                foreach ($rows as $record) {
1752
                    // Add to array
1753
                    array_push(
1754
                        $arrayOfRestrictionRolesOld,
1755
                        $record['title']
1756
                    );
1757
                }
1758
                // delete previous values
1759
                DB::delete(
1760
                    prefixTable('restriction_to_roles'),
1761
                    'item_id = %i',
1762
                    $inputData['itemId']
1763
                );
1764
1765
                // add roles for item
1766
                if (
1767
                    is_array($post_restricted_to_roles) === true
1768
                    && count($post_restricted_to_roles) > 0
1769
                ) {
1770
                    foreach ($post_restricted_to_roles as $role) {
1771
                        DB::insert(
1772
                            prefixTable('restriction_to_roles'),
1773
                            array(
1774
                                'role_id' => $role,
1775
                                'item_id' => $inputData['itemId'],
1776
                            )
1777
                        );
1778
                        $dataTmp = DB::queryfirstrow(
1779
                            'SELECT title
1780
                            FROM ' . prefixTable('roles_title') . '
1781
                            WHERE id = %i',
1782
                            $role
1783
                        );
1784
1785
                        // Add to array
1786
                        array_push(
1787
                            $arrayOfRestrictionRoles,
1788
                            $dataTmp['title']
1789
                        );
1790
                    }
1791
1792
                    if ((int) $SETTINGS['restricted_to'] === 1) {
1793
                        $diffRolesRestiction = array_diff(
1794
                            $arrayOfRestrictionRoles,
1795
                            $arrayOfRestrictionRolesOld
1796
                        );
1797
                    }
1798
                }
1799
            }
1800
            // Update CACHE table
1801
            updateCacheTable('update_value', (int) $inputData['itemId']);
1802
1803
1804
            // Manage OTP status
1805
            // Get current status
1806
            $otpStatus = DB::queryFirstRow(
1807
                'SELECT enabled as otp_is_enabled
1808
                FROM ' . prefixTable('items_otp') . '
1809
                WHERE item_id = %i',
1810
                $inputData['itemId']
1811
            );
1812
1813
            // Check if status has changed
1814
            if (DB::count() > 0 && (int) $otpStatus['otp_is_enabled'] !== (int) $post_otp_is_enabled) {
1815
                // Update status
1816
                DB::update(
1817
                    prefixTable('items_otp'),
1818
                    array(
1819
                        'enabled' => (int) $post_otp_is_enabled,
1820
                    ),
1821
                    'item_id = %i',
1822
                    $inputData['itemId']
1823
                );
1824
1825
                // Store updates performed
1826
                array_push(
1827
                    $arrayOfChanges,
1828
                    $lang->get('otp_status')
1829
                );
1830
1831
                // update LOG
1832
                logItems(
1833
                    $SETTINGS,
1834
                    (int) $inputData['itemId'],
1835
                    $inputData['label'],
1836
                    $session->get('user-id'),
1837
                    'at_modification',
1838
                    $session->get('user-login'),
1839
                    'at_otp_status:' . ((int) $post_otp_is_enabled === 0 ? 'disabled' : 'enabled')
1840
                );
1841
            } elseif (DB::count() === 0 && empty($post_otp_secret) === false) {
1842
                // Create the entry in items_otp table
1843
                // OTP doesn't exist then create it
1844
1845
                // Encrypt secret
1846
                $encryptedSecret = cryption(
1847
                    $post_otp_secret,
1848
                    '',
1849
                    'encrypt'
1850
                );
1851
                
1852
                // insert in table
1853
                DB::insert(
1854
                    prefixTable('items_otp'),
1855
                    array(
1856
                        'item_id' => $inputData['itemId'],
1857
                        'secret' => $encryptedSecret['string'],
1858
                        'phone_number' => $post_otp_phone_number,
1859
                        'timestamp' => time(),
1860
                        'enabled' => 1,
1861
                    )
1862
                );
1863
            }
1864
1865
            //---- Log all modifications done ----
1866
1867
            // RESTRICTIONS
1868
            if (count($diffRolesRestiction) > 0 || count($diffUsersRestiction) > 0) {
1869
                // Store updates performed
1870
                array_push(
1871
                    $arrayOfChanges,
1872
                    $lang->get('at_restriction')
1873
                );
1874
1875
                // Log
1876
                logItems(
1877
                    $SETTINGS,
1878
                    (int) $inputData['itemId'],
1879
                    $inputData['label'],
1880
                    $session->get('user-id'),
1881
                    'at_modification',
1882
                    $session->get('user-login'),
1883
                    'at_restriction : ' . (count($diffUsersRestiction) > 0 ?
1884
                        implode(', ', $arrayOfUsersRestriction) . (count($diffRolesRestiction) > 0 ? ', ' : '') : '') . (count($diffRolesRestiction) > 0 ? implode(', ', $arrayOfRestrictionRoles) : '')
1885
                );
1886
            }
1887
1888
            // LABEL
1889
            if ($data['label'] !== $inputData['label']) {
1890
                // Store updates performed
1891
                array_push(
1892
                    $arrayOfChanges,
1893
                    $lang->get('at_label')
1894
                );
1895
1896
                // Log
1897
                logItems(
1898
                    $SETTINGS,
1899
                    (int) $inputData['itemId'],
1900
                    $inputData['label'],
1901
                    $session->get('user-id'),
1902
                    'at_modification',
1903
                    $session->get('user-login'),
1904
                    'at_label : ' . $data['label'] . ' => ' . $inputData['label']
1905
                );
1906
            }
1907
            // LOGIN
1908
            if ($data['login'] !== $post_login) {
1909
                // Store updates performed
1910
                array_push(
1911
                    $arrayOfChanges,
1912
                    $lang->get('at_login')
1913
                );
1914
1915
                // Log
1916
                logItems(
1917
                    $SETTINGS,
1918
                    (int) $inputData['itemId'],
1919
                    $inputData['label'],
1920
                    $session->get('user-id'),
1921
                    'at_modification',
1922
                    $session->get('user-login'),
1923
                    'at_login : ' . $data['login'] . ' => ' . $post_login
1924
                );
1925
            }
1926
            // EMAIL
1927
            if ($post_email !== null && $data['email'] !== null && strcmp($data['email'], $post_email) !== 0) {
1928
                // Store updates performed
1929
                array_push(
1930
                    $arrayOfChanges,
1931
                    $lang->get('at_email')
1932
                );
1933
1934
                // Log
1935
                logItems(
1936
                    $SETTINGS,
1937
                    (int) $inputData['itemId'],
1938
                    $inputData['label'],
1939
                    $session->get('user-id'),
1940
                    'at_modification',
1941
                    $session->get('user-login'),
1942
                    'at_email : ' . $data['email'] . ' => ' . $post_email
1943
                );
1944
            }
1945
            // URL
1946
            if ($data['url'] !== $post_url && $post_url !== 'http://') {
1947
                // Store updates performed
1948
                array_push(
1949
                    $arrayOfChanges,
1950
                    $lang->get('at_url')
1951
                );
1952
1953
                // Log
1954
                logItems(
1955
                    $SETTINGS,
1956
                    (int) $inputData['itemId'],
1957
                    $inputData['label'],
1958
                    $session->get('user-id'),
1959
                    'at_modification',
1960
                    $session->get('user-login'),
1961
                    'at_url : ' . $data['url'] . ' => ' . $post_url
1962
                );
1963
            }
1964
            // DESCRIPTION
1965
            // deepcode ignore InsecureHash: md5 is used just to perform a string encrypted comparison
1966
            if (strcmp(md5(strip_tags($data['description'])), md5(strip_tags($post_description))) !== 0) {
1967
                // Store updates performed
1968
                array_push(
1969
                    $arrayOfChanges,
1970
                    $lang->get('at_description')
1971
                );
1972
1973
                // Log
1974
                logItems(
1975
                    $SETTINGS,
1976
                    (int) $inputData['itemId'],
1977
                    $inputData['label'],
1978
                    $session->get('user-id'),
1979
                    'at_modification',
1980
                    $session->get('user-login'),
1981
                    'at_description'
1982
                );
1983
            }
1984
            // FOLDER
1985
            if ((int) $data['id_tree'] !== (int) $inputData['folderId']) {
1986
                // Get name of folders
1987
                $dataTmp = DB::query('SELECT title FROM ' . prefixTable('nested_tree') . ' WHERE id IN %li', array($data['id_tree'], $inputData['folderId']));
1988
1989
                // Store updates performed
1990
                array_push(
1991
                    $arrayOfChanges,
1992
                    $lang->get('at_category')
1993
                );
1994
1995
                // Log
1996
                logItems(
1997
                    $SETTINGS,
1998
                    (int) $inputData['itemId'],
1999
                    $inputData['label'],
2000
                    $session->get('user-id'),
2001
                    'at_modification',
2002
                    $session->get('user-login'),
2003
                    'at_category : ' . $dataTmp[0]['title'] . ' => ' . $dataTmp[1]['title']
2004
                );
2005
            }
2006
            // ANYONE_CAN_MODIFY
2007
            if ((int) $post_anyone_can_modify !== (int) $data['anyone_can_modify']) {
2008
                // Store updates performed
2009
                array_push(
2010
                    $arrayOfChanges,
2011
                    $lang->get('at_anyoneconmodify') . ': ' . ((int) $post_anyone_can_modify === 0 ? $lang->get('disabled') : $lang->get('enabled'))
2012
                );
2013
2014
                // Log
2015
                logItems(
2016
                    $SETTINGS,
2017
                    (int) $inputData['itemId'],
2018
                    $inputData['label'],
2019
                    $session->get('user-id'),
2020
                    'at_modification',
2021
                    $session->get('user-login'),
2022
                    'at_anyoneconmodify : ' . ((int) $post_anyone_can_modify === 0 ? 'disabled' : 'enabled')
2023
                );
2024
            }
2025
2026
            // Reload new values
2027
            $dataItem = DB::queryfirstrow(
2028
                'SELECT *
2029
                FROM ' . prefixTable('items') . ' as i
2030
                INNER JOIN ' . prefixTable('log_items') . ' as l ON (l.id_item = i.id)
2031
                WHERE i.id = %i AND l.action = %s',
2032
                $inputData['itemId'],
2033
                'at_creation'
2034
            );
2035
            // Reload History
2036
            $history = '';
2037
            $rows = DB::query(
2038
                'SELECT l.date as date, l.action as action, l.raison as raison, u.login as login
2039
                FROM ' . prefixTable('log_items') . ' as l
2040
                LEFT JOIN ' . prefixTable('users') . ' as u ON (l.id_user=u.id)
2041
                WHERE l.action <> %s AND id_item=%s',
2042
                'at_shown',
2043
                $inputData['itemId']
2044
            );
2045
            foreach ($rows as $record) {
2046
                if ($record['raison'] === NULL) continue;
2047
                $reason = explode(':', $record['raison']);
2048
                if (count($reason) > 0) {
2049
                    $sentence = date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['date']) . ' - '
2050
                        . $record['login'] . ' - ' . $lang->get($record['action']) . ' - '
2051
                        . (empty($record['raison']) === false ? (count($reason) > 1 ? $lang->get(trim($reason[0])) . ' : ' . $reason[1]
2052
                            : $lang->get(trim($reason[0]))) : '');
2053
                    if (empty($history)) {
2054
                        $history = $sentence;
2055
                    } else {
2056
                        $history .= '<br />' . $sentence;
2057
                    }
2058
                }
2059
            }
2060
2061
            // generate 2d key
2062
            $session->set('user-key_tmp', bin2hex(GenerateCryptKey(16, false, true, true, false, true)));
2063
2064
            // Send email
2065
            if (is_array($post_diffusion_list) === true && count($post_diffusion_list) > 0) {
2066
                $cpt = 0;
2067
                foreach ($post_diffusion_list as $emailAddress) {
2068
                    if (empty($emailAddress) === false) {
2069
                        prepareSendingEmail(
2070
                            $lang->get('email_subject_item_updated'),
2071
                            str_replace(
2072
                                array('#item_label#', '#item_category#', '#item_id#', '#url#', '#name#', '#lastname#', '#folder_name#'),
2073
                                array($inputData['label'], $inputData['folderId'], $inputData['itemId'], $SETTINGS['cpassman_url'], $session->get('user-name'), $session->get('user-lastname'), $dataFolderSettings['title']),
2074
                                $lang->get('email_body_item_updated')
2075
                            ),
2076
                            $emailAddress,
2077
                            $post_diffusion_list_names[$cpt]
2078
                        );
2079
                        $cpt++;
2080
                    }
2081
                }
2082
            }
2083
2084
            // Remove the edition lock if no  encryption steps are needed
2085
            if ($encryptionTaskIsRequested === false) {
2086
                if (defined('LOG_TO_SERVER') && LOG_TO_SERVER === true) {
2087
                    error_log('Remove the edition lock if no  encryption steps are needed');
2088
                }
2089
                DB::delete(
2090
                    prefixTable('items_edition'), 
2091
                    'item_id = %i AND user_id = %i', 
2092
                    $inputData['itemId'],
2093
                    $session->get('user-id')
2094
                );
2095
            }
2096
2097
            // Notifiy changes to the users
2098
            notifyChangesToSubscribers($inputData['itemId'], $inputData['label'], $arrayOfChanges, $SETTINGS);
2099
2100
            // Prepare some stuff to return
2101
            $arrData = array(
2102
                'error' => false,
2103
                'message' => '',
2104
            );
2105
        } else {
2106
            echo (string) prepareExchangedData(
2107
                array(
2108
                    'error' => true,
2109
                    'message' => $lang->get('error_not_allowed_to_edit_item'),
2110
                ),
2111
                'encode'
2112
            );
2113
            break;
2114
        }
2115
        
2116
        // return data
2117
        echo (string) prepareExchangedData(
2118
            $arrData,
2119
            'encode'
2120
        );
2121
        break;
2122
2123
        /*
2124
        * CASE
2125
        * Copy an Item
2126
    */
2127
    case 'copy_item':
2128
        // Check KEY and rights
2129
        if ($inputData['key'] !== $session->get('key')) {
2130
            echo (string) prepareExchangedData(
2131
                array(
2132
                    'error' => true,
2133
                    'message' => $lang->get('key_is_not_correct'),
2134
                ),
2135
                'encode'
2136
            );
2137
            break;
2138
        }
2139
        if ($session->get('user-read_only') === 1) {
2140
            echo (string) prepareExchangedData(
2141
                array(
2142
                    'error' => true,
2143
                    'message' => $lang->get('error_not_allowed_to'),
2144
                ),
2145
                'encode'
2146
            );
2147
            break;
2148
        }
2149
2150
        // decrypt and retreive data in JSON format
2151
        $dataReceived = prepareExchangedData(
2152
            $inputData['data'],
2153
            'decode'
2154
        );
2155
2156
        // Prepare POST variables
2157
        $post_new_label = (string) filter_var($dataReceived['new_label'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
2158
        $post_source_id = (int) filter_var($dataReceived['source_id'], FILTER_SANITIZE_NUMBER_INT);
2159
        $post_dest_id = (int) filter_var($dataReceived['dest_id'], FILTER_SANITIZE_NUMBER_INT);
2160
        $inputData['itemId'] = (int) filter_var($dataReceived['item_id'], FILTER_SANITIZE_NUMBER_INT);
2161
2162
        // perform a check in case of Read-Only user creating an item in his PF
2163
        if (
2164
            (int) $session->get('user-read_only') === 1
2165
            && (in_array($post_source_id, $session->get('user-personal_folders')) === false
2166
                || in_array($post_dest_id, $session->get('user-personal_folders')) === false)
2167
        ) {
2168
            echo (string) prepareExchangedData(
2169
                array(
2170
                    'error' => true,
2171
                    'message' => $lang->get('error_not_allowed_to'),
2172
                ),
2173
                'encode'
2174
            );
2175
            break;
2176
        }
2177
2178
        // Init
2179
        $returnValues = '';
2180
        $pw = '';
2181
        $is_perso = 0;
2182
        $itemDataArray = array(
2183
            'pwd' => '',
2184
            'fields' => [],
2185
            'files' => [],
2186
        );
2187
2188
        if (
2189
            empty($inputData['itemId']) === false
2190
            && empty($post_dest_id) === false
2191
        ) {
2192
            // load the original record into an array
2193
            $originalRecord = DB::queryfirstrow(
2194
                'SELECT * FROM ' . prefixTable('items') . '
2195
                WHERE id = %i',
2196
                $inputData['itemId']
2197
            );
2198
2199
            // Check if the folder where this item is accessible to the user
2200
            if (in_array($originalRecord['id_tree'], $session->get('user-accessible_folders')) === false) {
2201
                echo (string) prepareExchangedData(
2202
                    array(
2203
                        'error' => true,
2204
                        'message' => $lang->get('error_not_allowed_to'),
2205
                    ),
2206
                    'encode'
2207
                );
2208
                break;
2209
            }
2210
2211
            // Load the destination folder record into an array
2212
            $dataDestination = DB::queryfirstrow(
2213
                'SELECT personal_folder FROM ' . prefixTable('nested_tree') . '
2214
                WHERE id = %i',
2215
                $post_dest_id
2216
            );
2217
2218
            // Get the ITEM object key for the user
2219
            $userKey = DB::queryFirstRow(
2220
                'SELECT share_key
2221
                FROM ' . prefixTable('sharekeys_items') . '
2222
                WHERE user_id = %i AND object_id = %i',
2223
                $session->get('user-id'),
2224
                $inputData['itemId']
2225
            );
2226
            if (DB::count() === 0) {
2227
                // ERROR - No sharekey found for this item and user
2228
                echo (string) prepareExchangedData(
2229
                    array(
2230
                        'error' => true,
2231
                        'message' => $lang->get('error_not_allowed_to'),
2232
                    ),
2233
                    'encode'
2234
                );
2235
                break;
2236
            }
2237
2238
            // Decrypt / Encrypt the password
2239
            $cryptedStuff = doDataEncryption(
2240
                base64_decode(
2241
                    doDataDecryption(
2242
                        $originalRecord['pw'],
2243
                        decryptUserObjectKey(
2244
                            $userKey['share_key'],
2245
                            $session->get('user-private_key')
2246
                        )
2247
                    )
2248
                )
2249
            );
2250
            // reaffect pw
2251
            $originalRecord['pw'] = $cryptedStuff['encrypted'];
2252
2253
            // store pwd object key
2254
            $itemDataArray['pwd'] = $cryptedStuff['objectKey'];
2255
2256
            // generate the query to update the new record with the previous values
2257
            $aSet = array();
2258
            foreach ($originalRecord as $key => $value) {
2259
                $aSet['item_key'] = uniqidReal(50);
2260
                $aSet['created_at'] = time();
2261
                if ($key === 'id_tree') {
2262
                    $aSet['id_tree'] = $post_dest_id;
2263
                } elseif ($key === 'label') {
2264
                    $aSet[$key] = $post_new_label;
2265
                } elseif ($key === 'viewed_no') {
2266
                    $aSet['viewed_no'] = '0';
2267
                } elseif ($key === 'pw' && empty($pw) === false) {
2268
                    $aSet['pw'] = $originalRecord['pw'];
2269
                    $aSet['pw_iv'] = '';
2270
                } elseif ($key === 'perso') {
2271
                    $aSet['perso'] = $is_perso;
2272
                } elseif ($key !== 'id' && $key !== 'key') {
2273
                    $aSet[$key] = $value;
2274
                }
2275
            }
2276
2277
            // insert the new record and get the new auto_increment id
2278
            DB::insert(
2279
                prefixTable('items'),
2280
                $aSet
2281
            );
2282
            $newItemId = DB::insertId();
2283
2284
            // Create sharekeys for users of this new ITEM
2285
            storeUsersShareKey(
2286
                prefixTable('sharekeys_items'),
2287
                (int) $dataDestination['personal_folder'],
2288
                (int) $post_dest_id,
2289
                (int) $newItemId,
2290
                $itemDataArray['pwd'],
2291
                true,
2292
                false,
2293
            );
2294
2295
            // --------------------
2296
            // Manage Custom Fields
2297
            $rows = DB::query(
2298
                'SELECT ci.id AS id, ci.data AS data, ci.field_id AS field_id, c.encrypted_data AS encrypted_data
2299
                FROM ' . prefixTable('categories_items') . ' AS ci
2300
                INNER JOIN ' . prefixTable('categories') . ' AS c ON (c.id = ci.field_id)
2301
                WHERE ci.item_id = %i',
2302
                $inputData['itemId']
2303
            );
2304
            foreach ($rows as $field) {
2305
                // Create the entry for the new item
2306
2307
                // Is the data encrypted
2308
                if ((int) $field['encrypted_data'] === 1) {
2309
                    // Get user key
2310
                    $userKey = DB::queryFirstRow(
2311
                        'SELECT share_key
2312
                        FROM ' . prefixTable('sharekeys_fields') . '
2313
                        WHERE user_id = %i AND object_id = %i',
2314
                        $session->get('user-id'),
2315
                        $field['id']
2316
                    );
2317
                    // Then decrypt original field value and encrypt with new key
2318
                    $cryptedStuff = doDataEncryption(
2319
                        base64_decode(
2320
                            doDataDecryption(
2321
                                $field['data'],
2322
                                decryptUserObjectKey(
2323
                                    $userKey['share_key'],
2324
                                    $session->get('user-private_key')
2325
                                )
2326
                            )
2327
                        )
2328
                    );
2329
                    // reaffect pw
2330
                    $field['data'] = $cryptedStuff['encrypted'];
2331
                }
2332
2333
                // store field text
2334
                DB::insert(
2335
                    prefixTable('categories_items'),
2336
                    array(
2337
                        'item_id' => $newItemId,
2338
                        'field_id' => $field['field_id'],
2339
                        'data' => (int) $field['encrypted_data'] === 1 ?
2340
                            $cryptedStuff['encrypted'] : $field['data'],
2341
                        'data_iv' => '',
2342
                        'encryption_type' => (int) $field['encrypted_data'] === 1 ?
2343
                            TP_ENCRYPTION_NAME : 'not_set',
2344
                    )
2345
                );
2346
                $newFieldId = DB::insertId();
2347
2348
                // Create sharekeys for current user
2349
                if ((int) $field['encrypted_data'] === 1) {
2350
                    // Create sharekeys for user
2351
                    storeUsersShareKey(
2352
                        prefixTable('sharekeys_fields'),
2353
                        (int) $dataDestination['personal_folder'],
2354
                        (int) $post_dest_id,
2355
                        (int) $newFieldId,
2356
                        $cryptedStuff['objectKey'],
2357
                        true,
2358
                        false,
2359
                    );
2360
2361
                    // Build list of fields
2362
                    array_push(
2363
                        $itemDataArray['fields'],
2364
                        array(
2365
                            'object_id' => $newFieldId,
2366
                            'object_key' => $cryptedStuff['objectKey'],
2367
                        )
2368
                    );
2369
                }
2370
            }
2371
            // <---
2372
2373
            // ------------------
2374
            // Manage attachments
2375
2376
            // get file key
2377
            $rows = DB::query(
2378
                'SELECT f.id AS id, f.file AS file, f.name AS name, f.status AS status, f.extension AS extension,
2379
                f.size AS size, f.type AS type, s.share_key AS share_key
2380
                FROM ' . prefixTable('files') . ' AS f
2381
                INNER JOIN ' . prefixTable('sharekeys_files') . ' AS s ON (f.id = s.object_id)
2382
                WHERE s.user_id = %i AND f.id_item = %i',
2383
                $session->get('user-id'),
2384
                $inputData['itemId']
2385
            );
2386
            foreach ($rows as $record) {
2387
                // Check if file still exists
2388
                if (file_exists($SETTINGS['path_to_upload_folder'] . DIRECTORY_SEPARATOR . TP_FILE_PREFIX . base64_decode($record['file'])) === true) {
2389
                    // Step1 - decrypt the file
2390
                    // deepcode ignore PT: path is sanitized inside decryptFile()
2391
                    $fileContent = decryptFile(
2392
                        $record['file'],
2393
                        $SETTINGS['path_to_upload_folder'],
2394
                        decryptUserObjectKey($record['share_key'], $session->get('user-private_key'))
2395
                    );
2396
2397
                    // Step2 - create file
2398
                    // deepcode ignore InsecureHash: md5 is used jonly for file name in order to get a hashed value in database
2399
                    $newFileName = md5(time() . '_' . $record['id']) . '.' . $record['extension'];
2400
                    $outstream = fopen($SETTINGS['path_to_upload_folder'] . DIRECTORY_SEPARATOR . $newFileName, 'ab');
2401
                    if ($outstream === false) {
2402
                        echo prepareExchangedData(
2403
                            array(
2404
                                'error' => true,
2405
                                'message' => $lang->get('error_cannot_open_file'),
2406
                            ),
2407
                            'encode'
2408
                        );
2409
                        break;
2410
                    }
2411
                    fwrite(
2412
                        $outstream,
2413
                        base64_decode($fileContent)
2414
                    );
2415
2416
                    // Step3 - encrypt the file
2417
                    $newFile = encryptFile($newFileName, $SETTINGS['path_to_upload_folder']);
2418
2419
                    // Step4 - store in database
2420
                    DB::insert(
2421
                        prefixTable('files'),
2422
                        array(
2423
                            'id_item' => $newItemId,
2424
                            'name' => $record['name'],
2425
                            'size' => $record['size'],
2426
                            'extension' => $record['extension'],
2427
                            'type' => $record['type'],
2428
                            'file' => $newFile['fileHash'],
2429
                            'status' => TP_ENCRYPTION_NAME,
2430
                            'confirmed' => 1,
2431
                        )
2432
                    );
2433
                    $newFileId = DB::insertId();
2434
2435
                    // Step5 - create sharekeys
2436
                    // Build list of fields
2437
                    array_push(
2438
                        $itemDataArray['files'],
2439
                        array(
2440
                            'object_id' => $newFileId,
2441
                            'object_key' => $newFile['objectKey'],
2442
                        )
2443
                    );
2444
2445
                    storeUsersShareKey(
2446
                        prefixTable('sharekeys_files'),
2447
                        (int) $dataDestination['personal_folder'],
2448
                        (int) $post_dest_id,
2449
                        (int) $newFileId,
2450
                        $newFile['objectKey'],
2451
                        true
2452
                    );
2453
                }
2454
            }
2455
            // <---
2456
2457
            // Create new task for the new item
2458
            // If it is not a personnal one
2459
            if ((int) $dataDestination['personal_folder'] !== 1) {
2460
                storeTask(
2461
                    'item_copy',
2462
                    $session->get('user-id'),
2463
                    0,
2464
                    (int) $post_dest_id,
2465
                    (int) $newItemId,
2466
                    $itemDataArray['pwd'],
2467
                    $itemDataArray['fields'],
2468
                    $itemDataArray['files'],
2469
                );
2470
            }
2471
2472
            // -------------------------
2473
            // Add specific restrictions
2474
            $rows = DB::query('SELECT * FROM ' . prefixTable('restriction_to_roles') . ' WHERE item_id = %i', $inputData['itemId']);
2475
            foreach ($rows as $record) {
2476
                DB::insert(
2477
                    prefixTable('restriction_to_roles'),
2478
                    array(
2479
                        'item_id' => $newItemId,
2480
                        'role_id' => $record['role_id'],
2481
                    )
2482
                );
2483
            }
2484
2485
            // Add Tags
2486
            $rows = DB::query('SELECT * FROM ' . prefixTable('tags') . ' WHERE item_id = %i', $inputData['itemId']);
2487
            foreach ($rows as $record) {
2488
                DB::insert(
2489
                    prefixTable('tags'),
2490
                    array(
2491
                        'item_id' => $newItemId,
2492
                        'tag' => $record['tag'],
2493
                    )
2494
                );
2495
            }
2496
2497
            // Add this duplicate in logs
2498
            logItems(
2499
                $SETTINGS,
2500
                (int) $newItemId,
2501
                $originalRecord['label'],
2502
                $session->get('user-id'),
2503
                'at_creation',
2504
                $session->get('user-login')
2505
            );
2506
            // Add the fact that item has been copied in logs
2507
            logItems(
2508
                $SETTINGS,
2509
                (int) $newItemId,
2510
                $originalRecord['label'],
2511
                $session->get('user-id'),
2512
                'at_copy',
2513
                $session->get('user-login')
2514
            );
2515
2516
            echo (string) prepareExchangedData(
2517
                array(
2518
                    'error' => false,
2519
                    'message' => '',
2520
                    'new_id' => $newItemId
2521
                ),
2522
                'encode'
2523
            );
2524
2525
            // Add new item to cache table.
2526
            updateCacheTable('add_value', (int) $newItemId);
2527
        } else {
2528
            // no item
2529
            echo (string) prepareExchangedData(
2530
                array(
2531
                    'error' => true,
2532
                    'message' => $lang->get('error_missing_id'),
2533
                ),
2534
                'encode'
2535
            );
2536
        }
2537
        break;
2538
2539
        /*
2540
        * CASE
2541
        * Display informations of selected item
2542
    */
2543
    case 'show_details_item':
2544
        // Check KEY and rights
2545
        if ($inputData['key'] !== $session->get('key')) {
2546
            echo (string) prepareExchangedData(
2547
                array(
2548
                    'error' => true,
2549
                    'message' => $lang->get('key_is_not_correct'),
2550
                ),
2551
                'encode'
2552
            );
2553
            break;
2554
        }
2555
2556
        // Step #1
2557
        $session->set('system-show_step2', false);
2558
2559
        // Decrypt and retreive data in JSON format
2560
        $dataReceived = prepareExchangedData(
2561
            $inputData['data'],
2562
            'decode'
2563
        );
2564
2565
        // Init post variables
2566
        $inputData['id'] = filter_var(($dataReceived['id']), FILTER_SANITIZE_NUMBER_INT);
2567
        $inputData['folderId'] = filter_var(($dataReceived['folder_id']), FILTER_SANITIZE_NUMBER_INT);
2568
        $post_expired_item = filter_var(($dataReceived['expired_item']), FILTER_SANITIZE_NUMBER_INT);
2569
        $post_restricted = filter_var(($dataReceived['restricted']), FILTER_SANITIZE_FULL_SPECIAL_CHARS);
2570
        $post_folder_access_level = isset($dataReceived['folder_access_level']) === true ?
2571
            filter_var(($dataReceived['folder_access_level']), FILTER_SANITIZE_FULL_SPECIAL_CHARS)
2572
            : '';
2573
        $post_item_rights = filter_var($dataReceived['rights'], FILTER_SANITIZE_NUMBER_INT);
2574
2575
        $arrData = array();
2576
        // return ID
2577
        $arrData['id'] = (int) $inputData['id'];
2578
        $arrData['id_user'] = API_USER_ID;
2579
        $arrData['author'] = 'API';
2580
2581
        // Check if item is deleted
2582
        // taking into account that item can be restored.
2583
        // so if restoration timestamp is higher than the deletion one
2584
        // then we can show it
2585
        $item_deleted = DB::queryFirstRow(
2586
            'SELECT *
2587
            FROM ' . prefixTable('log_items') . '
2588
            WHERE id_item = %i AND action = %s
2589
            ORDER BY date DESC
2590
            LIMIT 0, 1',
2591
            $inputData['id'],
2592
            'at_delete'
2593
        );
2594
        $dataDeleted = DB::count();
2595
2596
        $item_restored = DB::queryFirstRow(
2597
            'SELECT *
2598
            FROM ' . prefixTable('log_items') . '
2599
            WHERE id_item = %i AND action = %s
2600
            ORDER BY date DESC
2601
            LIMIT 0, 1',
2602
            $inputData['id'],
2603
            'at_restored'
2604
        );
2605
2606
        if ($dataDeleted !== 0 && intval($item_deleted['date']) > intval($item_restored['date'])) {
2607
            // This item is deleted => exit
2608
            echo (string) prepareExchangedData(
2609
                array(
2610
                    'error' => true,
2611
                    'message' => $lang->get('not_allowed_to_see_pw'),
2612
                    'show_detail_option' => 2,
2613
                ),
2614
                'encode'
2615
            );
2616
            break;
2617
        }
2618
2619
        // Get all informations for this item
2620
        $dataItem = DB::queryfirstrow(
2621
            'SELECT *
2622
            FROM ' . prefixTable('items') . ' as i
2623
            INNER JOIN ' . prefixTable('log_items') . ' as l ON (l.id_item = i.id)
2624
            WHERE i.id = %i AND l.action = %s',
2625
            $inputData['id'],
2626
            'at_creation'
2627
        );
2628
2629
        // Notification
2630
        DB::queryfirstrow(
2631
            'SELECT *
2632
            FROM ' . prefixTable('notification') . '
2633
            WHERE item_id = %i AND user_id = %i',
2634
            $inputData['id'],
2635
            $session->get('user-id')
2636
        );
2637
        if (DB::count() > 0) {
2638
            $arrData['notification_status'] = true;
2639
        } else {
2640
            $arrData['notification_status'] = false;
2641
        }
2642
2643
        // Get all USERS infos
2644
        $listeRestriction = is_null($dataItem['restricted_to']) === false ? array_filter(explode(';', $dataItem['restricted_to'])) : [];
2645
        $session->set('system-emails_list_for_notif', '');
2646
2647
        /*$user_in_restricted_list_of_item = false;
2648
        $rows = DB::query(
2649
            'SELECT id, login, email, admin, name, lastname
2650
            FROM ' . prefixTable('users') .'
2651
            WHERE id in %ls',
2652
            replace(';', ',', $dataItem['restricted_to'])
2653
        );
2654
        $listeRestriction = [];
2655
        foreach ($rows as $user) {
2656
            // Get auhtor
2657
            if ($user['id'] === $dataItem['id_user']) {
2658
                $arrData['author'] = $user['login'];
2659
                $arrData['author_email'] = $user['email'];
2660
                $arrData['id_user'] = (int) $dataItem['id_user'];
2661
            }
2662
2663
            // Get restriction list for users
2664
            if (in_array($user['id'], $listRest) === true) {
2665
                array_push($listeRestriction, $user['id']);
2666
                if ($session->get('user-id') === $user['id']) {
2667
                    $user_in_restricted_list_of_item = true;
2668
                }
2669
            }
2670
        }*/
2671
        $user_in_restricted_list_of_item = in_array($session->get('user-id'), $listeRestriction) === true ? true : false;
2672
2673
        // manage case of API user
2674
        if ($dataItem['id_user'] === API_USER_ID) {
2675
            $arrData['author'] = 'API [' . $dataItem['description'] . ']';
2676
            $arrData['id_user'] = API_USER_ID;
2677
            $arrData['author_email'] = '';
2678
            $arrData['notification_status'] = false;
2679
        }
2680
2681
        // Get all tags for this item
2682
        $tags = array();
2683
        $rows = DB::query(
2684
            'SELECT tag
2685
            FROM ' . prefixTable('tags') . '
2686
            WHERE item_id = %i',
2687
            $inputData['id']
2688
        );
2689
        foreach ($rows as $record) {
2690
            array_push($tags, $record['tag']);
2691
        }
2692
2693
        // TODO -> improve this check
2694
        // check that actual user can access this item
2695
        $restrictionActive = true;
2696
        $restrictedTo = is_null($dataItem['restricted_to']) === false ? array_filter(explode(';', $dataItem['restricted_to'])) : [];
2697
        if (
2698
            in_array($session->get('user-id'), $restrictedTo) === true
2699
            || ((int) $session->get('user-manager') === 1 && (int) $SETTINGS['manager_edit'] === 1)
2700
        ) {
2701
            $restrictionActive = false;
2702
        }
2703
        if (empty($dataItem['restricted_to']) === true) {
2704
            $restrictionActive = false;
2705
        }
2706
2707
        // Check if user has a role that is accepted
2708
        $rows_tmp = DB::query(
2709
            'SELECT role_id
2710
            FROM ' . prefixTable('restriction_to_roles') . '
2711
            WHERE item_id=%i',
2712
            $inputData['id']
2713
        );
2714
        foreach ($rows_tmp as $rec_tmp) {
2715
            if (in_array($rec_tmp['role_id'], explode(';', $session->get('user-roles')))) {
2716
                $restrictionActive = false;
2717
            }
2718
        }
2719
2720
        // Uncrypt PW
2721
        // Get the object key for the user
2722
        $userKey = DB::queryFirstRow(
2723
            'SELECT share_key
2724
            FROM ' . prefixTable('sharekeys_items') . '
2725
            WHERE user_id = %i AND object_id = %i',
2726
            $session->get('user-id'),
2727
            $inputData['id']
2728
        );
2729
        if (DB::count() === 0 || empty($dataItem['pw']) === true) {
2730
            // No share key found
2731
            $pwIsEmptyNormally = false;
2732
            // Is this a personal and defuse password?
2733
            if ((int) $dataItem['perso'] === 1 && substr($dataItem['pw'], 0, 3) === 'def') {
2734
                // Yes, then ask for decryption with old personal salt key
2735
                echo (string) prepareExchangedData(
2736
                    array(
2737
                        'error' => true,
2738
                        'message' => $lang->get('error'),
2739
                        'show_detail_option' => 2,
2740
                        'error_type' => 'private_items_to_encrypt',
2741
                    ),
2742
                    'encode'
2743
                );
2744
                break;
2745
            } else {
2746
                $pw = '';
2747
            }
2748
        } else {
2749
            $pwIsEmptyNormal == true;
2750
            $decryptedObject = decryptUserObjectKey($userKey['share_key'], $session->get('user-private_key'));
2751
            // if null then we have an error.
2752
            // suspecting bad password
2753
            if (empty($decryptedObject) === false) {
2754
                $pw = doDataDecryption(
2755
                    $dataItem['pw'],
2756
                    $decryptedObject
2757
                );
2758
                $arrData['pwd_encryption_error'] = false;
2759
                $arrData['pwd_encryption_error_message'] = '';
2760
            } else {
2761
                $pw = '';
2762
                $arrData['pwd_encryption_error'] = 'inconsistent_password';
2763
                $arrData['pwd_encryption_error_message'] = $lang->get('error_new_ldap_password_detected');
2764
            }
2765
        }
2766
2767
        // check user is admin
2768
        $session__list_restricted_folders_for_items = $session->get('system-list_restricted_folders_for_items') ?? [];
2769
        if (
2770
            (int) $session->get('user-admin') === 1
2771
            && (int) $dataItem['perso'] !== 1
2772
        ) {
2773
            $arrData['show_details'] = 0;
2774
            // ---
2775
            // ---
2776
        } elseif ((
2777
                (in_array($dataItem['id_tree'], $session->get('user-accessible_folders')) === true || (int) $session->get('user-admin') === 1)
2778
                && ((int) $dataItem['perso'] === 0 || ((int) $dataItem['perso'] === 1 && in_array($dataItem['id_tree'], $session->get('user-personal_folders')) === true))
2779
                && $restrictionActive === false)
2780
            || (isset($SETTINGS['anyone_can_modify']) && (int) $SETTINGS['anyone_can_modify'] === 1
2781
                && (int) $dataItem['anyone_can_modify'] === 1
2782
                && (in_array($dataItem['id_tree'], $session->get('user-accessible_folders')) || (int) $session->get('user-admin') === 1)
2783
                && $restrictionActive === false)
2784
            || (null !== $inputData['folderId']
2785
                && isset($session__list_restricted_folders_for_items[$inputData['folderId']])
2786
                && in_array($inputData['id'], $session__list_restricted_folders_for_items[$inputData['folderId']])
2787
                && (int) $post_restricted === 1
2788
                && $user_in_restricted_list_of_item === true)
2789
            || (isset($SETTINGS['restricted_to_roles']) && (int) $SETTINGS['restricted_to_roles'] === 1
2790
                && $restrictionActive === false)
2791
        ) {
2792
            // Check if actual USER can see this ITEM
2793
            // Allow show details
2794
            $arrData['show_details'] = 1;
2795
2796
            // Regarding user's roles, what type of modification is allowed?
2797
            /*$rows = DB::query(
2798
                'SELECT r.type
2799
                FROM '.prefixTable('roles_values').' AS r
2800
                WHERE r.folder_id = %i AND r.role_id IN %ls',
2801
                $dataItem['id_tree'],
2802
                $session->get('user-accessible_folders')
2803
            );
2804
            foreach ($rows as $record) {
2805
                // TODO
2806
            }*/
2807
2808
            // Display menu icon for deleting if user is allowed
2809
            if (
2810
                (int) $dataItem['id_user'] === (int) $session->get('user-id')
2811
                || (int) $session->get('user-admin') === 1
2812
                || ((int) $session->get('user-manager') === 1 && (int) $SETTINGS['manager_edit'] === 1)
2813
                || (int) $dataItem['anyone_can_modify'] === 1
2814
                || in_array($dataItem['id_tree'], $session->get('system-list_folders_editable_by_role')) === true
2815
                || in_array($session->get('user-id'), $restrictedTo) === true
2816
                //|| count($restrictedTo) === 0
2817
                || (int) $post_folder_access_level === 30
2818
                || (int) $post_item_rights >= 40
2819
            ) {
2820
                $arrData['user_can_modify'] = 1;
2821
                $user_is_allowed_to_modify = true;
2822
            } else {
2823
                $arrData['user_can_modify'] = 0;
2824
                $user_is_allowed_to_modify = false;
2825
            }
2826
2827
            // Get restriction list for roles
2828
            $listRestrictionRoles = array();
2829
            if (isset($SETTINGS['restricted_to_roles']) && (int) $SETTINGS['restricted_to_roles'] === 1) {
2830
                // Add restriction if item is restricted to roles
2831
                $rows = DB::query(
2832
                    'SELECT t.title, t.id
2833
                    FROM ' . prefixTable('roles_title') . ' AS t
2834
                    INNER JOIN ' . prefixTable('restriction_to_roles') . ' AS r ON (t.id=r.role_id)
2835
                    WHERE r.item_id = %i
2836
                    ORDER BY t.title ASC',
2837
                    $inputData['id']
2838
                );
2839
                foreach ($rows as $record) {
2840
                    if (!in_array($record['title'], $listRestrictionRoles)) {
2841
                        array_push($listRestrictionRoles, $record['id']);
2842
                    }
2843
                }
2844
            }
2845
            // Check if any KB is linked to this item
2846
            if (isset($SETTINGS['enable_kb']) && (int) $SETTINGS['enable_kb'] === 1) {
2847
                $tmp = array();
2848
                $rows = DB::query(
2849
                    'SELECT k.label, k.id
2850
                    FROM ' . prefixTable('kb_items') . ' as i
2851
                    INNER JOIN ' . prefixTable('kb') . ' as k ON (i.kb_id=k.id)
2852
                    WHERE i.item_id = %i
2853
                    ORDER BY k.label ASC',
2854
                    $inputData['id']
2855
                );
2856
                foreach ($rows as $record) {
2857
                    array_push(
2858
                        $tmp,
2859
                        array(
2860
                            'id' => $record['id'],
2861
                            'label' => $record['label'],
2862
                        )
2863
                    );
2864
                }
2865
                $arrData['links_to_kbs'] = $tmp;
2866
            }
2867
            // Prepare DIalogBox data
2868
            if ((int) $post_expired_item === 0) {
2869
                $arrData['show_detail_option'] = 0;
2870
            } elseif ($user_is_allowed_to_modify === true && (int) $post_expired_item === 1) {
2871
                $arrData['show_detail_option'] = 1;
2872
            } else {
2873
                $arrData['show_detail_option'] = 2;
2874
            }
2875
2876
            $arrData['label'] = $dataItem['label'] === '' ? '' : $dataItem['label'];
2877
            $arrData['pw'] = $pw;
2878
            $arrData['pw_decrypt_info'] = empty($pw) === true && $pwIsEmptyNormal === false ? 'error_no_sharekey_yet' : '';
2879
            $arrData['email'] = empty($dataItem['email']) === true || $dataItem['email'] === null ? '' : $dataItem['email'];
2880
            $arrData['url'] = empty($dataItem['url']) === true ? '' : $dataItem['url'];
2881
            $arrData['folder'] = $dataItem['id_tree'];
2882
            $arrData['description'] = $dataItem['description'];
2883
            $arrData['login'] = $dataItem['login'];
2884
            $arrData['id_restricted_to'] = $listeRestriction;
2885
            $arrData['id_restricted_to_roles'] = $listRestrictionRoles;
2886
            $arrData['tags'] = $tags;
2887
            $arrData['folder'] = (int) $dataItem['id_tree'];
2888
            $arrData['fa_icon'] = $dataItem['fa_icon'];
2889
            $arrData['item_key'] = $dataItem['item_key'];
2890
2891
            if (
2892
                isset($SETTINGS['enable_server_password_change'])
2893
                && (int) $SETTINGS['enable_server_password_change'] === 1
2894
            ) {
2895
                $arrData['auto_update_pwd_frequency'] = $dataItem['auto_update_pwd_frequency'];
2896
            } else {
2897
                $arrData['auto_update_pwd_frequency'] = '0';
2898
            }
2899
2900
            $arrData['anyone_can_modify'] = (int) $dataItem['anyone_can_modify'];
2901
2902
            // Add the fact that item has been viewed in logs
2903
            if (isset($SETTINGS['log_accessed']) && (int) $SETTINGS['log_accessed'] === 1) {
2904
                logItems(
2905
                    $SETTINGS,
2906
                    (int) $inputData['id'],
2907
                    $dataItem['label'],
2908
                    (int) $session->get('user-id'),
2909
                    'at_shown',
2910
                    $session->get('user-login')
2911
                );
2912
            }
2913
2914
            // statistics
2915
            DB::update(
2916
                prefixTable('items'),
2917
                array(
2918
                    'viewed_no' => $dataItem['viewed_no'] + 1,
2919
                    'updated_at' => time(),
2920
                ),
2921
                'id = %i',
2922
                $inputData['id']
2923
            );
2924
            $arrData['viewed_no'] = $dataItem['viewed_no'] + 1;
2925
2926
            // get fields
2927
            $fieldsTmp = array();
2928
            $arrCatList = $template_id = '';
2929
            if (isset($SETTINGS['item_extra_fields']) && (int) $SETTINGS['item_extra_fields'] === 1) {
2930
                // get list of associated Categories
2931
                $arrCatList = array();
2932
                $rows_tmp = DB::query(
2933
                    'SELECT id_category
2934
                    FROM ' . prefixTable('categories_folders') . '
2935
                    WHERE id_folder=%i',
2936
                    $inputData['folderId']
2937
                );
2938
                
2939
                if (DB::count() > 0) {
2940
                    foreach ($rows_tmp as $row) {
2941
                        array_push($arrCatList, (int) $row['id_category']);
2942
                    }
2943
2944
                    // get fields for this Item
2945
                    $rows_tmp = DB::query(
2946
                        'SELECT i.id AS id, i.field_id AS field_id, i.data AS data, i.item_id AS item_id,
2947
                        i.encryption_type AS encryption_type, c.encrypted_data AS encrypted_data, c.parent_id AS parent_id,
2948
                        c.type as field_type, c.masked AS field_masked, c.role_visibility AS role_visibility
2949
                        FROM ' . prefixTable('categories_items') . ' AS i
2950
                        INNER JOIN ' . prefixTable('categories') . ' AS c ON (i.field_id=c.id)
2951
                        WHERE i.item_id=%i AND c.parent_id IN %ls',
2952
                        $inputData['id'],
2953
                        $arrCatList
2954
                    );
2955
                    foreach ($rows_tmp as $row) {
2956
                        // Uncrypt data
2957
                        // Get the object key for the user
2958
                        //db::debugmode(true);
2959
                        $userKey = DB::queryFirstRow(
2960
                            'SELECT share_key
2961
                            FROM ' . prefixTable('sharekeys_fields') . '
2962
                            WHERE user_id = %i AND object_id = %i',
2963
                            $session->get('user-id'),
2964
                            $row['id']
2965
                        );
2966
                        //db::debugmode(false);
2967
                        $fieldText = [];
2968
                        if (DB::count() === 0 && (int) $row['encrypted_data'] === 1) {
2969
                            // Data should be encrypted but no key yet
2970
                            // System is currently creating the keys
2971
                            $fieldText = [
2972
                                'string' => '',
2973
                                'encrypted' => false,
2974
                                'error' => 'error_no_sharekey_yet',
2975
                            ];
2976
                        } else if (DB::count() === 0 && (int) $row['encrypted_data'] === 0) {
2977
                            // Data is not encrypted in DB
2978
                            $fieldText = [
2979
                                'string' => $row['data'],//#3945 - isBase64($row['data']) === true ? base64_decode($row['data']) : 
2980
                                'encrypted' => false,
2981
                                'error' => false,
2982
                            ];
2983
                        } else {
2984
                            // Data is encrypted in DB and we have a key
2985
                            $fieldText = [
2986
                                'string' => doDataDecryption(
2987
                                    $row['data'],
2988
                                    decryptUserObjectKey(
2989
                                        $userKey['share_key'],
2990
                                        $session->get('user-private_key')
2991
                                    )
2992
                                ),
2993
                                'encrypted' => true,
2994
                                'error' => '',
2995
                            ];
2996
                        }
2997
2998
                        // Manage textarea string
2999
                        /*if ($row['field_type'] === 'textarea') {
3000
                            $fieldText = $fieldText;
3001
                        }*/
3002
3003
                        // build returned list of Fields text
3004
                        array_push(
3005
                            $fieldsTmp,
3006
                            array(
3007
                                'id' => (int) $row['field_id'],
3008
                                'value' => $fieldText['string'],
3009
                                'encrypted' => (int) $fieldText['encrypted'],
3010
                                'parent_id' => (int) $row['parent_id'],
3011
                                'type' => $row['field_type'],
3012
                                'masked' => (int) $row['field_masked'],
3013
                                'error' => (string) $fieldText['error'],
3014
                            )
3015
                        );
3016
                    }
3017
                }
3018
            }
3019
3020
            // Now get the selected template (if exists)
3021
            if (isset($SETTINGS['item_creation_templates']) && (int) $SETTINGS['item_creation_templates'] === 1) {
3022
                $rows_tmp = DB::queryfirstrow(
3023
                    'SELECT category_id
3024
                    FROM ' . prefixTable('templates') . '
3025
                    WHERE item_id = %i',
3026
                    $inputData['id']
3027
                );
3028
                if (DB::count() > 0) {
3029
                    $template_id = $rows_tmp['category_id'];
3030
                }
3031
            }
3032
            //}
3033
            $arrData['fields'] = $fieldsTmp;
3034
            $arrData['categories'] = $arrCatList;
3035
            $arrData['template_id'] = (int) $template_id;
3036
            $arrData['to_be_deleted'] = '';
3037
3038
            // Evaluate if item is ready for all users
3039
            $rows_tmp = DB::queryfirstrow(
3040
                'SELECT finished_at
3041
                FROM ' . prefixTable('background_tasks') . '
3042
                WHERE item_id = %i',
3043
                $inputData['id']
3044
            );
3045
            $arrData['item_ready'] = DB::count() === 0 ? true : (DB::count() > 0 && empty($rows_tmp['finished_at']) === true ? false : true);
3046
3047
            // Manage user restriction
3048
            if (null !== $post_restricted) {
3049
                $arrData['restricted'] = $post_restricted;
3050
            } else {
3051
                $arrData['restricted'] = '';
3052
            }
3053
            // Decrement the number before being deleted
3054
            if (isset($SETTINGS['enable_delete_after_consultation']) && (int) $SETTINGS['enable_delete_after_consultation'] === 1) {
3055
                // Is the Item to be deleted?
3056
                $dataDelete = DB::queryfirstrow(
3057
                    'SELECT * 
3058
                    FROM ' . prefixTable('automatic_del') . '
3059
                    WHERE item_id = %i',
3060
                    $inputData['id']
3061
                );
3062
                if (DB::count() > 0) {
3063
                    $arrData['to_be_deleted'] = $dataDelete['del_value'];
3064
                    $arrData['to_be_deleted_type'] = (int) $dataDelete['del_type'];
3065
                }
3066
3067
                // Now delete if required
3068
                if ($dataDelete !== null && ((int) $dataDelete['del_enabled'] === 1
3069
                    || intval($arrData['id_user']) !== intval($session->get('user-id'))))
3070
                {
3071
                    if ((int) $dataDelete['del_type'] === 1 && $dataDelete['del_value'] >= 1) {
3072
                        // decrease counter
3073
                        DB::update(
3074
                            prefixTable('automatic_del'),
3075
                            array(
3076
                                'del_value' => $dataDelete['del_value'] - 1,
3077
                            ),
3078
                            'item_id = %i',
3079
                            $inputData['id']
3080
                        );
3081
                        // store value
3082
                        $arrData['to_be_deleted'] = $dataDelete['del_value'] - 1;
3083
                    } elseif (
3084
                        (int) $dataDelete['del_type'] === 1
3085
                        && $dataDelete['del_value'] <= 1
3086
                        || (int) $dataDelete['del_type'] === 2
3087
                        && $dataDelete['del_value'] < time()
3088
                    ) {
3089
                        $arrData['show_details'] = 0;
3090
                        // delete item
3091
                        DB::delete(prefixTable('automatic_del'), 'item_id = %i', $inputData['id']);
3092
                        // make inactive object
3093
                        DB::update(
3094
                            prefixTable('items'),
3095
                            array(
3096
                                'inactif' => 1,
3097
                                'deleted_at' => time(),
3098
                            ),
3099
                            'id = %i',
3100
                            $inputData['id']
3101
                        );
3102
3103
                        // log
3104
                        logItems(
3105
                            $SETTINGS,
3106
                            (int) $inputData['id'],
3107
                            $dataItem['label'],
3108
                            (int) $session->get('user-id'),
3109
                            'at_delete',
3110
                            $session->get('user-login'),
3111
                            'at_automatically_deleted'
3112
                        );
3113
3114
                        // Update cache table
3115
                        updateCacheTable('delete_value', (int) $inputData['id']);
3116
3117
                        $arrData['show_detail_option'] = 1;
3118
                        $arrData['to_be_deleted'] = 0;
3119
                    } elseif ($dataDelete['del_type'] === '2') {
3120
                        $arrData['to_be_deleted'] = date($SETTINGS['date_format'], (int) $dataDelete['del_value']);
3121
                    }
3122
                } else {
3123
                    $arrData['to_be_deleted'] = '';
3124
                }
3125
            } else {
3126
                $arrData['to_be_deleted'] = $lang->get('no');
3127
            }
3128
            // ---
3129
            // ---
3130
        } else {
3131
            $arrData['show_details'] = 0;
3132
            // get readable list of restriction
3133
            $listOfRestricted = '';
3134
            if (empty($dataItem['restricted_to']) === false) {
3135
                foreach (explode(';', $dataItem['restricted_to']) as $userRest) {
3136
                    if (empty($userRest) === false) {
3137
                        $dataTmp = DB::queryfirstrow('SELECT login FROM ' . prefixTable('users') . ' WHERE id= ' . $userRest);
3138
                        if (empty($listOfRestricted)) {
3139
                            $listOfRestricted = $dataTmp['login'];
3140
                        } else {
3141
                            $listOfRestricted .= ';' . $dataTmp['login'];
3142
                        }
3143
                    }
3144
                }
3145
            }
3146
            $arrData['restricted_to'] = $listOfRestricted;
3147
            $arrData['notification_list'] = '';
3148
            $arrData['notification_status'] = '';
3149
        }
3150
3151
        // Set a timestamp
3152
        $arrData['timestamp'] = time();
3153
3154
        // Set temporary session variable to allow step2
3155
        $session->set('system-show_step2', true);
3156
3157
        // Error
3158
        $arrData['error'] = '';
3159
3160
        // Encrypt data to return
3161
        echo (string) prepareExchangedData(
3162
            $arrData, 
3163
            'encode'
3164
        );
3165
        break;
3166
3167
        /*
3168
        * CASE
3169
        * Display History of the selected Item
3170
    */
3171
    case 'showDetailsStep2':
3172
        // Is this query expected (must be run after a step1 and not standalone)
3173
        if ($session->get('system-show_step2') !== true) {
3174
            // Check KEY and rights
3175
            if ($inputData['key'] !== $session->get('key')) {
3176
                echo (string) prepareExchangedData(
3177
                    array(
3178
                        'error' => true,
3179
                        'message' => $lang->get('key_is_not_correct'),
3180
                    ),
3181
                    'encode'
3182
                );
3183
                break;
3184
            }
3185
            if ($session->get('user-read_only') === 1) {
3186
                echo (string) prepareExchangedData(
3187
                    array(
3188
                        'error' => true,
3189
                        'message' => $lang->get('error_not_allowed_to'),
3190
                    ),
3191
                    'encode'
3192
                );
3193
                break;
3194
            }
3195
        }
3196
3197
        // prepare return array
3198
        $returnArray = [
3199
            'show_details' => 0,
3200
            'attachments' => [],
3201
            'favourite' => 0,
3202
            'otp_for_item_enabled' => 0,
3203
            'otp_phone_number' => '',
3204
            'otp_secret' => '',
3205
            'users_list' => [],
3206
            'roles_list' => [],
3207
            'has_change_proposal' => 0,
3208
            'setting_restricted_to_roles' => 0,
3209
            'otv_links' => 0,
3210
        ];
3211
3212
        // Load item data
3213
        $dataItem = DB::queryFirstRow(
3214
            'SELECT i.*, n.title AS folder_title, o.enabled AS otp_for_item_enabled, o.phone_number AS otp_phone_number, o.secret AS otp_secret
3215
            FROM ' . prefixTable('items') . ' AS i
3216
            INNER JOIN ' . prefixTable('nested_tree') . ' AS n ON (i.id_tree = n.id)
3217
            INNER JOIN ' . prefixTable('items_otp') . ' AS o ON (o.item_id = i.id)
3218
            WHERE i.id = %i',
3219
            $inputData['id']
3220
        );
3221
3222
        // check that actual user can access this item
3223
        $restrictionActive = true;
3224
        $restrictedTo = is_null($dataItem['restricted_to']) === false ? array_filter(explode(';', $dataItem['restricted_to'])) : [];
3225
        if (
3226
            in_array($session->get('user-id'), $restrictedTo)
3227
            || (((int) $session->get('user-manager') === 1 || (int) $session->get('user-can_manage_all_users') === 1)
3228
                && (int) $SETTINGS['manager_edit'] === 1)
3229
        ) {
3230
            $restrictionActive = false;
3231
        }
3232
        if (empty($dataItem['restricted_to'])) {
3233
            $restrictionActive = false;
3234
        }
3235
3236
        // Check if user has a role that is accepted
3237
        $rows_tmp = DB::query(
3238
            'SELECT role_id
3239
            FROM ' . prefixTable('restriction_to_roles') . '
3240
            WHERE item_id=%i',
3241
            $inputData['id']
3242
        );
3243
        foreach ($rows_tmp as $rec_tmp) {
3244
            if (in_array($rec_tmp['role_id'], explode(';', $session->get('user-roles')))) {
3245
                $restrictionActive = false;
3246
            }
3247
        }
3248
3249
        // check user is admin
3250
        $session__list_restricted_folders_for_items = $session->get('system-list_restricted_folders_for_items') ?? [];
3251
        if (
3252
            (int) $session->get('user-admin') === 1
3253
            && (int) $dataItem['perso'] === 0
3254
        ) {
3255
            $returnArray['show_details'] = 0;
3256
            echo (string) prepareExchangedData(
3257
                $returnArray,
3258
                'encode'
3259
            );
3260
        // Get all expected data about this ITEM
3261
        } else {
3262
            // generate 2d key
3263
            $session->set('user-key_tmp', bin2hex(GenerateCryptKey(16, false, true, true, false, true)));
3264
3265
            // Prepare files listing
3266
            $attachments = [];
3267
            
3268
            // launch query
3269
            $rows = DB::query(
3270
                'SELECT id, name, file, extension, size
3271
                FROM ' . prefixTable('files') . '
3272
                WHERE id_item = %i AND confirmed = 1',
3273
                $inputData['id']
3274
            );
3275
            foreach ($rows as $record) {
3276
                $filename = basename($record['name'], '.' . $record['extension']);
3277
                $filename = isBase64($filename) === true ? base64_decode($filename) : $filename;
3278
3279
                array_push(
3280
                    $attachments,
3281
                    array(
3282
                        'icon' => fileFormatImage(strtolower($record['extension'])),
3283
                        'filename' => $filename,
3284
                        'extension' => $record['extension'],
3285
                        'size' => formatSizeUnits((int) $record['size']),
3286
                        'is_image' => in_array(strtolower($record['extension']), TP_IMAGE_FILE_EXT) === true ? 1 : 0,
3287
                        'id' => $record['id'],
3288
                        'key' => $session->get('user-key_tmp'),
3289
                        'internalFilename' => basename($record['name'], '.' . $record['extension']),
3290
                    )
3291
                );
3292
            }
3293
            $returnArray['attachments'] = $attachments;
3294
3295
            // disable add bookmark if alread bookmarked
3296
            $returnArray['favourite'] = in_array($inputData['id'], $session->get('user-favorites')) === true ? 1 : 0;
3297
            
3298
            // get OTP enabled for item
3299
            $returnArray['otp_for_item_enabled'] = (int) $dataItem['otp_for_item_enabled'];
3300
            $returnArray['otp_phone_number'] = (string) $dataItem['otp_phone_number'];
3301
            if (empty($dataItem['otp_secret']) === false) {
3302
                $secret = cryption(
3303
                    $dataItem['otp_secret'],
3304
                    '',
3305
                    'decrypt'
3306
                )['string'];
3307
            } else {
3308
                $secret = '';
3309
            }
3310
            $returnArray['otp_secret'] = (string) $secret;
3311
3312
            // Add this item to the latests list
3313
            if ($session->has('user-latest_items') && $session->has('user-latest_items') && null !== $session->get('user-latest_items') && isset($SETTINGS['max_latest_items']) && 
3314
                in_array($dataItem['id'], $session->get('user-latest_items')) === false
3315
            ) {
3316
                if (count($session->get('user-latest_items')) >= $SETTINGS['max_latest_items']) {
3317
                    // delete last items
3318
                    SessionManager::specificOpsOnSessionArray('user-latest_items', 'pop');
3319
                }
3320
                SessionManager::specificOpsOnSessionArray('user-latest_items', 'unshift', $dataItem['id']);
3321
                // update DB
3322
                DB::update(
3323
                    prefixTable('users'),
3324
                    array(
3325
                        'latest_items' => implode(';', $session->get('user-latest_items')),
3326
                    ),
3327
                    'id=' . $session->get('user-id')
3328
                );
3329
            }
3330
3331
            // get list of roles
3332
            $listOptionsForUsers = array();
3333
            $listOptionsForRoles = array();
3334
            $rows = DB::query(
3335
                'SELECT r.role_id AS role_id, t.title AS title
3336
                FROM ' . prefixTable('roles_values') . ' AS r
3337
                INNER JOIN ' . prefixTable('roles_title') . ' AS t ON (r.role_id = t.id)
3338
                WHERE r.folder_id = %i',
3339
                $dataItem['id_tree']
3340
            );
3341
            foreach ($rows as $record) {
3342
                array_push(
3343
                    $listOptionsForRoles,
3344
                    array(
3345
                        'id' => (int) $record['role_id'],
3346
                        'title' => $record['title'],
3347
                    )
3348
                );
3349
                $rows2 = DB::query(
3350
                    'SELECT id, login, fonction_id, email, name, lastname
3351
                    FROM ' . prefixTable('users') . '
3352
                    WHERE fonction_id LIKE %s',
3353
                    '%' . $record['role_id'] . '%'
3354
                );
3355
                foreach ($rows2 as $record2) {
3356
                    foreach (explode(';', $record2['fonction_id']) as $role) {
3357
                        if (
3358
                            array_search($record2['id'], array_column($listOptionsForUsers, 'id')) === false
3359
                            && $role === $record['role_id']
3360
                        ) {
3361
                            array_push(
3362
                                $listOptionsForUsers,
3363
                                array(
3364
                                    'id' => (int) $record2['id'],
3365
                                    'login' => $record2['login'],
3366
                                    'name' => $record2['name'] . ' ' . $record2['lastname'],
3367
                                    'email' => $record2['email'],
3368
                                )
3369
                            );
3370
                        }
3371
                    }
3372
                }
3373
            }
3374
3375
            $returnArray['users_list'] = $listOptionsForUsers;
3376
            $returnArray['roles_list'] = $listOptionsForRoles;
3377
3378
            // send notification if enabled
3379
            if (isset($SETTINGS['enable_email_notification_on_item_shown']) === true && (int) $SETTINGS['enable_email_notification_on_item_shown'] === 1) {
3380
                // Get path
3381
                $arbo = $tree->getPath($dataItem['id_tree'], true);
3382
                $path = '';
3383
                foreach ($arbo as $elem) {
3384
                    if (empty($path) === true) {
3385
                        $path = htmlspecialchars(stripslashes(htmlspecialchars_decode($elem->title, ENT_QUOTES)), ENT_QUOTES) . ' ';
3386
                    } else {
3387
                        $path .= '&#8594; ' . htmlspecialchars(stripslashes(htmlspecialchars_decode($elem->title, ENT_QUOTES)), ENT_QUOTES);
3388
                    }
3389
                }
3390
                // Build text to show user
3391
                if (empty($path) === true) {
3392
                    $path = addslashes($dataItem['label']);
3393
                } else {
3394
                    $path = addslashes($dataItem['label']) . ' (' . $path . ')';
3395
                }
3396
3397
                // Add Admins to notification list if expected
3398
                $reveivers = [];
3399
                $rows = DB::query(
3400
                    'SELECT email
3401
                    FROM ' . prefixTable('users').'
3402
                    WHERE admin = %i',
3403
                    1
3404
                );
3405
                foreach ($rows as $user) {
3406
                    array_push($reveivers, $user['email']);
3407
                }
3408
3409
                // prepare sending email
3410
                prepareSendingEmail(
3411
                    $lang->get('email_on_open_notification_subject'),
3412
                    str_replace(
3413
                        array('#tp_user#', '#tp_item#', '#tp_link#'),
3414
                        array(
3415
                            addslashes($session->get('user-login')),
3416
                            $path,
3417
                            $SETTINGS['cpassman_url'] . '/index.php?page=items&group=' . $dataItem['id_tree'] . '&id=' . $dataItem['id'],
3418
                        ),
3419
                        $lang->get('email_on_open_notification_mail')
3420
                    ),
3421
                    implode(",", $reveivers),
3422
                    ""
3423
                );
3424
            }
3425
3426
            // has this item a change proposal
3427
            DB::query('SELECT * FROM ' . prefixTable('items_change') . ' WHERE item_id = %i', $inputData['id']);
3428
            $returnArray['has_change_proposal'] = DB::count();
3429
3430
            // Setting
3431
            $returnArray['setting_restricted_to_roles'] = isset($SETTINGS['restricted_to_roles']) === true
3432
                && (int) $SETTINGS['restricted_to_roles'] === 1 ? 1 : 0;
3433
3434
            // get OTV links
3435
            if (isset($SETTINGS['otv_is_enabled']) === true && (int) $SETTINGS['otv_is_enabled'] === 1) {
3436
                DB::query(
3437
                    'SELECT *
3438
                    FROM ' . prefixTable('otv') . '
3439
                    WHERE item_id = %i
3440
                    AND time_limit > %i',
3441
                    $inputData['id'],
3442
                    time()
3443
                );
3444
                $returnArray['otv_links'] = (int) DB::count();
3445
            }
3446
3447
            $session->set('system-show_step2', false);
3448
            
3449
            // deepcode ignore ServerLeak: Data is encrypted before being sent
3450
            echo (string) prepareExchangedData(
3451
                $returnArray,
3452
                'encode'
3453
            );
3454
        }
3455
        break;
3456
3457
        /*
3458
        * CASE
3459
        * Delete an item
3460
    */
3461
    case 'delete_item':
3462
        // Check KEY and rights
3463
        if ($inputData['key'] !== $session->get('key')) {
3464
            echo (string) prepareExchangedData(
3465
                array(
3466
                    'error' => true,
3467
                    'message' => $lang->get('key_is_not_correct'),
3468
                ),
3469
                'encode'
3470
            );
3471
            break;
3472
        }
3473
        if ($session->get('user-read_only') === 1) {
3474
            echo (string) prepareExchangedData(
3475
                array(
3476
                    'error' => true,
3477
                    'message' => $lang->get('error_not_allowed_to'),
3478
                ),
3479
                'encode'
3480
            );
3481
            break;
3482
        }
3483
3484
        // decrypt and retreive data in JSON format
3485
        $dataReceived = prepareExchangedData(
3486
            $inputData['data'],
3487
            'decode'
3488
        );
3489
        
3490
        // Prepare POST variables
3491
        $data = [
3492
            'itemId' => isset($dataReceived['item_id']) === true ? $dataReceived['item_id'] : '',
3493
            'folderId' => isset($dataReceived['folder_id']) === true ? $dataReceived['folder_id'] : '',
3494
            'accessLevel' => isset($dataReceived['access_level']) === true ? $dataReceived['access_level'] : '',
3495
            'itemKey' => isset($dataReceived['item_key']) === true ? $dataReceived['item_key'] : '',
3496
        ];
3497
        
3498
        $filters = [
3499
            'itemId' => 'cast:integer',
3500
            'folderId' => 'cast:integer',
3501
            'accessLevel' => 'cast:integer',
3502
            'itemKey' => 'trim|escape',
3503
        ];
3504
        
3505
        $inputData = dataSanitizer(
3506
            $data,
3507
            $filters,
3508
            $SETTINGS['cpassman_dir']
3509
        );
3510
        
3511
        if (empty($inputData['itemId']) === true && (empty($inputData['itemKey']) === true || is_null($inputData['itemKey']) === true)) {
3512
            echo (string) prepareExchangedData(
3513
                array(
3514
                    'error' => true,
3515
                    'message' => $lang->get('nothing_to_do'),
3516
                ),
3517
                'encode'
3518
            );
3519
            break;
3520
        }
3521
3522
        // Check that user can access this item
3523
        $granted = accessToItemIsGranted($inputData['itemId'], $SETTINGS);
3524
        if ($granted !== true) {
3525
            echo (string) prepareExchangedData(
3526
                array(
3527
                    'error' => true,
3528
                    'message' => $granted,
3529
                ),
3530
                'encode'
3531
            );
3532
            break;
3533
        }
3534
3535
        // Load item data
3536
        $data = DB::queryFirstRow(
3537
            'SELECT id_tree, id, label
3538
            FROM ' . prefixTable('items') . '
3539
            WHERE id = %i OR item_key = %s',
3540
            $inputData['itemId'],
3541
            $inputData['itemKey']
3542
        );
3543
        if (empty($inputData['itemId']) === true) {
3544
            $inputData['itemId'] = $data['id'];
3545
        }
3546
        $inputData['label'] = $data['label'];
3547
3548
        // Check that user can delete on this folder
3549
        $checkRights = getCurrentAccessRights(
3550
            $session->get('user-id'),
3551
            $inputData['itemId'],
3552
            (int) $data['id_tree'],
3553
        );
3554
3555
        if ($checkRights['error'] || !$checkRights['delete']) {
3556
            echo (string) prepareExchangedData(
3557
                array(
3558
                    'error' => true,
3559
                    'message' => $lang->get('error_not_allowed_to'),
3560
                ),
3561
                'encode'
3562
            );
3563
        }
3564
3565
        // delete item consists in disabling it
3566
        DB::update(
3567
            prefixTable('items'),
3568
            array(
3569
                'inactif' => '1',
3570
                'deleted_at' => time(),
3571
            ),
3572
            'id = %i OR item_key = %s',
3573
            $inputData['itemId'],
3574
            $inputData['itemKey']
3575
        );
3576
3577
        // log
3578
        logItems(
3579
            $SETTINGS,
3580
            (int) $inputData['itemId'],
3581
            $inputData['label'],
3582
            $session->get('user-id'),
3583
            'at_delete',
3584
            $session->get('user-login')
3585
        );
3586
        // Update CACHE table
3587
        updateCacheTable('delete_value', (int) $inputData['itemId']);
3588
3589
        echo (string) prepareExchangedData(
3590
            array(
3591
                'error' => false,
3592
                'message' => '',
3593
            ),
3594
            'encode'
3595
        );
3596
        break;
3597
3598
        
3599
    /*
3600
    * CASE
3601
    * Display OTP of the selected Item
3602
    */
3603
    case 'show_opt_code':
3604
        // Check KEY and rights
3605
        if ($inputData['key'] !== $session->get('key')) {
3606
            echo (string) prepareExchangedData(
3607
                array(
3608
                    'error' => true,
3609
                    'message' => $lang->get('key_is_not_correct'),
3610
                ),
3611
                'encode'
3612
            );
3613
            break;
3614
        }
3615
        if ($session->get('user-read_only') === 1) {
3616
            echo (string) prepareExchangedData(
3617
                array(
3618
                    'error' => true,
3619
                    'message' => $lang->get('error_not_allowed_to'),
3620
                ),
3621
                'encode'
3622
            );
3623
            break;
3624
        }
3625
3626
        // Load item data
3627
        $dataItem = DB::queryFirstRow(
3628
            'SELECT secret, enabled
3629
            FROM ' . prefixTable('items_otp') . '
3630
            WHERE item_id = %i',
3631
            $inputData['id']
3632
        );
3633
3634
        if (DB::count() > 0) {
3635
            // OTP exists then display it
3636
            $secret = cryption(
3637
                $dataItem['secret'],
3638
                '',
3639
                'decrypt'
3640
            )['string'];
3641
        }
3642
        
3643
        // Generate OTP code
3644
        if (empty($secret) === false) {
3645
            try {
3646
                $otp = TOTP::createFromSecret($secret);
3647
                $otpCode = $otp->now();
3648
                $otpExpiresIn = $otp->expiresIn();
3649
            } catch (RuntimeException $e) {
3650
                $error = true;
3651
                $otpCode = '';
3652
                $otpExpiresIn = '';
3653
                $message = $e->getMessage();
3654
            }
3655
        } else {
3656
            $otpCode = '';
3657
            $otpExpiresIn = '';
3658
        }
3659
        
3660
        // deepcode ignore ServerLeak: Data is encrypted before being sent
3661
        echo (string) prepareExchangedData(
3662
            array(
3663
                'error' => isset($error) === true ? $error : false,
3664
                'message' => isset($message) === true ? $message : '',
3665
                'otp_code' => $otpCode,
3666
                'otp_expires_in' => $otpExpiresIn,
3667
                'otp_enabled' => $dataItem['enabled'],
3668
            ),
3669
            'encode'
3670
        );
3671
        break;
3672
3673
        /*
3674
    * CASE
3675
    * Update a Group
3676
    */
3677
    case 'update_folder':
3678
        // Check KEY and rights
3679
        if ($inputData['key'] !== $session->get('key')) {
3680
            echo (string) prepareExchangedData(
3681
                array(
3682
                    'error' => true,
3683
                    'message' => $lang->get('key_is_not_correct'),
3684
                ),
3685
                'encode'
3686
            );
3687
            break;
3688
        }
3689
        if ($session->get('user-read_only') === 1) {
3690
            echo (string) prepareExchangedData(
3691
                array(
3692
                    'error' => true,
3693
                    'message' => $lang->get('error_not_allowed_to'),
3694
                ),
3695
                'encode'
3696
            );
3697
            break;
3698
        }
3699
        // decrypt and retreive data in JSON format
3700
        $dataReceived = prepareExchangedData(
3701
            $inputData['data'],
3702
            'decode'
3703
        );
3704
3705
        // Prepare variables
3706
        $title = filter_var(htmlspecialchars_decode($dataReceived['title'], ENT_QUOTES), FILTER_SANITIZE_FULL_SPECIAL_CHARS);
3707
        $inputData['folderId'] = filter_var(htmlspecialchars_decode($dataReceived['folder']), FILTER_SANITIZE_NUMBER_INT);
3708
3709
        // Check if user is allowed to access this folder
3710
        if (!in_array($inputData['folderId'], $session->get('user-accessible_folders'))) {
3711
            echo '[{"error" : "' . $lang->get('error_not_allowed_to') . '"}]';
3712
            break;
3713
        }
3714
3715
        // Check if title doesn't contains html codes
3716
        if (preg_match_all('|<[^>]+>(.*)</[^>]+>|U', $title, $out)) {
3717
            echo '[ { "error" : "' . $lang->get('error_html_codes') . '" } ]';
3718
            break;
3719
        }
3720
        // check that title is not numeric
3721
        if (is_numeric($title) === true) {
3722
            echo '[{"error" : "ERR_TITLE_ONLY_WITH_NUMBERS"}]';
3723
            break;
3724
        }
3725
3726
        // Check if duplicate folders name are allowed
3727
        if (isset($SETTINGS['duplicate_folder']) && $SETTINGS['duplicate_folder'] === '0') {
3728
            $data = DB::queryFirstRow('SELECT id, title FROM ' . prefixTable('nested_tree') . ' WHERE title = %s', $title);
3729
            if (empty($data['id']) === false && $dataReceived['folder'] !== $data['id']) {
3730
                echo '[ { "error" : "' . $lang->get('error_group_exist') . '" } ]';
3731
                break;
3732
            }
3733
        }
3734
3735
        // query on folder
3736
        $data = DB::queryfirstrow(
3737
            'SELECT parent_id, personal_folder
3738
            FROM ' . prefixTable('nested_tree') . '
3739
            WHERE id = %i',
3740
            $inputData['folderId']
3741
        );
3742
3743
        // check if complexity level is good
3744
        // if manager or admin don't care
3745
        if ($session->get('user-admin') !== 1 && $session->get('user-manager') !== 1 && $data['personal_folder'] === '0') {
3746
            $data = DB::queryfirstrow(
3747
                'SELECT valeur
3748
                FROM ' . prefixTable('misc') . '
3749
                WHERE intitule = %i AND type = %s',
3750
                $data['parent_id'],
3751
                'complex'
3752
            );
3753
            if (intval($dataReceived['complexity']) < intval($data['valeur'])) {
3754
                echo '[ { "error" : "' . $lang->get('error_folder_complexity_lower_than_top_folder') . ' [<b>' . TP_PW_COMPLEXITY[$data['valeur']][1] . '</b>]"} ]';
3755
                break;
3756
            }
3757
        }
3758
3759
        // update Folders table
3760
        $tmp = DB::queryFirstRow(
3761
            'SELECT title, parent_id, personal_folder FROM ' . prefixTable('nested_tree') . ' WHERE id = %i',
3762
            $dataReceived['folder']
3763
        );
3764
        if ($tmp['parent_id'] !== 0 || $tmp['title'] !== $session->get('user-id') || $tmp['personal_folder'] !== 1) {
3765
            DB::update(
3766
                prefixTable('nested_tree'),
3767
                array(
3768
                    'title' => $title,
3769
                ),
3770
                'id=%s',
3771
                $inputData['folderId']
3772
            );
3773
            // update complixity value
3774
            DB::update(
3775
                prefixTable('misc'),
3776
                array(
3777
                    'valeur' => $dataReceived['complexity'],
3778
                    'updated_at' => time(),
3779
                ),
3780
                'intitule = %s AND type = %s',
3781
                $inputData['folderId'],
3782
                'complex'
3783
            );
3784
            // rebuild fuild tree folder
3785
            $tree->rebuild();
3786
        }
3787
        // send data
3788
        echo '[{"error" : ""}]';
3789
        break;
3790
3791
        /*
3792
    * CASE
3793
    * Move a Group including sub-folders
3794
    */
3795
    case 'move_folder':
3796
        // Check KEY and rights
3797
        if ($inputData['key'] !== $session->get('key')) {
3798
            echo (string) prepareExchangedData(
3799
                array(
3800
                    'error' => true,
3801
                    'message' => $lang->get('key_is_not_correct'),
3802
                ),
3803
                'encode'
3804
            );
3805
            break;
3806
        }
3807
        if ($session->get('user-read_only') === 1) {
3808
            echo (string) prepareExchangedData(
3809
                array(
3810
                    'error' => true,
3811
                    'message' => $lang->get('error_not_allowed_to'),
3812
                ),
3813
                'encode'
3814
            );
3815
            break;
3816
        }
3817
        // decrypt and retreive data in JSON format
3818
        $dataReceived = prepareExchangedData(
3819
            $inputData['data'],
3820
            'decode'
3821
        );
3822
        $post_source_folder_id = filter_var(htmlspecialchars_decode($dataReceived['source_folder_id']), FILTER_SANITIZE_NUMBER_INT);
3823
        $post_target_folder_id = filter_var(htmlspecialchars_decode($dataReceived['target_folder_id']), FILTER_SANITIZE_NUMBER_INT);
3824
3825
        // Check that user can access this folder
3826
        if ((in_array($post_source_folder_id, $session->get('user-accessible_folders')) === false ||
3827
                in_array($post_target_folder_id, $session->get('user-accessible_folders')) === false) && ($post_target_folder_id === '0' &&
3828
                isset($SETTINGS['can_create_root_folder']) === true && (int) $SETTINGS['can_create_root_folder'] === 1)
3829
        ) {
3830
            $returnValues = '[{"error" : "' . $lang->get('error_not_allowed_to') . '"}]';
3831
            echo $returnValues;
3832
            break;
3833
        }
3834
3835
        $tmp_source = DB::queryFirstRow(
3836
            'SELECT title, parent_id, personal_folder
3837
            FROM ' . prefixTable('nested_tree') . '
3838
            WHERE id = %i',
3839
            $post_source_folder_id
3840
        );
3841
3842
        $tmp_target = DB::queryFirstRow(
3843
            'SELECT title, parent_id, personal_folder
3844
            FROM ' . prefixTable('nested_tree') . '
3845
            WHERE id = %i',
3846
            $post_target_folder_id
3847
        );
3848
3849
        // check if target is not a child of source
3850
        if ($tree->isChildOf($post_target_folder_id, $post_source_folder_id) === true) {
3851
            $returnValues = '[{"error" : "' . $lang->get('error_not_allowed_to') . '"}]';
3852
            echo $returnValues;
3853
            break;
3854
        }
3855
3856
        // check if source or target folder is PF. If Yes, then cancel operation
3857
        if ((int) $tmp_source['personal_folder'] === 1 || (int) $tmp_target['personal_folder'] === 1) {
3858
            $returnValues = '[{"error" : "' . $lang->get('error_not_allowed_to') . '"}]';
3859
            echo $returnValues;
3860
            break;
3861
        }
3862
3863
        // check if source or target folder is PF. If Yes, then cancel operation
3864
        if ($tmp_source['title'] === $session->get('user-id') || $tmp_target['title'] === $session->get('user-id')) {
3865
            $returnValues = '[{"error" : "' . $lang->get('error_not_allowed_to') . '"}]';
3866
            echo $returnValues;
3867
            break;
3868
        }
3869
3870
        // moving SOURCE folder
3871
        DB::update(
3872
            prefixTable('nested_tree'),
3873
            array(
3874
                'parent_id' => $post_target_folder_id,
3875
            ),
3876
            'id=%s',
3877
            $post_source_folder_id
3878
        );
3879
        $tree->rebuild();
3880
3881
        // send data
3882
        echo '[{"error" : ""}]';
3883
        break;
3884
3885
        /*
3886
    * CASE
3887
    * Store hierarchic position of Group
3888
    */
3889
    case 'save_position':
3890
        DB::update(
3891
            prefixTable('nested_tree'),
3892
            array(
3893
                'parent_id' => $inputData['destination'],
3894
            ),
3895
            'id = %i',
3896
            $inputData['source']
3897
        );
3898
        $tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
3899
        $tree->rebuild();
3900
        break;
3901
3902
        /*
3903
    * CASE
3904
    * List items of a group
3905
    */
3906
    case 'do_items_list_in_folder':
3907
        // Check KEY and rights
3908
        if ($inputData['key'] !== $session->get('key')) {
3909
            echo (string) prepareExchangedData(
3910
                array(
3911
                    'error' => true,
3912
                    'message' => $lang->get('error_not_allowed_to')." BOOH 1",
3913
                ),
3914
                'encode'
3915
            );
3916
            break;
3917
        }
3918
3919
        if (count($session->get('user-roles_array')) === 0) {
3920
            echo (string) prepareExchangedData(
3921
                array(
3922
                    'error' => true,
3923
                    'message' => $lang->get('error_not_allowed_to')." BOOH 2",
3924
                ),
3925
                'encode'
3926
            );
3927
            break;
3928
        }
3929
3930
        // decrypt and retreive data in JSON format
3931
        $dataReceived = prepareExchangedData(
3932
            $inputData['data'],
3933
            'decode'
3934
        );
3935
3936
        if (is_array($dataReceived) === true && array_key_exists('id', $dataReceived) === false) {
3937
            echo (string) prepareExchangedData(
3938
                array(
3939
                    'error' => true,
3940
                    'message' => $lang->get('error_unknown'),
3941
                ),
3942
                'encode'
3943
            );
3944
            break;
3945
        }
3946
3947
        // Prepare POST variables
3948
        $inputData['id'] = filter_var($dataReceived['id'], FILTER_SANITIZE_NUMBER_INT);
3949
        $post_restricted = filter_var($dataReceived['restricted'], FILTER_SANITIZE_NUMBER_INT);
3950
        $post_start = filter_var($dataReceived['start'], FILTER_SANITIZE_NUMBER_INT);
3951
        $post_nb_items_to_display_once = filter_var($dataReceived['nb_items_to_display_once'], FILTER_SANITIZE_NUMBER_INT);
3952
3953
        $arr_arbo = [];
3954
        $folderIsPf = in_array($inputData['id'], $session->get('user-personal_folders')) === true ? true : false;
3955
        $showError = 0;
3956
        $itemsIDList = $rights = $returnedData = $uniqueLoadData = $html_json = array();
3957
        // Build query limits
3958
        if (empty($post_start) === true) {
3959
            $start = 0;
3960
        } else {
3961
            $start = $post_start;
3962
        }
3963
3964
        // to do only on 1st iteration
3965
        if ((int) $start === 0) {
3966
            // Prepare tree
3967
            $arbo = $tree->getPath($inputData['id'], true);
3968
            foreach ($arbo as $elem) {
3969
                // Personnal folder
3970
                if ((int) $elem->title === (int) $session->get('user-id') && (int) $elem->nlevel === 1) {
3971
                    $elem->title = $session->get('user-login');
3972
                }
3973
                // Store path elements
3974
                array_push(
3975
                    $arr_arbo,
3976
                    array(
3977
                        'id' => $elem->id,
3978
                        'title' => htmlspecialchars(stripslashes(htmlspecialchars_decode($elem->title, ENT_QUOTES)), ENT_QUOTES),
3979
                        'visible' => in_array($elem->id, $session->get('user-accessible_folders')) ? 1 : 0,
3980
                    )
3981
                );
3982
            }
3983
            $uniqueLoadData['path'] = $arr_arbo;
3984
3985
            // store last folder accessed in cookie
3986
            $arr_cookie_options = array (
3987
                'expires' => time() + TP_ONE_DAY_SECONDS * 5,
3988
                'path' => '/', 
3989
                'secure' => true,
3990
                'httponly' => true,
3991
                'samesite' => 'Lax' // None || Lax  || Strict
3992
            );
3993
            // deepcode ignore WebCookieSecureDisabledByDefault: defined in $arr_cookie_options, deepcode ignore WebCookieHttpOnlyDisabledByDefault: defined in $arr_cookie_options
3994
            setcookie('jstree_select', $inputData['id'], $arr_cookie_options);
3995
3996
            // CHeck if roles have 'allow_pw_change' set to true
3997
            $forceItemEditPrivilege = false;
3998
            foreach ($session->get('user-roles_array') as $role) {
3999
                $roleQ = DB::queryfirstrow(
4000
                    'SELECT allow_pw_change
4001
                    FROM ' . prefixTable('roles_title') . '
4002
                    WHERE id = %i',
4003
                    $role
4004
                );
4005
                if ((int) $roleQ['allow_pw_change'] === 1) {
4006
                    $forceItemEditPrivilege = true;
4007
                    break;
4008
                }
4009
            }
4010
4011
            // is this folder a personal one
4012
            $folder_is_personal = in_array($inputData['id'], $session->get('user-personal_folders'));
4013
            $uniqueLoadData['folder_is_personal'] = $folder_is_personal;
4014
4015
            $folder_is_in_personal = in_array(
4016
                $inputData['id'],
4017
                array_merge(
4018
                    $session->get('user-personal_visible_folders'),
4019
                    $session->get('user-personal_folders')
4020
                )
4021
            );
4022
            $uniqueLoadData['folder_is_in_personal'] = $folder_is_in_personal;
4023
4024
4025
            // check role access on this folder (get the most restrictive) (2.1.23)
4026
            if ((int) $folder_is_personal === 0) {
4027
                $accessLevel = 20;
4028
                $arrTmp = [];
4029
                
4030
                foreach ($session->get('user-roles_array') as $role) {
4031
                    $access = DB::queryFirstRow(
4032
                        'SELECT type FROM ' . prefixTable('roles_values') . ' WHERE role_id = %i AND folder_id = %i',
4033
                        $role,
4034
                        $inputData['id']
4035
                    );
4036
                    if (DB::count()>0) {
4037
                        if ($access['type'] === 'R') {
4038
                            array_push($arrTmp, 10);
4039
                        } elseif ($access['type'] === 'W') {
4040
                            array_push($arrTmp, 30);
4041
                        } elseif (
4042
                            $access['type'] === 'ND'
4043
                            || ($forceItemEditPrivilege === true && $access['type'] === 'NDNE')
4044
                        ) {
4045
                            array_push($arrTmp, 20);
4046
                        } elseif ($access['type'] === 'NE') {
4047
                            array_push($arrTmp, 10);
4048
                        } elseif ($access['type'] === 'NDNE') {
4049
                            array_push($arrTmp, 15);
4050
                        } else {
4051
                            // Ensure to give access Right if allowed folder
4052
                            if (in_array($inputData['id'], $session->get('user-accessible_folders')) === true) {
4053
                                array_push($arrTmp, 30);
4054
                            } else {
4055
                                array_push($arrTmp, 0);
4056
                            }
4057
                        }
4058
                    } else {
4059
                        // Ensure to give access Right if allowed folder
4060
                        if (in_array($inputData['id'], $session->get('user-accessible_folders')) === true) {
4061
                            array_push($arrTmp, 50);
4062
                        } else {
4063
                            array_push($arrTmp, 0);
4064
                        }
4065
                    }
4066
                }
4067
                // 3.0.0.0 - changed  MIN to MAX
4068
                $accessLevel = count($arrTmp) > 0 ? max($arrTmp) : $accessLevel;
4069
            } else {
4070
                $accessLevel = 30;
4071
            }
4072
            $uniqueLoadData['accessLevel'] = $accessLevel;
4073
            $uniqueLoadData['showError'] = $showError;
4074
4075
            // check if items exist
4076
            $where = new WhereClause('and');
4077
            $session__user_list_folders_limited = $session->get('user-list_folders_limited');
4078
            if (null !== $post_restricted && (int) $post_restricted === 1 && empty($session__user_list_folders_limited[$inputData['id']]) === false) {
4079
                $counter = count($session__user_list_folders_limited[$inputData['id']]);
4080
                $uniqueLoadData['counter'] = $counter;
4081
                // check if this folder is visible
4082
            } elseif (!in_array(
4083
                $inputData['id'],
4084
                array_merge(
4085
                    $session->get('user-accessible_folders'),
4086
                    array_keys($session->get('system-list_restricted_folders_for_items')),
4087
                    array_keys($session->get('user-list_folders_limited'))
4088
                )
4089
            )) {
4090
                echo (string) prepareExchangedData(
4091
                    array(
4092
                        'error' => 'not_authorized',
4093
                        'arborescence' => $arr_arbo,
4094
                    ),
4095
                    'encode'
4096
                );
4097
                break;
4098
            } else {
4099
                DB::query(
4100
                    'SELECT *
4101
                    FROM ' . prefixTable('items') . '
4102
                    WHERE inactif = %i',
4103
                    0
4104
                );
4105
                $counter = DB::count();
4106
                $uniqueLoadData['counter'] = $counter;
4107
            }
4108
4109
            // Get folder complexity
4110
            $folderComplexity = DB::queryFirstRow(
4111
                'SELECT valeur FROM ' . prefixTable('misc') . ' WHERE type = %s AND intitule = %i',
4112
                'complex',
4113
                $inputData['id']
4114
            );
4115
            $folderComplexity = $folderComplexity !== null ? (int) $folderComplexity['valeur'] : 0;
4116
            $uniqueLoadData['folderComplexity'] = $folderComplexity;
4117
4118
            // Has this folder some categories to be displayed?
4119
            $categoriesStructure = array();
4120
            if (isset($SETTINGS['item_extra_fields']) && (int) $SETTINGS['item_extra_fields'] === 1) {
4121
                $folderRow = DB::query(
4122
                    'SELECT id_category
4123
                    FROM ' . prefixTable('categories_folders') . '
4124
                    WHERE id_folder = %i',
4125
                    $inputData['id']
4126
                );
4127
                foreach ($folderRow as $category) {
4128
                    array_push(
4129
                        $categoriesStructure,
4130
                        $category['id_category']
4131
                    );
4132
                }
4133
            }
4134
            $uniqueLoadData['categoriesStructure'] = $categoriesStructure;
4135
4136
            /*$categoriesStructure = array();
4137
            if (isset($SETTINGS['item_extra_fields']) && (int) $SETTINGS['item_extra_fields'] === 1) {
4138
                $folderRow = DB::query(
4139
                    'SELECT f.id_category, c.title AS title
4140
                    FROM '.prefixTable('categories_folders').' AS f
4141
                    INNER JOIN '.prefixTable('categories').' AS c ON (c.id = f.id_category)
4142
                    WHERE f.id_folder = %i',
4143
                    $inputData['id']
4144
                );
4145
                foreach ($folderRow as $category) {
4146
                    $arrFields = array();
4147
                    // Get each category definition with fields
4148
                    $categoryRow = DB::query(
4149
                        "SELECT *
4150
                        FROM ".prefixTable("categories")."
4151
                        WHERE parent_id=%i
4152
                        ORDER BY `order` ASC",
4153
                        $category['id_category']
4154
                    );
4155
4156
                    if (DB::count() > 0) {
4157
                        foreach ($categoryRow as $field) {
4158
                            // Is this Field visibile by user?
4159
                            if ($field['role_visibility'] === 'all'
4160
                                || count(
4161
                                    array_intersect(
4162
                                        explode(';', $session->get('user-roles')),
4163
                                        explode(',', $field['role_visibility'])
4164
                                    )
4165
                                ) > 0
4166
                            ) {
4167
                                array_push(
4168
                                    $arrFields,
4169
                                    array(
4170
                                        $field['id'],
4171
                                        $field['title'],
4172
                                        $field['encrypted_data'],
4173
                                        $field['type'],
4174
                                        $field['masked'],
4175
                                        $field['is_mandatory']
4176
                                    )
4177
                                );
4178
                            }
4179
                        }
4180
                    }
4181
4182
                    // store the categories
4183
                    array_push(
4184
                        $categoriesStructure,
4185
                        array(
4186
                            $category['id_category'],
4187
                            $category['title'],
4188
                            $arrFields
4189
                        )
4190
                    );
4191
                }
4192
            }
4193
            $uniqueLoadData['categoriesStructure'] = $categoriesStructure;
4194
            */
4195
4196
            if ($session->has('system-list_folders_editable_by_role') && $session->has('system-list_folders_editable_by_role') && null !== $session->get('system-list_folders_editable_by_role')) {
4197
                $list_folders_editable_by_role = in_array($inputData['id'], $session->get('system-list_folders_editable_by_role'));
4198
            } else {
4199
                $list_folders_editable_by_role = '';
4200
            }
4201
            $uniqueLoadData['list_folders_editable_by_role'] = $list_folders_editable_by_role;
4202
        } else {
4203
            $uniqueLoadData = json_decode(
4204
                filter_var($dataReceived['uniqueLoadData'], FILTER_UNSAFE_RAW),
4205
                true
4206
            );
4207
4208
            // initialize main variables
4209
            $showError = $uniqueLoadData['showError'];
4210
            $accessLevel = $uniqueLoadData['accessLevel'];
4211
            $counter = $uniqueLoadData['counter'];
4212
            $counter_full = $uniqueLoadData['counter_full'];
4213
            $categoriesStructure = $uniqueLoadData['categoriesStructure'];
4214
            $folderComplexity = $uniqueLoadData['folderComplexity'];
4215
            $folder_is_personal = $uniqueLoadData['folder_is_personal'];
4216
            $folder_is_in_personal = $uniqueLoadData['folder_is_in_personal'];
4217
            //$list_folders_editable_by_role = $uniqueLoadData['list_folders_editable_by_role'];
4218
        }
4219
        
4220
        // prepare query WHere conditions
4221
        $where = new WhereClause('and');
4222
        $session__user_list_folders_limited = $session->get('user-list_folders_limited');
4223
        if (null !== $post_restricted && (int) $post_restricted === 1 && empty($session__user_list_folders_limited[$inputData['id']]) === false) {
4224
            $where->add('i.id IN %ls', $session__user_list_folders_limited[$inputData['id']]);
4225
        } else {
4226
            $where->add('i.id_tree=%i', $inputData['id']);
4227
        }
4228
4229
        // build the HTML for this set of Items
4230
        if ($counter > 0 && empty($showError)) {
4231
            // init variables
4232
            $expired_item = false;
4233
            $limited_to_items = '';
4234
4235
            // List all ITEMS
4236
            if ($folderIsPf === false) {
4237
                $where->add('i.inactif=%i', 0);
4238
                $sql_e='(SELECT date FROM ' . prefixTable('log_items') 
4239
                    . " WHERE action = 'at_creation' AND id_item=i.id " 
4240
                    . 'union all SELECT date FROM '. prefixTable('log_items') 
4241
                    . " WHERE action = 'at_modification' AND raison = 'at_pw'
4242
                    AND id_item=i.id ORDER BY date DESC LIMIT 1)";
4243
                $where->add('l.date=%l', $sql_e);
4244
                if (empty($limited_to_items) === false) {
4245
                    $where->add('i.id IN %ls', explode(',', $limited_to_items));
4246
                }
4247
4248
                $query_limit = ' LIMIT ' .
4249
                    $start . ',' .
4250
                    $post_nb_items_to_display_once;
4251
                //db::debugmode(true);
4252
                $rows = DB::query(
4253
                    'SELECT i.id AS id, i.item_key AS item_key, MIN(i.restricted_to) AS restricted_to, MIN(i.perso) AS perso,
4254
                    MIN(i.label) AS label, MIN(i.description) AS description, MIN(i.pw) AS pw, MIN(i.login) AS login,
4255
                    MIN(i.anyone_can_modify) AS anyone_can_modify, l.date AS date, i.id_tree AS tree_id, i.fa_icon AS fa_icon,
4256
                    MIN(n.renewal_period) AS renewal_period,
4257
                    MIN(l.action) AS log_action,
4258
                    l.id_user AS log_user,
4259
                    i.url AS link,
4260
                    i.email AS email
4261
                    FROM ' . prefixTable('items') . ' AS i
4262
                    INNER JOIN ' . prefixTable('nested_tree') . ' AS n ON (i.id_tree = n.id)
4263
                    INNER JOIN ' . prefixTable('log_items') . ' AS l ON (i.id = l.id_item)
4264
                    WHERE %l
4265
                    GROUP BY i.id, l.date, l.id_user, l.action
4266
                    ORDER BY i.label ASC, l.date DESC' . $query_limit,
4267
                    $where
4268
                );
4269
                //db::debugmode(false);
4270
            } else {
4271
                $post_nb_items_to_display_once = 'max';
4272
                $where->add('i.inactif=%i', 0);
4273
4274
                $rows = DB::query(
4275
                    'SELECT i.id AS id, i.item_key AS item_key, MIN(i.restricted_to) AS restricted_to, MIN(i.perso) AS perso,
4276
                    MIN(i.label) AS label, MIN(i.description) AS description, MIN(i.pw) AS pw, MIN(i.login) AS login,
4277
                    MIN(i.anyone_can_modify) AS anyone_can_modify,l.date AS date, i.id_tree AS tree_id, i.fa_icon AS fa_icon,
4278
                    MIN(n.renewal_period) AS renewal_period,
4279
                    MIN(l.action) AS log_action,
4280
                    l.id_user AS log_user,
4281
                    i.url AS link,
4282
                    i.email AS email
4283
                    FROM ' . prefixTable('items') . ' AS i
4284
                    INNER JOIN ' . prefixTable('nested_tree') . ' AS n ON (i.id_tree = n.id)
4285
                    INNER JOIN ' . prefixTable('log_items') . ' AS l ON (i.id = l.id_item)
4286
                    WHERE %l
4287
                    GROUP BY i.id, l.date, l.id_user, l.action
4288
                    ORDER BY i.label ASC, l.date DESC',
4289
                    $where
4290
                );
4291
            }
4292
4293
            $idManaged = '';
4294
4295
            foreach ($rows as $record) {
4296
                // exclude all results except the first one returned by query
4297
                if (empty($idManaged) === true || $idManaged !== $record['id']) {
4298
                    // Fix a bug on Personal Item creation - field `perso` must be set to `1`
4299
                    if ((int) $record['perso'] !== 1 && (int) $folder_is_personal === 1) {
4300
                        DB::update(
4301
                            prefixTable('items'),
4302
                            array(
4303
                                'perso' => 1,
4304
                                'updated_at' => time(),
4305
                            ),
4306
                            'id=%i',
4307
                            $record['id']
4308
                        );
4309
                        $record['perso'] = 1;
4310
                    }
4311
4312
                    // Does this item has restriction to groups of users?
4313
                    $item_is_restricted_to_role = false;
4314
                    DB::queryfirstrow(
4315
                        'SELECT role_id
4316
                        FROM ' . prefixTable('restriction_to_roles') . '
4317
                        WHERE item_id = %i',
4318
                        $record['id']
4319
                    );
4320
                    if (DB::count() > 0) {
4321
                        $item_is_restricted_to_role = true;
4322
                    }
4323
4324
                    // Has this item a restriction to Groups of Users
4325
                    $user_is_included_in_role = false;
4326
                    DB::query(
4327
                        'SELECT role_id
4328
                        FROM ' . prefixTable('restriction_to_roles') . '
4329
                        WHERE item_id = %i AND role_id IN %ls',
4330
                        $record['id'],
4331
                        $session->get('user-roles_array')
4332
                    );
4333
                    if (DB::count() > 0) {
4334
                        $user_is_included_in_role = true;
4335
                    }
4336
4337
                    // Is user in restricted list of users
4338
                    if (empty($record['restricted_to']) === false) {
4339
                        if (
4340
                            in_array($session->get('user-id'), explode(';', $record['restricted_to'])) === true
4341
                            || (((int) $session->get('user-manager') === 1 || (int) $session->get('user-can_manage_all_users') === 1)
4342
                                && (int) $SETTINGS['manager_edit'] === 1)
4343
                        ) {
4344
                            $user_is_in_restricted_list = true;
4345
                        } else {
4346
                            $user_is_in_restricted_list = false;
4347
                        }
4348
                    } else {
4349
                        $user_is_in_restricted_list = false;
4350
                    }
4351
4352
                    // Get Expiration date
4353
                    $expired_item = 0;
4354
                    if (
4355
                        (int) $SETTINGS['activate_expiration'] === 1
4356
                        && $record['renewal_period'] > 0
4357
                        && ($record['date'] + ($record['renewal_period'] * TP_ONE_MONTH_SECONDS)) < time()
4358
                    ) {
4359
                        $expired_item = 1;
4360
                    }
4361
                    // Init
4362
                    $html_json[$record['id']]['expired'] = (int) $expired_item;
4363
                    $html_json[$record['id']]['item_id'] = (int) $record['id'];
4364
                    $html_json[$record['id']]['item_key'] = (string) $record['item_key'];
4365
                    $html_json[$record['id']]['tree_id'] = (int) $record['tree_id'];
4366
                    $html_json[$record['id']]['label'] = strip_tags($record['label']);
4367
                    if (isset($SETTINGS['show_description']) === true && (int) $SETTINGS['show_description'] === 1 && is_null($record['description']) === false && empty($record['description']) === false) {
4368
                        $html_json[$record['id']]['desc'] = mb_substr(preg_replace('#<[^>]+>#', ' ', $record['description']), 0, 200);
4369
                    } else {
4370
                        $html_json[$record['id']]['desc'] = '';
4371
                    }
4372
                    $html_json[$record['id']]['login'] = $record['login'];
4373
                    $html_json[$record['id']]['anyone_can_modify'] = (int) $record['anyone_can_modify'];
4374
                    $html_json[$record['id']]['is_result_of_search'] = 0;
4375
                    $html_json[$record['id']]['is_favourited'] = in_array($record['id'], $session->get('user-favorites')) === true ? 1 : 0;
4376
                    $html_json[$record['id']]['link'] = $record['link'];
4377
                    $html_json[$record['id']]['email'] = $record['email'] ?? '';
4378
                    $html_json[$record['id']]['fa_icon'] = $record['fa_icon'];
4379
4380
                    // Possible values:
4381
                    // 0 -> no access to item
4382
                    // 10 -> appears in list but no view
4383
                    // 20 -> can view without edit (no copy) or move
4384
                    // 30 -> can view without edit (no copy) but can move
4385
                    // 40 -> can edit but not move
4386
                    // 50 -> can edit and move
4387
                    $itemIsPersonal = false;
4388
4389
                    // Let's identify the rights belonging to this ITEM
4390
                    if (
4391
                        (int) $record['perso'] === 1
4392
                        && $record['log_action'] === 'at_creation'
4393
                        && $record['log_user'] === $session->get('user-id')
4394
                        && (int) $folder_is_in_personal === 1
4395
                        && (int) $folder_is_personal === 1
4396
                    ) {
4397
                        // Case 1 - Is this item personal and user its owner?
4398
                        // If yes then allow
4399
                        // If no then continue
4400
                        $itemIsPersonal = true;
4401
                        $right = 70;
4402
                        // ---
4403
                        // ----- END CASE 1 -----
4404
                    } elseif ((($session->has('user-manager') && (int) $session->get('user-manager') && $session->has('user-manager') && (int) $session->get('user-manager') && null !== $session->get('user-manager') && (int) $session->get('user-manager') === 1)
4405
                            || ($session->has('user-can_manage_all_users') && (int) $session->get('user-can_manage_all_users') && $session->has('user-can_manage_all_users') && (int) $session->get('user-can_manage_all_users') && null !== $session->get('user-can_manage_all_users') && (int) $session->get('user-can_manage_all_users') === 1))
4406
                        && (isset($SETTINGS['manager_edit']) === true && (int) $SETTINGS['manager_edit'] === 1)
4407
                        && (int) $record['perso'] !== 1
4408
                        && $user_is_in_restricted_list === true
4409
                    ) {
4410
                        // Case 2 - Is user manager and option "manager_edit" set to true?
4411
                        // Allow all rights
4412
                        $right = 70;
4413
                        // ---
4414
                        // ----- END CASE 2 -----
4415
                    } elseif (
4416
                        (int) $record['anyone_can_modify'] === 1
4417
                        && (int) $record['perso'] !== 1
4418
                        && (int) $session->get('user-read_only') === 0
4419
                    ) {
4420
                        // Case 3 - Has this item the setting "anyone can modify" set to true?
4421
                        // Allow all rights
4422
                        $right = 70;
4423
                        // ---
4424
                        // ----- END CASE 3 -----
4425
                    } elseif (
4426
                        $user_is_in_restricted_list === true
4427
                        && (int) $record['perso'] !== 1
4428
                        && (int) $session->get('user-read_only') === 0
4429
                    ) {
4430
                        // Case 4 - Is this item limited to Users? Is current user in this list?
4431
                        // Allow all rights
4432
                        $right = 70;
4433
                        // ---
4434
                        // ----- END CASE 4 -----
4435
                    } elseif (
4436
                        $user_is_included_in_role === true
4437
                        && (int) $record['perso'] !== 1
4438
                        && (int) $session->get('user-read_only') === 0
4439
                    ) {
4440
                        // Case 5 - Is this item limited to group of users? Is current user in one of those groups?
4441
                        // Allow all rights
4442
                        $right = 60;
4443
                        // ---
4444
                        // ----- END CASE 5 -----
4445
                    } elseif (
4446
                        (int) $record['perso'] !== 1
4447
                        && (int) $session->get('user-read_only') === 1
4448
                    ) {
4449
                        // Case 6 - Is user readonly?
4450
                        // Allow limited rights
4451
                        $right = 10;
4452
                        // ---
4453
                        // ----- END CASE 6 -----
4454
                    } elseif (
4455
                        (int) $record['perso'] !== 1
4456
                        && in_array($record['tree_id'], $session->get('user-allowed_folders_by_definition'))
4457
                    ) {
4458
                        // Case 7 - Is folder allowed by definition for this user?
4459
                        // Allow limited rights
4460
                        $right = 70;
4461
                        // ---
4462
                        // ----- END CASE 7 -----
4463
                    } elseif (
4464
                        (int) $record['perso'] !== 1
4465
                        && (int) $session->get('user-read_only') === 1
4466
                    ) {
4467
                        // Case 8 - Is user allowed to access?
4468
                        // Allow rights
4469
                        $right = 10;
4470
                        // ---
4471
                        // ----- END CASE 8 -----
4472
                    } elseif (($user_is_included_in_role === false && $item_is_restricted_to_role === true)
4473
                        && (int) $record['perso'] !== 1
4474
                        && (int) $session->get('user-read_only') === 0
4475
                    ) {
4476
                        // Case 9 - Is this item limited to Users or Groups? Is current user in this list?
4477
                        // If no then Allow none
4478
                        $right = 10;
4479
                        // ---
4480
                        // ----- END CASE 9 -----
4481
                    } else {
4482
                        // Define the access based upon setting on folder
4483
                        // 0 -> no access to item
4484
                        // 10 -> appears in list but no view
4485
                        // 20 -> can view without edit (no copy) or move or delete
4486
                        // 30 -> can view without edit (no copy) or delete but can move
4487
                        // 40 -> can edit but not move and not delete
4488
                        // 50 -> can edit and delete but not move
4489
                        // 60 -> can edit and move but not delete
4490
                        // 70 -> can edit and move
4491
                        if ((int) $accessLevel === 0) {
4492
                            $right = 0;
4493
                        } elseif ((10 <= (int) $accessLevel) && ((int) $accessLevel < 20)) {
4494
                            $right = 20;
4495
                        } elseif ((20 <= (int) $accessLevel) && ((int) $accessLevel < 30)) {
4496
                            $right = 60;
4497
                        } elseif ((int) $accessLevel === 30) {
4498
                            $right = 70;
4499
                        } else {
4500
                            $right = 10;
4501
                        }
4502
                    }
4503
4504
                    // Now finalize the data to send back
4505
                    $html_json[$record['id']]['rights'] = $right;
4506
                    $html_json[$record['id']]['perso'] = 'fa-tag mi-red';
4507
                    $html_json[$record['id']]['sk'] = $itemIsPersonal === true ? 1 : 0;
4508
                    $html_json[$record['id']]['display'] = $right > 0 ? 1 : 0;
4509
                    $html_json[$record['id']]['open_edit'] = in_array($right, array(40, 50, 60, 70)) === true ? 1 : 0;
4510
                    $html_json[$record['id']]['canMove'] = in_array($right, array(30, 60, 70)) === true ? 1 : 0;
4511
4512
                    //*************** */
4513
4514
                    // Build array with items
4515
                    array_push(
4516
                        $itemsIDList,
4517
                        array(
4518
                            'id' => (int) $record['id'],
4519
                            //'display' => $displayItem,
4520
                            'edit' => $html_json[$record['id']]['open_edit'],
4521
                        )
4522
                    );
4523
                }
4524
                $idManaged = $record['id'];
4525
            }
4526
4527
            $rights = recupDroitCreationSansComplexite($inputData['id']);
4528
        }
4529
4530
        // DELETE - 2.1.19 - AND (l.action = 'at_creation' OR (l.action = 'at_modification' AND l.raison LIKE 'at_pw :%'))
4531
        // count
4532
        if ((int) $start === 0) {
4533
            DB::query(
4534
                'SELECT i.id
4535
                FROM ' . prefixTable('items') . ' as i
4536
                INNER JOIN ' . prefixTable('nested_tree') . ' as n ON (i.id_tree = n.id)
4537
                INNER JOIN ' . prefixTable('log_items') . ' as l ON (i.id = l.id_item)
4538
                WHERE %l
4539
                ORDER BY i.label ASC, l.date DESC',
4540
                $where
4541
            );
4542
            $counter_full = DB::count();
4543
            $uniqueLoadData['counter_full'] = $counter_full;
4544
        }
4545
4546
        // Check list to be continued status
4547
        if ($post_nb_items_to_display_once !== 'max' && ($post_nb_items_to_display_once + $start) < $counter_full) {
4548
            $listToBeContinued = 'yes';
4549
        } else {
4550
            $listToBeContinued = 'end';
4551
        }
4552
4553
        // Prepare returned values
4554
        $returnValues = array(
4555
            'html_json' => $html_json,
4556
            //'folder_requests_psk' => $findPfGroup,
4557
            'arborescence' => $arr_arbo,
4558
            'array_items' => $itemsIDList,
4559
            'error' => $showError,
4560
            //'saltkey_is_required' => $folderIsPf === true ? 1 : 0,
4561
            'show_clipboard_small_icons' => isset($SETTINGS['copy_to_clipboard_small_icons']) && (int) $SETTINGS['copy_to_clipboard_small_icons'] === 1 ? 1 : 0,
4562
            'next_start' => intval($post_nb_items_to_display_once) + intval($start),
4563
            'list_to_be_continued' => $listToBeContinued,
4564
            'items_count' => $counter,
4565
            'counter_full' => $counter_full,
4566
            'folder_complexity' => (int) $folderComplexity,
4567
            'categoriesStructure' => $categoriesStructure,
4568
            'access_level' => $accessLevel,
4569
            'IsPersonalFolder' => $folderIsPf === true ? 1 : 0,
4570
            'uniqueLoadData' => json_encode($uniqueLoadData),
4571
        );
4572
        // Check if $rights is not null
4573
        if (count($rights) > 0) {
4574
            $returnValues = array_merge($returnValues, $rights);
4575
        }
4576
4577
        // Encrypt data to return
4578
        echo (string) prepareExchangedData(
4579
            $returnValues,
4580
            'encode'
4581
        );
4582
4583
        break;
4584
4585
    case 'show_item_password':
4586
        // Check KEY
4587
        if ($inputData['key'] !== $session->get('key')) {
4588
            echo (string) prepareExchangedData(
4589
                array(
4590
                    'error' => true,
4591
                    'message' => $lang->get('key_is_not_correct'),
4592
                ),
4593
                'encode'
4594
            );
4595
            break;
4596
        }
4597
4598
        // Run query
4599
        $dataItem = DB::queryfirstrow(
4600
            'SELECT i.pw AS pw, s.share_key AS share_key
4601
            FROM ' . prefixTable('items') . ' AS i
4602
            INNER JOIN ' . prefixTable('sharekeys_items') . ' AS s ON (s.object_id = i.id)
4603
            WHERE user_id = %i AND i.item_key = %s',
4604
            $session->get('user-id'),
4605
            $inputData['itemKey']
4606
        );
4607
        
4608
        // Uncrypt PW
4609
        if (DB::count() === 0) {
4610
            // No share key found
4611
            $pw = '';
4612
        } else {
4613
            $pw = doDataDecryption(
4614
                $dataItem['pw'],
4615
                decryptUserObjectKey(
4616
                    $dataItem['share_key'],
4617
                    $session->get('user-private_key')
4618
                )
4619
            );
4620
            
4621
            $log = 'Used user ID: '.$session->get('user-id')."\n";
4622
            $log .= 'Used user Private key: '.$session->get('user-private_key')."\n";
4623
            $log .= '$currentUserKey: '.$dataItem['share_key']."\n";
4624
            $log .= 'itemKey: '.decryptUserObjectKey(
4625
                $dataItem['share_key'],
4626
                $session->get('user-private_key')
4627
            )."\n\n";
4628
        }
4629
4630
        $returnValues = array(
4631
            'error' => false,
4632
            'password' => $pw,
4633
            'password_error' => '',
4634
        );
4635
4636
        // Encrypt data to return
4637
        echo (string) prepareExchangedData(
4638
            $returnValues,
4639
            'encode'
4640
        );
4641
        break;
4642
4643
        /*
4644
    * CASE
4645
    * Get complexity level of a group
4646
    */
4647
    case 'get_complixity_level':
4648
        // get some info about ITEM
4649
        if (null !== $inputData['itemId'] && empty($inputData['itemId']) === false) {
4650
            // get if existing edition lock
4651
            $dataItemEditionLocks = DB::query(
4652
                'SELECT timestamp, user_id
4653
                FROM ' . prefixTable('items_edition') . '
4654
                WHERE item_id = %i 
4655
                ORDER BY increment_id DESC',
4656
                $inputData['itemId']
4657
            );
4658
            
4659
            if (WIP === true) error_log('Existing edition locks: '.DB::count());
4660
4661
            // Check if item has no edition lock
4662
            if ((int) DB::count() > 0 ) {
4663
                // get last edition lock
4664
                $dataLastItemEditionLock = $dataItemEditionLocks[0];
4665
4666
                // Calculate the edition grace delay
4667
                if (isset($SETTINGS['delay_item_edition']) && $SETTINGS['delay_item_edition'] > 0 && empty($dataTmp['timestamp']) === false) {
4668
                    $delay = $SETTINGS['delay_item_edition'];
4669
                } else {
4670
                    $delay = EDITION_LOCK_PERIOD; // One day delay
4671
                }
4672
                if (WIP === true) error_log('delay: ' . $delay);
4673
4674
                // We remove old edition locks if delay is expired meaning more than 1 day long
4675
                if (round(abs(time() - $dataTmp['timestamp']),0) > $delay) {
4676
                    // Case where time is expired
4677
                    // In this case, delete edition lock and possible ongoing processes
4678
                    // and continue editing this time
4679
                    // We coonsidere if the most recent item is still locked then all other locks can be removed
4680
                    if (WIP === true)  error_log('Delay is expired, removing old locks');
4681
                    foreach ($dataItemEditionLocks as $itemEditionLock) {
4682
                        // delete lock
4683
                        DB::delete(
4684
                            prefixTable('items_edition'), 
4685
                            'item_id = %i', 
4686
                            $inputData['itemId']
4687
                        );
4688
4689
                        // Get process Id
4690
                        $processDetail = DB::queryFirstRow(
4691
                            'SELECT increment_id
4692
                            FROM ' . prefixTable('background_tasks') . '
4693
                            WHERE item_id = %i AND finished_at = ""',
4694
                            $inputData['itemId']
4695
                        );
4696
4697
                        // Delete related Task Process
4698
                        if (DB::count() > 0) {
4699
                            deleteProcessAndRelatedTasks((int) $processDetail['increment_id']);
4700
                        }
4701
                    }
4702
                }
4703
4704
                // check if user is currently the one that is editing
4705
                if ((int) $dataItemEditionLock['user_id'] === (int) $session->get('user-id')) {
4706
                    // CASE where no encryption process is pending
4707
                    // get if existing process ongoing for this item
4708
                    $dataItemProcessOngoing = DB::queryFirstRow(
4709
                        'SELECT JSON_EXTRACT(arguments, "$.all_users_except_id") AS all_users_except_id
4710
                        FROM ' . prefixTable('background_tasks') . '
4711
                        WHERE item_id = %i AND finished_at = ""
4712
                        ORDER BY increment_id DESC',
4713
                        $inputData['itemId']
4714
                    );
4715
4716
                    if ((int) DB::count() === 0) {
4717
                        // Delete the existing edition lock and let the user edit
4718
                        DB::delete(
4719
                            prefixTable('items_edition'), 
4720
                            'item_id = %i AND user_id = %i', 
4721
                            $inputData['itemId'],
4722
                            $session->get('user-id')
4723
                        );
4724
                    } else {
4725
                        // Case where encryption process is pending
4726
                        // Then no edition is possible
4727
                        $returnValues = array(
4728
                            'error' => true,
4729
                            'message' => $lang->get('error_no_edition_possible_locked'),
4730
                        );
4731
                        echo (string) prepareExchangedData(
4732
                            $returnValues,
4733
                            'encode'
4734
                        );
4735
                        break;
4736
                    }
4737
                } elseif (round(abs(time() - $dataTmp['timestamp']),0) <= $delay) {
4738
                    // Case where edition lock is already taken by another user
4739
                    // Then no edition is possible
4740
                    $returnValues = array(
4741
                        'error' => true,
4742
                        'message' => $lang->get('error_no_edition_possible_locked'),
4743
                    );
4744
                    echo (string) prepareExchangedData(
4745
                        $returnValues,
4746
                        'encode'
4747
                    );
4748
                    break;
4749
                }
4750
            }
4751
4752
            // create edition lock on this item for this user
4753
            DB::insert(
4754
                prefixTable('items_edition'),
4755
                array(
4756
                    'timestamp' => time(),
4757
                    'item_id' => $inputData['itemId'],
4758
                    'user_id' => (int) $session->get('user-id'),
4759
                )
4760
            );
4761
        }
4762
4763
        // do query on this folder
4764
        $data_this_folder = DB::queryFirstRow(
4765
            'SELECT id, personal_folder, title
4766
            FROM ' . prefixTable('nested_tree') . '
4767
            WHERE id = %s',
4768
            $inputData['folderId']
4769
        );
4770
4771
        // check if user can perform this action
4772
        if (
4773
            null !== $inputData['context']
4774
            && empty($inputData['context']) === false
4775
        ) {
4776
            if (
4777
                $inputData['context'] === 'create_folder'
4778
                || $inputData['context'] === 'edit_folder'
4779
                || $inputData['context'] === 'delete_folder'
4780
                || $inputData['context'] === 'copy_folder'
4781
            ) {
4782
                if (
4783
                    (int) $session->get('user-admin') !== 1
4784
                    && ((int) $session->get('user-manager') !== 1)
4785
                    && (isset($SETTINGS['enable_user_can_create_folders'])
4786
                        && (int) $SETTINGS['enable_user_can_create_folders'] !== 1)
4787
                    && ((int) $data_this_folder['personal_folder'] !== 1 && $data_this_folder['title'] !== $session->get('user-id'))   // take into consideration if this is a personal folder
4788
                ) {
4789
                    $returnValues = array(
4790
                        'error' => true,
4791
                        'message' => $lang->get('error_not_allowed_to'),
4792
                    );
4793
                    echo (string) prepareExchangedData(
4794
                        $returnValues,
4795
                        'encode'
4796
                    );
4797
                    break;
4798
                }
4799
            }
4800
        }
4801
4802
        // Get required Complexity for this Folder
4803
        $visibilite = '';
4804
        $data = DB::queryFirstRow(
4805
            'SELECT m.valeur, n.personal_folder
4806
            FROM ' . prefixTable('misc') . ' AS m
4807
            INNER JOIN ' . prefixTable('nested_tree') . ' AS n ON (m.intitule = n.id)
4808
            WHERE type=%s AND intitule = %s',
4809
            'complex',
4810
            $inputData['folderId']
4811
        );
4812
4813
        if (isset($data['valeur']) === true && (empty($data['valeur']) === false || $data['valeur'] === '0')) {
4814
            $complexity = TP_PW_COMPLEXITY[$data['valeur']][1];
4815
            $folder_is_personal = (int) $data['personal_folder'];
4816
4817
            // Prepare Item actual visibility (what Users/Roles can see it)
4818
            $rows = DB::query(
4819
                'SELECT t.title
4820
                FROM ' . prefixTable('roles_values') . ' as v
4821
                INNER JOIN ' . prefixTable('roles_title') . ' as t ON (v.role_id = t.id)
4822
                WHERE v.folder_id = %i
4823
                GROUP BY title',
4824
                $inputData['folderId']
4825
            );
4826
            foreach ($rows as $record) {
4827
                if (empty($visibilite)) {
4828
                    $visibilite = $record['title'];
4829
                } else {
4830
                    $visibilite .= ' - ' . $record['title'];
4831
                }
4832
            }
4833
        } else {
4834
            $complexity = $lang->get('not_defined');
4835
4836
            // if not defined, then previous query failed and personal_folder is null
4837
            // do new query to know if current folder is pf
4838
            $data_pf = DB::queryFirstRow(
4839
                'SELECT personal_folder
4840
                FROM ' . prefixTable('nested_tree') . '
4841
                WHERE id = %s',
4842
                $inputData['folderId']
4843
            );
4844
            
4845
            $folder_is_personal = $data_pf !== null ? (int) $data_pf['personal_folder'] : 0;
4846
            
4847
            $visibilite = $session->get('user-name') . ' ' . $session->get('user-lastname') . ' (' . $session->get('user-login') . ')';
4848
        }
4849
4850
        recupDroitCreationSansComplexite($inputData['folderId']);
4851
4852
        // get list of roles
4853
        $listOptionsForUsers = array();
4854
        $listOptionsForRoles = array();
4855
        $rows = DB::query(
4856
            'SELECT r.role_id AS role_id, t.title AS title
4857
            FROM ' . prefixTable('roles_values') . ' AS r
4858
            INNER JOIN ' . prefixTable('roles_title') . ' AS t ON (r.role_id = t.id)
4859
            WHERE r.folder_id = %i',
4860
            $inputData['folderId']
4861
        );
4862
        foreach ($rows as $record) {
4863
            array_push(
4864
                $listOptionsForRoles,
4865
                array(
4866
                    'id' => $record['role_id'],
4867
                    'title' => $record['title'],
4868
                )
4869
            );
4870
            $rows2 = DB::query(
4871
                'SELECT id, login, fonction_id, email, name, lastname
4872
                FROM ' . prefixTable('users') . '
4873
                WHERE admin = 0 AND fonction_id is not null'
4874
            );
4875
            foreach ($rows2 as $record2) {
4876
                foreach (explode(';', $record2['fonction_id']) as $role) {
4877
                    if (
4878
                        array_search($record2['id'], array_column($listOptionsForUsers, 'id')) === false
4879
                        && $role === $record['role_id']
4880
                    ) {
4881
                        array_push(
4882
                            $listOptionsForUsers,
4883
                            array(
4884
                                'id' => $record2['id'],
4885
                                'login' => $record2['login'],
4886
                                'name' => $record2['name'] . ' ' . $record2['lastname'],
4887
                                'email' => $record2['email'],
4888
                            )
4889
                        );
4890
                    }
4891
                }
4892
            }
4893
        }
4894
        
4895
        // Get access level for this folder
4896
        $accessLevel = 20;
4897
        if ($folder_is_personal === 0) {
4898
            $arrTmp = [];
4899
            foreach ($session->get('user-roles_array') as $role) {
4900
                //db::debugmode(true);
4901
                $access = DB::queryFirstRow(
4902
                    'SELECT type
4903
                    FROM ' . prefixTable('roles_values') . '
4904
                    WHERE role_id = %i AND folder_id = %i',
4905
                    $role,
4906
                    $inputData['folderId']
4907
                );
4908
                //db::debugmode(false);
4909
                if (DB::count()>0) {
4910
                    if ($access['type'] === 'R') {
4911
                        array_push($arrTmp, 10);
4912
                    } elseif ($access['type'] === 'W') {
4913
                        array_push($arrTmp, 30);
4914
                    } elseif ($access['type'] === 'ND') {
4915
                        array_push($arrTmp, 20);
4916
                    } elseif ($access['type'] === 'NE') {
4917
                        array_push($arrTmp, 10);
4918
                    } elseif ($access['type'] === 'NDNE') {
4919
                        array_push($arrTmp, 15);
4920
                    } else {
4921
                        // Ensure to give access Right if allowed folder
4922
                        if (in_array($inputData['id'], $session->get('user-accessible_folders')) === true) {
4923
                            array_push($arrTmp, 30);
4924
                        } else {
4925
                            array_push($arrTmp, 0);
4926
                        }
4927
                    }
4928
                }
4929
            }
4930
            // 3.0.0.0 - changed  MIN to MAX
4931
            $accessLevel = count($arrTmp) > 0 ? max($arrTmp) : $accessLevel;
4932
        } elseif ($folder_is_personal === 1) {
4933
            $accessLevel = 30;
4934
        }
4935
4936
        $returnValues = array(
4937
            'folderId' => (int) $inputData['folderId'],
4938
            'error' => false,
4939
            'val' => $data !== null ? (int) $data['valeur'] : 0,
4940
            'visibility' => $visibilite,
4941
            'complexity' => $complexity,
4942
            'personal' => $folder_is_personal,
4943
            'usersList' => $listOptionsForUsers,
4944
            'rolesList' => $listOptionsForRoles,
4945
            'setting_restricted_to_roles' => isset($SETTINGS['restricted_to_roles']) === true
4946
                && (int) $SETTINGS['restricted_to_roles'] === 1 ? 1 : 0,
4947
            'itemAccessRight' => isset($accessLevel) === true ? $accessLevel : '',
4948
        );
4949
        echo (string) prepareExchangedData(
4950
            $returnValues,
4951
            'encode'
4952
        );
4953
        break;
4954
4955
    case 'handle_item_edition_lock':
4956
        // Check KEY
4957
        if ($inputData['key'] !== $session->get('key')) {
4958
            echo (string) prepareExchangedData(
4959
                array(
4960
                    'error' => true,
4961
                    'message' => $lang->get('key_is_not_correct'),
4962
                ),
4963
                'encode'
4964
            );
4965
            break;
4966
        }
4967
4968
        // decrypt and retreive data in JSON format
4969
        $dataReceived = prepareExchangedData(
4970
            $inputData['data'],
4971
            'decode'
4972
        );
4973
        $itemId = filter_var($dataReceived['item_id'], FILTER_SANITIZE_NUMBER_INT);
4974
        $action = filter_var($dataReceived['action'], FILTER_SANITIZE_SPECIAL_CHARS);
4975
4976
        if ($action === 'release_lock') {
4977
            DB::delete(
4978
                prefixTable('items_edition'), 
4979
                'item_id = %i AND user_id = %i', 
4980
                $itemId,
4981
                $session->get('user-id')
4982
            );
4983
        }
4984
        
4985
        break;
4986
4987
        /*
4988
    * CASE
4989
    * DELETE attached file from an item
4990
    */
4991
    case 'delete_attached_file':
4992
        // Check KEY
4993
        if ($inputData['key'] !== $session->get('key')) {
4994
            echo (string) prepareExchangedData(
4995
                array(
4996
                    'error' => true,
4997
                    'message' => $lang->get('key_is_not_correct'),
4998
                ),
4999
                'encode'
5000
            );
5001
            break;
5002
        }
5003
5004
        // decrypt and retreive data in JSON format
5005
        $dataReceived = prepareExchangedData(
5006
            $inputData['data'],
5007
            'decode'
5008
        );
5009
        $fileId = filter_var($dataReceived['file_id'], FILTER_SANITIZE_NUMBER_INT);
5010
5011
        // Get some info before deleting
5012
        $data = DB::queryFirstRow(
5013
            'SELECT name, id_item, file
5014
            FROM ' . prefixTable('files') . '
5015
            WHERE id = %i',
5016
            $fileId
5017
        );
5018
5019
        // Load item data
5020
        $data_item = DB::queryFirstRow(
5021
            'SELECT id_tree
5022
            FROM ' . prefixTable('items') . '
5023
            WHERE id = %i',
5024
            $data['id_item']
5025
        );
5026
5027
        // Check that user can access this folder
5028
        if (in_array($data_item['id_tree'], $session->get('user-accessible_folders')) === false) {
5029
            echo (string) prepareExchangedData(
5030
                array('error' => 'ERR_FOLDER_NOT_ALLOWED'),
5031
                'encode'
5032
            );
5033
            break;
5034
        }
5035
5036
        if (empty($data['id_item']) === false) {
5037
            // Delete from FILES table
5038
            DB::delete(
5039
                prefixTable('files'),
5040
                'id = %i',
5041
                $fileId
5042
            );
5043
5044
            // Update the log
5045
            logItems(
5046
                $SETTINGS,
5047
                (int) $data['id_item'],
5048
                $data['name'],
5049
                $session->get('user-id'),
5050
                'at_modification',
5051
                $session->get('user-login'),
5052
                'at_del_file : ' . $data['name']
5053
            );
5054
5055
            // DElete sharekeys
5056
            DB::delete(
5057
                prefixTable('sharekeys_files'),
5058
                'object_id = %i',
5059
                $fileId
5060
            );
5061
5062
            // Delete file from server
5063
            $fileToDelete = $SETTINGS['path_to_upload_folder'] . '/' . TP_FILE_PREFIX . base64_decode($data['file']);
5064
            $fileToDelete = realpath($fileToDelete);
5065
            if ($fileToDelete && strpos($fileToDelete, $SETTINGS['path_to_upload_folder']) === 0) {
5066
                fileDelete($fileToDelete, $SETTINGS);
5067
            }
5068
        }
5069
5070
        echo (string) prepareExchangedData(
5071
            array(
5072
                'error' => false,
5073
                'message' => '',
5074
            ),
5075
            'encode'
5076
        );
5077
        break;
5078
5079
        /*
5080
    * FUNCTION
5081
    * Launch an action when clicking on a quick icon
5082
    * $action = 0 => Make not favorite
5083
    * $action = 1 => Make favorite
5084
    */
5085
    case 'action_on_quick_icon':
5086
        // Check KEY and rights
5087
        if (
5088
            $inputData['key'] !== $session->get('key')
5089
            || $session->get('user-read_only') === 1 || !isset($SETTINGS['pwd_maximum_length'])
5090
        ) {
5091
            // error
5092
            exit;
5093
        }
5094
5095
        // decrypt and retreive data in JSON format
5096
        $dataReceived = prepareExchangedData(
5097
            $inputData['data'],
5098
            'decode'
5099
        );
5100
        $inputData['action'] = (int) filter_var($dataReceived['action'], FILTER_SANITIZE_NUMBER_INT);
5101
        $inputData['itemId'] = (int) filter_var($dataReceived['item_id'], FILTER_SANITIZE_NUMBER_INT);
5102
5103
        if ((int) $inputData['action'] === 0) {
5104
            // Add new favourite
5105
            SessionManager::addRemoveFromSessionArray('user-favorites', [$inputData['itemId']], 'add');
5106
            DB::update(
5107
                prefixTable('users'),
5108
                array(
5109
                    'favourites' => implode(';', $session->get('user-favorites')),
5110
                ),
5111
                'id = %i',
5112
                $session->get('user-id')
5113
            );
5114
            // Update SESSION with this new favourite
5115
            $data = DB::queryfirstrow(
5116
                'SELECT label,id_tree
5117
                FROM ' . prefixTable('items') . '
5118
                WHERE id = %i',
5119
                $inputData['itemId']
5120
            );
5121
            SessionManager::addRemoveFromSessionAssociativeArray(
5122
                'user-favorites_tab',
5123
                [
5124
                    $inputData['itemId'] => [
5125
                        'label' => $data['label'],
5126
                        'url' => 'index.php?page=items&amp;group=' . $data['id_tree'] . '&amp;id=' . $inputData['itemId'],
5127
                    ],
5128
                ],
5129
                'add'
5130
            );
5131
        } elseif ((int) $inputData['action'] === 1) {
5132
            // delete from session
5133
            SessionManager::addRemoveFromSessionArray('user-favorites', [$inputData['itemId']], 'remove');
5134
5135
            // delete from DB
5136
            DB::update(
5137
                prefixTable('users'),
5138
                array(
5139
                    'favourites' => implode(';', $session->get('user-favorites')),
5140
                ),
5141
                'id = %i',
5142
                $session->get('user-id')
5143
            );
5144
            // refresh session fav list
5145
            if ($session->has('user-favorites_tab') && $session->has('user-favorites_tab') && null !== $session->get('user-favorites_tab')) {
5146
                $user_favorites_tab = $session->get('user-favorites_tab');
5147
                foreach ($user_favorites_tab as $key => $value) {
5148
                    if ($key === $inputData['id']) {
5149
                        SessionManager::addRemoveFromSessionAssociativeArray('user-favorites_tab', [$key], 'remove');
5150
                        break;
5151
                    }
5152
                }
5153
            }
5154
        }
5155
        break;
5156
5157
        /*
5158
    * CASE
5159
    * Move an ITEM
5160
    */
5161
    case 'move_item':
5162
        // Check KEY and rights
5163
        if ($inputData['key'] !== $session->get('key')) {
5164
            echo (string) prepareExchangedData(
5165
                array(
5166
                    'error' => true,
5167
                    'message' => $lang->get('key_is_not_correct'),
5168
                ),
5169
                'encode'
5170
            );
5171
            break;
5172
        }
5173
        if ($session->get('user-read_only') === 1 || isset($SETTINGS['pwd_maximum_length']) === false) {
5174
            echo (string) prepareExchangedData(
5175
                array(
5176
                    'error' => true,
5177
                    'message' => $lang->get('error_not_allowed_to'),
5178
                ),
5179
                'encode'
5180
            );
5181
            break;
5182
        }
5183
5184
        // decrypt and retreive data in JSON format
5185
        $dataReceived = prepareExchangedData(
5186
            $inputData['data'],
5187
            'decode'
5188
        );
5189
        $inputData['folderId'] = (int) filter_var($dataReceived['folder_id'], FILTER_SANITIZE_NUMBER_INT);
5190
        $inputData['itemId'] = (int) filter_var($dataReceived['item_id'], FILTER_SANITIZE_NUMBER_INT);
5191
5192
        // get data about item
5193
        $dataSource = DB::queryfirstrow(
5194
            'SELECT i.pw, f.personal_folder,i.id_tree, f.title,i.label
5195
            FROM ' . prefixTable('items') . ' as i
5196
            INNER JOIN ' . prefixTable('nested_tree') . ' as f ON (i.id_tree=f.id)
5197
            WHERE i.id=%i',
5198
            $inputData['itemId']
5199
        );
5200
5201
        // Check that user can delete on old folder
5202
        $checkRights = getCurrentAccessRights(
5203
            $session->get('user-id'),
5204
            $inputData['itemId'],
5205
            (int) $dataSource['id_tree'],
5206
        );
5207
5208
        if ($checkRights['error'] || !$checkRights['delete']) {
5209
            echo (string) prepareExchangedData(
5210
                array(
5211
                    'error' => true,
5212
                    'message' => $lang->get('error_not_allowed_to'),
5213
                ),
5214
                'encode'
5215
            );
5216
            break;
5217
        }
5218
5219
        // Check that user can write on requested folder
5220
        $checkRights = getCurrentAccessRights(
5221
            $session->get('user-id'),
5222
            $inputData['itemId'],
5223
            $inputData['folderId'],
5224
        );
5225
5226
        if ($checkRights['error'] || !$checkRights['edit']) {
5227
            echo (string) prepareExchangedData(
5228
                array(
5229
                    'error' => true,
5230
                    'message' => $lang->get('error_not_allowed_to'),
5231
                ),
5232
                'encode'
5233
            );
5234
            break;
5235
        }
5236
5237
        // get data about new folder
5238
        $dataDestination = DB::queryfirstrow(
5239
            'SELECT personal_folder, title
5240
            FROM ' . prefixTable('nested_tree') . '
5241
            WHERE id = %i',
5242
            $inputData['folderId']
5243
        );
5244
5245
        // Check that user can access this folder
5246
        if (
5247
            in_array($dataSource['id_tree'], $session->get('user-accessible_folders')) === false
5248
            || in_array($inputData['folderId'], $session->get('user-accessible_folders')) === false
5249
            //|| (int) $dataSource['personal_folder'] === (int) $dataDestination['personal_folder']
5250
        ) {
5251
            echo (string) prepareExchangedData(
5252
                array(
5253
                    'error' => true,
5254
                    'message' => $lang->get('error_not_allowed_to'),
5255
                ),
5256
                'encode'
5257
            );
5258
            break;
5259
        }
5260
5261
        // Manage possible cases
5262
        if ((int) $dataSource['personal_folder'] === 0 && (int) $dataDestination['personal_folder'] === 0) {
5263
            // Previous is non personal folder and new too
5264
            // Just update is needed. Item key is the same
5265
            DB::update(
5266
                prefixTable('items'),
5267
                array(
5268
                    'id_tree' => $inputData['folderId'],
5269
                    'updated_at' => time(),
5270
                ),
5271
                'id=%i',
5272
                $inputData['itemId']
5273
            );
5274
            // ---
5275
            // ---
5276
        } elseif ((int) $dataSource['personal_folder'] === 0 && (int) $dataDestination['personal_folder'] === 1) {
5277
            // Source is public and destination is personal
5278
            // Decrypt and remove all sharekeys (items, fields, files)
5279
            // Encrypt only for the user
5280
5281
            // Remove all item sharekeys items
5282
            DB::delete(
5283
                prefixTable('sharekeys_items'),
5284
                'object_id = %i AND user_id != %i',
5285
                $inputData['itemId'],
5286
                $session->get('user-id')
5287
            );
5288
5289
            // Remove all item sharekeys fields
5290
            // Get fields for this Item
5291
            $rows = DB::query(
5292
                'SELECT id
5293
                FROM ' . prefixTable('categories_items') . '
5294
                WHERE item_id = %i',
5295
                $inputData['itemId']
5296
            );
5297
            foreach ($rows as $field) {
5298
                DB::delete(
5299
                    prefixTable('sharekeys_fields'),
5300
                    'object_id = %i AND user_id != %i',
5301
                    $field['id'],
5302
                    $session->get('user-id')
5303
                );
5304
            }
5305
5306
            // Remove all item sharekeys files
5307
            // Get FILES for this Item
5308
            $rows = DB::query(
5309
                'SELECT id
5310
                FROM ' . prefixTable('files') . '
5311
                WHERE id_item = %i',
5312
                $inputData['itemId']
5313
            );
5314
            foreach ($rows as $attachment) {
5315
                DB::delete(
5316
                    prefixTable('sharekeys_files'),
5317
                    'object_id = %i AND user_id != %i',
5318
                    $attachment['id'],
5319
                    $session->get('user-id')
5320
                );
5321
            }
5322
5323
            // update pw
5324
            DB::update(
5325
                prefixTable('items'),
5326
                array(
5327
                    'id_tree' => $inputData['folderId'],
5328
                    'perso' => 1,
5329
                    'updated_at' => time(),
5330
                ),
5331
                'id=%i',
5332
                $inputData['itemId']
5333
            );
5334
            // ---
5335
            // ---
5336
        } elseif ((int) $dataSource['personal_folder'] === 1 && (int) $dataDestination['personal_folder'] === 1) {
5337
            // If previous is personal folder and new is personal folder too => no key exist on item
5338
            // just update is needed. Item key is the same
5339
            DB::update(
5340
                prefixTable('items'),
5341
                array(
5342
                    'id_tree' => $inputData['folderId'],
5343
                    'updated_at' => time(),
5344
                ),
5345
                'id=%i',
5346
                $inputData['itemId']
5347
            );
5348
            // ---
5349
            // ---
5350
        } elseif ((int) $dataSource['personal_folder'] === 1 && (int) $dataDestination['personal_folder'] === 0) {
5351
            // If previous is personal folder and new is not personal folder => no key exist on item => add new
5352
            // Create keys for all users
5353
5354
            // Get the ITEM object key for the user
5355
            $userKey = DB::queryFirstRow(
5356
                'SELECT share_key
5357
                FROM ' . prefixTable('sharekeys_items') . '
5358
                WHERE user_id = %i AND object_id = %i',
5359
                $session->get('user-id'),
5360
                $inputData['itemId']
5361
            );
5362
            if (DB::count() > 0) {
5363
                $objectKey = decryptUserObjectKey($userKey['share_key'], $session->get('user-private_key'));
5364
5365
                // This is a public object
5366
                $users = DB::query(
5367
                    'SELECT id, public_key
5368
                    FROM ' . prefixTable('users') . '
5369
                    WHERE id NOT IN ("' . OTV_USER_ID . '","' . SSH_USER_ID . '","' . API_USER_ID . '","' . $session->get('user-id') . '")
5370
                    AND public_key != ""'
5371
                );
5372
                foreach ($users as $user) {
5373
                    // Insert in DB the new object key for this item by user
5374
                    DB::insert(
5375
                        prefixTable('sharekeys_items'),
5376
                        array(
5377
                            'object_id' => $inputData['itemId'],
5378
                            'user_id' => (int) $user['id'],
5379
                            'share_key' => encryptUserObjectKey($objectKey, $user['public_key']),
5380
                        )
5381
                    );
5382
                }
5383
            }
5384
5385
            // Get the FIELDS object key for the user
5386
            // Get fields for this Item
5387
            $rows = DB::query(
5388
                'SELECT id
5389
                FROM ' . prefixTable('categories_items') . '
5390
                WHERE item_id = %i',
5391
                $inputData['itemId']
5392
            );
5393
            foreach ($rows as $field) {
5394
                $userKey = DB::queryFirstRow(
5395
                    'SELECT share_key
5396
                    FROM ' . prefixTable('sharekeys_fields') . '
5397
                    WHERE user_id = %i AND object_id = %i',
5398
                    $session->get('user-id'),
5399
                    $field['id']
5400
                );
5401
                if (DB::count() > 0) {
5402
                    $objectKey = decryptUserObjectKey($userKey['share_key'], $session->get('user-private_key'));
5403
5404
                    // This is a public object
5405
                    $users = DB::query(
5406
                        'SELECT id, public_key
5407
                        FROM ' . prefixTable('users') . '
5408
                        WHERE id NOT IN ("' . OTV_USER_ID . '","' . SSH_USER_ID . '","' . API_USER_ID . '","' . $session->get('user-id') . '")
5409
                        AND public_key != ""'
5410
                    );
5411
                    foreach ($users as $user) {
5412
                        // Insert in DB the new object key for this item by user
5413
                        DB::insert(
5414
                            prefixTable('sharekeys_fields'),
5415
                            array(
5416
                                'object_id' => $field['id'],
5417
                                'user_id' => (int) $user['id'],
5418
                                'share_key' => encryptUserObjectKey($objectKey, $user['public_key']),
5419
                            )
5420
                        );
5421
                    }
5422
                }
5423
            }
5424
5425
            // Get the FILE object key for the user
5426
            // Get FILES for this Item
5427
            $rows = DB::query(
5428
                'SELECT id
5429
                FROM ' . prefixTable('files') . '
5430
                WHERE id_item = %i',
5431
                $inputData['itemId']
5432
            );
5433
            foreach ($rows as $attachment) {
5434
                $userKey = DB::queryFirstRow(
5435
                    'SELECT share_key
5436
                    FROM ' . prefixTable('sharekeys_files') . '
5437
                    WHERE user_id = %i AND object_id = %i',
5438
                    $session->get('user-id'),
5439
                    $attachment['id']
5440
                );
5441
                if (DB::count() > 0) {
5442
                    $objectKey = decryptUserObjectKey($userKey['share_key'], $session->get('user-private_key'));
5443
5444
                    // This is a public object
5445
                    $users = DB::query(
5446
                        'SELECT id, public_key
5447
                        FROM ' . prefixTable('users') . '
5448
                        WHERE id NOT IN ("' . OTV_USER_ID . '","' . SSH_USER_ID . '","' . API_USER_ID . '","' . $session->get('user-id') . '")
5449
                        AND public_key != ""'
5450
                    );
5451
                    foreach ($users as $user) {
5452
                        // Insert in DB the new object key for this item by user
5453
                        DB::insert(
5454
                            prefixTable('sharekeys_files'),
5455
                            array(
5456
                                'object_id' => $attachment['id'],
5457
                                'user_id' => (int) $user['id'],
5458
                                'share_key' => encryptUserObjectKey($objectKey, $user['public_key']),
5459
                            )
5460
                        );
5461
                    }
5462
                }
5463
            }
5464
5465
            // update item
5466
            DB::update(
5467
                prefixTable('items'),
5468
                array(
5469
                    'id_tree' => $inputData['folderId'],
5470
                    'perso' => 0,
5471
                    'updated_at' => time(),
5472
                ),
5473
                'id=%i',
5474
                $inputData['itemId']
5475
            );
5476
        }
5477
5478
        // Log item moved
5479
        logItems(
5480
            $SETTINGS,
5481
            (int) $inputData['itemId'],
5482
            $dataSource['label'],
5483
            $session->get('user-id'),
5484
            'at_modification',
5485
            $session->get('user-login'),
5486
            'at_moved : ' . $dataSource['title'] . ' -> ' . $dataDestination['title']
5487
        );
5488
5489
        // Update cache table
5490
        updateCacheTable('update_value', (int) $inputData['itemId']);
5491
5492
        $returnValues = array(
5493
            'error' => '',
5494
            'message' => '',
5495
            'from_folder' => $dataSource['id_tree'],
5496
            'to_folder' => $inputData['folderId'],
5497
        );
5498
        echo (string) prepareExchangedData(
5499
            $returnValues,
5500
            'encode'
5501
        );
5502
        break;
5503
5504
        /*
5505
    * CASE
5506
    * MASSIVE Move an ITEM
5507
    */
5508
    case 'mass_move_items':
5509
        // Check KEY and rights
5510
        if ($inputData['key'] !== $session->get('key')) {
5511
            echo (string) prepareExchangedData(
5512
                array(
5513
                    'error' => true,
5514
                    'message' => $lang->get('key_is_not_correct'),
5515
                ),
5516
                'encode'
5517
            );
5518
            break;
5519
        }
5520
        if ($session->get('user-read_only') === 1 || isset($SETTINGS['pwd_maximum_length']) === false) {
5521
            echo (string) prepareExchangedData(
5522
                array(
5523
                    'error' => true,
5524
                    'message' => $lang->get('error_not_allowed_to'),
5525
                ),
5526
                'encode'
5527
            );
5528
            break;
5529
        }
5530
5531
        // decrypt and retreive data in JSON format
5532
        $dataReceived = prepareExchangedData(
5533
            $inputData['data'],
5534
            'decode'
5535
        );
5536
        $inputData['folderId'] = filter_var($dataReceived['folder_id'], FILTER_SANITIZE_NUMBER_INT);
5537
        $post_item_ids = filter_var($dataReceived['item_ids'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
5538
5539
        // loop on items to move
5540
        foreach (explode(';', $post_item_ids) as $item_id) {
5541
            if (empty($item_id) === false) {
5542
                // get data about item
5543
                $dataSource = DB::queryfirstrow(
5544
                    'SELECT i.pw, f.personal_folder,i.id_tree, f.title,i.label
5545
                    FROM ' . prefixTable('items') . ' as i
5546
                    INNER JOIN ' . prefixTable('nested_tree') . ' as f ON (i.id_tree=f.id)
5547
                    WHERE i.id=%i',
5548
                    $item_id
5549
                );
5550
5551
                // Check that user can access this folder
5552
                if (
5553
                    in_array($dataSource['id_tree'], $session->get('user-accessible_folders')) === false
5554
                    || in_array($inputData['folderId'], $session->get('user-accessible_folders')) === false
5555
                ) {
5556
                    echo (string) prepareExchangedData(
5557
                        array(
5558
                            'error' => true,
5559
                            'message' => $lang->get('error_not_allowed_to'),
5560
                        ),
5561
                        'encode'
5562
                    );
5563
                    exit;
5564
                }
5565
5566
                // get data about new folder
5567
                $dataDestination = DB::queryfirstrow(
5568
                    'SELECT personal_folder, title FROM ' . prefixTable('nested_tree') . ' WHERE id = %i',
5569
                    $inputData['folderId']
5570
                );
5571
5572
                // previous is non personal folder and new too
5573
                if (
5574
                    (int) $dataSource['personal_folder'] === 0
5575
                    && (int) $dataDestination['personal_folder'] === 0
5576
                ) {
5577
                    // just update is needed. Item key is the same
5578
                    DB::update(
5579
                        prefixTable('items'),
5580
                        array(
5581
                            'id_tree' => $inputData['folderId'],
5582
                            'updated_at' => time(),
5583
                        ),
5584
                        'id = %i',
5585
                        $item_id
5586
                    );
5587
                    // ---
5588
                    // ---
5589
                    // ---
5590
                } elseif (
5591
                    (int) $dataSource['personal_folder'] === 0
5592
                    && (int) $dataDestination['personal_folder'] === 1
5593
                ) {
5594
                    // Source is public and destination is personal
5595
                    // Decrypt and remove all sharekeys (items, fields, files)
5596
                    // Encrypt only for the user
5597
5598
                    // Remove all item sharekeys items
5599
                    DB::delete(
5600
                        prefixTable('sharekeys_items'),
5601
                        'object_id = %i AND user_id != %i',
5602
                        $item_id,
5603
                        $session->get('user-id')
5604
                    );
5605
5606
                    // Remove all item sharekeys fields
5607
                    // Get fields for this Item
5608
                    $rows = DB::query(
5609
                        'SELECT id
5610
                        FROM ' . prefixTable('categories_items') . '
5611
                        WHERE item_id = %i',
5612
                        $item_id
5613
                    );
5614
                    foreach ($rows as $field) {
5615
                        DB::delete(
5616
                            prefixTable('sharekeys_fields'),
5617
                            'object_id = %i AND user_id != %i',
5618
                            $field['id'],
5619
                            $session->get('user-id')
5620
                        );
5621
                    }
5622
5623
                    // Remove all item sharekeys files
5624
                    // Get FILES for this Item
5625
                    $rows = DB::query(
5626
                        'SELECT id
5627
                        FROM ' . prefixTable('files') . '
5628
                        WHERE id_item = %i',
5629
                        $item_id
5630
                    );
5631
                    foreach ($rows as $attachment) {
5632
                        DB::delete(
5633
                            prefixTable('sharekeys_files'),
5634
                            'object_id = %i AND user_id != %i',
5635
                            $attachment['id'],
5636
                            $session->get('user-id')
5637
                        );
5638
                    }
5639
5640
                    // update pw
5641
                    DB::update(
5642
                        prefixTable('items'),
5643
                        array(
5644
                            'id_tree' => $inputData['folderId'],
5645
                            'perso' => 1,
5646
                            'updated_at' => time(),
5647
                        ),
5648
                        'id = %i',
5649
                        $item_id
5650
                    );
5651
                    // ---
5652
                    // ---
5653
                    // ---
5654
                } elseif (
5655
                    (int) $dataSource['personal_folder'] === 1
5656
                    && (int) $dataDestination['personal_folder'] === 1
5657
                ) {
5658
                    // If previous is personal folder and new is personal folder too => no key exist on item
5659
                    // just update is needed. Item key is the same
5660
                    DB::update(
5661
                        prefixTable('items'),
5662
                        array(
5663
                            'id_tree' => $inputData['folderId'],
5664
                            'updated_at' => time(),
5665
                        ),
5666
                        'id = %i',
5667
                        $item_id
5668
                    );
5669
                    // ---
5670
                    // ---
5671
                    // ---
5672
                } elseif (
5673
                    (int) $dataSource['personal_folder'] === 1
5674
                    && (int) $dataDestination['personal_folder'] === 0
5675
                ) {
5676
                    // If previous is personal folder and new is not personal folder => no key exist on item => add new
5677
                    // Create keys for all users
5678
5679
                    // Get the ITEM object key for the user
5680
                    $userKey = DB::queryFirstRow(
5681
                        'SELECT share_key
5682
                        FROM ' . prefixTable('sharekeys_items') . '
5683
                        WHERE user_id = %i AND object_id = %i',
5684
                        $session->get('user-id'),
5685
                        $item_id
5686
                    );
5687
                    if (DB::count() > 0) {
5688
                        $objectKey = decryptUserObjectKey($userKey['share_key'], $session->get('user-private_key'));
5689
5690
                        // This is a public object
5691
                        $users = DB::query(
5692
                            'SELECT id, public_key
5693
                            FROM ' . prefixTable('users') . '
5694
                            WHERE id NOT IN ("' . OTV_USER_ID . '","' . SSH_USER_ID . '","' . API_USER_ID . '","' . $session->get('user-id') . '")
5695
                            AND public_key != ""'
5696
                        );
5697
                        foreach ($users as $user) {
5698
                            // Insert in DB the new object key for this item by user
5699
                            DB::insert(
5700
                                prefixTable('sharekeys_items'),
5701
                                array(
5702
                                    'object_id' => $item_id,
5703
                                    'user_id' => (int) $user['id'],
5704
                                    'share_key' => encryptUserObjectKey($objectKey, $user['public_key']),
5705
                                )
5706
                            );
5707
                        }
5708
                    }
5709
5710
                    // Get the FIELDS object key for the user
5711
                    // Get fields for this Item
5712
                    $rows = DB::query(
5713
                        'SELECT id
5714
                        FROM ' . prefixTable('categories_items') . '
5715
                        WHERE item_id = %i',
5716
                        $item_id
5717
                    );
5718
                    foreach ($rows as $field) {
5719
                        $userKey = DB::queryFirstRow(
5720
                            'SELECT share_key
5721
                            FROM ' . prefixTable('sharekeys_fields') . '
5722
                            WHERE user_id = %i AND object_id = %i',
5723
                            $session->get('user-id'),
5724
                            $field['id']
5725
                        );
5726
                        if (DB::count() > 0) {
5727
                            $objectKey = decryptUserObjectKey($userKey['share_key'], $session->get('user-private_key'));
5728
5729
                            // This is a public object
5730
                            $users = DB::query(
5731
                                'SELECT id, public_key
5732
                                FROM ' . prefixTable('users') . '
5733
                                WHERE id NOT IN ("' . OTV_USER_ID . '","' . SSH_USER_ID . '","' . API_USER_ID . '","' . $session->get('user-id') . '")
5734
                                AND public_key != ""'
5735
                            );
5736
                            foreach ($users as $user) {
5737
                                // Insert in DB the new object key for this item by user
5738
                                DB::insert(
5739
                                    prefixTable('sharekeys_fields'),
5740
                                    array(
5741
                                        'object_id' => $field['id'],
5742
                                        'user_id' => (int) $user['id'],
5743
                                        'share_key' => encryptUserObjectKey($objectKey, $user['public_key']),
5744
                                    )
5745
                                );
5746
                            }
5747
                        }
5748
                    }
5749
5750
                    // Get the FILE object key for the user
5751
                    // Get FILES for this Item
5752
                    $rows = DB::query(
5753
                        'SELECT id
5754
                        FROM ' . prefixTable('files') . '
5755
                        WHERE id_item = %i',
5756
                        $item_id
5757
                    );
5758
                    foreach ($rows as $attachment) {
5759
                        $userKey = DB::queryFirstRow(
5760
                            'SELECT share_key
5761
                            FROM ' . prefixTable('sharekeys_files') . '
5762
                            WHERE user_id = %i AND object_id = %i',
5763
                            $session->get('user-id'),
5764
                            $attachment['id']
5765
                        );
5766
                        if (DB::count() > 0) {
5767
                            $objectKey = decryptUserObjectKey($userKey['share_key'], $session->get('user-private_key'));
5768
5769
                            // This is a public object
5770
                            $users = DB::query(
5771
                                'SELECT id, public_key
5772
                                FROM ' . prefixTable('users') . '
5773
                                WHERE id NOT IN ("' . OTV_USER_ID . '","' . SSH_USER_ID . '","' . API_USER_ID . '","' . $session->get('user-id') . '")
5774
                                AND public_key != ""'
5775
                            );
5776
                            foreach ($users as $user) {
5777
                                // Insert in DB the new object key for this item by user
5778
                                DB::insert(
5779
                                    prefixTable('sharekeys_files'),
5780
                                    array(
5781
                                        'object_id' => $attachment['id'],
5782
                                        'user_id' => (int) $user['id'],
5783
                                        'share_key' => encryptUserObjectKey($objectKey, $user['public_key']),
5784
                                    )
5785
                                );
5786
                            }
5787
                        }
5788
                    }
5789
5790
                    // update item
5791
                    DB::update(
5792
                        prefixTable('items'),
5793
                        array(
5794
                            'id_tree' => $inputData['folderId'],
5795
                            'perso' => 0,
5796
                            'updated_at' => time(),
5797
                        ),
5798
                        'id=%i',
5799
                        $item_id
5800
                    );
5801
                }
5802
                // Log item moved
5803
                logItems(
5804
                    $SETTINGS,
5805
                    (int) $item_id,
5806
                    $dataSource['label'],
5807
                    $session->get('user-id'),
5808
                    'at_modification',
5809
                    $session->get('user-login'),
5810
                    'at_moved : ' . $dataSource['title'] . ' -> ' . $dataDestination['title']
5811
                );
5812
            }
5813
        }
5814
5815
        // reload cache table
5816
        require_once $SETTINGS['cpassman_dir'] . '/sources/main.functions.php';
5817
        updateCacheTable('reload', null);
5818
5819
        echo (string) prepareExchangedData(
5820
            array(
5821
                'error' => false,
5822
                'message' => '',
5823
            ),
5824
            'encode'
5825
        );
5826
        break;
5827
5828
        /*
5829
        * CASE
5830
        * MASSIVE Delete an item
5831
    */
5832
    case 'mass_delete_items':
5833
        // Check KEY and rights
5834
        if ($inputData['key'] !== $session->get('key')) {
5835
            echo (string) prepareExchangedData(
5836
                array(
5837
                    'error' => true,
5838
                    'message' => $lang->get('key_is_not_correct'),
5839
                ),
5840
                'encode'
5841
            );
5842
            break;
5843
        }
5844
        if ($session->get('user-read_only') === 1) {
5845
            echo (string) prepareExchangedData(
5846
                array(
5847
                    'error' => true,
5848
                    'message' => $lang->get('error_not_allowed_to'),
5849
                ),
5850
                'encode'
5851
            );
5852
            break;
5853
        }
5854
5855
        // decrypt and retreive data in JSON format
5856
        $dataReceived = prepareExchangedData(
5857
            $inputData['data'],
5858
            'decode'
5859
        );
5860
        $post_item_ids = filter_var($dataReceived['item_ids'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
5861
5862
        // perform a check in case of Read-Only user creating an item in his PF
5863
        if ($session->get('user-read_only') === 1) {
5864
            echo (string) prepareExchangedData(
5865
                array(
5866
                    'error' => true,
5867
                    'message' => $lang->get('error_not_allowed_to'),
5868
                ),
5869
                'encode'
5870
            );
5871
            break;
5872
        }
5873
5874
        // loop on items to move
5875
        foreach (explode(';', $post_item_ids) as $item_id) {
5876
            if (empty($item_id) === false) {
5877
                // get info
5878
                $dataSource = DB::queryfirstrow(
5879
                    'SELECT label, id_tree
5880
                    FROM ' . prefixTable('items') . '
5881
                    WHERE id=%i',
5882
                    $item_id
5883
                );
5884
5885
                // Check that user can access this folder
5886
                if (
5887
                    in_array($dataSource['id_tree'], $session->get('user-accessible_folders')) === false
5888
                ) {
5889
                    echo (string) prepareExchangedData(
5890
                        array(
5891
                            'error' => true,
5892
                            'message' => $lang->get('error_not_allowed_to'),
5893
                        ),
5894
                        'encode'
5895
                    );
5896
                    break;
5897
                }
5898
5899
                // delete item consists in disabling it
5900
                DB::update(
5901
                    prefixTable('items'),
5902
                    array(
5903
                        'inactif' => '1',
5904
                        'deleted_at' => time(),
5905
                    ),
5906
                    'id = %i',
5907
                    $item_id
5908
                );
5909
5910
                // log
5911
                logItems(
5912
                    $SETTINGS,
5913
                    (int) $item_id,
5914
                    $dataSource['label'],
5915
                    $session->get('user-id'),
5916
                    'at_delete',
5917
                    $session->get('user-login')
5918
                );
5919
5920
                // Update CACHE table
5921
                updateCacheTable('delete_value', (int) $item_id);
5922
            }
5923
        }
5924
5925
        echo (string) prepareExchangedData(
5926
            array(
5927
                'error' => false,
5928
                'message' => '',
5929
            ),
5930
            'encode'
5931
        );
5932
        break;
5933
5934
        /*
5935
        * CASE
5936
        * Send email
5937
    */
5938
    case 'send_email':
5939
        // Check KEY
5940
        if ($inputData['key'] !== $session->get('key')) {
5941
            echo (string) prepareExchangedData(
5942
                array(
5943
                    'error' => true,
5944
                    'message' => $lang->get('key_is_not_correct'),
5945
                ),
5946
                'encode'
5947
            );
5948
            break;
5949
        }
5950
        if ($session->get('user-read_only') === 1) {
5951
            echo (string) prepareExchangedData(
5952
                array(
5953
                    'error' => true,
5954
                    'message' => $lang->get('error_not_allowed_to'),
5955
                ),
5956
                'encode'
5957
            );
5958
            break;
5959
        }
5960
5961
        // decrypt and retrieve data in JSON format
5962
        $dataReceived = prepareExchangedData(
5963
            $inputData['data'],
5964
            'decode'
5965
        );
5966
5967
        // Prepare variables
5968
        $inputData['id'] = filter_var($dataReceived['id'], FILTER_SANITIZE_NUMBER_INT);
5969
        $inputData['receipt'] = filter_var($dataReceived['receipt'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
5970
        $inputData['cat'] = filter_var($dataReceived['cat'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
5971
        $post_content = $request->request->has('name') ? explode(',', $request->request->filter('content', '', FILTER_SANITIZE_FULL_SPECIAL_CHARS)) : '';
5972
5973
        // get links url
5974
        if (empty($SETTINGS['email_server_url']) === true) {
5975
            $SETTINGS['email_server_url'] = $SETTINGS['cpassman_url'];
5976
        }
5977
        if ($inputData['cat'] === 'request_access_to_author') {
5978
            // Variables
5979
            $dataAuthor = DB::queryfirstrow('SELECT email,login FROM ' . prefixTable('users') . ' WHERE id = ' . $post_content[1]);
5980
            $dataItem = DB::queryfirstrow('SELECT label, id_tree FROM ' . prefixTable('items') . ' WHERE id = ' . $post_content[0]);
5981
5982
            // Get path
5983
            $path = geItemReadablePath(
5984
                (int) $dataItem['id_tree'],
5985
                $dataItem['label'],
5986
                $SETTINGS
5987
            );
5988
5989
            // Prepare email
5990
            prepareSendingEmail(
5991
                $lang->get('email_request_access_subject'),
5992
                str_replace(
5993
                    array('#tp_item_author#', '#tp_user#', '#tp_item#'),
5994
                    array(' ' . addslashes($dataAuthor['login']), addslashes($session->get('user-login')), $path),
5995
                    $lang->get('email_request_access_mail')
5996
                ),
5997
                $dataAuthor['email'],
5998
                ""
5999
            );
6000
        } elseif ($inputData['cat'] === 'share_this_item') {
6001
            $dataItem = DB::queryfirstrow(
6002
                'SELECT label,id_tree
6003
                FROM ' . prefixTable('items') . '
6004
                WHERE id= %i',
6005
                $inputData['id']
6006
            );
6007
6008
            // Get path
6009
            $path = geItemReadablePath(
6010
                (int) $dataItem['id_tree'],
6011
                $dataItem['label'],
6012
                $SETTINGS
6013
            );
6014
6015
            // Prepare email
6016
            prepareSendingEmail(
6017
                $lang->get('email_share_item_subject'),
6018
                str_replace(
6019
                    array(
6020
                        '#tp_link#',
6021
                        '#tp_user#',
6022
                        '#tp_item#',
6023
                    ),
6024
                    array(
6025
                        empty($SETTINGS['email_server_url']) === false ?
6026
                            $SETTINGS['email_server_url'] . '/index.php?page=items&group=' . $dataItem['id_tree'] . '&id=' . $inputData['id'] : $SETTINGS['cpassman_url'] . '/index.php?page=items&group=' . $dataItem['id_tree'] . '&id=' . $inputData['id'],
6027
                        addslashes($session->get('user-login')),
6028
                        addslashes($path),
6029
                    ),
6030
                    $lang->get('email_share_item_mail')
6031
                ),
6032
                $inputData['receipt'],
6033
                ""
6034
            );
6035
        }
6036
6037
        echo (string) prepareExchangedData(
6038
            array(
6039
                'error' => false,
6040
                'message' => '',
6041
            ),
6042
            'encode'
6043
        );
6044
        break;
6045
6046
    /*
6047
    * CASE
6048
    * manage notification of an Item
6049
    */
6050
    /*
6051
    case 'notify_a_user':
6052
        if ($inputData['key'] !== $session->get('key')) {
6053
            echo '[{"error" : "something_wrong"}]';
6054
            break;
6055
        }
6056
        if ($inputData['notifyType'] === 'on_show') {
6057
            // Check if values already exist
6058
            $data = DB::queryfirstrow(
6059
                'SELECT notification FROM ' . prefixTable('items') . ' WHERE id = %i',
6060
                $inputData['itemId']
6061
            );
6062
            $notifiedUsers = explode(';', $data['notification']);
6063
            // User is not in actual notification list
6064
            if ($inputData['status'] === 'true' && !in_array($inputData['userId'], $notifiedUsers)) {
6065
                // User is not in actual notification list and wants to be notified
6066
                DB::update(
6067
                    prefixTable('items'),
6068
                    array(
6069
                        'notification' => empty($data['notification']) ?
6070
                            $inputData['userId'] . ';'
6071
                            : $data['notification'] . $inputData['userId'] ,
6072
                    ),
6073
                    'id=%i',
6074
                    $inputData['itemId']
6075
                );
6076
                echo '[{"error" : "", "new_status":"true"}]';
6077
                break;
6078
            }
6079
            if ($inputData['status'] === 'false' && in_array($inputData['userId'], $notifiedUsers)) {
6080
                // TODO : delete user from array and store in DB
6081
                // User is in actual notification list and doesn't want to be notified
6082
                DB::update(
6083
                    prefixTable('items'),
6084
                    array(
6085
                        'notification' => empty($data['notification']) ?
6086
                        $inputData['userId']
6087
                            : $data['notification'] . ';' . $inputData['userId'],
6088
                    ),
6089
                    'id=%i',
6090
                    $inputData['itemId']
6091
                );
6092
            }
6093
        }
6094
        break;
6095
    */
6096
6097
        /*
6098
    * CASE
6099
    * Item History Log - add new entry
6100
    */
6101
    case 'history_entry_add':
6102
        if ($inputData['key'] !== $session->get('key')) {
6103
            $data = array('error' => 'key_is_wrong');
6104
            echo (string) prepareExchangedData(
6105
                $data,
6106
                'encode'
6107
            );
6108
            break;
6109
        }
6110
6111
        // decrypt and retreive data in JSON format
6112
        $dataReceived = prepareExchangedData(
6113
            $inputData['data'],
6114
            'decode'
6115
        );
6116
6117
        $item_id = filter_var($dataReceived['item_id'], FILTER_SANITIZE_NUMBER_INT);
6118
        $label = filter_var($dataReceived['label'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
6119
        $date = filter_var($dataReceived['date'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
6120
        $time = filter_var($dataReceived['time'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
6121
        $session__user_list_folders_limited = $session->get('user-list_folders_limited');
6122
6123
        // Get all informations for this item
6124
        $dataItem = DB::queryfirstrow(
6125
            'SELECT *
6126
            FROM ' . prefixTable('items') . ' as i
6127
            INNER JOIN ' . prefixTable('log_items') . ' as l ON (l.id_item = i.id)
6128
            WHERE i.id=%i AND l.action = %s',
6129
            $item_id,
6130
            'at_creation'
6131
        );
6132
        // check that actual user can access this item
6133
        $restrictionActive = true;
6134
        $restrictedTo = is_null($dataItem['restricted_to']) === false ? array_filter(explode(';', $dataItem['restricted_to'])) : [];
6135
        if (in_array($session->get('user-id'), $restrictedTo)) {
6136
            $restrictionActive = false;
6137
        }
6138
        if (empty($dataItem['restricted_to'])) {
6139
            $restrictionActive = false;
6140
        }
6141
6142
        if (((in_array($dataItem['id_tree'], $session->get('user-accessible_folders'))) && ((int) $dataItem['perso'] === 0 || ((int) $dataItem['perso'] === 1 && $dataItem['id_user'] === $session->get('user-id'))) && $restrictionActive === false)
6143
            || (isset($SETTINGS['anyone_can_modify']) && (int) $SETTINGS['anyone_can_modify'] === 1 && (int) $dataItem['anyone_can_modify'] === 1 && (in_array($dataItem['id_tree'], $session->get('user-accessible_folders')) || (int) $session->get('user-admin') === 1) && $restrictionActive === false)
6144
            || (is_array($session__user_list_folders_limited[$inputData['folderId']]) === true && in_array($inputData['id'], $session__user_list_folders_limited[$inputData['folderId']]) === true)
6145
        ) {
6146
            // Query
6147
            logItems(
6148
                $SETTINGS,
6149
                (int) $item_id,
6150
                $dataItem['label'],
6151
                $session->get('user-id'),
6152
                'at_manual',
6153
                $session->get('user-login'),
6154
                htmlspecialchars_decode($label, ENT_QUOTES),
6155
                null,
6156
                (string) dateToStamp($date.' '.$time, $SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'])
6157
            );
6158
            // Prepare new line
6159
            $data = DB::queryfirstrow(
6160
                'SELECT * FROM ' . prefixTable('log_items') . ' WHERE id_item = %i ORDER BY date DESC',
6161
                $item_id
6162
            );
6163
            $historic = date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $data['date']) . ' - ' . $session->get('user-login') . ' - ' . $lang->get($data['action']) . ' - ' . $data['raison'];
6164
            // send back
6165
            $data = array(
6166
                'error' => '',
6167
                'new_line' => '<br>' . addslashes($historic),
6168
            );
6169
            echo (string) prepareExchangedData(
6170
                $data,
6171
                'encode'
6172
            );
6173
        } else {
6174
            $data = array('error' => 'something_wrong');
6175
            echo (string) prepareExchangedData(
6176
                $data,
6177
                'encode'
6178
            );
6179
            break;
6180
        }
6181
        break;
6182
6183
        /*
6184
    * CASE
6185
    * Free Item for Edition
6186
    */
6187
    case 'free_item_for_edition':
6188
        // Check KEY
6189
        if ($inputData['key'] !== $session->get('key')) {
6190
            echo '[ { "error" : "key_not_conform" } ]';
6191
            break;
6192
        }
6193
        // Do
6194
        DB::delete(
6195
            prefixTable('items_edition'),
6196
            'item_id = %i',
6197
            $inputData['id']
6198
        );
6199
        break;
6200
6201
        /*
6202
    * CASE
6203
    * Check if Item has been changed since loaded
6204
    */
6205
    /*
6206
    case 'is_item_changed':
6207
        $data = DB::queryFirstRow(
6208
            'SELECT date FROM ' . prefixTable('log_items') . ' WHERE action = %s AND id_item = %i ORDER BY date DESC',
6209
            'at_modification',
6210
            $inputData['itemId']
6211
        );
6212
        // Check if it's in a personal folder. If yes, then force complexity overhead.
6213
        if ((int) $data['date'] > (int) $inputData['timestamp']) {
6214
            echo '{ "modified" : "1" }';
6215
        } else {
6216
            echo '{ "modified" : "0" }';
6217
        }
6218
        break;
6219
        */
6220
6221
        /*
6222
    * CASE
6223
    * Check if Item has been changed since loaded
6224
    */
6225
    case 'generate_OTV_url':
6226
        // Check KEY
6227
        if ($inputData['key'] !== $session->get('key')) {
6228
            echo '[ { "error" : "key_not_conform" } ]';
6229
            break;
6230
        }
6231
6232
        // decrypt and retreive data in JSON format
6233
        $dataReceived = prepareExchangedData(
6234
            $inputData['data'],
6235
            'decode'
6236
        );
6237
6238
        // delete all existing old otv codes
6239
        $rows = DB::query('SELECT id FROM ' . prefixTable('otv') . ' WHERE time_limit < ' . time());
6240
        foreach ($rows as $record) {
6241
            DB::delete(prefixTable('otv'), 'id=%i', $record['id']);
6242
        }
6243
6244
        // generate session
6245
        $otv_code = GenerateCryptKey(32, false, true, true, false, true);
6246
        $otv_key = GenerateCryptKey(32, false, true, true, false, true);
6247
6248
        // Generate Defuse key
6249
        $otv_user_code_encrypted = defuse_generate_personal_key($otv_key);
6250
6251
        // check if psk is correct.
6252
        $otv_key_encoded = defuse_validate_personal_key(
6253
            $otv_key,
6254
            $otv_user_code_encrypted
6255
        );
6256
6257
        // Decrypt the pwd
6258
        // Should we log a password change?
6259
        $itemQ = DB::queryFirstRow(
6260
            'SELECT s.share_key, i.pw
6261
            FROM ' . prefixTable('items') . ' AS i
6262
            INNER JOIN ' . prefixTable('sharekeys_items') . ' AS s ON (i.id = s.object_id)
6263
            WHERE s.user_id = %i AND s.object_id = %i',
6264
            $session->get('user-id'),
6265
            $dataReceived['id']
6266
        );
6267
        if (DB::count() === 0 || empty($itemQ['pw']) === true) {
6268
            // No share key found
6269
            $pw = '';
6270
        } else {
6271
            $pw = base64_decode(doDataDecryption(
6272
                $itemQ['pw'],
6273
                decryptUserObjectKey(
6274
                    $itemQ['share_key'],
6275
                    $session->get('user-private_key')
6276
                )
6277
            ));
6278
        }
6279
6280
        // Encrypt it with DEFUSE using the generated code as key
6281
        // This is required as the OTV is used by someone without any Teampass account
6282
        $passwd = cryption(
6283
            $pw,
6284
            $otv_key_encoded,
6285
            'encrypt',
6286
            $SETTINGS
6287
        );
6288
        $timestampReference = time();
6289
6290
        DB::insert(
6291
            prefixTable('otv'),
6292
            array(
6293
                'id' => null,
6294
                'item_id' => $dataReceived['id'],
6295
                'timestamp' => $timestampReference,
6296
                'originator' => intval($session->get('user-id')),
6297
                'code' => $otv_code,
6298
                'encrypted' => $passwd['string'],
6299
                'time_limit' => (int) $dataReceived['days'] * (int) TP_ONE_DAY_SECONDS + time(),
6300
                'max_views' => (int) $dataReceived['views'],
6301
                'shared_globaly' => 0,
6302
            )
6303
        );
6304
        $newID = DB::insertId();
6305
6306
        // Prepare URL content
6307
        $otv_session = array(
6308
            'otv' => true,
6309
            'code' => $otv_code,
6310
            'key' => $otv_key_encoded,
6311
            'stamp' => $timestampReference,
6312
        );
6313
6314
        if (isset($SETTINGS['otv_expiration_period']) === false) {
6315
            $SETTINGS['otv_expiration_period'] = 7;
6316
        }
6317
        $url = $SETTINGS['cpassman_url'] . '/index.php?' . http_build_query($otv_session);
6318
6319
        echo json_encode(
6320
            array(
6321
                'error' => '',
6322
                'url' => $url,
6323
                'otv_id' => $newID,
6324
            )
6325
        );
6326
        break;
6327
6328
    /*
6329
    * CASE
6330
    * Check if Item has been changed since loaded
6331
    */
6332
    case 'update_OTV_url':
6333
        // Check KEY
6334
        if ($inputData['key'] !== $session->get('key')) {
6335
            echo '[ { "error" : "key_not_conform" } ]';
6336
            break;
6337
        }
6338
6339
        // decrypt and retreive data in JSON format
6340
        $dataReceived = prepareExchangedData(
6341
            $inputData['data'],
6342
            'decode'
6343
        );
6344
6345
        // get parameters from original link
6346
        $url = $dataReceived['original_link'];
6347
        $parts = parse_url($url);
6348
        if(isset($parts['query'])){
6349
            parse_str($parts['query'], $orignal_link_parameters);
6350
        } else {
6351
            $orignal_link_parameters = array();
6352
        }
6353
6354
        // update database
6355
        DB::update(
6356
            prefixTable('otv'),
6357
            array(
6358
                'time_limit' => (int) $dataReceived['days'] * (int) TP_ONE_DAY_SECONDS + time(),
6359
                'max_views' => (int) $dataReceived['views'],
6360
                'shared_globaly' => (int) $dataReceived['shared_globaly'] === 1 ? 1 : 0,
6361
            ),
6362
            'id = %i',
6363
            $dataReceived['otv_id']
6364
        );
6365
6366
        // Prepare URL content
6367
        $otv_session = [
6368
            'otv' => true,
6369
            'code' => $orignal_link_parameters['code'],
6370
            'key' => $orignal_link_parameters['key'],
6371
            'stamp' => $orignal_link_parameters['stamp'],
6372
        ];
6373
6374
        if ((int) $dataReceived['shared_globaly'] === 1 && isset($SETTINGS['otv_subdomain']) === true && empty($SETTINGS['otv_subdomain']) === false) {
6375
            // Inject subdomain in URL by convering www. to subdomain.
6376
            $domain_scheme = parse_url($SETTINGS['cpassman_url'], PHP_URL_SCHEME);
6377
            $domain_host = parse_url($SETTINGS['cpassman_url'], PHP_URL_HOST);
6378
            if (str_contains($domain_host, 'www.') === true) {
6379
                $domain_host = (string) $SETTINGS['otv_subdomain'] . '.' . substr($domain_host, 4);
6380
            } else {
6381
                $domain_host = (string) $SETTINGS['otv_subdomain'] . '.' . $domain_host;
6382
            }
6383
            $url = $domain_scheme.'://'.$domain_host . '/index.php?'.http_build_query($otv_session);
6384
        } else {
6385
            $url = $SETTINGS['cpassman_url'] . '/index.php?'.http_build_query($otv_session);
6386
        }
6387
6388
        echo (string) prepareExchangedData(
6389
            array(
6390
                'error' => false,
6391
                'new_url' => $url,
6392
            ),
6393
            'encode'
6394
        );
6395
        break;
6396
6397
6398
        /*
6399
    * CASE
6400
    * Free Item for Edition
6401
    */
6402
    case 'image_preview_preparation':
6403
        // Check KEY
6404
        if ($inputData['key'] !== $session->get('key')) {
6405
            echo (string) prepareExchangedData(
6406
                array(
6407
                    'error' => true,
6408
                    'message' => $lang->get('key_is_not_correct'),
6409
                ),
6410
                'encode'
6411
            );
6412
            break;
6413
        }
6414
6415
        // get file info
6416
        $file_info = DB::queryfirstrow(
6417
            'SELECT f.id AS id, f.file AS file, f.name AS name, f.status AS status,
6418
            f.extension AS extension, f.type AS type,
6419
            s.share_key AS share_key
6420
            FROM ' . prefixTable('files') . ' AS f
6421
            INNER JOIN ' . prefixTable('sharekeys_files') . ' AS s ON (f.id = s.object_id)
6422
            WHERE s.user_id = %i AND s.object_id = %i',
6423
            $session->get('user-id'),
6424
            $inputData['id']
6425
        );
6426
6427
        // Check if user has this sharekey
6428
        if (empty($file_info['share_key']) === true) {
6429
            echo (string) prepareExchangedData(
6430
                array(
6431
                    'error' => true,
6432
                    'message' => $lang->get('no_sharekey_found'),
6433
                ),
6434
                'encode'
6435
            );
6436
            break;
6437
        }
6438
6439
        //$fileName = basename($file_info['name'], '.'.$file_info['extension']);
6440
6441
        // prepare image info
6442
        $post_title = basename($file_info['name'], '.' . $file_info['extension']);
6443
        $post_title = isBase64($post_title) === true ? base64_decode($post_title) : $post_title;
6444
        
6445
        // Get image content
6446
        // deepcode ignore PT: File and path are secured directly inside the function decryptFile()
6447
        $fileContent = decryptFile(
6448
            $file_info['file'],
6449
            $SETTINGS['path_to_upload_folder'],
6450
            decryptUserObjectKey($file_info['share_key'], $session->get('user-private_key'))
6451
        );
6452
6453
        // Check error
6454
        if (isset($fileContent['error']) === true) {
6455
            echo (string) prepareExchangedData(
6456
                array(
6457
                    'error' => true,
6458
                    'message' => $fileContent['message'],
6459
                ),
6460
                'encode'
6461
            );
6462
            break;
6463
        }
6464
6465
        // Encrypt data to return
6466
        echo (string) prepareExchangedData(
6467
            array(
6468
                'error' => false,
6469
                'filename' => $post_title . '.' . $file_info['extension'],
6470
                'file_type' => $file_info['type'],
6471
                'file_content' => $fileContent,
6472
            ),
6473
            'encode'
6474
        );
6475
        break;
6476
6477
        /*
6478
    * CASE
6479
    * Free Item for Edition
6480
    */
6481
    /*
6482
    case 'delete_file':
6483
        // Check KEY
6484
        if ($inputData['key'] !== $session->get('key')) {
6485
            echo '[ { "error" : "key_not_conform" } ]';
6486
            break;
6487
        }
6488
6489
        // get file info
6490
        $result = DB::queryfirstrow(
6491
            'SELECT file FROM ' . prefixTable('files') . ' WHERE id=%i',
6492
            intval(substr(filter_input(INPUT_POST, 'uri', FILTER_SANITIZE_FULL_SPECIAL_CHARS), 1))
6493
        );
6494
6495
        fileDelete($SETTINGS['path_to_upload_folder'] . '/' . $result['file'] . $inputData['fileSuffix'], $SETTINGS);
6496
6497
        break;
6498
        */
6499
6500
        /*
6501
    * CASE
6502
    * Get list of users that have access to the folder
6503
    */
6504
    case 'check_for_title_duplicate':
6505
        // Check KEY
6506
        if ($inputData['key'] !== $session->get('key')) {
6507
            echo '[ { "error" : "key_not_conform" } ]';
6508
            break;
6509
        }
6510
        $duplicate = 0;
6511
6512
        // decrypt and retreive data in JSON format
6513
        $dataReceived = prepareExchangedData(
6514
            $inputData['data'],
6515
            'decode'
6516
        );
6517
        // Prepare variables
6518
        $label = htmlspecialchars_decode($dataReceived['label']);
6519
        $idFolder = $dataReceived['idFolder'];
6520
6521
        // don't check if Personal Folder
6522
        $data = DB::queryFirstRow('SELECT title FROM ' . prefixTable('nested_tree') . ' WHERE id = %i', $idFolder);
6523
        if ($data['title'] === $session->get('user-id')) {
6524
            // send data
6525
            echo '[{"duplicate" : "' . $duplicate . '" , error" : ""}]';
6526
        } else {
6527
            if ($inputData['option'] === 'same_folder') {
6528
                // case unique folder
6529
                DB::query(
6530
                    'SELECT label
6531
                    FROM ' . prefixTable('items') . '
6532
                    WHERE id_tree = %i AND label = %s',
6533
                    $idFolder,
6534
                    $label
6535
                );
6536
            } else {
6537
                // case complete database
6538
6539
                //get list of personal folders
6540
                $arrayPf = array();
6541
                if (empty($row['id']) === false) {
6542
                    $rows = DB::query(
6543
                        'SELECT id FROM ' . prefixTable('nested_tree') . ' WHERE personal_folder = %i',
6544
                        '1'
6545
                    );
6546
                    foreach ($rows as $record) {
6547
                        if (!in_array($record['id'], $arrayPf)) {
6548
                            array_push($arrayPf, $record['id']);
6549
                        }
6550
                    }
6551
                }
6552
6553
                // build WHERE condition
6554
                $where = new WhereClause('and');
6555
                $where->add('id_tree = %i', $idFolder);
6556
                $where->add('label = %s', $label);
6557
                if (empty($arrayPf) === false) {
6558
                    $where->add('id_tree NOT IN (' . implode(',', $arrayPf) . ')');
6559
                }
6560
6561
                DB::query(
6562
                    'SELECT label
6563
                    FROM ' . prefixTable('items') . '
6564
                    WHERE %l',
6565
                    $where
6566
                );
6567
            }
6568
6569
            // count results
6570
            if (DB::count() > 0) {
6571
                $duplicate = 1;
6572
            }
6573
6574
            // send data
6575
            echo '[{"duplicate" : "' . $duplicate . '" , "error" : ""}]';
6576
        }
6577
        break;
6578
6579
        /*
6580
    * CASE
6581
    * Get list of users that have access to the folder
6582
    */
6583
    case 'refresh_visible_folders':
6584
        // Check KEY
6585
        if ($inputData['key'] !== $session->get('key')) {
6586
            echo (string) prepareExchangedData(
6587
                array(
6588
                    'error' => true,
6589
                    'message' => $lang->get('key_is_not_correct'),
6590
                ),
6591
                'encode'
6592
            );
6593
            break;
6594
        }
6595
        $arr_data = [];
6596
        $arrayFolders = [];
6597
6598
        // decrypt and retreive data in JSON format
6599
        $dataReceived = prepareExchangedData(
6600
            $inputData['data'],
6601
            'decode'
6602
        );
6603
6604
        // Will we show the root folder?
6605
        if ($session->has('user-can_create_root_folder') && (int) $session->get('user-can_create_root_folder') && $session->has('user-can_create_root_folder') && (int) $session->get('user-can_create_root_folder') && null !== $session->get('user-can_create_root_folder') && (int) $session->get('user-can_create_root_folder') === 1
6606
        ) {
6607
            $arr_data['can_create_root_folder'] = 1;
6608
        } else {
6609
            $arr_data['can_create_root_folder'] = 0;
6610
        }
6611
6612
        // do we have a cache to be used?
6613
        if (isset($dataReceived['force_refresh_cache']) === true && $dataReceived['force_refresh_cache'] === false) {
6614
            $goCachedFolders = loadFoldersListByCache('visible_folders', 'folders');
6615
            if ($goCachedFolders['state'] === true) {
6616
                $arr_data['folders'] = json_decode($goCachedFolders['data'], true);
6617
                // send data
6618
                echo (string) prepareExchangedData(
6619
                    [
6620
                        'error' => 'false',
6621
                        'html_json' => ($arr_data),
6622
                        'extra' => isset($goCachedFolders['extra']) ? $goCachedFolders['extra'] : '',
6623
                    ],
6624
                    'encode'
6625
                );
6626
                break;
6627
            }
6628
        }
6629
        // Build list of visible folders
6630
        if (
6631
            (int) $session->get('user-admin') === 1
6632
        ) {
6633
            $session->set('user-accessible_folders', $session->get('user-personal_visible_folders'));
6634
        }
6635
6636
        if (null !== $session->get('user-list_folders_limited') && count($session->get('user-list_folders_limited')) > 0) {
6637
            $listFoldersLimitedKeys = array_keys($session->get('user-list_folders_limited'));
6638
        } else {
6639
            $listFoldersLimitedKeys = array();
6640
        }
6641
        // list of items accessible but not in an allowed folder
6642
        if (
6643
            null !== $session->get('system-list_restricted_folders_for_items') &&
6644
            count($session->get('system-list_restricted_folders_for_items')) > 0
6645
        ) {
6646
            $listRestrictedFoldersForItemsKeys = array_keys($session->get('system-list_restricted_folders_for_items'));
6647
        } else {
6648
            $listRestrictedFoldersForItemsKeys = array();
6649
        }
6650
        
6651
        //Build tree
6652
        $tree->rebuild();
6653
        $folders = $tree->getDescendants();
6654
        foreach ($folders as $folder) {
6655
            // Be sure that user can only see folders he/she is allowed to
6656
            if (
6657
                in_array($folder->id, $session->get('user-forbiden_personal_folders')) === false
6658
                || in_array($folder->id, $session->get('user-accessible_folders')) === true
6659
                || in_array($folder->id, $listFoldersLimitedKeys) === true
6660
                || in_array($folder->id, $listRestrictedFoldersForItemsKeys) === true
6661
            ) {
6662
                // Init
6663
                $displayThisNode = false;
6664
6665
                // Check if any allowed folder is part of the descendants of this node
6666
                $nodeDescendants = $tree->getDescendantsFromTreeArray($folders, $folder->id);
6667
                foreach ($nodeDescendants as $node) {
6668
                    // manage tree counters
6669
                    if (
6670
                        in_array($node, array_merge($session->get('user-accessible_folders'), $session->get('system-list_restricted_folders_for_items'))) === true
6671
                        || (is_array($listFoldersLimitedKeys) === true && in_array($node, $listFoldersLimitedKeys) === true)
6672
                        || (is_array($listRestrictedFoldersForItemsKeys) === true && in_array($node, $listRestrictedFoldersForItemsKeys) === true)
6673
                    ) {
6674
                        $displayThisNode = true;
6675
                        //break;
6676
                    }
6677
                }
6678
6679
                if ($displayThisNode === true) {
6680
                    // ALL FOLDERS
6681
                    // Build path
6682
                    $arbo = $tree->getPath($folder->id, false);
6683
                    $path = '';
6684
                    foreach ($arbo as $elem) {
6685
                        $path = (empty($path) ? '' : $path . ' / ') . htmlspecialchars(stripslashes(htmlspecialchars_decode($elem->title, ENT_QUOTES)), ENT_QUOTES);
6686
                    }
6687
6688
                    // Build array
6689
                    array_push($arrayFolders, [
6690
                        'id' => (int) $folder->id,
6691
                        'level' => (int) $folder->nlevel,
6692
                        'title' => ((int) $folder->title === (int) $session->get('user-id') && (int) $folder->nlevel === 1) ? $session->get('user-login') : $folder->title,
6693
                        'disabled' => (
6694
                            in_array($folder->id, $session->get('user-accessible_folders')) === false
6695
                            || in_array($folder->id, $session->get('user-read_only_folders')) === true
6696
                        ) ? 1 : 0,
6697
                        'parent_id' => (int) $folder->parent_id,
6698
                        'perso' => (int) $folder->personal_folder,
6699
                        'path' => htmlspecialchars($path),
6700
                        'is_visible_active' => (null !== $session->get('user-read_only_folders') && in_array($folder->id, $session->get('user-read_only_folders'))) ? 1 : 0,
6701
                    ]);
6702
                }
6703
            }
6704
        }
6705
        if (empty($arrayFolders) === false) {
6706
            // store array to return
6707
            $arr_data['folders'] = $arrayFolders;
6708
6709
            // update session
6710
            $session->set('user-folders_list', $arr_data['folders']);
6711
6712
            // update cache
6713
            cacheTreeUserHandler(
6714
                (int) $session->get('user-id'),
6715
                json_encode($arr_data['folders']),
6716
                $SETTINGS,
6717
                'visible_folders',
6718
            );
6719
        }
6720
6721
        // send data
6722
        echo (string) prepareExchangedData(
6723
            [
6724
                'error' => 'false',
6725
                'html_json' => $arr_data,
6726
            ],
6727
            'encode'
6728
        );
6729
6730
        break;
6731
6732
        /*
6733
    * CASE
6734
    * Get list of users that have access to the folder
6735
    */
6736
    case 'refresh_folders_other_info':
6737
        // Check KEY
6738
        if ($inputData['key'] !== $session->get('key')) {
6739
            echo (string) prepareExchangedData(
6740
                array(
6741
                    'error' => true,
6742
                    'message' => $lang->get('key_is_not_correct'),
6743
                ),
6744
                'encode'
6745
            );
6746
            break;
6747
        }
6748
6749
        $ret = [];
6750
        $foldersArray = json_decode($inputData['data'], true);
6751
        if (is_array($foldersArray) === true && $inputData['data'] !== '[null]') {
6752
            $rows = DB::query(
6753
                'SELECT id, categories
6754
                FROM ' . prefixTable('nested_tree') . '
6755
                WHERE id IN (%l)',
6756
                implode(',', $foldersArray)
6757
            );
6758
            foreach ($rows as $record) {
6759
                if (empty($record['categories']) === false) {
6760
                    array_push(
6761
                        $ret,
6762
                        array($record['id'] => json_decode($record['categories'], true))
6763
                    );
6764
                }
6765
            }
6766
        }
6767
6768
        // send data
6769
        echo (string) prepareExchangedData(
6770
            [
6771
                'error' => '',
6772
                'result' => $ret,
6773
            ],
6774
            'encode'
6775
        );
6776
6777
        break;
6778
6779
        /*
6780
    * CASE
6781
    * Load item history
6782
    */
6783
    case 'load_item_history':
6784
        // Check KEY
6785
        if ($inputData['key'] !== $session->get('key')) {
6786
            echo (string) prepareExchangedData(
6787
                array('error' => 'ERR_KEY_NOT_CORRECT'),
6788
                'encode'
6789
            );
6790
            break;
6791
        }
6792
        
6793
        // get item info
6794
        $dataItem = DB::queryFirstRow(
6795
            'SELECT *
6796
            FROM ' . prefixTable('items') . '
6797
            WHERE id=%i',
6798
            $inputData['itemId']
6799
        );
6800
6801
        // get item history
6802
        $history = [];
6803
        $previous_passwords = [];
6804
        $rows = DB::query(
6805
            'SELECT l.date as date, l.action as action, l.raison as raison,
6806
                u.login as login, u.avatar_thumb as avatar_thumb, u.name as name, u.lastname as lastname,
6807
                l.old_value as old_value
6808
            FROM ' . prefixTable('log_items') . ' as l
6809
            INNER JOIN ' . prefixTable('users') . ' as u ON (l.id_user=u.id)
6810
            WHERE id_item=%i AND l.action NOT IN (%l)
6811
            ORDER BY date DESC',
6812
            $inputData['itemId'],
6813
            '"at_shown","at_password_copied", "at_shown", "at_password_shown"'
6814
        );
6815
        foreach ($rows as $record) {
6816
            if (empty($record['raison']) === true) {
6817
                $reason[0] = '';
6818
            } else {
6819
                $reason = array_map('trim', explode(':', $record['raison']));
6820
            }
6821
            
6822
            // imported via API
6823
            if (empty($record['login']) === true) {
6824
                $record['login'] = $lang->get('imported_via_api') . ' [' . $record['raison'] . ']';
6825
            }
6826
            
6827
            // Prepare avatar
6828
            if (isset($record['avatar_thumb']) && empty($record['avatar_thumb']) === false) {
6829
                if (file_exists($SETTINGS['cpassman_dir'] . '/includes/avatars/' . $record['avatar_thumb'])) {
6830
                    $avatar = $SETTINGS['cpassman_url'] . '/includes/avatars/' . $record['avatar_thumb'];
6831
                } else {
6832
                    $avatar = $SETTINGS['cpassman_url'] . '/includes/images/photo.jpg';
6833
                }
6834
            } else {
6835
                $avatar = $SETTINGS['cpassman_url'] . '/includes/images/photo.jpg';
6836
            }
6837
6838
            // Prepare action
6839
            $action = '';
6840
            $detail = '';
6841
            if ($reason[0] === 'at_pw') {
6842
                $action = $lang->get($reason[0]);
6843
                
6844
                // get previous password
6845
                if (empty($record['old_value']) === false) {
6846
                    $previous_pwd = cryption(
6847
                        $record['old_value'],
6848
                        '',
6849
                        'decrypt'
6850
                    );
6851
                    array_push(
6852
                        $previous_passwords, 
6853
                        [
6854
                            'password' => htmlentities($previous_pwd['string']),
6855
                            'date' => date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['date']),
6856
                        ]
6857
                    );
6858
                }
6859
            } elseif ($record['action'] === 'at_manual') {
6860
                $detail = $reason[0];
6861
                $action = $lang->get($record['action']);
6862
            } elseif ($reason[0] === 'at_description') {
6863
                $action = $lang->get('description_has_changed');
6864
            } elseif (empty($record['raison']) === false && $reason[0] !== 'at_creation') {
6865
                $action = $lang->get($reason[0]);
6866
                if ($reason[0] === 'at_moved') {
6867
                    $tmp = explode(' -> ', $reason[1]);
6868
                    $detail = $lang->get('from') . ' <span class="font-weight-light">' . $tmp[0] . '</span> ' . $lang->get('to') . ' <span class="font-weight-light">' . $tmp[1] . ' </span>';
6869
                } elseif ($reason[0] === 'at_field') {
6870
                    $tmp = explode(' => ', $reason[1]);
6871
                    if (count($tmp) > 1) {
6872
                        $detail = '<b>' . trim($tmp[0]) . '</b> | ' . $lang->get('previous_value') .
6873
                            ': <span class="font-weight-light">' . trim($tmp[1]) . '</span>';
6874
                    } else {
6875
                        $detail = trim($reason[1]);
6876
                    }
6877
                } elseif (in_array($reason[0], array('at_restriction', 'at_email', 'at_login', 'at_label', 'at_url', 'at_tag')) === true) {
6878
                    $tmp = explode(' => ', $reason[1]);
6879
                    $detail = empty(trim($tmp[0])) === true ?
6880
                        $lang->get('no_previous_value') : $lang->get('previous_value') . ': <span class="font-weight-light">' . $tmp[0] . ' </span>';
6881
                } elseif ($reason[0] === 'at_automatic_del') {
6882
                    $detail = $lang->get($reason[1]);
6883
                } elseif ($reason[0] === 'at_anyoneconmodify' || $reason[0] === 'at_otp_status') {
6884
                    $detail = $lang->get($reason[1]);
6885
                } elseif ($reason[0] === 'at_add_file' || $reason[0] === 'at_del_file') {
6886
                    $tmp = explode(':', $reason[1]);
6887
                    $tmp = explode('.', $tmp[0]);
6888
                    $detail = isBase64($tmp[0]) === true ?
6889
                        base64_decode($tmp[0]) . '.' . $tmp[1] : $tmp[0];
6890
                } elseif ($reason[0] === 'at_import') {
6891
                    $detail = '';
6892
                } elseif (in_array($reason[0], array('csv', 'pdf')) === true) {
6893
                    $detail = $reason[0];
6894
                    $action = $lang->get('exported_to_file');
6895
                } else {
6896
                    $detail = $reason[0];
6897
                }
6898
            } else {
6899
                $detail = $lang->get($record['action']);
6900
                $action = '';
6901
            }
6902
6903
            array_push(
6904
                $history,
6905
                array(
6906
                    'avatar' => $avatar,
6907
                    'login' => $record['login'],
6908
                    'name' => $record['name'] . ' ' . $record['lastname'],
6909
                    'date' => date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['date']),
6910
                    'action' => $action,
6911
                    'detail' => $detail,
6912
                )
6913
            );
6914
        }
6915
6916
        // order previous passwords by date
6917
        $key_values = array_column($previous_passwords, 'date'); 
6918
        array_multisort($key_values, /** @scrutinizer ignore-type */SORT_DESC, $previous_passwords);
6919
6920
        // send data
6921
        // deepcode ignore ServerLeak: Data is encrypted before being sent
6922
        echo (string) prepareExchangedData(
6923
            [
6924
                'error' => '',
6925
                'history' => $history,
6926
                'previous_passwords' => $previous_passwords,
6927
            ],
6928
            'encode'
6929
        );
6930
6931
        break;
6932
6933
    case 'suggest_item_change':
6934
        // Check KEY
6935
        if ($inputData['key'] !== $session->get('key')) {
6936
            echo (string) prepareExchangedData(
6937
                array(
6938
                    'error' => 'key_not_conform',
6939
                    'message' => $lang->get('key_is_not_correct'),
6940
                ),
6941
                'encode'
6942
            );
6943
            break;
6944
        }
6945
        // decrypt and retrieve data in JSON format
6946
        $data_received = prepareExchangedData(
6947
            $inputData['data'],
6948
            'decode'
6949
        );
6950
6951
        // prepare variables
6952
        $label = htmlspecialchars_decode($data_received['label'], ENT_QUOTES);
6953
        $pwd = htmlspecialchars_decode($data_received['password']);
6954
        $login = htmlspecialchars_decode($data_received['login'], ENT_QUOTES);
6955
        $email = htmlspecialchars_decode($data_received['email']);
6956
        $url = htmlspecialchars_decode($data_received['url']);
6957
        $folder = htmlspecialchars_decode($data_received['folder_id']);
6958
        $comment = htmlspecialchars_decode($data_received['comment']);
6959
        $item_id = htmlspecialchars_decode($data_received['item_id']);
6960
6961
        if (empty($pwd)) {
6962
            $cryptedStuff['encrypted'] = '';
6963
            $cryptedStuff['objectKey'] = '';
6964
        } else {
6965
            $cryptedStuff = doDataEncryption($pwd);
6966
        }
6967
6968
        // query
6969
        DB::insert(
6970
            prefixTable('items_change'),
6971
            array(
6972
                'item_id' => $item_id,
6973
                'label' => $label,
6974
                'pw' => $encrypt['string'],
6975
                'login' => $login,
6976
                'email' => $email,
6977
                'url' => $url,
6978
                'description' => '',
6979
                'comment' => $comment,
6980
                'folder_id' => $folder,
6981
                'user_id' => (int) $session->get('user-id'),
6982
                'timestamp' => time(),
6983
            )
6984
        );
6985
        $newID = DB::insertId();
6986
6987
        // Create sharekeys for users
6988
        storeUsersShareKey(
6989
            prefixTable('sharekeys_items'),
6990
            0,
6991
            (int) $folder,
6992
            (int) $newID,
6993
            $cryptedStuff['objectKey'],
6994
        );
6995
6996
        // get some info to add to the notification email
6997
        $resp_user = DB::queryfirstrow(
6998
            'SELECT login FROM ' . prefixTable('users') . ' WHERE id = %i',
6999
            $session->get('user-id')
7000
        );
7001
        $resp_folder = DB::queryfirstrow(
7002
            'SELECT title FROM ' . prefixTable('nested_tree') . ' WHERE id = %i',
7003
            $folder
7004
        );
7005
7006
        // notify Managers
7007
        $emailSettings = new EmailSettings($SETTINGS);
7008
        $emailService = new EmailService();
7009
        $rows = DB::query(
7010
            'SELECT email
7011
            FROM ' . prefixTable('users') . '
7012
            WHERE `gestionnaire` = %i AND `email` IS NOT NULL',
7013
            1
7014
        );
7015
        foreach ($rows as $record) {
7016
            $emailService->sendMail(
7017
                $lang->get('suggestion_notify_subject'),
7018
                str_replace(array('#tp_label#', '#tp_user#', '#tp_folder#'), array(addslashes($label), addslashes($resp_user['login']), addslashes($resp_folder['title'])), $lang->get('suggestion_notify_body')),
7019
                $record['email'],
7020
                $emailSettings
7021
            );
7022
        }
7023
7024
        echo (string) prepareExchangedData(
7025
            array(
7026
                'error' => '',
7027
            ),
7028
            'encode'
7029
        );
7030
        break;
7031
7032
    case 'build_list_of_users':
7033
        // Check KEY
7034
        if ($inputData['key'] !== $session->get('key')) {
7035
            echo '[ { "error" : "key_not_conform" } ]';
7036
            break;
7037
        }
7038
7039
        // Get list of users
7040
        $usersList = array();
7041
        $usersString = '';
7042
        $rows = DB::query('SELECT id,login,email FROM ' . prefixTable('users') . ' ORDER BY login ASC');
7043
        foreach ($rows as $record) {
7044
            $usersList[$record['login']] = array(
7045
                'id' => $record['id'],
7046
                'login' => $record['login'],
7047
                'email' => $record['email'],
7048
            );
7049
            $usersString .= $record['id'] . '#' . $record['login'] . ';';
7050
        }
7051
7052
        $data = array(
7053
            'error' => '',
7054
            'list' => $usersString,
7055
        );
7056
7057
        // send data
7058
        echo (string) prepareExchangedData(
7059
            $data,
7060
            'encode'
7061
        );
7062
        break;
7063
7064
    case 'send_request_access':
7065
        // Check KEY
7066
        if ($inputData['key'] !== $session->get('key')) {
7067
            echo (string) prepareExchangedData(
7068
                array(
7069
                    'error' => 'key_not_conform',
7070
                    'message' => $lang->get('key_is_not_correct'),
7071
                ),
7072
                'encode'
7073
            );
7074
            break;
7075
        }
7076
        // decrypt and retrieve data in JSON format
7077
        $dataReceived = prepareExchangedData(
7078
            $inputData['data'],
7079
            'decode'
7080
        );
7081
7082
        // prepare variables
7083
        //$post_email_body = filter_var($dataReceived['email'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
7084
        $inputData['itemId'] = (int) filter_var($dataReceived['id'], FILTER_SANITIZE_NUMBER_INT);
7085
7086
        // Send email
7087
        $dataItem = DB::queryfirstrow(
7088
            'SELECT label, id_tree
7089
            FROM ' . prefixTable('items') . '
7090
            WHERE id = %i',
7091
            $inputData['itemId']
7092
        );
7093
7094
        // Do log
7095
        logItems(
7096
            $SETTINGS,
7097
            (int) $inputData['itemId'],
7098
            $dataItem['label'],
7099
            $session->get('user-id'),
7100
            'at_access',
7101
            $session->get('user-login')
7102
        );
7103
7104
        // Return
7105
        echo (string) prepareExchangedData(
7106
            array(
7107
                'error' => false,
7108
                'message' => '',
7109
            ),
7110
            'encode'
7111
        );
7112
7113
        break;
7114
7115
        /*
7116
    * CASE
7117
    * save_notification_status
7118
    */
7119
    case 'save_notification_status':
7120
        // Check KEY
7121
        if ($inputData['key'] !== $session->get('key')) {
7122
            echo (string) prepareExchangedData(
7123
                array(
7124
                    'error' => 'key_not_conform',
7125
                    'message' => $lang->get('key_is_not_correct'),
7126
                ),
7127
                'encode'
7128
            );
7129
            break;
7130
        }
7131
        // decrypt and retrieve data in JSON format
7132
        $dataReceived = prepareExchangedData(
7133
            $inputData['data'],
7134
            'decode'
7135
        );
7136
7137
        // prepare variables
7138
        $post_notification_status = (int) filter_var($dataReceived['notification_status'], FILTER_SANITIZE_NUMBER_INT);
7139
        $inputData['itemId'] = (int) filter_var($dataReceived['item_id'], FILTER_SANITIZE_NUMBER_INT);
7140
7141
        DB::query(
7142
            'SELECT *
7143
            FROM ' . prefixTable('notification') . '
7144
            WHERE item_id = %i AND user_id = %i',
7145
            $inputData['itemId'],
7146
            $session->get('user-id')
7147
        );
7148
        if (DB::count() > 0) {
7149
            // Notification is set for this user on this item
7150
            if ((int) $post_notification_status === 0) {
7151
                // Remove the notification
7152
                DB::delete(
7153
                    prefixTable('notification'),
7154
                    'item_id = %i AND user_id = %i',
7155
                    $inputData['itemId'],
7156
                    $session->get('user-id')
7157
                );
7158
            }
7159
        } else {
7160
            // Notification is not set on this item
7161
            if ((int) $post_notification_status === 1) {
7162
                // Add the notification
7163
                DB::insert(
7164
                    prefixTable('notification'),
7165
                    array(
7166
                        'item_id' => $inputData['itemId'],
7167
                        'user_id' => (int) $session->get('user-id'),
7168
                    )
7169
                );
7170
            }
7171
        }
7172
7173
        $data = array(
7174
            'error' => false,
7175
            'message' => '',
7176
        );
7177
7178
        // send data
7179
        echo (string) prepareExchangedData(
7180
            $data,
7181
            'encode'
7182
        );
7183
7184
        break;
7185
7186
        /*
7187
    * CASE
7188
    * delete_uploaded_files_but_not_saved
7189
    */
7190
    case 'delete_uploaded_files_but_not_saved':
7191
        // Check KEY
7192
        if ($inputData['key'] !== $session->get('key')) {
7193
            echo (string) prepareExchangedData(
7194
                array(
7195
                    'error' => 'key_not_conform',
7196
                    'message' => $lang->get('key_is_not_correct'),
7197
                ),
7198
                'encode'
7199
            );
7200
            break;
7201
        }
7202
        // decrypt and retrieve data in JSON format
7203
        $dataReceived = prepareExchangedData(
7204
            $inputData['data'],
7205
            'decode'
7206
        );
7207
7208
        // prepare variables
7209
        $inputData['itemId'] = (int) filter_var($dataReceived['item_id'], FILTER_SANITIZE_NUMBER_INT);
7210
7211
        // Delete non confirmed files for this item
7212
        // And related logs
7213
        $rows = DB::query(
7214
            'SELECT id, file AS filename
7215
            FROM ' . prefixTable('files') . '
7216
            WHERE id_item = %i AND confirmed = %i',
7217
            $inputData['itemId'],
7218
            0
7219
        );
7220
        foreach ($rows as $file) {
7221
            // Delete file in DB
7222
            DB::delete(
7223
                prefixTable('files'),
7224
                'id = %i',
7225
                $file['id']
7226
            );
7227
7228
            // Delete file on server
7229
            unlink($SETTINGS['path_to_upload_folder'] . '/' . TP_FILE_PREFIX . base64_decode($file['filename']));
7230
7231
            // Delete related logs
7232
            $logFile = DB::query(
7233
                'SELECT increment_id, raison
7234
                FROM ' . prefixTable('log_items') . '
7235
                WHERE id_item = %i AND id_user = %i AND action = %s AND raison LIKE "at_add_file :%"',
7236
                $inputData['itemId'],
7237
                $session->get('user-id'),
7238
                'at_modification'
7239
            );
7240
            foreach ($logFile as $log) {
7241
                $tmp = explode(':', $log['raison']);
7242
                if (count($tmp) === 3 && (int) $tmp[2] === (int) $file['id']) {
7243
                    DB::delete(
7244
                        prefixTable('log_items'),
7245
                        'increment_id = %i',
7246
                        $log['increment_id']
7247
                    );
7248
                }
7249
            }
7250
        }
7251
7252
        $data = array(
7253
            'error' => false,
7254
            'message' => '',
7255
        );
7256
7257
        // send data
7258
        echo (string) prepareExchangedData(
7259
            $data,
7260
            'encode'
7261
        );
7262
7263
        break;
7264
7265
        /*
7266
    * CASE
7267
    * confirm_attachments
7268
    */
7269
    case 'confirm_attachments':
7270
        // Check KEY
7271
        if ($inputData['key'] !== $session->get('key')) {
7272
            echo (string) prepareExchangedData(
7273
                array(
7274
                    'error' => 'key_not_conform',
7275
                    'message' => $lang->get('key_is_not_correct'),
7276
                ),
7277
                'encode'
7278
            );
7279
            break;
7280
        }
7281
        // decrypt and retrieve data in JSON format
7282
        $dataReceived = prepareExchangedData(
7283
            $inputData['data'],
7284
            'decode'
7285
        );
7286
7287
        // prepare variables
7288
        $inputData['itemId'] = (int) filter_var($dataReceived['item_id'], FILTER_SANITIZE_NUMBER_INT);
7289
7290
        // Confirm attachments
7291
        $rows = DB::query(
7292
            'SELECT id, file AS filename
7293
            FROM ' . prefixTable('files') . '
7294
            WHERE id_item = %i AND confirmed = %i',
7295
            $inputData['itemId'],
7296
            0
7297
        );
7298
        foreach ($rows as $file) {
7299
            DB::update(
7300
                prefixTable('files'),
7301
                array(
7302
                    'confirmed' => 1,
7303
                ),
7304
                'id_item = %i',
7305
                $inputData['itemId']
7306
            );
7307
        }
7308
7309
        $data = array(
7310
            'error' => false,
7311
            'message' => '',
7312
        );
7313
7314
        // send data
7315
        echo (string) prepareExchangedData(
7316
            $data,
7317
            'encode'
7318
        );
7319
7320
        break;
7321
7322
    /*
7323
    * CASE
7324
    * check_current_access_rights
7325
    */
7326
    case 'check_current_access_rights':
7327
        // Check KEY
7328
        if ($inputData['key'] !== $session->get('key')) {
7329
            echo (string) prepareExchangedData(
7330
                array(
7331
                    'error' => 'key_not_conform',
7332
                    'message' => $lang->get('key_is_not_correct'),
7333
                ),
7334
                'encode'
7335
            );
7336
            break;
7337
        }
7338
7339
        // Init
7340
        $editionLock = false;
7341
7342
        // decrypt and retrieve data in JSON format
7343
        $dataReceived = prepareExchangedData(
7344
            $inputData['data'],
7345
            'decode'
7346
        );
7347
        
7348
        // prepare variables
7349
        $inputData['userId'] = (int) filter_var($dataReceived['userId'], FILTER_SANITIZE_NUMBER_INT);
7350
        $inputData['itemId'] = (int) filter_var($dataReceived['itemId'], FILTER_SANITIZE_NUMBER_INT);
7351
        $inputData['treeId'] = (int) filter_var($dataReceived['treeId'], FILTER_SANITIZE_NUMBER_INT);
7352
7353
        // Check rights
7354
        $data = getCurrentAccessRights(
7355
            $inputData['userId'],
7356
            $inputData['itemId'],
7357
            $inputData['treeId'],
7358
        );
7359
7360
        // send data
7361
        echo (string) prepareExchangedData(
7362
            $data,
7363
            'encode'
7364
        );
7365
7366
        break;
7367
}
7368
7369
// Build the QUERY in case of GET
7370
if (isset($inputData['getType'])) {
7371
    switch ($inputData['getType']) {
7372
        /*
7373
        * CASE
7374
        * Autocomplet for TAGS
7375
        */
7376
        case 'autocomplete_tags':
7377
            // Get a list off all existing TAGS
7378
            $listOfTags = '';
7379
            $rows = DB::query('SELECT tag FROM ' . prefixTable('tags') . ' WHERE tag LIKE %ss GROUP BY tag', $inputData['getTerm']);
7380
            foreach ($rows as $record) {
7381
                if (empty($listOfTags)) {
7382
                    $listOfTags = '"' . $record['tag'] . '"';
7383
                } else {
7384
                    $listOfTags .= ', "' . $record['tag'] . '"';
7385
                }
7386
            }
7387
            echo '[' . $listOfTags . ']';
7388
            break;
7389
    }
7390
}
7391
7392
/**
7393
 * Identify if this group authorize creation of item without the complexit level reached
7394
 *
7395
 * @param int $groupe ID for group
7396
 *
7397
 * @return array list of roles
7398
*/
7399
function recupDroitCreationSansComplexite($groupe)
7400
{
7401
    $data = DB::queryFirstRow(
7402
        'SELECT bloquer_creation, bloquer_modification, personal_folder
7403
        FROM ' . prefixTable('nested_tree') . ' WHERE id = %i',
7404
        $groupe
7405
    );
7406
    // Check if it's in a personal folder. If yes, then force complexity overhead.
7407
    if ($data !== null && (int) $data['personal_folder'] === 1) {
7408
        return array(
7409
            'bloquer_modification_complexite' => 1,
7410
            'bloquer_creation_complexite' => 1,
7411
        );
7412
    }
7413
7414
    return array(
7415
        'bloquer_modification_complexite' => $data !== null ? (int) $data['bloquer_modification'] : 0,
7416
        'bloquer_creation_complexite' => $data !== null ? (int) $data['bloquer_creation'] : 0,
7417
    );
7418
}
7419
7420
/**
7421
 * Permits to identify what icon to display depending on file extension.
7422
 *
7423
 * @param string $ext extension
7424
 *
7425
 * @return string
7426
 */
7427
function fileFormatImage($ext)
7428
{
7429
    if (in_array($ext, TP_OFFICE_FILE_EXT)) {
7430
        $image = 'fas fa-file-word';
7431
    } elseif ($ext === 'pdf') {
7432
        $image = 'fas fa-file-pdf';
7433
    } elseif (in_array($ext, TP_IMAGE_FILE_EXT)) {
7434
        $image = 'fas fa-file-image';
7435
    } elseif ($ext === 'txt') {
7436
        $image = 'fas fa-file-alt';
7437
    } else {
7438
        $image = 'fas fa-file';
7439
    }
7440
7441
    return $image;
7442
}
7443
7444
7445
/**
7446
 * Get rights of user on specific folder/item.
7447
 * 
7448
 * @param int $userId ID of user.
7449
 * @param int $itemId ID of item.
7450
 * @param int $treeId ID of folder.
7451
 * 
7452
 * @return array with access rights.
7453
 */
7454
function getCurrentAccessRights(int $userId, int $itemId, int $treeId): array
7455
{
7456
    $session = SessionManager::getSession();
7457
    
7458
    // Check if the item is locked and whether the current user can edit it
7459
    $editionLock = isItemLocked($itemId, $session, $userId);
7460
7461
    // Retrieve user's visible folders from the cache_tree table
7462
    $visibleFolders = getUserVisibleFolders($userId);
7463
7464
    // Check if the folder is in the user's read-only list
7465
    if (in_array($treeId, $session->get('user-read_only_folders'))) {
7466
        return getAccessResponse(false, true, false, false);
7467
    }
7468
    
7469
    // Check if the folder is in the user's allowed folders list defined by admin
7470
    if (in_array($treeId, $session->get('user-allowed_folders_by_definition'))) {
7471
        return getAccessResponse(false, true, true, true);
7472
    }
7473
7474
    // Check if the folder is personal to the user
7475
    foreach ($visibleFolders as $folder) {
7476
        if ($folder['id'] == $treeId && (int) $folder['perso'] === 1) {
7477
            return getAccessResponse(false, true, true, true);
7478
        }
7479
    }
7480
7481
    // Determine the user's access rights based on their roles for this folder
7482
    [$edit, $delete] = getRoleBasedAccess($session, $treeId);
7483
7484
    // Log access rights information if logging is enabled
7485
    if (LOG_TO_SERVER === true) {
7486
        error_log("TEAMPASS - Folder: $treeId - User: $userId - edit: $edit - delete: $delete");
7487
    }
7488
7489
    return getAccessResponse(false, true, $edit, $delete, $editionLock);
7490
}
7491
7492
/**
7493
 * Checks if the item is locked by another user or if there is an ongoing encryption process.
7494
 * If the item is locked, the function determines if the lock has expired or not.
7495
 * 
7496
 * @param int $itemId The ID of the item to check
7497
 * @param object $session The current session object
7498
 * @param int $userId The ID of the current user
7499
 * 
7500
 * @return bool True if the item is locked, false otherwise
7501
 */
7502
function isItemLocked(int $itemId, $session, int $userId): bool
7503
{
7504
    global $SETTINGS;
7505
7506
    // Retrieve the current lock information for the item
7507
    $itemLockInfo = DB::queryFirstRow('SELECT timestamp, user_id FROM ' . prefixTable('items_edition') . ' WHERE item_id = %i', $itemId);
7508
7509
    // Check if the item is locked by another user
7510
    if ($itemLockInfo && $itemLockInfo['user_id'] !== $userId) {
7511
        // Determine the delay period, using the setting or a default value
7512
        $delay = ($SETTINGS['delay_item_edition'] ?? EDITION_LOCK_PERIOD) * 60;
7513
        $lockExpired = (time() - $itemLockInfo['timestamp']) > $delay;
7514
7515
        // If the lock hasn't expired, mark the item as locked
7516
        if (!$lockExpired) {
7517
            return true;
7518
        }
7519
7520
        // If the lock has expired, remove the lock for the current user
7521
        DB::delete(prefixTable('items_edition'), 'item_id = %i AND user_id = %i', $itemId, $session->get('user-id'));
7522
    }
7523
    
7524
    // Check if there's an ongoing background encryption process for the item
7525
    $ongoingProcess = DB::queryFirstRow(
7526
        'SELECT 1 FROM ' . prefixTable('background_tasks') . ' WHERE item_id = %i AND finished_at = "" LIMIT 1', 
7527
        $itemId
7528
    );
7529
7530
    // Return true if an ongoing process is found, otherwise false
7531
    return $ongoingProcess ? true : false;
7532
}
7533
7534
/**
7535
 * Retrieves the list of visible folders for a specific user from the cache_tree table.
7536
 * 
7537
 * @param int $userId The ID of the user
7538
 * 
7539
 * @return array An array of visible folders for the user
7540
 */
7541
function getUserVisibleFolders(int $userId): array
7542
{
7543
    // Query to retrieve visible folders for the user
7544
    $data = DB::queryFirstRow('SELECT visible_folders FROM ' . prefixTable('cache_tree') . ' WHERE user_id = %i', $userId);
7545
    
7546
    // Decode JSON data into an array; return an empty array if the data is invalid
7547
    return json_decode($data['visible_folders'], true) ?? [];
7548
}
7549
7550
/**
7551
 * Determines access rights (edit/delete) based on the user's roles for a given folder.
7552
 * It checks the roles_values table to see the permissions defined for each role.
7553
 * 
7554
 * @param object $session The current session object
7555
 * @param int $treeId The ID of the folder to check access rights for
7556
 * 
7557
 * @return array An array containing edit and delete access rights [edit, delete]
7558
 */
7559
function getRoleBasedAccess($session, int $treeId): array
7560
{
7561
    $edit = $delete = false;
7562
    
7563
    // Retrieve all role IDs assigned to the user
7564
    $roles = array_column($session->get('system-array_roles'), 'id');
7565
7566
    // Query the access rights for the given roles and folder
7567
    $accessTypes = DB::queryFirstColumn(
7568
        'SELECT type FROM ' . prefixTable('roles_values') . ' WHERE role_id IN %ls AND folder_id = %i', 
7569
        $roles, 
7570
        $treeId
7571
    );
7572
7573
    // Determine access rights based on the retrieved types
7574
    foreach ($accessTypes as $access) {
7575
        switch ($access) {
7576
            case 'ND': // No Delete
7577
                $edit = true;
7578
                $delete = false;
7579
                break;
7580
            case 'NE': // No Edit
7581
                $edit = false;
7582
                $delete = true;
7583
                break;
7584
            case 'NDNE':
7585
            case 'R': // Read only
7586
                $edit = $delete = false;
7587
                break;
7588
            case 'W': // Write access
7589
                $edit = $delete = true;
7590
                break;
7591
        }
7592
    }
7593
    return [$edit, $delete];
7594
}
7595
7596
/**
7597
 * Constructs the final access response array with the given parameters.
7598
 * 
7599
 * @param bool $error Indicates if there was an error
7600
 * @param bool $access Indicates if the user has access
7601
 * @param bool $edit Indicates if the user has edit rights
7602
 * @param bool $delete Indicates if the user has delete rights
7603
 * @param bool $editionLocked Indicates if the edition is locked
7604
 * 
7605
 * @return array An array containing the access rights information
7606
 */
7607
function getAccessResponse(bool $error, bool $access, bool $edit, bool $delete, bool $editionLocked = false): array
7608
{
7609
    return [
7610
        'error' => $error,
7611
        'access' => $access,
7612
        'edit' => $edit,
7613
        'delete' => $delete,
7614
        'edition_locked' => $editionLocked,
7615
    ];
7616
}
7617
7618