Passed
Push — master ( 97d9b0...f5b400 )
by Nils
06:48 queued 15s
created

purgeDeletedUserById()   C

Complexity

Conditions 8
Paths 103

Size

Total Lines 177
Code Lines 102

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 1
Metric Value
cc 8
eloc 102
c 3
b 1
f 1
nc 103
nop 1
dl 0
loc 177
rs 6.7355

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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      users.queries.php
26
 * @author    Nils Laumaillé ([email protected])
27
 * @copyright 2009-2025 Teampass.net
28
 * @license   GPL-3.0
29
 * @see       https://www.teampass.net
30
 */
31
32
use LdapRecord\Connection;
33
use TeampassClasses\NestedTree\NestedTree;
34
use TeampassClasses\SessionManager\SessionManager;
35
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
36
use TeampassClasses\Language\Language;
37
use TeampassClasses\PerformChecks\PerformChecks;
38
use TeampassClasses\ConfigManager\ConfigManager;
39
use TeampassClasses\PasswordManager\PasswordManager;
40
use TeampassClasses\EmailService\EmailService;
41
use TeampassClasses\EmailService\EmailSettings;
42
use TeampassClasses\OAuth2Controller\OAuth2Controller;
43
44
// Load functions
45
require_once 'main.functions.php';
46
47
// init
48
loadClasses('DB');
49
$session = SessionManager::getSession();
50
$request = SymfonyRequest::createFromGlobals();
51
$lang = new Language($session->get('user-language') ?? 'english');
52
53
// Load config
54
$configManager = new ConfigManager();
55
$SETTINGS = $configManager->getAllSettings();
56
57
// Do checks
58
$checkUserAccess = new PerformChecks(
59
    dataSanitizer(
60
        [
61
            'type' => htmlspecialchars($request->request->get('type', ''), ENT_QUOTES, 'UTF-8'),
62
        ],
63
        [
64
            'type' => 'trim|escape',
65
        ],
66
    ),
67
    [
68
        'user_id' => returnIfSet($session->get('user-id'), null),
69
        'user_key' => returnIfSet($session->get('key'), null),
70
    ]
71
);
72
// Handle the case
73
echo $checkUserAccess->caseHandler();
74
if ($checkUserAccess->checkSession() === false || $checkUserAccess->userAccessPage('profile') === false) {
75
    // Not allowed page
76
    $session->set('system-error_code', ERR_NOT_ALLOWED);
77
    include $SETTINGS['cpassman_dir'] . '/error.php';
78
    exit;
79
}
80
81
// Define Timezone
82
date_default_timezone_set($SETTINGS['timezone'] ?? 'UTC');
83
84
// Set header properties
85
header('Content-type: text/html; charset=utf-8');
86
header('Cache-Control: no-cache, no-store, must-revalidate');
87
88
// --------------------------------- //
89
90
// Prepare post variables
91
$post_key = filter_input(INPUT_POST, 'key', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
92
$post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
93
$post_data = filter_input(INPUT_POST, 'data', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES);
94
$isprofileupdate = filter_input(INPUT_POST, 'isprofileupdate', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
95
$password_do_not_change = 'do_not_change';
96
97
98
//Load Tree
99
$tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
100
101
if (null !== $post_type) {
102
103
    // List of post types allowed to all users
104
    $all_users_can_access = [
105
        'get_generate_keys_progress',
106
        'user_profile_update',
107
        'save_user_change',
108
    ];
109
110
    // decrypt and retrieve data in JSON format
111
    $dataReceived = [];
112
    if (!empty($post_data)) {
113
        $dataReceived = prepareExchangedData(
114
            $post_data,
115
            'decode'
116
        );
117
    }
118
119
    // Non-manager user
120
    if ((int) $session->get('user-admin') !== 1 &&
121
        (int) $session->get('user-manager') !== 1 &&
122
        (int) $session->get('user-can_manage_all_users') !== 1) {
123
124
        // Administrative type requested -> deny
125
        if (!in_array($post_type, $all_users_can_access)) {
126
            echo prepareExchangedData(
127
                array(
128
                    'error' => true,
129
                    'message' => $lang->get('error_not_allowed_to'),
130
                ),
131
                'encode'
132
            );
133
            exit;
134
        } else if (isset($dataReceived['user_id'])) {
135
            // If user isn't manager, he can't change user_id
136
            $dataReceived['user_id'] = (int) $session->get('user-id');
137
        }
138
    }
139
140
    // For administrative types only, do additional check whether user is manager 
141
    // and $dataReceived['user_id'] is defined to ensure that this manager can
142
    // modify this user account.
143
    if (!in_array($post_type, $all_users_can_access) &&
144
        (int) $session->get('user-admin') !== 1 && !empty($dataReceived['user_id'])) {
145
146
        // Get info about user to modify
147
        $targetUserInfos = DB::queryFirstRow(
148
            'SELECT admin, gestionnaire, can_manage_all_users, isAdministratedByRole FROM ' . prefixTable('users') . '
149
            WHERE id = %i',
150
            (int) $dataReceived['user_id']
151
        );
152
153
        // User not exists
154
        if (DB::count() === 0) {
155
            echo prepareExchangedData(
156
                array(
157
                    'error' => true,
158
                    'message' => $lang->get('error_not_allowed_to'),
159
                ),
160
                'encode'
161
            );
162
            exit;
163
        }
164
165
        // Managers can't edit administrator or other manager
166
        if ((int) $targetUserInfos['admin'] === 1 ||
167
            (int) $targetUserInfos['can_manage_all_users'] === 1 ||
168
            (int) $targetUserInfos['gestionnaire'] === 1) {
169
170
                echo prepareExchangedData(
171
                    array(
172
                        'error' => true,
173
                        'message' => $lang->get('error_not_allowed_to'),
174
                    ),
175
                    'encode'
176
                );
177
                exit;
178
            }
179
180
        // Manager of basic/ro users in this role
181
        if ((int) $session->get('user-manager') === 1
182
            && !in_array($targetUserInfos['isAdministratedByRole'], $session->get('user-roles_array'))) {
183
184
            echo prepareExchangedData(
185
                array(
186
                    'error' => true,
187
                    'message' => $lang->get('error_not_allowed_to'),
188
                ),
189
                'encode'
190
            );
191
            exit;
192
        }
193
    }
194
195
    switch ($post_type) {
196
        /*
197
         * ADD NEW USER
198
         */
199
        case 'add_new_user':
200
            // Check KEY
201
            if ($post_key !== $session->get('key')) {
202
                echo prepareExchangedData(
203
                    array(
204
                        'error' => true,
205
                        'message' => $lang->get('key_is_not_correct'),
206
                    ),
207
                    'encode'
208
                );
209
                break;
210
            } elseif ($session->get('user-read_only') === 1) {
211
                echo prepareExchangedData(
212
                    array(
213
                        'error' => true,
214
                        'message' => $lang->get('error_not_allowed_to'),
215
                    ),
216
                    'encode'
217
                );
218
                break;
219
            }
220
221
            // Check if current user can add a new user
222
            if ((int) $session->get('user-admin') === 0 && (int) $session->get('user-can_manage_all_users') === 0 && (int) $session->get('user-manager') === 0) {
223
                echo prepareExchangedData(
224
                    array(
225
                        'error' => true,
226
                        'message' => $lang->get('error_not_allowed_to'),
227
                    ),
228
                    'encode'
229
                );
230
                break;
231
            }
232
233
            // Prepare variables
234
            $login = filter_var($dataReceived['login'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
235
            $email = filter_var($dataReceived['email'], FILTER_SANITIZE_EMAIL);
236
            $lastname = filter_var($dataReceived['lastname'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
237
            $name = filter_var($dataReceived['name'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
238
            $is_admin = filter_var($dataReceived['admin'], FILTER_SANITIZE_NUMBER_INT);
239
            $is_manager = filter_var($dataReceived['manager'], FILTER_SANITIZE_NUMBER_INT);
240
            $is_hr = filter_var($dataReceived['hr'], FILTER_SANITIZE_NUMBER_INT);
241
            $is_read_only = filter_var($dataReceived['read_only'], FILTER_SANITIZE_NUMBER_INT) || 0;
242
            $has_personal_folder = filter_var($dataReceived['personal_folder'], FILTER_SANITIZE_NUMBER_INT);
243
            $new_folder_role_domain = filter_var($dataReceived['new_folder_role_domain'], FILTER_SANITIZE_NUMBER_INT);
244
            $domain = filter_var($dataReceived['domain'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
245
            $is_administrated_by = filter_var($dataReceived['isAdministratedByRole'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
246
            $groups = filter_var_array($dataReceived['groups'], FILTER_SANITIZE_NUMBER_INT) ?? [];
247
            $allowed_flds = filter_var_array($dataReceived['allowed_flds'], FILTER_SANITIZE_NUMBER_INT) ?? [];
248
            $forbidden_flds = filter_var_array($dataReceived['forbidden_flds'], FILTER_SANITIZE_NUMBER_INT) ?? [];
249
            $post_root_level = filter_var($dataReceived['form-create-root-folder'], FILTER_SANITIZE_NUMBER_INT);
250
            $mfa_enabled = filter_var($dataReceived['mfa_enabled'], FILTER_SANITIZE_NUMBER_INT);
251
252
            // Only administrators can create managers or administrators accounts.
253
            if ((int) $session->get('user-admin') !== 1 
254
                && ((int) $is_admin === 1 || (int) $is_manager === 1 || (int) $is_hr === 1)) {
255
256
                echo prepareExchangedData(
257
                    array(
258
                        'error' => true,
259
                        'message' => $lang->get('error_not_allowed_to'),
260
                    ),
261
                    'encode'
262
                );
263
                break;
264
            }
265
266
            // Empty user
267
            if (empty($login) === true) {
268
                echo prepareExchangedData(
269
                    array(
270
                        'error' => true,
271
                        'message' => $lang->get('error_empty_data'),
272
                    ),
273
                    'encode'
274
                );
275
                break;
276
            }
277
            // Check if user exists (active or soft-deleted)
278
            $existingUser = DB::queryFirstRow(
279
                'SELECT id, login, deleted_at
280
                FROM ' . prefixTable('users') . '
281
                WHERE (login = %s AND deleted_at IS NULL)
282
                OR (login LIKE %s AND deleted_at IS NOT NULL)',
283
                $login,
284
                $login . '_deleted_%'
285
            );
286
287
            if (is_null($existingUser)) {
288
                // Generate pwd
289
                $password = generateQuickPassword();
290
291
                // Generate new keys with transparent recovery support
292
                $userKeys = generateUserKeys($password, $SETTINGS);
293
294
                // load password library
295
                $passwordManager = new PasswordManager();
296
297
                // Prepare variables
298
                $hashedPassword = $passwordManager->hashPassword($password);
299
                if ($passwordManager->verifyPassword($hashedPassword, $password) === false) {
300
                    echo prepareExchangedData(
301
                        array(
302
                            'error' => true,
303
                            'message' => $lang->get('pw_hash_not_correct'),
304
                        ),
305
                        'encode'
306
                    );
307
                    break;
308
                }
309
310
                // Add user in DB
311
                DB::insert(
312
                    prefixTable('users'),
313
                    array(
314
                        'login' => $login,
315
                        'name' => $name,
316
                        'lastname' => $lastname,
317
                        'pw' => $hashedPassword,
318
                        'email' => $email,
319
                        'admin' => empty($is_admin) === true ? 0 : $is_admin,
320
                        'can_manage_all_users' => empty($is_hr) === true ? 0 : $is_hr,
321
                        'gestionnaire' => empty($is_manager) === true ? 0 : $is_manager,
322
                        'read_only' => empty($is_read_only) === true ? 0 : $is_read_only,
323
                        'personal_folder' => empty($has_personal_folder) === true ? 0 : $has_personal_folder,
324
                        'user_language' => $SETTINGS['default_language'],
325
                        'isAdministratedByRole' => $is_administrated_by,
326
                        'encrypted_psk' => '',
327
                        'last_pw_change' => time(),
328
                        'public_key' => $userKeys['public_key'],
329
                        'private_key' => $userKeys['private_key'],
330
                        'special' => 'auth-pwd-change',
331
                        'is_ready_for_usage' => 0,
332
                        'otp_provided' => 0,
333
                        'can_create_root_folder' => empty($post_root_level) === true ? 0 : $post_root_level,
334
                        'mfa_enabled' => empty($mfa_enabled) === true ? 0 : $mfa_enabled,
335
                        'created_at' => time(),
336
                        'personal_items_migrated' => 1,
337
                    )
338
                );
339
                $new_user_id = DB::insertId();
340
341
                // Add Groups and Roles
342
                setUserRoles($new_user_id, $groups, 'manual');
343
                setUserGroups($new_user_id, $allowed_flds);
344
                setUserForbiddenGroups($new_user_id, $forbidden_flds);
345
346
                // Create personnal folder
347
                if ((int) $has_personal_folder === 1) {
348
                    DB::insert(
349
                        prefixTable('nested_tree'),
350
                        array(
351
                            'parent_id' => '0',
352
                            'title' => $new_user_id,
353
                            'bloquer_creation' => '0',
354
                            'bloquer_modification' => '0',
355
                            'personal_folder' => '1',
356
                            'categories' => '',
357
                        )
358
                    );
359
                    $tree->rebuild();
360
                }
361
                // Create folder and role for domain
362
                if ((int) $new_folder_role_domain === 1) {
363
                    // create folder
364
                    DB::insert(
365
                        prefixTable('nested_tree'),
366
                        array(
367
                            'parent_id' => 0,
368
                            'title' => $domain,
369
                            'personal_folder' => 0,
370
                            'renewal_period' => 0,
371
                            'bloquer_creation' => '0',
372
                            'bloquer_modification' => '0',
373
                        )
374
                    );
375
                    $new_folder_id = DB::insertId();
376
                    // Add complexity
377
                    DB::insert(
378
                        prefixTable('misc'),
379
                        array(
380
                            'type' => 'complex',
381
                            'intitule' => $new_folder_id,
382
                            'valeur' => 50,
383
                            'created_at' => time(),
384
                        )
385
                    );
386
                    // Create role
387
                    DB::insert(
388
                        prefixTable('roles_title'),
389
                        array(
390
                            'title' => $domain,
391
                        )
392
                    );
393
                    $new_role_id = DB::insertId();
394
                    // Associate new role to new folder
395
                    DB::insert(
396
                        prefixTable('roles_values'),
397
                        array(
398
                            'folder_id' => $new_folder_id,
399
                            'role_id' => $new_role_id,
400
                        )
401
                    );
402
                    // Add the new user to this role
403
                    DB::update(
404
                        prefixTable('users'),
405
                        array(
406
                            'fonction_id' => is_int($new_role_id),
407
                        ),
408
                        'id=%i',
409
                        $new_user_id
410
                    );
411
                    // rebuild tree
412
                    $tree->rebuild();
413
                }
414
415
                // Create the API key
416
                DB::insert(
417
                    prefixTable('api'),
418
                    array(
419
                        'type' => 'user',
420
                        'user_id' => $new_user_id,
421
                        'value' => encryptUserObjectKey(base64_encode(base64_encode(uniqidReal(39))), $userKeys['public_key']),
422
                        'timestamp' => time(),
423
                    )
424
                );
425
426
                // get links url
427
                if (empty($SETTINGS['email_server_url']) === true) {
428
                    $SETTINGS['email_server_url'] = $SETTINGS['cpassman_url'];
429
                }
430
431
                // Launch process for user keys creation
432
                // No OTP is provided here, no need.
433
                handleUserKeys(
434
                    (int) $new_user_id,
435
                    (string) $password,
436
                    (int) isset($SETTINGS['maximum_number_of_items_to_treat']) === true ? $SETTINGS['maximum_number_of_items_to_treat'] : NUMBER_ITEMS_IN_BATCH,
437
                    "",
438
                    true,
439
                    true,
440
                    true,
441
                    false,
442
                    (string) $lang->get('email_body_user_config_6'),
443
                );
444
445
                // update LOG
446
                logEvents(
447
                    $SETTINGS,
448
                    'user_mngt',
449
                    'at_user_added',
450
                    (string) $session->get('user-id'),
451
                    $session->get('user-login'),
452
                    (string) $new_user_id
453
                );
454
455
                echo prepareExchangedData(
456
                    array(
457
                        'error' => false,
458
                        'user_id' => $new_user_id,
459
                        'message' => '',
460
                    ),
461
                    'encode'
462
                );
463
            } else {
464
                // Check if it's a soft-deleted user
465
                $errorMessage = $lang->get('error_user_exists');
466
                if (empty($deletedUser) === false) {
467
                    $errorMessage = 'A deleted user with this login already exists (ID: ' . $deletedUser['id'] . '). Please restore the user instead of creating a new one.';
468
                }
469
470
                echo prepareExchangedData(
471
                    array(
472
                        'error' => true,
473
                        'message' => $errorMessage,
474
                    ),
475
                    'encode'
476
                );
477
            }
478
            break;
479
480
            /*
481
         * Delete the user
482
         */
483
        case 'delete_user':
484
            // Check KEY
485
            if ($post_key !== $session->get('key')) {
486
                echo prepareExchangedData(
487
                    array(
488
                        'error' => true,
489
                        'message' => $lang->get('key_is_not_correct'),
490
                    ),
491
                    'encode'
492
                );
493
                break;
494
            } elseif ($session->get('user-read_only') === 1) {
495
                echo prepareExchangedData(
496
                    array(
497
                        'error' => true,
498
                        'message' => $lang->get('error_not_allowed_to'),
499
                    ),
500
                    'encode'
501
                );
502
                break;
503
            }
504
505
            // Prepare variables
506
            $userId  = filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
507
508
            if (empty($userId)) {
509
                echo prepareExchangedData(
510
                    [
511
                        'error' => true,
512
                        'message' => $lang->get('error_empty_data'),
513
                    ],
514
                    'encode'
515
                );
516
                break;
517
            }
518
519
            // Get info about user to delete
520
            $data_user = DB::queryFirstRow(
521
                'SELECT login, admin, isAdministratedByRole FROM ' . prefixTable('users') . '
522
                WHERE id = %i',
523
                $userId 
524
            );        
525
            if (empty($data_user)) {
526
                throw new Exception($lang->get('error_user_not_exists'));
527
            }
528
529
            DB::startTransaction();
530
            try {
531
                // Is this user allowed to do this?
532
                if (
533
                    (int) $session->get('user-admin') === 1
534
                    || (in_array($data_user['isAdministratedByRole'], $session->get('user-roles_array')))
535
                    || ((int) $session->get('user-can_manage_all_users') === 1 && (int) $data_user['admin'] !== 1)
536
                ) {
537
                    $timestamp = time();
538
                    $deletedSuffix = '_deleted_' . $timestamp;
539
540
                    // delete user in database
541
                    DB::update(
542
                        prefixTable('users'),
543
                        array(
544
                            'login' => $data_user['login'].$deletedSuffix,
545
                            'deleted_at' => $timestamp,
546
                            'disabled' => 1,
547
                            'special' => 'none',
548
                            'auth_type' => 'none'
549
                        ),
550
                        'id = %i',
551
                        $userId
552
                    );
553
                    
554
                    // update LOG
555
                    logEvents($SETTINGS, 'user_mngt', 'at_user_deleted', (string) $session->get('user-id'), $session->get('user-login'), $userId);
556
557
                    // Count deleted users
558
                    $deletedAccountsCount = (int) DB::queryFirstField("SELECT COUNT(id) FROM " . prefixTable('users') . " WHERE deleted_at IS NOT NULL");
559
560
                    DB::commit();
561
562
                    //Send back
563
                    echo prepareExchangedData(
564
                        array(
565
                            'error' => false,
566
                            'message' => '',
567
                            'deleted_accounts_count' => $deletedAccountsCount,
568
                        ),
569
                        'encode'
570
                    );
571
                } else {
572
                    //Send back
573
                    echo prepareExchangedData(
574
                        array(
575
                            'error' => false,
576
                            'message' => $lang->get('error_not_allowed_to'),
577
                        ),
578
                        'encode'
579
                    );
580
                }
581
            } catch (Exception $e) {
582
                DB::rollback();
583
                
584
                echo prepareExchangedData(
585
                    [
586
                        'error' => true,
587
                        'message' => $lang->get('error') . ': ' . $e->getMessage(),
588
                    ],
589
                    'encode'
590
                );
591
            }
592
            break;
593
594
        /*
595
         * Check the domain
596
         */
597
        case 'check_domain':
598
            $return = array();
599
            // Check if folder exists
600
            $data = DB::query(
601
                'SELECT * FROM ' . prefixTable('nested_tree') . '
602
                WHERE title = %s AND parent_id = %i',
603
                filter_input(INPUT_POST, 'domain', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
604
                '0'
605
            );
606
            $counter = DB::count();
607
            if ($counter != 0) {
608
                $return['folder'] = 'exists';
609
            } else {
610
                $return['folder'] = 'not_exists';
611
            }
612
            // Check if role exists
613
            $data = DB::query(
614
                'SELECT * FROM ' . prefixTable('roles_title') . '
615
                WHERE title = %s',
616
                filter_input(INPUT_POST, 'domain', FILTER_SANITIZE_FULL_SPECIAL_CHARS)
617
            );
618
            $counter = DB::count();
619
            if ($counter != 0) {
620
                $return['role'] = 'exists';
621
            } else {
622
                $return['role'] = 'not_exists';
623
            }
624
625
            echo json_encode($return);
626
            break;
627
628
        /*
629
         * delete the timestamp value for specified user => disconnect
630
         */
631
        case 'disconnect_user':
632
            // Check KEY
633
            if (filter_input(INPUT_POST, 'key', FILTER_SANITIZE_FULL_SPECIAL_CHARS) !== filter_var($session->get('key'), FILTER_SANITIZE_FULL_SPECIAL_CHARS)) {
634
                echo '[ { "error" : "key_not_conform" } ]';
635
                break;
636
            }
637
638
            $post_user_id = filter_input(INPUT_POST, 'user_id', FILTER_SANITIZE_NUMBER_INT);
639
640
            // Get info about user to delete
641
            $data_user = DB::queryFirstRow(
642
                'SELECT admin, isAdministratedByRole, gestionnaire
643
                FROM ' . prefixTable('users') . '
644
                WHERE id = %i',
645
                $post_user_id
646
            );
647
648
            // Is this user allowed to do this?
649
            if (
650
                (int) $session->get('user-admin') === 1
651
                || (in_array($data_user['isAdministratedByRole'], $session->get('user-roles_array')))
652
                || ((int) $session->get('user-can_manage_all_users') === 1 && (int) $data_user['admin'] !== 1)
653
            ) {
654
                // Do
655
                DB::update(
656
                    prefixTable('users'),
657
                    array(
658
                        'timestamp' => '',
659
                        'key_tempo' => '',
660
                        'session_end' => '',
661
                    ),
662
                    'id = %i',
663
                    $post_user_id
664
                );
665
            }
666
            break;
667
668
        /*
669
         * Get user info
670
         */
671
        case 'get_user_info':
672
            // Check KEY
673
            if ($post_key !== $session->get('key')) {
674
                echo prepareExchangedData(
675
                    array(
676
                        'error' => true,
677
                        'message' => $lang->get('key_is_not_correct'),
678
                    ),
679
                    'encode'
680
                );
681
                break;
682
            } elseif ($session->get('user-read_only') === 1) {
683
                echo prepareExchangedData(
684
                    array(
685
                        'error' => true,
686
                        'message' => $lang->get('error_not_allowed_to'),
687
                    ),
688
                    'encode'
689
                );
690
                break;
691
            }
692
            
693
            // Prepare variables
694
            $post_id = (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
695
696
            // Get info about user
697
            $rowUser = getUserCompleteData(null, $post_id);
698
699
            // Is this user allowed to do this?
700
            if (
701
                (int) $session->get('user-admin') === 1
702
                || (in_array($rowUser['isAdministratedByRole'], $session->get('user-roles_array')) === true)
703
                || ((int) $session->get('user-can_manage_all_users') === 1 && $rowUser['admin'] !== '1')
704
            ) {
705
                $arrData = array();
706
                $arrFunction = array();
707
                $arrMngBy = array();
708
                $arrFldForbidden = array();
709
                $arrFldAllowed = array();
710
711
                //Build tree
712
                $tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
713
714
                // get FUNCTIONS
715
                $functionsList = array();
716
                $selected = '';
717
                $users_functions = array_filter(array_unique(explode(';', empty($rowUser['fonction_id'].';'.$rowUser['roles_from_ad_groups']) === true ? '' : $rowUser['fonction_id'].';'.$rowUser['roles_from_ad_groups'])));
718
719
                $session->set('user-roles_array', explode(';', $session->get('user-roles')));
720
                $rows = DB::query('
721
                    SELECT id,title,creator_id 
722
                    FROM ' . prefixTable('roles_title') .'
723
                    WHERE id IN %li',
724
                    $session->get('user-roles_array')
725
                );
726
                foreach ($rows as $record) {
727
                    if (
728
                        (int) $session->get('user-admin') === 1
729
                        || (((int) $session->get('user-manager') === 1 || (int) $session->get('user-can_manage_all_users') === 1))
730
                    ) {
731
                        if (in_array($record['id'], $users_functions)) {
732
                            $selected = 'selected';
733
734
                            array_push(
735
                                $arrFunction,
736
                                array(
737
                                    'title' => $record['title'],
738
                                    'id' => $record['id'],
739
                                )
740
                            );
741
                        } else {
742
                            $selected = '';
743
                        }
744
745
                        array_push(
746
                            $functionsList,
747
                            array(
748
                                'title' => $record['title'],
749
                                'id' => $record['id'],
750
                                'selected' => $selected,
751
                            )
752
                        );
753
                    }
754
                }
755
756
                // get MANAGEDBY
757
                $rolesList = array();
758
                $managedBy = array();
759
                $selected = '';
760
                $rows = DB::query('SELECT id,title FROM ' . prefixTable('roles_title') . ' ORDER BY title ASC');
761
                foreach ($rows as $reccord) {
762
                    $rolesList[$reccord['id']] = array('id' => $reccord['id'], 'title' => $reccord['title']);
763
                }
764
765
                array_push(
766
                    $managedBy,
767
                    array(
768
                        'title' => $lang->get('administrators_only'),
769
                        'id' => 0,
770
                    )
771
                );
772
                foreach ($rolesList as $fonction) {
773
                    if ($session->get('user-admin') === 1 || in_array($fonction['id'], $session->get('user-roles_array'))) {
774
                        if ($rowUser['isAdministratedByRole'] == $fonction['id']) {
775
                            $selected = 'selected';
776
777
                            array_push(
778
                                $arrMngBy,
779
                                array(
780
                                    'title' => $fonction['title'],
781
                                    'id' => $fonction['id'],
782
                                )
783
                            );
784
                        } else {
785
                            $selected = '';
786
                        }
787
788
                        array_push(
789
                            $managedBy,
790
                            array(
791
                                'title' => $lang->get('managers_of') . ' ' . $fonction['title'],
792
                                'id' => $fonction['id'],
793
                                'selected' => $selected,
794
                            )
795
                        );
796
                    }
797
                }
798
799
                if (count($arrMngBy) === 0) {
800
                    array_push(
801
                        $arrMngBy,
802
                        array(
803
                            'title' => $lang->get('administrators_only'),
804
                            'id' => '0',
805
                        )
806
                    );
807
                }
808
809
                // get FOLDERS FORBIDDEN
810
                $forbiddenFolders = array();
811
                $userForbidFolders = explode(';', is_null($rowUser['groupes_interdits']) === true ? '' : $rowUser['groupes_interdits']);
812
                $tree_desc = $tree->getDescendants();
813
                foreach ($tree_desc as $t) {
814
                    if (in_array($t->id, $session->get('user-accessible_folders')) && in_array($t->id, $session->get('user-personal_visible_folders')) === false) {
815
                        $selected = '';
816
                        if (in_array($t->id, $userForbidFolders)) {
817
                            $selected = 'selected';
818
819
                            array_push(
820
                                $arrFldForbidden,
821
                                array(
822
                                    'title' => htmlspecialchars($t->title, ENT_COMPAT, 'UTF-8'),
823
                                    'id' => $t->id,
824
                                )
825
                            );
826
                        }
827
                        array_push(
828
                            $forbiddenFolders,
829
                            array(
830
                                'id' => $t->id,
831
                                'selected' => $selected,
832
                                'title' => @htmlspecialchars($t->title, ENT_COMPAT, 'UTF-8'),
833
                            )
834
                        );
835
                    }
836
                }
837
838
                // get FOLDERS ALLOWED
839
                $allowedFolders = array();
840
                $userAllowFolders = explode(';', $rowUser['groupes_visibles']);
841
                $tree_desc = $tree->getDescendants();
842
                foreach ($tree_desc as $t) {
843
                    if (
844
                        in_array($t->id, $session->get('user-accessible_folders')) === true
845
                        && in_array($t->id, $session->get('user-personal_visible_folders')) === false
846
                    ) {
847
                        $selected = '';
848
                        if (in_array($t->id, $userAllowFolders)) {
849
                            $selected = 'selected';
850
851
                            array_push(
852
                                $arrFldAllowed,
853
                                array(
854
                                    'title' => htmlspecialchars($t->title, ENT_COMPAT, 'UTF-8'),
855
                                    'id' => $t->id,
856
                                )
857
                            );
858
                        }
859
860
                        array_push(
861
                            $allowedFolders,
862
                            array(
863
                                'id' => $t->id,
864
                                'selected' => $selected,
865
                                'title' => @htmlspecialchars($t->title, ENT_COMPAT, 'UTF-8'),
866
                            )
867
                        );
868
                    }
869
                }
870
871
                // get USER STATUS
872
                if ($rowUser['disabled'] == 1) {
873
                    $arrData['info'] = $lang->get('user_info_locked') . '<br><input type="checkbox" value="unlock" name="1" class="chk">&nbsp;<label for="1">' . $lang->get('user_info_unlock_question') . '</label><br><input type="checkbox"  value="delete" id="account_delete" class="chk mr-2" name="2" onclick="confirmDeletion()">label for="2">' . $lang->get('user_info_delete_question') . '</label>';
874
                } else {
875
                    $arrData['info'] = $lang->get('user_info_active') . '<br><input type="checkbox" value="lock" class="chk">&nbsp;' . $lang->get('user_info_lock_question');
876
                }
877
878
                $arrData['error'] = false;
879
                $arrData['login'] = $rowUser['login'];
880
                $arrData['name'] = empty($rowUser['name']) === false && $rowUser['name'] !== NULL ? $rowUser['name'] : '';
881
                $arrData['lastname'] = empty($rowUser['lastname']) === false && $rowUser['lastname'] !== NULL ? $rowUser['lastname'] : '';
882
                $arrData['email'] = $rowUser['email'];
883
                $arrData['function'] = $functionsList;
884
                $arrData['managedby'] = $managedBy;
885
                $arrData['foldersForbid'] = $forbiddenFolders;
886
                $arrData['foldersAllow'] = $allowedFolders;
887
                $arrData['share_function'] = $arrFunction;
888
                $arrData['share_managedby'] = $arrMngBy;
889
                $arrData['share_forbidden'] = $arrFldForbidden;
890
                $arrData['share_allowed'] = $arrFldAllowed;
891
                $arrData['disabled'] = (int) $rowUser['disabled'];
892
                $arrData['gestionnaire'] = (int) $rowUser['gestionnaire'];
893
                $arrData['read_only'] = (int) $rowUser['read_only'];
894
                $arrData['can_create_root_folder'] = (int) $rowUser['can_create_root_folder'];
895
                $arrData['personal_folder'] = (int) $rowUser['personal_folder'];
896
                $arrData['can_manage_all_users'] = (int) $rowUser['can_manage_all_users'];
897
                $arrData['admin'] = (int) $rowUser['admin'];
898
                $arrData['password'] = $password_do_not_change;
899
                $arrData['mfa_enabled'] = (int) $rowUser['mfa_enabled'];
900
901
                echo prepareExchangedData(
902
                    $arrData,
903
                    'encode'
904
                );
905
            } else {
906
                echo prepareExchangedData(
907
                    array(
908
                        'error' => true,
909
                        'message' => $lang->get('error_not_allowed_to'),
910
                    ),
911
                    'encode'
912
                );
913
            }
914
915
            break;
916
917
        /*
918
         * EDIT user
919
         */
920
        case 'store_user_changes':
921
            // Check KEY
922
            if ($post_key !== $session->get('key')) {
923
                echo prepareExchangedData(
924
                    array(
925
                        'error' => true,
926
                        'message' => $lang->get('key_is_not_correct'),
927
                    ),
928
                    'encode'
929
                );
930
                break;
931
            } elseif ($session->get('user-read_only') === 1) {
932
                echo prepareExchangedData(
933
                    array(
934
                        'error' => true,
935
                        'message' => $lang->get('error_not_allowed_to'),
936
                    ),
937
                    'encode'
938
                );
939
                break;
940
            }
941
942
            // Prepare variables
943
            $post_id = (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
944
            $post_login = (string) filter_var($dataReceived['login'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
945
            $post_email = (string) filter_var($dataReceived['email'], FILTER_SANITIZE_EMAIL);
946
            $post_lastname = (string) filter_var($dataReceived['lastname'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
947
            $post_name = (string) filter_var($dataReceived['name'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
948
            $post_is_admin = (int) filter_var($dataReceived['admin'], FILTER_SANITIZE_NUMBER_INT);
949
            $post_is_manager = (int) filter_var($dataReceived['manager'], FILTER_SANITIZE_NUMBER_INT);
950
            $post_is_hr = (int) filter_var($dataReceived['hr'], FILTER_SANITIZE_NUMBER_INT);
951
            $post_is_read_only = (int) filter_var($dataReceived['read_only'], FILTER_SANITIZE_NUMBER_INT);
952
            $post_has_personal_folder = (int) filter_var($dataReceived['personal_folder'], FILTER_SANITIZE_NUMBER_INT);
953
            $post_is_administrated_by = (string) filter_var($dataReceived['isAdministratedByRole'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
954
            $post_groups = filter_var_array($dataReceived['groups'], FILTER_SANITIZE_NUMBER_INT);
955
            $post_allowed_flds = filter_var_array($dataReceived['allowed_flds'], FILTER_SANITIZE_NUMBER_INT);
956
            $post_forbidden_flds = filter_var_array($dataReceived['forbidden_flds'], FILTER_SANITIZE_NUMBER_INT);
957
            $post_root_level = (int) filter_var($dataReceived['form-create-root-folder'], FILTER_SANITIZE_NUMBER_INT);
958
            $post_mfa_enabled = (int) filter_var($dataReceived['mfa_enabled'], FILTER_SANITIZE_NUMBER_INT);
959
960
            // Get info about user to modify
961
            $data_user = DB::queryFirstRow(
962
                'SELECT admin, gestionnaire, can_manage_all_users, isAdministratedByRole 
963
                FROM ' . prefixTable('users') . '
964
                WHERE id = %i',
965
                $post_id
966
            );
967
968
            // If user removes administrator role on administrator user
969
            // then ensure that it exists still one administrator
970
            if ((int) $data_user['admin'] === 1 && (int) $post_is_admin !== 1) {
971
                // count number of admins
972
                $users = DB::query(
973
                    'SELECT id
974
                    FROM ' . prefixTable('users') . '
975
                    WHERE admin = 1 AND email != "" AND pw != "" AND id != %i',
976
                    $post_id
977
                );
978
                if (DB::count() === 0) {
979
                    echo prepareExchangedData(
980
                        array(
981
                            'error' => true,
982
                            'message' => $lang->get('at_least_one_administrator_is_requested'),
983
                        ),
984
                        'encode'
985
                    );
986
                    break;
987
                }
988
            }
989
            
990
            // Init post variables
991
            $post_action_to_perform = filter_var(htmlspecialchars_decode($dataReceived['action_on_user']), FILTER_SANITIZE_FULL_SPECIAL_CHARS);
992
            $action_to_perform_after = '';
993
            
994
            // Exclude roles from AD - PR #3635
995
            $adRolesResult = DB::query(
996
                'SELECT role_id
997
                FROM ' . prefixTable('users_roles') . '
998
                WHERE user_id = %i AND source = %s',
999
                $post_id,
1000
                'ad'
1001
            );
1002
            $adRoles = array_column($adRolesResult, 'role_id');
1003
1004
            $fonctions = [];
1005
            if (!is_null($post_groups) && !empty($adRoles)) {
1006
                foreach ($post_groups as $post_group) {
1007
                    if (!in_array($post_group, $adRoles)) {
1008
                        $fonctions[] = $post_group;
1009
                    }
1010
                }
1011
            }
1012
            $post_groups = empty($fonctions) === true ? $post_groups : $fonctions;
1013
1014
1015
            // Build array of update
1016
            $changeArray = array(
1017
                'login' => $post_login,
1018
                'name' => $post_name,
1019
                'lastname' => $post_lastname,
1020
                'email' => $post_email,
1021
                'admin' => empty($post_is_admin) === true ? 0 : $post_is_admin,
1022
                'can_manage_all_users' => empty($post_is_hr) === true ? 0 : $post_is_hr,
1023
                'gestionnaire' => empty($post_is_manager) === true ? 0 : $post_is_manager,
1024
                'read_only' => empty($post_is_read_only) === true ? 0 : $post_is_read_only,
1025
                'personal_folder' => empty($post_has_personal_folder) === true ? 0 : $post_has_personal_folder,
1026
                'user_language' => $SETTINGS['default_language'],
1027
                'isAdministratedByRole' => $post_is_administrated_by,
1028
                'can_create_root_folder' => empty($post_root_level) === true ? 0 : $post_root_level,
1029
                'mfa_enabled' => empty($post_mfa_enabled) === true ? 0 : $post_mfa_enabled,
1030
            );
1031
1032
            // Manage user password change
1033
            // This can occur only if user changes his own password
1034
            // In other case, next condition must be wrong
1035
            if (
1036
                isset($post_password) === true
1037
                && $post_password !== $password_do_not_change
1038
                && $post_id === $session->get('user-id')
1039
            ) {
1040
                // load password library
1041
                $passwordManager = new PasswordManager();
1042
1043
                $changeArray['pw'] = $passwordManager->hashPassword($post_password);
1044
                $changeArray['key_tempo'] = '';
1045
1046
                // We need to adapt the private key with new password
1047
                $session->set('user-private_key', encryptPrivateKey($post_password, $session->get('user-private_key')));
1048
            }
1049
1050
            // Empty user
1051
            if (empty($post_login) === true) {
1052
                echo prepareExchangedData(
1053
                    array(
1054
                        'error' => true,
1055
                        'message' => $lang->get('error_empty_data'),
1056
                    ),
1057
                    'encode'
1058
                );
1059
                break;
1060
            }
1061
1062
            // User has email?
1063
            if (empty($post_email) === true) {
1064
                echo prepareExchangedData(
1065
                    array(
1066
                        'error' => true,
1067
                        'message' => $lang->get('error_no_email'),
1068
                    ),
1069
                    'encode'
1070
                );
1071
                break;
1072
            }
1073
1074
            // Is this user allowed to do this?
1075
            if (
1076
                // Administrator user
1077
                (int) $session->get('user-admin') === 1
1078
                // Manager of basic/ro users in this role but don't allow promote user to admin or managers roles
1079
                || ((int) $session->get('user-manager') === 1
1080
                    && in_array($data_user['isAdministratedByRole'], $session->get('user-roles_array'))
1081
                    && (int) $post_is_admin !== 1 && (int) $data_user['admin'] !== 1
1082
                    && (int) $post_is_hr !== 1 && (int) $data_user['can_manage_all_users'] !== 1
1083
                    && (int) $post_is_manager !== 1 && (int) $data_user['gestionnaire'] !== 1)
1084
                // Manager of all basic/ro users but don't allow promote user to admin or managers roles
1085
                || ((int) $session->get('user-can_manage_all_users') === 1
1086
                    && (int) $post_is_admin !== 1 && (int) $data_user['admin'] !== 1
1087
                    && (int) $post_is_hr !== 1 && (int) $data_user['can_manage_all_users'] !== 1
1088
                    && (int) $post_is_manager !== 1 && (int) $data_user['gestionnaire'] !== 1)
1089
            ) {
1090
                // delete account
1091
                // delete user in database
1092
                if ($post_action_to_perform === 'delete') {
1093
                    DB::delete(
1094
                        prefixTable('users'),
1095
                        'id = %i',
1096
                        $post_id
1097
                    );
1098
                    // delete personal folder and subfolders
1099
                    $data = DB::queryFirstRow(
1100
                        'SELECT id FROM ' . prefixTable('nested_tree') . '
1101
                        WHERE title = %s AND personal_folder = %i',
1102
                        $post_id,
1103
                        '1'
1104
                    );
1105
                    // Get through each subfolder
1106
                    if (!empty($data['id'])) {
1107
                        $folders = $tree->getDescendants($data['id'], true);
1108
                        foreach ($folders as $folder) {
1109
                            // delete folder
1110
                            DB::delete(prefixTable('nested_tree'), 'id = %i AND personal_folder = %i', $folder->id, '1');
1111
                            // delete items & logs
1112
                            $items = DB::query(
1113
                                'SELECT id FROM ' . prefixTable('items') . '
1114
                                WHERE id_tree=%i AND perso = %i',
1115
                                $folder->id,
1116
                                '1'
1117
                            );
1118
                            foreach ($items as $item) {
1119
                                // Delete item
1120
                                DB::delete(prefixTable('items'), 'id = %i', $item['id']);
1121
                                // log
1122
                                DB::delete(prefixTable('log_items'), 'id_item = %i', $item['id']);
1123
                            }
1124
                        }
1125
                        // rebuild tree
1126
                        $tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
1127
                        $tree->rebuild();
1128
                    }
1129
1130
                    // Delete Roles
1131
                    DB::delete(
1132
                        prefixTable('users_roles'),
1133
                        'user_id = %i',
1134
                        $post_id
1135
                    );
1136
1137
                    // Delete Groups
1138
                    DB::delete(
1139
                        prefixTable('users_groups'),
1140
                        'user_id = %i',
1141
                        $post_id
1142
                    );
1143
                    DB::delete(
1144
                        prefixTable('users_groups_forbidden'),
1145
                        'user_id = %i',
1146
                        $post_id
1147
                    );
1148
1149
                    // Delete Latest items
1150
                    DB::delete(
1151
                        prefixTable('users_latest_items'),
1152
                        'user_id = %i',
1153
                        $post_id
1154
                    );
1155
1156
                    // Delete favorites
1157
                    DB::delete(
1158
                        prefixTable('users_favorites'),
1159
                        'user_id = %i',
1160
                        $post_id
1161
                    );
1162
1163
1164
                    // update LOG
1165
                    logEvents($SETTINGS, 'user_mngt', 'at_user_deleted', (string) $session->get('user-id'), $session->get('user-login'), $post_id);
1166
                } else {
1167
                    // Get old data about user
1168
                    $oldData = getUserCompleteData(null, $post_id);
1169
1170
                    // update SESSION
1171
                    if ($session->get('user-id') === $post_id) {
1172
                        $session->set('user-lastname', $post_lastname);
1173
                        $session->set('user-name', $post_name);
1174
                        $session->set('user-email', $post_email);
1175
                    }
1176
1177
                    // Has the groups changed? If yes then ask for a keys regeneration
1178
                    $arrOldData = array_filter(explode(';', $oldData['fonction_id']));
1179
                    $post_groups = is_null($post_groups) === true ? array() : array_filter($post_groups);
1180
1181
                    if ($arrOldData != $post_groups && (int) $oldData['admin'] !== 1) {
1182
                        $action_to_perform_after = 'encrypt_keys';
1183
                    }
1184
1185
                    // update user
1186
                    DB::update(
1187
                        prefixTable('users'),
1188
                        $changeArray,
1189
                        'id = %i',
1190
                        $post_id
1191
                    );
1192
1193
                    // Add Groups and Roles
1194
                    setUserRoles($post_id, $post_groups, 'manual');
1195
                    setUserGroups($post_id, $post_allowed_flds);
1196
                    setUserForbiddenGroups($post_id, $post_forbidden_flds);
1197
1198
                    // CLear cache tree for this user to force tree
1199
                    DB::delete(
1200
                        prefixTable('cache_tree'),
1201
                        'user_id = %i',
1202
                        $post_id
1203
                    );
1204
1205
                    // update LOG
1206
                    if ($oldData['email'] !== $post_email) {
1207
                        logEvents($SETTINGS, 'user_mngt', 'at_user_email_changed:' . $oldData['email'], (string) $session->get('user-id'), $session->get('user-login'), $post_id);
1208
                    }
1209
                }
1210
                echo prepareExchangedData(
1211
                    array(
1212
                        'error' => false,
1213
                        'message' => '',
1214
                        'post_action' => $action_to_perform_after,
1215
                    ),
1216
                    'encode'
1217
                );
1218
            } else {
1219
                echo prepareExchangedData(
1220
                    array(
1221
                        'error' => true,
1222
                        'message' => $lang->get('error_not_allowed_to'),
1223
                    ),
1224
                    'encode'
1225
                );
1226
            }
1227
            break;
1228
1229
        /*
1230
         * IS LOGIN AVAILABLE?
1231
         */
1232
        case 'is_login_available':
1233
            // Check KEY
1234
            if ($post_key !== $session->get('key')) {
1235
                echo prepareExchangedData(
1236
                    array(
1237
                        'error' => true,
1238
                        'message' => $lang->get('key_is_not_correct'),
1239
                    ),
1240
                    'encode'
1241
                );
1242
                break;
1243
            } elseif ($session->get('user-read_only') === 1) {
1244
                echo prepareExchangedData(
1245
                    array(
1246
                        'error' => true,
1247
                        'message' => $lang->get('error_not_allowed_to'),
1248
                    ),
1249
                    'encode'
1250
                );
1251
                break;
1252
            }
1253
1254
            $login = (string) filter_input(INPUT_POST, 'login', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
1255
            DB::queryFirstRow(
1256
                'SELECT * FROM ' . prefixTable('users') . '
1257
                WHERE (login = %s AND deleted_at IS NULL) 
1258
                OR login LIKE %s',
1259
                $login,
1260
                $login.'_deleted_%%'
1261
            );
1262
1263
            echo prepareExchangedData(
1264
                array(
1265
                    'error' => false,
1266
                    'login_exists' => DB::count(),
1267
                ),
1268
                'encode'
1269
            );
1270
1271
            break;
1272
1273
        /*
1274
         * GET USER FOLDER RIGHT
1275
         */
1276
        case 'user_folders_rights':
1277
            // Check KEY
1278
            if ($post_key !== $session->get('key')) {
1279
                echo prepareExchangedData(
1280
                    array(
1281
                        'error' => true,
1282
                        'message' => $lang->get('key_is_not_correct'),
1283
                    ),
1284
                    'encode'
1285
                );
1286
                break;
1287
            } elseif ($session->get('user-read_only') === 1) {
1288
                echo prepareExchangedData(
1289
                    array(
1290
                        'error' => true,
1291
                        'message' => $lang->get('error_not_allowed_to'),
1292
                    ),
1293
                    'encode'
1294
                );
1295
                break;
1296
            }
1297
1298
            // Prepare variables
1299
            $post_id = (int) filter_input(INPUT_POST, 'user_id', FILTER_SANITIZE_NUMBER_INT);
1300
1301
            $arrData = array();
1302
1303
            //Build tree
1304
            $tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
1305
1306
            // get User info
1307
            $rowUser = getUserCompleteData(null, $post_id);
1308
1309
            // get rights
1310
            $arrFolders = [];
1311
            $foldersData = [];
1312
            $html = '';
1313
1314
            if (isset($SETTINGS['ldap_mode']) === true && (int) $SETTINGS['ldap_mode'] === 1 && isset($SETTINGS['enable_ad_users_with_ad_groups']) === true && (int) $SETTINGS['enable_ad_users_with_ad_groups'] === 1) {
1315
                $rowUser['fonction_id'] = empty($rowUser['fonction_id'])  === true ? $rowUser['roles_from_ad_groups'] : $rowUser['fonction_id']. ';' . $rowUser['roles_from_ad_groups'];
1316
            }
1317
            $arrData['functions'] = array_filter(explode(';', $rowUser['fonction_id']));
1318
            $arrData['allowed_folders'] = array_filter(explode(';', $rowUser['groupes_visibles']));
1319
            $arrData['denied_folders'] = array_filter(explode(';', $rowUser['groupes_interdits']));
1320
1321
            // Exit if no roles
1322
            if (count($arrData['functions']) > 0) {
1323
                // refine folders based upon roles
1324
                $rows = DB::query(
1325
                    'SELECT rv.folder_id, rv.type
1326
                    FROM ' . prefixTable('roles_values') . ' as rv
1327
                    INNER JOIN ' . prefixTable('nested_tree') . ' as nt ON rv.folder_id = nt.id
1328
                    WHERE rv.role_id IN %ls AND nt.personal_folder = 0
1329
                    ORDER BY rv.folder_id ASC',
1330
                    $arrData['functions']
1331
                );
1332
                foreach ($rows as $record) {
1333
                    $bFound = false;
1334
                    $x = 0;
1335
                    foreach ($arrFolders as $fld) {
1336
                        if ($fld['id'] === $record['folder_id']) {
1337
                            // get the level of access on the folder
1338
                            $arrFolders[$x]['type'] = evaluateFolderAccesLevel($record['type'], $arrFolders[$x]['type']);
1339
                            $bFound = true;
1340
                            break;
1341
                        }
1342
                        ++$x;
1343
                    }
1344
                    if ($bFound === false && in_array($record['folder_id'], $arrData['denied_folders']) === false) {
1345
                        array_push($arrFolders, array('id' => $record['folder_id'], 'type' => $record['type'], 'special' => false));
1346
                    }
1347
                }
1348
1349
                // add allowed folders
1350
                foreach($arrData['allowed_folders'] as $Fld) {
1351
                    array_push($arrFolders, array('id' => $Fld, 'type' => 'W', 'special' => true));
1352
                }
1353
                
1354
                $tree_desc = $tree->getDescendants();
1355
                foreach ($tree_desc as $t) {
1356
                    if ((int) $t->personal_folder === 1 && $t->title !== $rowUser['id']) {
1357
                        // skip personal folders
1358
                        continue;
1359
                    }
1360
                    foreach ($arrFolders as $fld) {
1361
                        if ($fld['id'] === $t->id) {
1362
                            // get folder name
1363
                            $row = DB::queryFirstRow(
1364
                                'SELECT title, nlevel, id
1365
                                FROM ' . prefixTable('nested_tree') . '
1366
                                WHERE id = %i',
1367
                                $fld['id']
1368
                            );
1369
1370
                            $foldersData[] = [
1371
                                'id' => $row['id'],
1372
                                'title' => $row['title'],
1373
                                'nlevel' => $row['nlevel'],
1374
                                'type' => $fld['type'],
1375
                                'special' => $fld['special']
1376
                            ];
1377
1378
                            break;
1379
                        }
1380
                    }
1381
                }
1382
1383
                $html_full = '<table id="table-folders" class="table table-bordered table-striped dt-responsive nowrap" style="width:100%"><tbody>' .
1384
                    $html . '</tbody></table>';
1385
            } else {
1386
                $html_full = '';
1387
            }
1388
1389
            echo prepareExchangedData(
1390
                array(
1391
                    'folders' => $foldersData,
1392
                    'user' => [
1393
                        'login' => $rowUser['login'],
1394
                        'name' => $rowUser['name'],
1395
                        'lastname' => $rowUser['lastname']
1396
                    ],
1397
                    'error' => false,
1398
                    'message' => '',
1399
                ),
1400
                'encode'
1401
            );
1402
            break;
1403
1404
        /*
1405
        * GET LIST OF USERS
1406
        */
1407
        case 'get_list_of_users_for_sharing':
1408
            // Check KEY
1409
            if ($post_key !== $session->get('key')) {
1410
                echo prepareExchangedData(
1411
                    array(
1412
                        'error' => true,
1413
                        'message' => $lang->get('key_is_not_correct'),
1414
                    ),
1415
                    'encode'
1416
                );
1417
                break;
1418
            } elseif ($session->get('user-read_only') === 1) {
1419
                echo prepareExchangedData(
1420
                    array(
1421
                        'error' => true,
1422
                        'message' => $lang->get('error_not_allowed_to'),
1423
                    ),
1424
                    'encode'
1425
                );
1426
                break;
1427
            }
1428
1429
            $arrUsers = [];
1430
1431
            // Requête adaptée avec les nouvelles tables relationnelles
1432
            if ((int) $session->get('user-admin') === 0 && (int) $session->get('user-can_manage_all_users') === 0) {
1433
                $rows = DB::query(
1434
                    'SELECT u.*,
1435
                    GROUP_CONCAT(DISTINCT CASE WHEN ur.source = "manual" THEN ur.role_id END ORDER BY ur.role_id SEPARATOR ";") AS fonction_id,
1436
                    GROUP_CONCAT(DISTINCT ug.group_id ORDER BY ug.group_id SEPARATOR ";") AS groupes_visibles,
1437
                    GROUP_CONCAT(DISTINCT ugf.group_id ORDER BY ugf.group_id SEPARATOR ";") AS groupes_interdits
1438
                    FROM ' . prefixTable('users') . ' AS u
1439
                    LEFT JOIN ' . prefixTable('users_roles') . ' AS ur ON (u.id = ur.user_id)
1440
                    LEFT JOIN ' . prefixTable('users_groups') . ' AS ug ON (u.id = ug.user_id)
1441
                    LEFT JOIN ' . prefixTable('users_groups_forbidden') . ' AS ugf ON (u.id = ugf.user_id)
1442
                    WHERE u.admin = %i AND u.isAdministratedByRole IN %ls AND u.deleted_at IS NULL AND u.disabled = %i
1443
                    GROUP BY u.id',
1444
                    0,
1445
                    array_filter($session->get('user-roles_array')),
1446
                    0
1447
                );
1448
            } else {
1449
                $rows = DB::query(
1450
                    'SELECT u.*,
1451
                    GROUP_CONCAT(DISTINCT CASE WHEN ur.source = "manual" THEN ur.role_id END ORDER BY ur.role_id SEPARATOR ";") AS fonction_id,
1452
                    GROUP_CONCAT(DISTINCT ug.group_id ORDER BY ug.group_id SEPARATOR ";") AS groupes_visibles,
1453
                    GROUP_CONCAT(DISTINCT ugf.group_id ORDER BY ugf.group_id SEPARATOR ";") AS groupes_interdits
1454
                    FROM ' . prefixTable('users') . ' AS u
1455
                    LEFT JOIN ' . prefixTable('users_roles') . ' AS ur ON (u.id = ur.user_id)
1456
                    LEFT JOIN ' . prefixTable('users_groups') . ' AS ug ON (u.id = ug.user_id)
1457
                    LEFT JOIN ' . prefixTable('users_groups_forbidden') . ' AS ugf ON (u.id = ugf.user_id)
1458
                    WHERE u.admin = %i AND u.deleted_at IS NULL AND u.disabled = %i
1459
                    GROUP BY u.id',
1460
                    0,
1461
                    0
1462
                );
1463
            }
1464
1465
            foreach ($rows as $record) {
1466
                // Assurer que les champs sont des chaînes vides si NULL
1467
                $record['fonction_id'] = $record['fonction_id'] ?? '';
1468
                $record['groupes_visibles'] = $record['groupes_visibles'] ?? '';
1469
                $record['groupes_interdits'] = $record['groupes_interdits'] ?? '';
1470
                
1471
                // Get roles
1472
                $groups = [];
1473
                $groupIds = [];
1474
                if (!empty($record['fonction_id'])) {
1475
                    foreach (explode(';', $record['fonction_id']) as $group) {
1476
                        if (!empty($group)) {
1477
                            $tmp = DB::queryFirstRow(
1478
                                'SELECT id, title FROM ' . prefixTable('roles_title') . '
1479
                                WHERE id = %i',
1480
                                $group
1481
                            );
1482
                            if ($tmp !== null) {
1483
                                array_push($groups, $tmp['title']);
1484
                                array_push($groupIds, $tmp['id']);
1485
                            }
1486
                        }
1487
                    }
1488
                }
1489
1490
                // Get managed_by
1491
                $managedBy = DB::queryFirstRow(
1492
                    'SELECT id, title FROM ' . prefixTable('roles_title') . '
1493
                    WHERE id = %i',
1494
                    $record['isAdministratedByRole']
1495
                );
1496
1497
                // Get Allowed folders
1498
                $foldersAllowed = [];
1499
                $foldersAllowedIds = [];
1500
                if (!empty($record['groupes_visibles'])) {
1501
                    foreach (explode(';', $record['groupes_visibles']) as $role) {
1502
                        if (!empty($role)) {
1503
                            $tmp = DB::queryFirstRow(
1504
                                'SELECT id, title FROM ' . prefixTable('nested_tree') . '
1505
                                WHERE id = %i',
1506
                                $role
1507
                            );
1508
                            array_push($foldersAllowed, $tmp !== null ? $tmp['title'] : $lang->get('none'));
1509
                            array_push($foldersAllowedIds, $tmp !== null ? $tmp['id'] : -1);
1510
                        }
1511
                    }
1512
                }
1513
1514
                // Get denied folders
1515
                $foldersForbidden = [];
1516
                $foldersForbiddenIds = [];
1517
                if (!empty($record['groupes_interdits'])) {
1518
                    foreach (explode(';', $record['groupes_interdits']) as $role) {
1519
                        if (!empty($role)) {
1520
                            $tmp = DB::queryFirstRow(
1521
                                'SELECT id, title FROM ' . prefixTable('nested_tree') . '
1522
                                WHERE id = %i',
1523
                                $role
1524
                            );
1525
                            array_push($foldersForbidden, $tmp !== null ? $tmp['title'] : $lang->get('none'));
1526
                            array_push($foldersForbiddenIds, $tmp !== null ? $tmp['id'] : -1);
1527
                        }
1528
                    }
1529
                }
1530
1531
                // Store
1532
                array_push(
1533
                    $arrUsers,
1534
                    array(
1535
                        'id' => $record['id'],
1536
                        'name' => $record['name'],
1537
                        'lastname' => $record['lastname'],
1538
                        'login' => $record['login'],
1539
                        'groups' => implode(', ', $groups),
1540
                        'groupIds' => $groupIds,
1541
                        'managedBy' => $managedBy === null ? $lang->get('administrator') : $managedBy['title'],
1542
                        'managedById' => $managedBy === null ? 0 : $managedBy['id'],
1543
                        'foldersAllowed' => implode(', ', $foldersAllowed),
1544
                        'foldersAllowedIds' => $foldersAllowedIds,
1545
                        'foldersForbidden' => implode(', ', $foldersForbidden),
1546
                        'foldersForbiddenIds' => $foldersForbiddenIds,
1547
                        'admin' => $record['admin'],
1548
                        'manager' => $record['gestionnaire'],
1549
                        'hr' => $record['can_manage_all_users'],
1550
                        'readOnly' => $record['read_only'],
1551
                        'personalFolder' => $record['personal_folder'],
1552
                        'rootFolder' => $record['can_create_root_folder'],
1553
                    )
1554
                );
1555
            }
1556
1557
            echo prepareExchangedData(
1558
                array(
1559
                    'error' => false,
1560
                    'values' => $arrUsers,
1561
                ),
1562
                'encode'
1563
            );
1564
1565
            break;
1566
1567
1568
        /*
1569
        * UPDATE USERS RIGHTS BY SHARING
1570
        */
1571
        case 'update_users_rights_sharing':
1572
            // Check KEY
1573
            if ($post_key !== $session->get('key')) {
1574
                echo prepareExchangedData(
1575
                    array(
1576
                        'error' => true,
1577
                        'message' => $lang->get('key_is_not_correct'),
1578
                    ),
1579
                    'encode'
1580
                );
1581
                break;
1582
            } elseif ($session->get('user-read_only') === 1) {
1583
                echo prepareExchangedData(
1584
                    array(
1585
                        'error' => true,
1586
                        'message' => $lang->get('error_not_allowed_to'),
1587
                    ),
1588
                    'encode'
1589
                );
1590
                break;
1591
            }
1592
1593
            // Prepare variables
1594
            $data = [
1595
                'source_id' => isset($dataReceived['source_id']) === true ? $dataReceived['source_id'] : 0,
1596
                'destination_ids' => isset($dataReceived['destination_ids']) === true ? $dataReceived['destination_ids'] : 0,
1597
                'user_functions' => isset($dataReceived['user_functions']) === true ? $dataReceived['user_functions'] : '',
1598
                'user_managedby' => isset($dataReceived['user_managedby']) === true ? $dataReceived['user_managedby'] : '',
1599
                'user_fldallowed' => isset($dataReceived['user_fldallowed']) === true ? $dataReceived['user_fldallowed'] : '',
1600
                'user_fldforbid' => isset($dataReceived['user_fldforbid']) === true ? $dataReceived['user_fldforbid'] : '',
1601
                'user_admin' => isset($dataReceived['user_admin']) === true ? $dataReceived['user_admin'] : 0,
1602
                'user_manager' => isset($dataReceived['user_manager']) === true ? $dataReceived['user_manager'] : 0,
1603
                'user_hr' => isset($dataReceived['user_hr']) === true ? $dataReceived['user_hr'] : 0,
1604
                'user_readonly' => isset($dataReceived['user_readonly']) === true ? $dataReceived['user_readonly'] : 1,
1605
                'user_personalfolder' => isset($dataReceived['user_personalfolder']) === true ? $dataReceived['user_personalfolder'] : 0,
1606
                'user_rootfolder' => isset($dataReceived['user_rootfolder']) === true ? $dataReceived['user_rootfolder'] : 0,
1607
            ];
1608
            
1609
            $filters = [
1610
                'source_id' => 'cast:integer',
1611
                'destination_ids' => 'trim|escape',
1612
                'user_functions' => 'trim|escape',
1613
                'user_managedby' => 'trim|escape',
1614
                'user_fldallowed' => 'trim|escape',
1615
                'user_fldforbid' => 'trim|escape',
1616
                'user_admin' => 'cast:integer',
1617
                'user_manager' => 'cast:integer',
1618
                'user_hr' => 'cast:integer',
1619
                'user_readonly' => 'cast:integer',
1620
                'user_personalfolder' => 'cast:integer',
1621
                'user_rootfolder' => 'cast:integer',
1622
            ];
1623
            
1624
            $inputData = dataSanitizer(
1625
                $data,
1626
                $filters
1627
            );
1628
1629
            // Check send values
1630
            if ($inputData['source_id'] === 0 || $inputData['destination_ids'] === 0) {
1631
                // error
1632
                echo prepareExchangedData(
1633
                    array(
1634
                        'error' => true,
1635
                        'message' => $lang->get('error_not_allowed_to'),
1636
                    ),
1637
                    'encode'
1638
                );
1639
            }
1640
1641
            // Get info about user
1642
            $data_user = DB::queryFirstRow(
1643
                'SELECT admin, isAdministratedByRole FROM ' . prefixTable('users') . '
1644
                WHERE id = %i',
1645
                $inputData['source_id']
1646
            );
1647
1648
            // Is this user allowed to do this?
1649
            if (
1650
                (int) $session->get('user-admin') === 1
1651
                || (in_array($data_user['isAdministratedByRole'], $session->get('user-roles_array')))
1652
                || ((int) $session->get('user-can_manage_all_users') === 1 && (int) $data_user['admin'] !== 1)
1653
            ) {
1654
                foreach ($inputData['destination_ids'] as $dest_user_id) {
1655
                    // Is this user allowed to do this?
1656
                    if (
1657
                        (int) $session->get('user-admin') === 1
1658
                        || (in_array($data_user['isAdministratedByRole'], $session->get('user-roles_array')))
1659
                        || ((int) $session->get('user-can_manage_all_users') === 1 && (int) $data_user['admin'] !== 1)
1660
                    ) {
1661
                        // Update user roles in users_roles table
1662
                        $roleIds = array_filter(
1663
                            explode(';', str_replace(',', ';', (string) $inputData['user_functions']))
1664
                        );
1665
                        setUserRoles((int) $dest_user_id, $roleIds, 'manual');
1666
                        
1667
                        // Update allowed folders in users_groups table
1668
                        $allowedFolders = array_filter(
1669
                            explode(';', str_replace(',', ';', (string) $inputData['user_fldallowed']))
1670
                        );
1671
                        setUserGroups((int) $dest_user_id, $allowedFolders);
1672
                        
1673
                        // Update forbidden folders in users_groups_forbidden table
1674
                        $forbiddenFolders = array_filter(
1675
                            explode(';', str_replace(',', ';', (string) $inputData['user_fldforbid']))
1676
                        );
1677
                        setUserForbiddenGroups((int) $dest_user_id, $forbiddenFolders);
1678
                        
1679
                        // Update other user fields in users table
1680
                        DB::update(
1681
                            prefixTable('users'),
1682
                            array(
1683
                                'isAdministratedByRole' => $inputData['user_managedby'],
1684
                                'gestionnaire' => $inputData['user_manager'],
1685
                                'read_only' => $inputData['user_readonly'],
1686
                                'can_create_root_folder' => $inputData['user_rootfolder'],
1687
                                'personal_folder' => $inputData['user_personalfolder'],
1688
                                'can_manage_all_users' => $inputData['user_hr'],
1689
                                'admin' => $inputData['user_admin'],
1690
                            ),
1691
                            'id = %i',
1692
                            $dest_user_id
1693
                        );
1694
                    }
1695
                }
1696
            }
1697
1698
            echo prepareExchangedData(
1699
                array(
1700
                    'error' => false,
1701
                ),
1702
                'encode'
1703
            );
1704
1705
            break;
1706
1707
1708
            /*
1709
         * UPDATE USER PROFILE
1710
         */
1711
        case 'user_profile_update':
1712
            // Check KEY
1713
            if ($post_key !== $session->get('key')) {
1714
                echo prepareExchangedData(
1715
                    array(
1716
                        'error' => true,
1717
                        'message' => $lang->get('key_is_not_correct'),
1718
                    ),
1719
                    'encode'
1720
                );
1721
                break;
1722
            }
1723
1724
            // Check user
1725
            if (
1726
                null === $session->get('user-id')
1727
                || empty($session->get('user-id')) === true
1728
            ) {
1729
                echo prepareExchangedData(
1730
                    array(
1731
                        'error' => true,
1732
                        'message' => $lang->get('no_user'),
1733
                    ),
1734
                    'encode'
1735
                );
1736
                break;
1737
            }
1738
1739
            if (empty($dataReceived) === false) {
1740
                // Sanitize
1741
                $data = [
1742
                    'email' => isset($dataReceived['email']) === true ? $dataReceived['email'] : '',
1743
                    'timezone' => isset($dataReceived['timezone']) === true ? $dataReceived['timezone'] : '',
1744
                    'language' => isset($dataReceived['language']) === true ? $dataReceived['language'] : '',
1745
                    'treeloadstrategy' => isset($dataReceived['treeloadstrategy']) === true ? $dataReceived['treeloadstrategy'] : '',
1746
                    'agsescardid' => isset($dataReceived['agsescardid']) === true ? $dataReceived['agsescardid'] : '',
1747
                    'name' => isset($dataReceived['name']) === true ? $dataReceived['name'] : '',
1748
                    'lastname' => isset($dataReceived['lastname']) === true ? $dataReceived['lastname'] : '',
1749
                    'split_view_mode' => isset($dataReceived['split_view_mode']) === true ? $dataReceived['split_view_mode'] : '',
1750
                    'show_subfolders' => isset($dataReceived['show_subfolders']) === true ? $dataReceived['show_subfolders'] : '',
1751
                ];
1752
                
1753
                $filters = [
1754
                    'email' => 'trim|escape',
1755
                    'timezone' => 'trim|escape',
1756
                    'language' => 'trim|escape',
1757
                    'treeloadstrategy' => 'trim|escape',
1758
                    'agsescardid' => 'trim|escape',
1759
                    'name' => 'trim|escape',
1760
                    'lastname' => 'trim|escape',
1761
                    'split_view_mode' => 'cast:integer',
1762
                    'show_subfolders' => 'cast:integer',
1763
                ];
1764
                
1765
                $inputData = dataSanitizer(
1766
                    $data,
1767
                    (array) $filters
1768
                );
1769
1770
                // Prevent LFI.
1771
                $inputData['language'] = preg_replace('/[^a-z_]/', "", $inputData['language']);
1772
1773
                // Force english if non-existent language.
1774
                if (!file_exists(__DIR__."/../includes/language/".$inputData['language'].".php")) {
1775
                    $inputData['language'] = 'english';
1776
                }
1777
1778
                // Data to update
1779
                $update_fields = [
1780
                    'split_view_mode' => $inputData['split_view_mode'],
1781
                    'show_subfolders' => $inputData['show_subfolders'],
1782
                ];
1783
1784
                // Update SETTINGS
1785
                $session->set('user-split_view_mode', (int) $inputData['split_view_mode']);
1786
                $session->set('user-show_subfolders', (int) $inputData['show_subfolders']);
1787
1788
                // User profile edit enabled
1789
                if (($SETTINGS['disable_user_edit_profile'] ?? '0') === '0') {
1790
                    // Update database
1791
                    $update_fields['email']    = $inputData['email'];
1792
                    $update_fields['name']     = $inputData['name'];
1793
                    $update_fields['lastname'] = $inputData['lastname'];
1794
                    // Update session
1795
                    $session->set('user-email', $inputData['email']);
1796
                    $session->set('user-name', $inputData['name']);
1797
                    $session->set('user-lastname', $inputData['lastname']);    
1798
                }
1799
1800
                // User language edit enabled
1801
                if (($SETTINGS['disable_user_edit_language'] ?? '0') === '0') {
1802
                    // Update database
1803
                    $update_fields['user_language'] = $inputData['language'];
1804
                    // Update session
1805
                    $session->set('user-language', $inputData['language']);
1806
                }
1807
1808
                // User timezone edit enabled
1809
                if (($SETTINGS['disable_user_edit_timezone'] ?? '0') === '0') {
1810
                    // Update database
1811
                    $update_fields['usertimezone'] = $inputData['timezone'];
1812
                    // Update session
1813
                    $session->set('user-timezone', $inputData['timezone']);
1814
                }
1815
1816
                // User can edit tree load strategy
1817
                if (($SETTINGS['disable_user_edit_tree_load_strategy'] ?? '0') === '0') {
1818
                    // Update database
1819
                    $update_fields['treeloadstrategy'] = $inputData['treeloadstrategy'];
1820
                    // Update session
1821
                    $session->set('user-tree_load_strategy', $inputData['treeloadstrategy']);
1822
                }
1823
1824
                // update user
1825
                DB::update(
1826
                    prefixTable('users'),
1827
                    $update_fields,
1828
                    'id = %i',
1829
                    $session->get('user-id')
1830
                );
1831
1832
            } else {
1833
                // An error appears on JSON format
1834
                echo prepareExchangedData(
1835
                    array(
1836
                        'error' => true,
1837
                        'message' => $lang->get('json_error_format'),
1838
                    ),
1839
                    'encode'
1840
                );
1841
            }
1842
1843
            // Encrypt data to return
1844
            echo prepareExchangedData(
1845
                array(
1846
                    'error' => false,
1847
                    'message' => '',
1848
                    'name' => $session->get('user-name'),
1849
                    'lastname' => $session->get('user-lastname'),
1850
                    'email' => $session->get('user-email'),
1851
                    'split_view_mode' => $session->get('user-split_view_mode'),
1852
                    'show_subfolders' => $session->get('user-show_subfolders'),
1853
                ),
1854
                'encode'
1855
            );
1856
            break;
1857
1858
            //CASE where refreshing table
1859
        case 'save_user_change':
1860
            // Check KEY
1861
            if ($post_key !== $session->get('key')) {
1862
                echo prepareExchangedData(
1863
                    array(
1864
                        'error' => true,
1865
                        'message' => $lang->get('key_is_not_correct'),
1866
                    ),
1867
                    'encode'
1868
                );
1869
                break;
1870
            } elseif ($session->get('user-read_only') === 1) {
1871
                echo prepareExchangedData(
1872
                    array(
1873
                        'error' => true,
1874
                        'message' => $lang->get('error_not_allowed_to'),
1875
                    ),
1876
                    'encode'
1877
                );
1878
                break;
1879
            }
1880
1881
            // prepare variables
1882
            $post_user_id = filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
1883
            $post_field = filter_var($dataReceived['field'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
1884
            $post_new_value = filter_var($dataReceived['value'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
1885
            $post_context = filter_var($dataReceived['context'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
1886
1887
            // If
1888
            if (empty($post_context) === false && $post_context === 'add_one_role_to_user') {
1889
                $data_user = DB::queryFirstRow(
1890
                    'SELECT fonction_id, public_key
1891
                    FROM ' . prefixTable('users') . '
1892
                    WHERE id = %i',
1893
                    $post_user_id
1894
                );
1895
1896
                if ($data_user) {
1897
                    // Ensure array is unique
1898
                    $post_new_value = str_replace(',', ';', $data_user['fonction_id']) . ';' . $post_new_value;
1899
                    $post_new_value = implode(';', array_unique(explode(';', $post_new_value)));
1900
                } else {
1901
                    // User not found
1902
                    echo prepareExchangedData(
1903
                        array(
1904
                            'error' => true,
1905
                            'message' => $lang->get('user_not_exists'),
1906
                        ),
1907
                        'encode'
1908
                    );
1909
                    break;
1910
                }
1911
            }
1912
1913
            // Manage specific case of api key
1914
            if($post_field === 'user_api_key') {
1915
                $encrypted_key = encryptUserObjectKey(base64_encode($post_new_value), $session->get('user-public_key'));
1916
                $session->set('user-api_key', $post_new_value);
1917
1918
                // test if user has an api key
1919
                $data_user = DB::queryFirstRow(
1920
                    'SELECT value
1921
                    FROM ' . prefixTable('api') . '
1922
                    WHERE user_id = %i',
1923
                    $post_user_id
1924
                );
1925
                if ($data_user) {
1926
                    // update
1927
                    DB::update(
1928
                        prefixTable('api'),
1929
                        array(
1930
                            'value' => $encrypted_key,
1931
                            'timestamp' => time()
1932
                        ),
1933
                        'user_id = %i',
1934
                        $post_user_id
1935
                    );
1936
                } else {
1937
                    // insert
1938
                    DB::insert(
1939
                        prefixTable('api'),
1940
                        array(
1941
                            'type' => 'user',
1942
                            'user_id' => $post_user_id,
1943
                            'value' => $encrypted_key,
1944
                            'timestamp' => time()
1945
                        )
1946
                    );
1947
                }
1948
1949
                // send data
1950
                echo prepareExchangedData(
1951
                    array(
1952
                        'error' => false,
1953
                        'message' => ''
1954
                    ),
1955
                    'encode'
1956
                );
1957
1958
                break;
1959
            }
1960
1961
            DB::update(
1962
                prefixTable('users'),
1963
                array(
1964
                    $post_field => $post_new_value,
1965
                ),
1966
                'id = %i',
1967
                $post_user_id
1968
            );
1969
1970
            // special case
1971
            if ($post_field === 'auth_type' && $post_new_value === 'ldap') {
1972
                /*DB::update(
1973
                    prefixTable('users'),
1974
                    array(
1975
                        'special' => 'recrypt-private-key',
1976
                    ),
1977
                    'id = %i',
1978
                    $post_user_id
1979
                );*/
1980
            }
1981
1982
            // send data
1983
            echo prepareExchangedData(
1984
                array(
1985
                    'error' => false,
1986
                    'message' => ''
1987
                ),
1988
                'encode'
1989
            );
1990
1991
            break;
1992
1993
        /*
1994
        * GET LDAP LIST OF USERS
1995
        */
1996
        case 'get_list_of_users_in_ldap':
1997
            // Check KEY
1998
            if ($post_key !== $session->get('key')) {
1999
                echo prepareExchangedData(
2000
                    array(
2001
                        'error' => true,
2002
                        'message' => $lang->get('key_is_not_correct'),
2003
                    ),
2004
                    'encode'
2005
                );
2006
                break;
2007
            }
2008
            
2009
            // Build ldap configuration array
2010
            $config = [
2011
                // Mandatory Configuration Options
2012
                'hosts'            => explode(',', (string) $SETTINGS['ldap_hosts']),
2013
                'base_dn'          => $SETTINGS['ldap_bdn'],
2014
                'username'         => $SETTINGS['ldap_username'],
2015
                'password'         => $SETTINGS['ldap_password'],
2016
            
2017
                // Optional Configuration Options
2018
                'port'             => $SETTINGS['ldap_port'],
2019
                'use_ssl'          => (int) $SETTINGS['ldap_ssl'] === 1 ? true : false,
2020
                'use_tls'          => (int) $SETTINGS['ldap_tls'] === 1 ? true : false,
2021
                'version'          => 3,
2022
                'timeout'          => 5,
2023
                'follow_referrals' => false,
2024
            
2025
                // Custom LDAP Options
2026
                'options' => [
2027
                    // See: http://php.net/ldap_set_option
2028
                    LDAP_OPT_X_TLS_REQUIRE_CERT => isset($SETTINGS['ldap_tls_certificate_check']) === false ? 'LDAP_OPT_X_TLS_NEVER' : $SETTINGS['ldap_tls_certificate_check'],
2029
                ]
2030
            ];
2031
            //prepare connection
2032
            $connection = new Connection($config);
2033
2034
            // Connect to LDAP
2035
            try {
2036
                $connection->connect();
2037
            
2038
            } catch (\LdapRecord\Auth\BindException $e) {
2039
                $error = $e->getDetailedError();
2040
                if ($error && defined('LOG_TO_SERVER') && LOG_TO_SERVER === true) {
2041
                    error_log('TEAMPASS Error - LDAP - '.$error->getErrorCode()." - ".$error->getErrorMessage(). " - ".$error->getDiagnosticMessage());
2042
                }
2043
                // deepcode ignore ServerLeak: No important data is sent and it is encrypted before sending
2044
                echo prepareExchangedData(
2045
                    array(
2046
                        'error' => true,
2047
                        'message' => "An error occurred.",
2048
                    ),
2049
                    'encode'
2050
                );
2051
                break;
2052
            }
2053
2054
            $adUsersToSync = array();
2055
            $adRoles = array();
2056
            $usersAlreadyInTeampass = array();
2057
            $adUsedAttributes = array(
2058
                'dn', 'mail', 'givenname', 'samaccountname', 'sn', $SETTINGS['ldap_user_attribute'],
2059
                'memberof', 'name', 'displayname', 'cn', 'shadowexpire', 'distinguishedname'
2060
            );
2061
2062
            try {
2063
                $results = $connection->query()
2064
                    ->rawfilter($SETTINGS['ldap_user_object_filter'])
2065
                    ->in((empty($SETTINGS['ldap_dn_additional_user_dn']) === false ? $SETTINGS['ldap_dn_additional_user_dn'].',' : '').$SETTINGS['ldap_bdn'])
2066
                    ->whereHas($SETTINGS['ldap_user_attribute'])
2067
                    ->paginate(100);
2068
            } catch (\LdapRecord\Auth\BindException $e) {
2069
                $error = $e->getDetailedError();
2070
                if ($error && defined('LOG_TO_SERVER') && LOG_TO_SERVER === true) {
2071
                    error_log('TEAMPASS Error - LDAP - '.$error->getErrorCode()." - ".$error->getErrorMessage(). " - ".$error->getDiagnosticMessage());
2072
                }
2073
                // deepcode ignore ServerLeak: No important data is sent and it is encrypted before sending
2074
                echo prepareExchangedData(
2075
                    array(
2076
                        'error' => true,
2077
                        'message' => "An error occurred.",
2078
                    ),
2079
                    'encode'
2080
                );
2081
                break;
2082
            }
2083
            
2084
            foreach ($results as $adUser) {
2085
                if (isset($adUser[$SETTINGS['ldap_user_attribute']][0]) === false) continue;
2086
                // Build the list of all groups in AD
2087
                if (isset($adUser['memberof']) === true) {
2088
                    foreach($adUser['memberof'] as $j => $adUserGroup) {
2089
                        if (empty($adUserGroup) === false && $j !== "count") {
2090
                            $adGroup = substr($adUserGroup, 3, strpos($adUserGroup, ',') - 3);
2091
                            if (in_array($adGroup, $adRoles) === false && empty($adGroup) === false) {
2092
                                array_push($adRoles, $adGroup);
2093
                            }
2094
                        }
2095
                    }
2096
                }
2097
2098
                // Is user in Teampass ?
2099
                $userLogin = $adUser[$SETTINGS['ldap_user_attribute']][0];
2100
                if (null !== $userLogin) {
2101
                    // Get his ID
2102
                    $userInfo = getUserCompleteData($userLogin);
2103
                    
2104
                    // Loop on all user attributes
2105
                    $tmp = [
2106
                        'userInTeampass' => DB::count() > 0 ? (int) $userInfo['id'] : DB::count(),
2107
                        'userAuthType' => isset($userInfo['auth_type']) === true ? $userInfo['auth_type'] : 0,                        
2108
                    ];
2109
                    foreach ($adUsedAttributes as $userAttribute) {
2110
                        if (isset($adUser[$userAttribute]) === true) {
2111
                            if (is_array($adUser[$userAttribute]) === true && array_key_first($adUser[$userAttribute]) !== 'count') {
2112
                                // Loop on all entries
2113
                                $tmpAttrValue = '';
2114
                                foreach ($adUser[$userAttribute] as $userAttributeEntry) {
2115
                                    if ($userAttribute === 'memberof') {
2116
                                        $userAttributeEntry = substr($userAttributeEntry, 3, strpos($userAttributeEntry, ',') - 3);
2117
                                    }
2118
                                    if (empty($tmpAttrValue) === true) {
2119
                                        $tmpAttrValue = $userAttributeEntry;
2120
                                    } else {
2121
                                        $tmpAttrValue .= ','.$userAttributeEntry;
2122
                                    }
2123
                                }
2124
                                $tmp[$userAttribute] = $tmpAttrValue;
2125
                            } else {
2126
                                $tmp[$userAttribute] = $adUser[$userAttribute];
2127
                            }
2128
                        }
2129
                    }
2130
                    array_push($adUsersToSync, $tmp);
2131
                }
2132
            }
2133
2134
            // Get all groups in Teampass
2135
            $teampassRoles = array();
2136
            $rows = DB::query('SELECT id,title FROM ' . prefixTable('roles_title'));
2137
            foreach ($rows as $record) {
2138
                array_push(
2139
                    $teampassRoles,
2140
                    array(
2141
                        'id' => $record['id'],
2142
                        'title' => $record['title']
2143
                    )
2144
                );
2145
            }
2146
2147
            echo (string) prepareExchangedData(
2148
                array(
2149
                    'error' => false,
2150
                    'entries' => $adUsersToSync,
2151
                    'ldap_groups' => $adRoles,
2152
                    'teampass_groups' => $teampassRoles,
2153
                    'usersAlreadyInTeampass' => $usersAlreadyInTeampass,
2154
                ), 
2155
                'encode'
2156
            );
2157
2158
            break;
2159
2160
        /*
2161
         * ADD USER FROM LDAP OR OAUTH2
2162
         */
2163
        case 'add_user_from_ad':
2164
            // Check KEY
2165
            if ($post_key !== $session->get('key')) {
2166
                echo prepareExchangedData(
2167
                    array(
2168
                        'error' => true,
2169
                        'message' => $lang->get('key_is_not_correct'),
2170
                    ),
2171
                    'encode'
2172
                );
2173
                break;
2174
            }
2175
2176
            // Prepare variables
2177
            $post_login = filter_var($dataReceived['login'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
2178
            $post_name = filter_var($dataReceived['name'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
2179
            $post_lastname = filter_var($dataReceived['lastname'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
2180
            $post_email = filter_var($dataReceived['email'], FILTER_SANITIZE_EMAIL);
2181
            $post_roles = filter_var_array(
2182
                $dataReceived['roles'],
2183
                FILTER_SANITIZE_NUMBER_INT
2184
            );
2185
            $post_authType = filter_var($dataReceived['authType'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
2186
2187
            // Empty user
2188
            if (empty($post_login) === true || empty($post_email) === true) {
2189
                echo prepareExchangedData(
2190
                    array(
2191
                        'error' => true,
2192
                        'message' => $lang->get('user_must_have_login_and_email'),
2193
                    ),
2194
                    'encode'
2195
                );
2196
                break;
2197
            }
2198
            // Check if user already exists
2199
            $data = DB::query(
2200
                'SELECT id, fonction_id, groupes_interdits, groupes_visibles
2201
                FROM ' . prefixTable('users') . '
2202
                WHERE login = %s',
2203
                $post_login
2204
            );
2205
2206
            if (DB::count() === 0) {
2207
                // check if admin role is set. If yes then check if originator is allowed
2208
                if ((int) $session->get('user-admin') !== 1 && (int) $session->get('user-manager') !== 1) {
2209
                    echo prepareExchangedData(
2210
                        array(
2211
                            'error' => true,
2212
                            'message' => $lang->get('error_empty_data'),
2213
                        ),
2214
                        'encode'
2215
                    );
2216
                    break;
2217
                }
2218
2219
                // load password library
2220
                $passwordManager = new PasswordManager();
2221
2222
                // Prepare variables
2223
                $password = generateQuickPassword(12, true);
2224
                $hashedPassword = $passwordManager->hashPassword($password);
2225
                if ($passwordManager->verifyPassword($hashedPassword, $password) === false) {
2226
                    echo prepareExchangedData(
2227
                        array(
2228
                            'error' => true,
2229
                            'message' => $lang->get('error_not_allowed_to'),
2230
                        ),
2231
                        'encode'
2232
                    );
2233
                    break;
2234
                }
2235
            } else {
2236
                echo prepareExchangedData(
2237
                    array(
2238
                        'error' => true,
2239
                        'message' => $lang->get('error_user_exists'),
2240
                    ),
2241
                    'encode'
2242
                );
2243
                break;
2244
            }
2245
2246
            
2247
            // We need to create his keys with transparent recovery support
2248
            $userKeys = generateUserKeys($password, $SETTINGS);
2249
2250
            // Prepare user data for insertion
2251
            $userData = array(
2252
                'login' => $post_login,
2253
                'pw' => $hashedPassword,
2254
                'email' => $post_email,
2255
                'name' => $post_name,
2256
                'lastname' => $post_lastname,
2257
                'admin' => '0',
2258
                'gestionnaire' => '0',
2259
                'can_manage_all_users' => '0',
2260
                'personal_folder' => (int) $SETTINGS['enable_pf_feature'] === 1 ? 1 : 0,
2261
                'last_pw_change' => time(),
2262
                'user_language' => $SETTINGS['default_language'],
2263
                'encrypted_psk' => '',
2264
                'isAdministratedByRole' => (isset($SETTINGS['oauth_new_user_is_administrated_by']) === true && empty($SETTINGS['oauth_new_user_is_administrated_by']) === false) ? $SETTINGS['oauth_new_user_is_administrated_by'] : 0,
2265
                'public_key' => $userKeys['public_key'],
2266
                'private_key' => $userKeys['private_key'],
2267
                'special' => 'user_added_from_ad',
2268
                'auth_type' => $post_authType,
2269
                'is_ready_for_usage' => isset($SETTINGS['enable_tasks_manager']) === true && (int) $SETTINGS['enable_tasks_manager'] === 1 ? 0 : 1,
2270
                'created_at' => time(),
2271
                'personal_items_migrated' => 1,
2272
                'otp_provided' => 1,
2273
            );
2274
2275
            // Add transparent recovery fields if available
2276
            if (isset($userKeys['user_seed'])) {
2277
                $userData['user_derivation_seed'] = $userKeys['user_seed'];
2278
                $userData['private_key_backup'] = $userKeys['private_key_backup'];
2279
                $userData['key_integrity_hash'] = $userKeys['key_integrity_hash'];
2280
                $userData['last_pw_change'] = time();
2281
            }
2282
2283
            // Insert user in DB
2284
            DB::insert(
2285
                prefixTable('users'),
2286
                $userData
2287
            );
2288
            $newUserId = DB::insertId();            
2289
2290
            // Add Groups and Roles
2291
            setUserRoles($newUserId, $post_roles, 'manual');
2292
2293
            // Handle private key
2294
            insertPrivateKeyWithCurrentFlag(
2295
                $newUserId,
2296
                $userKeys['private_key'],        
2297
            );
2298
2299
            // Create the API key
2300
            DB::insert(
2301
                prefixTable('api'),
2302
                array(
2303
                    'type' => 'user',
2304
                    'value' => encryptUserObjectKey(base64_encode(uniqidReal(39)), $userKeys['public_key']),
2305
                    'timestamp' => time(),
2306
                    'user_id' => $newUserId,
2307
                    'allowed_folders' => '',
2308
                )
2309
            );
2310
2311
            // Create personnal folder
2312
            if (isset($SETTINGS['enable_pf_feature']) === true && (int) $SETTINGS['enable_pf_feature'] === 1) {
2313
                DB::insert(
2314
                    prefixTable('nested_tree'),
2315
                    array(
2316
                        'parent_id' => '0',
2317
                        'title' => $newUserId,
2318
                        'bloquer_creation' => '0',
2319
                        'bloquer_modification' => '0',
2320
                        'personal_folder' => '1',
2321
                        'fa_icon' => 'fas fa-folder',
2322
                        'fa_icon_selected' => 'fas fa-folder-open',
2323
                        'categories' => '',
2324
                    )
2325
                );
2326
2327
                // Rebuild tree
2328
                $tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
2329
                $tree->rebuild();
2330
            }
2331
2332
            // Send email to new user
2333
            if (isset($SETTINGS['enable_tasks_manager']) === false || (int) $SETTINGS['enable_tasks_manager'] === 0) {
2334
                $emailSettings = new EmailSettings($SETTINGS);
2335
                $emailService = new EmailService();
2336
                $emailService->sendMail(
2337
                    $lang->get('email_subject_new_user'),
2338
                    str_replace(
2339
                        array('#tp_login#', '#enc_code#', '#tp_link#'),
2340
                        array(addslashes($post_login), addslashes($password), $SETTINGS['email_server_url']),
2341
                        $lang->get('email_body_user_added_from_ldap_encryption_code')
2342
                    ),
2343
                    $post_email,
2344
                    $emailSettings
2345
                );
2346
            }
2347
            
2348
            echo prepareExchangedData(
2349
                array(
2350
                    'error' => false,
2351
                    'message' => '',
2352
                    'user_id' => $newUserId,
2353
                    'user_code' => $password,
2354
                    'post_action' => isset($SETTINGS['enable_tasks_manager']) === true && (int) $SETTINGS['enable_tasks_manager'] === 1 ? 'prepare_tasks' : 'encrypt_keys',
2355
                ),
2356
                'encode'
2357
            );
2358
2359
            break;
2360
2361
        /*
2362
         * CHANGE USER AUTHENTICATION TYPE
2363
         */
2364
        case 'change_user_auth_type':
2365
            // Check KEY
2366
            if ($post_key !== $session->get('key')) {
2367
                echo prepareExchangedData(
2368
                    array(
2369
                        'error' => true,
2370
                        'message' => $lang->get('key_is_not_correct'),
2371
                    ),
2372
                    'encode'
2373
                );
2374
                break;
2375
            }
2376
2377
            // Prepare variables
2378
            $post_id = filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
2379
            $post_auth = filter_var($dataReceived['auth_type'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
2380
2381
            // Empty user
2382
            if (empty($post_id) === true) {
2383
                echo prepareExchangedData(
2384
                    array(
2385
                        'error' => true,
2386
                        'message' => $lang->get('user_not_exists'),
2387
                    ),
2388
                    'encode'
2389
                );
2390
                break;
2391
            }
2392
            // Check if user already exists
2393
            DB::query(
2394
                'SELECT id
2395
                FROM ' . prefixTable('users') . '
2396
                WHERE id = %i',
2397
                $post_id
2398
            );
2399
2400
            if (DB::count() > 0) {
2401
                // Change authentication type in DB
2402
                DB::update(
2403
                    prefixTable('users'),
2404
                    array(
2405
                        'auth_type' => $post_auth,
2406
                    ),
2407
                    'id = %i',
2408
                    $post_id
2409
                );
2410
            } else {
2411
                echo prepareExchangedData(
2412
                    array(
2413
                        'error' => true,
2414
                        'message' => $lang->get('user_not_exists'),
2415
                    ),
2416
                    'encode'
2417
                );
2418
                break;
2419
            }
2420
2421
            echo prepareExchangedData(
2422
                array(
2423
                    'message' => '',
2424
                    'error' => false,
2425
                ),
2426
                'encode'
2427
            );
2428
2429
            break;
2430
        
2431
2432
        /*
2433
        * GET OAUTH2 LIST OF USERS
2434
        */
2435
        case 'get_list_of_users_in_oauth2':
2436
            // Check KEY
2437
            if ($post_key !== $session->get('key')) {
2438
                echo prepareExchangedData(
2439
                    array(
2440
                        'error' => true,
2441
                        'message' => $lang->get('key_is_not_correct'),
2442
                    ),
2443
                    'encode'
2444
                );
2445
                break;
2446
            }
2447
2448
            // Création d'une instance du contrôleur
2449
            $OAuth2 = new OAuth2Controller($SETTINGS);
2450
2451
            // Traitement de la réponse de callback Azure
2452
            $usersList = $OAuth2->getAllUsers();            
2453
2454
            // Get all groups in Teampass
2455
            $teampassRoles = array();
2456
            $titleToIdMap = [];
2457
            $rows = DB::query('SELECT id,title FROM ' . prefixTable('roles_title'));
2458
            foreach ($rows as $record) {
2459
                array_push(
2460
                    $teampassRoles,
2461
                    array(
2462
                        'id' => $record['id'],
2463
                        'title' => $record['title']
2464
                    )
2465
                );
2466
                $titleToIdMap[$record['title']] = $record['id'];
2467
            }
2468
2469
            // Do init
2470
            $adUsersToSync = [];
2471
            $adRoles = [];
2472
            $usersAlreadyInTeampass = [];
2473
2474
            function nameFromEmail($email) {
2475
                // Utiliser une expression régulière pour extraire le texte avant le domaine
2476
                if (preg_match('/^(.+)@/', $email, $matches)) {
2477
                    return $matches[1];
2478
                } else {
2479
                    return false;
2480
                }
2481
            }
2482
            
2483
            foreach ($usersList as $oAuthUser) {
2484
                // Build the list of all groups in AD
2485
                if (isset($oAuthUser['groups']) === true) {
2486
                    foreach ($oAuthUser['groups'] as $group) {
2487
                        if (
2488
                            isset($group['displayName']) && !in_array($group['displayName'], $adRoles)
2489
                            && $SETTINGS['oauth_self_register_groups'] !== $group['displayName']
2490
                        ) {
2491
                            $adRoles[] = $group['displayName'];
2492
                        }
2493
                    }
2494
                }
2495
2496
                // Is user in Teampass ?
2497
                $userLogin = nameFromEmail($oAuthUser['userPrincipalName']);
2498
                if (null !== $userLogin) {
2499
                    //error_log(print_r($oAuthUser,true));
2500
                    // Get his ID and auth type
2501
                    $userInfo = DB::queryFirstRow(
2502
                        'SELECT id, login, auth_type
2503
                        FROM ' . prefixTable('users') . '
2504
                        WHERE login = %s',
2505
                        $userLogin
2506
                    );
2507
                    
2508
                    // Get user's roles from users_roles table (all sources)
2509
                    $userGroupsInTeampass = [];
2510
                    if ($userInfo !== null) {
2511
                        $userRoles = DB::query(
2512
                            'SELECT role_id FROM ' . prefixTable('users_roles') . '
2513
                            WHERE user_id = %i',
2514
                            $userInfo['id']
2515
                        );
2516
                        $userGroupsInTeampass = array_column($userRoles, 'role_id');
2517
                    }
2518
                    
2519
                    // Loop on all user attributes
2520
                    $userADInfos = [
2521
                        'userInTeampass' => isset($userInfo) ? (int) $userInfo['id'] : 0,
2522
                        'userAuthType' => isset($userInfo) ? $userInfo['auth_type'] : 0,     
2523
                        'login' => $userLogin,
2524
                        'mail' => '',
2525
                    ];
2526
                    foreach ($oAuthUser as $key => $value) {
2527
                        if ($key !== 'groups') {
2528
                            $userADInfos[$key] = $value;
2529
                        } else {
2530
                            $userADInfos[$key] = array_column($value, 'displayName');
2531
                        }
2532
                    }
2533
2534
                    // Mettre à jour $user['groups']
2535
                    $updatedGroups = array();
2536
                    foreach ($userADInfos['groups'] as $groupName) {
2537
                        if (isset($titleToIdMap[$groupName])) {
2538
                            $updatedGroups[] = array(
2539
                                'name' => $groupName,
2540
                                'id' => $titleToIdMap[$groupName],
2541
                                'insideGroupInTeampass' => in_array($titleToIdMap[$groupName], $userGroupsInTeampass) ? 1 : 0,
2542
                            );
2543
                        } else {
2544
                            $updatedGroups[] = array(
2545
                                'name' => $groupName,
2546
                                'id' => null,
2547
                                'insideGroupInTeampass' => 0,
2548
                            );
2549
                        }
2550
                    }
2551
2552
                    // Mettre à jour $user['groups'] avec les nouveaux groupes
2553
                    $userADInfos['groups'] = $updatedGroups;
2554
                    array_push($adUsersToSync, $userADInfos);
2555
                }
2556
            }
2557
2558
            echo (string) prepareExchangedData(
2559
                array(
2560
                    'error' => false,
2561
                    'ad_users' => $adUsersToSync,
2562
                    'ad_groups' => $adRoles,
2563
                    'teampass_groups' => $teampassRoles,
2564
                ), 
2565
                'encode'
2566
            );
2567
2568
            break;
2569
2570
2571
        /*
2572
         * CHANGE USER DISABLE
2573
         */
2574
        case 'manage_user_disable_status':
2575
            // Check KEY
2576
            if ($post_key !== $session->get('key')) {
2577
                echo prepareExchangedData(
2578
                    array(
2579
                        'error' => true,
2580
                        'message' => $lang->get('key_is_not_correct'),
2581
                    ),
2582
                    'encode'
2583
                );
2584
                break;
2585
            }
2586
2587
            // Is this user allowed to do this?
2588
            if (
2589
                (int) $session->get('user-admin') !== 1
2590
                && (int) $session->get('user-can_manage_all_users') !== 1
2591
            ) {
2592
                echo prepareExchangedData(
2593
                    array(
2594
                        'error' => true,
2595
                        'message' => $lang->get('error_not_allowed_to'),
2596
                    ),
2597
                    'encode'
2598
                );
2599
                break;
2600
            }
2601
2602
            // Prepare variables
2603
            $post_id = filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
2604
            $post_user_disabled = filter_var($dataReceived['disabled_status'], FILTER_SANITIZE_NUMBER_INT);
2605
2606
2607
            // Empty user
2608
            if (empty($post_id) === true) {
2609
                echo prepareExchangedData(
2610
                    array(
2611
                        'error' => true,
2612
                        'message' => $lang->get('user_not_exists'),
2613
                    ),
2614
                    'encode'
2615
                );
2616
                break;
2617
            }
2618
            // Check if user already exists
2619
            DB::query(
2620
                'SELECT id
2621
                FROM ' . prefixTable('users') . '
2622
                WHERE id = %i',
2623
                $post_id
2624
            );
2625
2626
            if (DB::count() > 0) {
2627
                // Change authentication type in DB
2628
                DB::update(
2629
                    prefixTable('users'),
2630
                    array(
2631
                        'disabled' => empty($post_user_disabled) === true ? 0 : $post_user_disabled,
2632
                    ),
2633
                    'id = %i',
2634
                    $post_id
2635
                );
2636
2637
                // update LOG
2638
                logEvents(
2639
                    $SETTINGS,
2640
                    'user_mngt',
2641
                    $post_user_disabled === 1 ? 'at_user_locked' : 'at_user_unlocked',
2642
                    (string) $session->get('user-id'),
2643
                    $session->get('user-login'),
2644
                    $post_id
2645
                );
2646
            } else {
2647
                echo prepareExchangedData(
2648
                    array(
2649
                        'error' => true,
2650
                        'message' => $lang->get('user_not_exists'),
2651
                    ),
2652
                    'encode'
2653
                );
2654
                break;
2655
            }
2656
2657
            echo prepareExchangedData(
2658
                array(
2659
                    'message' => '',
2660
                    'error' => false,
2661
                ),
2662
                'encode'
2663
            );
2664
2665
            break;
2666
2667
        case "create_new_user_tasks":
2668
            // Check KEY
2669
            if ($post_key !== $session->get('key')) {
2670
                echo prepareExchangedData(
2671
                    array(
2672
                        'error' => true,
2673
                        'message' => $lang->get('key_is_not_correct'),
2674
                    ),
2675
                    'encode'
2676
                );
2677
                break;
2678
            }
2679
2680
            // Prepare variables
2681
            $post_user_id = filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
2682
            $post_user_code = filter_var($dataReceived['user_code'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
2683
2684
            // Search TP_USER in db        
2685
            $userTP = DB::queryFirstRow(
2686
                'SELECT pw
2687
                FROM ' . prefixTable('users') . '
2688
                WHERE id = %i',
2689
                TP_USER_ID
2690
            );
2691
            if (DB::count() === 0) {
2692
                return prepareExchangedData(
2693
                    array(
2694
                        'error' => true,
2695
                        'message' => 'User not exists',
2696
                    ),
2697
                    'encode'
2698
                );
2699
            }
2700
2701
            // Create process
2702
            DB::insert(
2703
                prefixTable('background_tasks'),
2704
                array(
2705
                    'created_at' => time(),
2706
                    'process_type' => 'create_user_keys',
2707
                    'arguments' => json_encode([
2708
                        'new_user_id' => (int) $post_user_id,
2709
                        'new_user_pwd' => '',
2710
                        'new_user_code' => cryption($post_user_code, '','encrypt', $SETTINGS)['string'],
2711
                        'owner_id' => (int) TP_USER_ID,
2712
                        'creator_pwd' => $userTP['pw'],
2713
                        'email_body' => $lang->get('email_body_user_config_5'),
2714
                        'send_email' => 1,
2715
                        'otp_provided_new_value' => 0,
2716
                        'user_self_change' => 0,
2717
                    ]),
2718
                    'updated_at' => '',
2719
                    'finished_at' => '',
2720
                    'output' => '',
2721
                )
2722
            );
2723
            $processId = DB::insertId();
2724
2725
            // Create tasks
2726
            createUserTasks(
2727
                $processId,
2728
                isset($SETTINGS['maximum_number_of_items_to_treat']) === true ? $SETTINGS['maximum_number_of_items_to_treat'] : NUMBER_ITEMS_IN_BATCH
2729
            );
2730
2731
            // Generate user keys with the code and transparent recovery support
2732
            $userKeys = generateUserKeys($post_user_code, $SETTINGS);
2733
2734
            // Prepare update data
2735
            $updateData = array(
2736
                'is_ready_for_usage' => 1,
2737
                'otp_provided' => 0,
2738
                'ongoing_process_id' => $processId,
2739
                'special' => 'generate-keys',
2740
                'public_key' => $userKeys['public_key'],
2741
                'private_key' => $userKeys['private_key'],
2742
                // Notify user that he must re download his keys:
2743
                'keys_recovery_time' => NULL,
2744
            );
2745
2746
            // Add transparent recovery fields if available
2747
            if (isset($userKeys['user_seed'])) {
2748
                $updateData['user_derivation_seed'] = $userKeys['user_seed'];
2749
                $updateData['private_key_backup'] = $userKeys['private_key_backup'];
2750
                $updateData['key_integrity_hash'] = $userKeys['key_integrity_hash'];
2751
                $updateData['last_pw_change'] = time();
2752
            }
2753
2754
            // Update user
2755
            DB::update(
2756
                prefixTable('users'),
2757
                $updateData,
2758
                'id = %i',
2759
                $post_user_id
2760
            );
2761
2762
            echo prepareExchangedData(
2763
                array(
2764
                    'message' => '',
2765
                    'error' => false,
2766
                ),
2767
                'encode'
2768
            );
2769
2770
            break;
2771
2772
        /*
2773
        * WHAT IS THE PROGRESS OF GENERATING NEW KEYS AND OTP FOR A USER
2774
        */
2775
        case 'get_generate_keys_progress':
2776
            // Check KEY
2777
            if ($post_key !== $session->get('key')) {
2778
                echo prepareExchangedData(
2779
                    array(
2780
                        'error' => true,
2781
                        'message' => $lang->get('key_is_not_correct'),
2782
                    ),
2783
                    'encode'
2784
                );
2785
                break;
2786
            } elseif ($session->get('user-read_only') === 1) {
2787
                echo prepareExchangedData(
2788
                    array(
2789
                        'error' => true,
2790
                        'message' => $lang->get('error_not_allowed_to'),
2791
                    ),
2792
                    'encode'
2793
                );
2794
                break;
2795
            }
2796
2797
            if (isset($dataReceived['user_id']) === false) {
2798
                // Exit nothing to be done
2799
                echo prepareExchangedData(
2800
                    array(
2801
                        'error' => true,
2802
                        'message' => '',
2803
                        'user_id' => '',
2804
                        'status' => '',
2805
                        'debug' => '',
2806
                    ),
2807
                    'encode'
2808
                );
2809
            }
2810
2811
            // Prepare variables
2812
            $user_id = filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
2813
2814
            // get user info
2815
            $processesProgress = DB::query(
2816
                'SELECT u.ongoing_process_id, pt.task, pt.updated_at, pt.finished_at, pt.is_in_progress
2817
                FROM ' . prefixTable('users') . ' AS u
2818
                INNER JOIN ' . prefixTable('background_subtasks') . ' AS pt ON (pt.task_id = u.ongoing_process_id)
2819
                WHERE u.id = %i',
2820
                $user_id
2821
            );
2822
2823
            $finished_steps = 0;
2824
            $nb_steps = count($processesProgress);
2825
            foreach($processesProgress as $process) {
2826
                if ((int) $process['is_in_progress'] === -1) {
2827
                    $finished_steps ++;
2828
                }
2829
            }
2830
2831
            echo prepareExchangedData(
2832
                array(
2833
                    'error' => false,
2834
                    'message' => '',
2835
                    'user_id' => $user_id,
2836
                    'status' => $finished_steps === $nb_steps ? 'finished' : number_format($finished_steps/$nb_steps*100, 0).'%',
2837
                    'debug' => $finished_steps.",".$nb_steps,
2838
                ),
2839
                'encode'
2840
            );
2841
2842
            break;
2843
2844
2845
        /**
2846
         * CHECK IF USER IS FINISHED WITH GENERATING NEW KEYS AND OTP FOR A USER
2847
         */
2848
        case "get_user_infos":
2849
            // Check KEY
2850
            if ($post_key !== $session->get('key')) {
2851
                echo prepareExchangedData(
2852
                    array(
2853
                        'error' => true,
2854
                        'message' => $lang->get('key_is_not_correct'),
2855
                    ),
2856
                    'encode'
2857
                );
2858
                break;
2859
            } elseif ($session->get('user-read_only') === 1) {
2860
                echo prepareExchangedData(
2861
                    array(
2862
                        'error' => true,
2863
                        'message' => $lang->get('error_not_allowed_to'),
2864
                    ),
2865
                    'encode'
2866
                );
2867
                break;
2868
            }
2869
2870
            // Prepare variables
2871
            $user_id = filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
2872
2873
            $fullUserInfos = getFullUserInfos((int) $user_id);
2874
2875
            // Filter only on useful fields
2876
            $userInfos['id'] = $fullUserInfos['id'];
2877
            $userInfos['ongoing_process_id'] = $fullUserInfos['ongoing_process_id'];
2878
2879
            echo prepareExchangedData(
2880
                array(
2881
                    'error' => false,
2882
                    'message' => '',
2883
                    'user_id' => $user_id,
2884
                    'user_infos' => $userInfos,
2885
                    'debug' => '',
2886
                ),
2887
                'encode'
2888
            );
2889
2890
            break;
2891
        
2892
        case "reset_antibruteforce":
2893
            // Check KEY
2894
            if ($post_key !== $session->get('key')) {
2895
                echo prepareExchangedData(
2896
                    array(
2897
                        'error' => true,
2898
                        'message' => $lang->get('key_is_not_correct'),
2899
                    ),
2900
                    'encode'
2901
                );
2902
                break;
2903
            }
2904
2905
            // Prepare variables
2906
            $login = getFullUserInfos((int) $dataReceived['user_id'])['login'];
2907
2908
            // Delete all logs for this user
2909
            DB::delete(
2910
                prefixTable('auth_failures'),
2911
                'source = %s AND value = %s',
2912
                'login',
2913
                $login
2914
            );
2915
            
2916
            break;
2917
        
2918
        case "list_deleted_users":
2919
            // Check KEY
2920
            if ($post_key !== $session->get('key')) {
2921
                echo prepareExchangedData(
2922
                    array(
2923
                        'error' => true,
2924
                        'message' => $lang->get('key_is_not_correct'),
2925
                    ),
2926
                    'encode'
2927
                );
2928
                break;
2929
            }
2930
2931
            $result = listDeletedUsers();
2932
2933
            echo prepareExchangedData(
2934
                array(
2935
                    'error' => false,
2936
                    'result' => $result,
2937
                    'debug' => '',
2938
                ),
2939
                'encode'
2940
            );
2941
            
2942
            break;
2943
        
2944
        case "purge_user":
2945
            // Check KEY
2946
            if ($post_key !== $session->get('key')) {
2947
                echo prepareExchangedData(
2948
                    array(
2949
                        'error' => true,
2950
                        'message' => $lang->get('key_is_not_correct'),
2951
                    ),
2952
                    'encode'
2953
                );
2954
                break;
2955
            }
2956
2957
            // Prepare variables
2958
            $userId = (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
2959
        
2960
            if (empty($userId)) {
2961
                echo prepareExchangedData([
2962
                    'error' => true,
2963
                    'message' => $lang->get('error_empty_data'),
2964
                ], 'encode');
2965
                break;
2966
            }
2967
            
2968
            $result = purgeDeletedUserById($userId);
2969
            $deletedAccountsCount = (int) DB::queryFirstField("SELECT COUNT(id) FROM " . prefixTable('users') . " WHERE deleted_at IS NOT NULL");
2970
2971
            echo prepareExchangedData(
2972
                [
2973
                    'error' => false,
2974
                    'result' => $result,
2975
                    'deleted_accounts_count' => $deletedAccountsCount,
2976
                ],
2977
                'encode'
2978
            );
2979
            
2980
            break;
2981
2982
        case 'get_purgeable_users':
2983
            // Check KEY
2984
            if ($post_key !== $session->get('key')) {
2985
                echo prepareExchangedData(
2986
                    array(
2987
                        'error' => true,
2988
                        'message' => $lang->get('key_is_not_correct'),
2989
                    ),
2990
                    'encode'
2991
                );
2992
                break;
2993
            }
2994
2995
            // Check if user is admin
2996
            if ($session->get('user-admin') !== 1 && $session->get('user-can_manage_all_users') !== 1) {
2997
                echo prepareExchangedData(
2998
                    [
2999
                        'error' => true,
3000
                        'message' => $lang->get('error_not_allowed'),
3001
                    ],
3002
                    'encode'
3003
                );
3004
                break;
3005
            }
3006
3007
            // Prepare variables
3008
            $daysRetention = filter_var($dataReceived['days_retention'], FILTER_SANITIZE_NUMBER_INT);
3009
            $daysRetention = empty($daysRetention) ? 90 : (int)$daysRetention;
3010
            $cutoffTimestamp = time() - ($daysRetention * 86400);
3011
            
3012
            try {
3013
                // Get list of users to delete
3014
                $users = DB::query(
3015
                    "SELECT id FROM " . prefixTable("users") . " 
3016
                    WHERE deleted_at IS NOT NULL 
3017
                    AND deleted_at > 0
3018
                    AND deleted_at < %i
3019
                    ORDER BY deleted_at ASC",
3020
                    $cutoffTimestamp
3021
                );
3022
                
3023
                $userIds = array_column($users, 'id');
3024
                
3025
                echo prepareExchangedData(
3026
                    [
3027
                        'error' => false,
3028
                        'user_ids' => $userIds,
3029
                        'count' => count($userIds),
3030
                        'retention_days' => $daysRetention
3031
                    ],
3032
                    'encode'
3033
                );
3034
                
3035
            } catch (Exception $e) {
3036
                echo prepareExchangedData(
3037
                    [
3038
                        'error' => true,
3039
                        'message' => $lang->get('error') . ': ' . $e->getMessage(),
3040
                    ],
3041
                    'encode'
3042
                );
3043
            }
3044
            
3045
            break;
3046
3047
        case 'purge_users_batch':            
3048
            // Check KEY
3049
            if ($post_key !== $session->get('key')) {
3050
                echo prepareExchangedData(
3051
                    array(
3052
                        'error' => true,
3053
                        'message' => $lang->get('key_is_not_correct'),
3054
                    ),
3055
                    'encode'
3056
                );
3057
                break;
3058
            }
3059
3060
            // Check if user is admin
3061
            if ($session->get('user-admin') !== 1 && $session->get('user-can_manage_all_users') !== 1) {
3062
                echo prepareExchangedData(
3063
                    [
3064
                        'error' => true,
3065
                        'message' => $lang->get('error_not_allowed'),
3066
                    ],
3067
                    'encode'
3068
                );
3069
                break;
3070
            }
3071
3072
            // Prepare variables
3073
            $daysRetention = filter_var($dataReceived['days_retention'], FILTER_SANITIZE_NUMBER_INT);
3074
            $userIds = filter_var_array(
3075
                $dataReceived['user_ids'],
3076
                FILTER_SANITIZE_NUMBER_INT
3077
            );
3078
            
3079
            // Ensure user id has been provided
3080
            if (empty($userIds) || !is_array($userIds)) {
3081
                echo prepareExchangedData(
3082
                    [
3083
                        'error' => true,
3084
                        'message' => $lang->get('error_empty_data'),
3085
                    ],
3086
                    'encode'
3087
                );
3088
                break;
3089
            }
3090
            
3091
            $purgedCount = 0;
3092
            $errors = [];
3093
            $cutoffTimestamp = time() - ((int)$daysRetention * 86400);        
3094
                        
3095
            foreach ($userIds as $userId) {
3096
                $userId = (int)$userId;
3097
                
3098
                try {
3099
                    $result = purgeDeletedUserById($userId);
3100
                    $purgedCount++;
3101
                    
3102
                } catch (Exception $e) {
3103
                    DB::rollback();
3104
                    $errors[] = "User ID $userId: " . $e->getMessage();
3105
                }
3106
            }
3107
            
3108
            $deletedAccountsCount = (int) DB::queryFirstField("SELECT COUNT(id) FROM " . prefixTable('users') . " WHERE deleted_at IS NOT NULL");
3109
3110
            echo prepareExchangedData(
3111
                [
3112
                    'error' => false,
3113
                    'purged_count' => $purgedCount,
3114
                    'total_in_batch' => count($userIds),
3115
                    'errors' => $errors,
3116
                    'message' => $purgedCount . ' user(s) purged in this batch',
3117
                    'deletedAccountsCount' => $deletedAccountsCount,
3118
                ],
3119
                'encode'
3120
            );
3121
            
3122
            break;
3123
3124
        case 'restore_user':
3125
            // Check KEY
3126
            if ($post_key !== $session->get('key')) {
3127
                echo prepareExchangedData(
3128
                    array(
3129
                        'error' => true,
3130
                        'message' => $lang->get('key_is_not_correct'),
3131
                    ),
3132
                    'encode'
3133
                );
3134
                break;
3135
            }
3136
3137
            // Check if user is admin
3138
            if ($session->get('user-admin') !== 1) {
3139
                echo prepareExchangedData(
3140
                    array('error' => true, 'message' => 'Insufficient rights'),
3141
                    'encode'
3142
                );
3143
                break;
3144
            }
3145
3146
            // Prepare variables
3147
            $userId = filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT);
3148
            
3149
            // Get info about user
3150
            $data_user = DB::queryFirstRow(
3151
                'SELECT login FROM ' . prefixTable('users') . ' WHERE id = %i',
3152
                $userId
3153
            );
3154
            
3155
            if ($data_user === null) {
3156
                echo prepareExchangedData(
3157
                    array('error' => true, 'message' => 'User not found'),
3158
                    'encode'
3159
                );
3160
                break;
3161
            }
3162
            
3163
            // Remove user suffix "_deleted_timestamp"
3164
            $deletedSuffix = '_deleted_' . substr($data_user['login'], strrpos($data_user['login'], '_deleted_') + 9);
3165
            $originalLogin = str_replace($deletedSuffix, '', $data_user['login']);
3166
                        
3167
            // Check if an active user with the original login already exists
3168
            $existingUser = DB::queryFirstRow(
3169
                'SELECT id FROM ' . prefixTable('users') . '
3170
                WHERE login = %s AND deleted_at IS NULL AND id != %i',
3171
                $originalLogin,
3172
                $userId
3173
            );
3174
3175
            if (DB::count() > 0) {
3176
                echo prepareExchangedData(
3177
                    array(
3178
                        'error' => true,
3179
                        'message' => 'Cannot restore user: an active user with login "' . $originalLogin . '" already exists (ID: ' . $existingUser['id'] . ')'
3180
                    ),
3181
                    'encode'
3182
                );
3183
                break;
3184
            }
3185
            
3186
            // Restore user
3187
            DB::update(
3188
                prefixTable('users'),
3189
                array(
3190
                    'login' => $originalLogin,
3191
                    'deleted_at' => null,
3192
                    'disabled' => 0,
3193
                ),
3194
                'id = %i',
3195
                $userId
3196
            );
3197
            
3198
            echo prepareExchangedData(
3199
                array('error' => false, 'message' => 'User restored successfully'),
3200
                'encode'
3201
            );
3202
            break;
3203
    }
3204
    // # NEW LOGIN FOR USER HAS BEEN DEFINED ##
3205
} elseif (!empty(filter_input(INPUT_POST, 'newValue', FILTER_SANITIZE_FULL_SPECIAL_CHARS))) {
3206
    // Prepare POST variables
3207
    $value = explode('_', filter_input(INPUT_POST, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS));
3208
    $post_newValue = filter_input(INPUT_POST, 'newValue', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
3209
3210
    // Get info about user
3211
    $data_user = DB::queryFirstRow(
3212
        'SELECT admin, isAdministratedByRole FROM ' . prefixTable('users') . '
3213
        WHERE id = %i',
3214
        $value[1]
3215
    );
3216
3217
    // Is this user allowed to do this?
3218
    if (
3219
        (int) $session->get('user-admin') === 1
3220
        || (in_array($data_user['isAdministratedByRole'], $session->get('user-roles_array')))
3221
        || ((int) $session->get('user-can_manage_all_users') === 1 && (int) $data_user['admin'] !== 1)
3222
        || ($session->get('user-id') === $value[1])
3223
    ) {
3224
        if ($value[0] === 'userlanguage') {
3225
            $value[0] = 'user_language';
3226
            $post_newValue = strtolower($post_newValue);
3227
        }
3228
        
3229
        // Check that operation is allowed
3230
        if (in_array(
3231
            $value[0],
3232
            array('login', 'pw', 'email', 'treeloadstrategy', 'usertimezone', 'yubico_user_key', 'yubico_user_id', 'agses-usercardid', 'user_language', 'psk', 'split_view_mode', 'show_subfolders')
3233
        )) {
3234
            DB::update(
3235
                prefixTable('users'),
3236
                array(
3237
                    $value[0] => $post_newValue,
3238
                ),
3239
                'id = %i',
3240
                $value[1]
3241
            );
3242
            // update LOG
3243
            logEvents(
3244
                $SETTINGS,
3245
                'user_mngt',
3246
                'at_user_new_' . $value[0] . ':' . $value[1],
3247
                (string) $session->get('user-id'),
3248
                $session->get('user-login'),
3249
                filter_input(INPUT_POST, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS)
3250
            );
3251
3252
            // refresh SESSION if requested
3253
            // Session keys mapping
3254
            $sessionMapping = [
3255
                'treeloadstrategy' => 'user-tree_load_strategy',
3256
                'usertimezone' => 'user-timezone',
3257
                'userlanguage' => 'user-language',
3258
                'agses-usercardid' => null, 
3259
                'email' => 'user-email',
3260
                'split_view_mode' => 'user-split_view_mode',
3261
                'show_subfolders' => 'user-show_subfolders',
3262
            ];
3263
            // Update session
3264
            if (array_key_exists($value[0], $sessionMapping)) {
3265
                $sessionKey = $sessionMapping[$value[0]];
3266
                if ($sessionKey !== null) {
3267
                    $session->set($sessionKey, $post_newValue);
3268
                }
3269
            }
3270
            
3271
            // Display info
3272
            echo htmlentities($post_newValue, ENT_QUOTES);
3273
        }
3274
    }
3275
    // # ADMIN FOR USER HAS BEEN DEFINED ##
3276
} elseif (null !== filter_input(INPUT_POST, 'newadmin', FILTER_SANITIZE_NUMBER_INT)) {
3277
    $id = explode('_', filter_input(INPUT_POST, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS));
3278
3279
    // Get info about user
3280
    $data_user = DB::queryFirstRow(
3281
        'SELECT admin, isAdministratedByRole FROM ' . prefixTable('users') . '
3282
        WHERE id = %i',
3283
        $id[1]
3284
    );
3285
3286
    // Is this user allowed to do this?
3287
    if (
3288
        (int) $session->get('user-admin') === 1
3289
        || (in_array($data_user['isAdministratedByRole'], $session->get('user-roles_array')))
3290
        || ((int) $session->get('user-can_manage_all_users') === 1 && (int) $data_user['admin'] !== 1)
3291
        || ($session->get('user-id') === $id[1])
3292
    ) {
3293
        DB::update(
3294
            prefixTable('users'),
3295
            array(
3296
                'admin' => filter_input(INPUT_POST, 'newadmin', FILTER_SANITIZE_NUMBER_INT),
3297
            ),
3298
            'id = %i',
3299
            $id[1]
3300
        );
3301
        // Display info
3302
        if (filter_input(INPUT_POST, 'newadmin', FILTER_SANITIZE_NUMBER_INT) === 1) {
3303
            echo 'Oui';
3304
        } else {
3305
            echo 'Non';
3306
        }
3307
    }
3308
}
3309
3310
/**
3311
 * List deleted users
3312
 * 
3313
 * @return array
3314
 */
3315
function listDeletedUsers(): array
3316
{
3317
    $users = DB::query(
3318
        "SELECT id, login, email, deleted_at, 
3319
                DATEDIFF(NOW(), FROM_UNIXTIME(deleted_at)) as days_since_deletion
3320
         FROM " . prefixTable("users") . " 
3321
         WHERE deleted_at IS NOT NULL 
3322
         AND deleted_at > 0
3323
         ORDER BY deleted_at DESC"
3324
    );
3325
    
3326
    return [
3327
        'error' => false,
3328
        'users' => $users,
3329
        'count' => count($users)
3330
    ];
3331
}
3332
3333
/**
3334
 * Purge deleted user by ID
3335
 * 
3336
 * @param int $userId
3337
 * @return array
3338
 */
3339
function purgeDeletedUserById($userId): array
3340
{
3341
    $session = SessionManager::getSession();
3342
    $lang = new Language($session->get('user-language') ?? 'english');
3343
    
3344
    // Vérifier que l'utilisateur est bien marqué deleted
3345
    $user = DB::queryFirstRow(
3346
        "SELECT id, login, deleted_at FROM " . prefixTable("users") . " 
3347
         WHERE id = %i 
3348
         AND deleted_at IS NOT NULL 
3349
         AND deleted_at > 0",
3350
        $userId
3351
    );
3352
    
3353
    if (!$user) {
3354
        return [
3355
            'error' => true,
3356
            'message' => 'User not found or not deleted'
3357
        ];
3358
    }
3359
3360
    DB::startTransaction();
3361
    
3362
    try {
3363
        // Delete private keys
3364
        DB::delete(
3365
            prefixTable('user_private_keys'),
3366
            'user_id = %i',
3367
            $userId
3368
        );       
3369
3370
        // delete user api
3371
        DB::delete(
3372
            prefixTable('api'),
3373
            'user_id = %i',
3374
            $userId
3375
        );
3376
        
3377
        // Delete cache
3378
        DB::delete(
3379
            prefixTable('cache'),
3380
            'author = %i',
3381
            $userId
3382
        );
3383
3384
        // delete personal folder and subfolders
3385
        $data = DB::queryFirstRow(
3386
            'SELECT id FROM ' . prefixTable('nested_tree') . '
3387
            WHERE title = %s AND personal_folder = %i',
3388
            $userId,
3389
            '1'
3390
        );
3391
3392
        // Delete tokens
3393
        DB::delete(
3394
            prefixTable('tokens'),
3395
            'user_id = %i',
3396
            $userId
3397
        );
3398
3399
        // Get through each subfolder
3400
        if (!empty($data['id'])) {
3401
            $tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
3402
            $folders = $tree->getDescendants($data['id'], true);
3403
            foreach ($folders as $folder) {
3404
                // delete folder
3405
                DB::delete(prefixTable('nested_tree'), 'id = %i AND personal_folder = %i', $folder->id, '1');
3406
                // delete items & logs
3407
                $items = DB::query(
3408
                    'SELECT id FROM ' . prefixTable('items') . '
3409
                    WHERE id_tree=%i AND perso = %i',
3410
                    $folder->id,
3411
                    '1'
3412
                );
3413
                foreach ($items as $item) {
3414
                    // Delete item
3415
                    DB::delete(prefixTable('items'), 'id = %i', $item['id']);
3416
                    // log
3417
                    DB::delete(prefixTable('log_items'), 'id_item = %i', $item['id']);
3418
                }
3419
            }
3420
            // rebuild tree
3421
            $tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
3422
            $tree->rebuild();
3423
        }
3424
3425
        // Delete objects keys
3426
        deleteUserObjetsKeys((int) $userId);
3427
        
3428
        // Delete user
3429
        DB::delete(
3430
            prefixTable('users'),
3431
            'id = %i',
3432
            $userId
3433
        );   
3434
3435
        // Delete any process related to user
3436
        $processes = DB::query(
3437
            'SELECT increment_id
3438
            FROM ' . prefixTable('background_tasks') . '
3439
            WHERE JSON_EXTRACT(arguments, "$.new_user_id") = %i',
3440
            $userId
3441
        );
3442
        $process_id = -1;
3443
        foreach ($processes as $process) {
3444
            // Delete task
3445
            DB::delete(
3446
                prefixTable('background_subtasks'),
3447
                'task_id = %i',
3448
                $process['increment_id']
3449
            );
3450
            $process_id = $process['increment_id'];
3451
        }
3452
        // Delete main process
3453
        if ($process_id > -1) {
3454
            DB::delete(
3455
                prefixTable('background_tasks'),
3456
                'increment_id = %i',
3457
                $process_id
3458
            );
3459
        }
3460
3461
        // Delete Roles
3462
        DB::delete(
3463
            prefixTable('users_roles'),
3464
            'user_id = %i',
3465
            $userId
3466
        );
3467
3468
        // Delete Groups
3469
        DB::delete(
3470
            prefixTable('users_groups'),
3471
            'user_id = %i',
3472
            $userId
3473
        );
3474
        DB::delete(
3475
            prefixTable('users_groups_forbidden'),
3476
            'user_id = %i',
3477
            $userId
3478
        );
3479
3480
        // Delete Latest items
3481
        DB::delete(
3482
            prefixTable('users_latest_items'),
3483
            'user_id = %i',
3484
            $userId
3485
        );
3486
3487
        // Delete favorites
3488
        DB::delete(
3489
            prefixTable('users_favorites'),
3490
            'user_id = %i',
3491
            $userId
3492
        );
3493
        
3494
        // Log de la purge
3495
        logEvents(
3496
            $GLOBALS['SETTINGS'],
3497
            'user_mngt',
3498
            'user_purged',
3499
            (string) $session->get('user-id'),
3500
            $session->get('login'),
3501
            $userId
3502
        );
3503
        
3504
        DB::commit();
3505
        
3506
        return [
3507
            'error' => false,
3508
            'message' => $lang->get('user_purged_successfully')
3509
        ];
3510
        
3511
    } catch (Exception $e) {
3512
        DB::rollback();
3513
        return [
3514
            'error' => true,
3515
            'message' => $e->getMessage()
3516
        ];
3517
    }
3518
}
3519
3520
/**
3521
 * Purge old deleted users
3522
 * 
3523
 * @param int $daysRetention
3524
 * @return array
3525
 *//*
3526
function purgeOldDeletedUsers($daysRetention = 90): array
3527
{
3528
    $session = SessionManager::getSession();
3529
    $lang = new Language($session->get('user-language') ?? 'english');
3530
3531
    $cutoffTimestamp = time() - ($daysRetention * 86400);
3532
    
3533
    // Récupérer les utilisateurs à purger
3534
    $usersToDelete = DB::query(
3535
        "SELECT id, login FROM " . prefixTable("users") . " 
3536
         WHERE deleted_at IS NOT NULL 
3537
         AND deleted_at > 0
3538
         AND deleted_at < %i",
3539
        $cutoffTimestamp
3540
    );
3541
    
3542
    $purgedCount = 0;
3543
    $errors = [];
3544
    
3545
    foreach ($usersToDelete as $user) {
3546
        $result = purgeDeletedUserById($user['id']);
3547
        
3548
        if ($result['error']) {
3549
            $errors[] = $user['login'] . ': ' . $result['message'];
3550
        } else {
3551
            $purgedCount++;
3552
        }
3553
    }
3554
    
3555
    return [
3556
        'error' => count($errors) > 0,
3557
        'purged_count' => $purgedCount,
3558
        'total_found' => count($usersToDelete),
3559
        'errors' => $errors,
3560
        'message' => $purgedCount . ' ' . $lang->get('users_purged_successfully')
3561
    ];
3562
}*/
3563
3564
/**
3565
 * Return the level of access on a folder.
3566
 *
3567
 * @param string $new_val      New value
3568
 * @param string $existing_val Current value
3569
 *
3570
 * @return string Returned index
3571
 */
3572
function evaluateFolderAccesLevel($new_val, $existing_val)
3573
{
3574
    $levels = array(
3575
        'W' => 30,
3576
        'ND' => 20,
3577
        'NE' => 15,
3578
        'NDNE' => 10,
3579
        'R' => 10,
3580
    );
3581
3582
    $current_level_points = empty($existing_val) === true ? 0 : $levels[$existing_val];
3583
    $new_level_points = empty($new_val) === true ? 0 : $levels[$new_val];
3584
3585
    // check if new is > to current one (always keep the highest level)
3586
    if (($new_val === 'ND' && $existing_val === 'NE')
3587
        || ($new_val === 'NE' && $existing_val === 'ND')
3588
    ) {
3589
        return 'NDNE';
3590
    } else {
3591
        if ($current_level_points > $new_level_points) {
3592
            return $existing_val;
3593
        } else {
3594
            return $new_val;
3595
        }
3596
    }
3597
}
3598