Passed
Push — teampass_3.0 ( ad0650...a80954 )
by Nils
05:29
created

continueReEncryptingUserSharekeys()   D

Complexity

Conditions 15
Paths 11

Size

Total Lines 170
Code Lines 106

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 2 Features 0
Metric Value
cc 15
eloc 106
c 4
b 2
f 0
nc 11
nop 6
dl 0
loc 170
rs 4.7333

How to fix   Long Method    Complexity   

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 library is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 * ---
12
 * @project   Teampass
13
 * @file      main.queries.php
14
 * ---
15
 * @author    Nils Laumaillé ([email protected])
16
 * @copyright 2009-2022 Teampass.net
17
 * @license   https://spdx.org/licenses/GPL-3.0-only.html#licenseText GPL-3.0
18
 * ---
19
 * @see       https://www.teampass.net
20
 */
21
22
if (isset($_SESSION) === false) {
23
    include_once 'SecureHandler.php';
24
    session_name('teampass_session');
25
    session_start();
26
    $_SESSION['CPM'] = 1;
27
}
28
29
if (isset($_SESSION['CPM']) === false || $_SESSION['CPM'] !== 1) {
30
    $_SESSION['error']['code'] = '1004';
31
    include '../error.php';
32
    exit();
33
}
34
35
// Load config
36
if (file_exists('../includes/config/tp.config.php')) {
37
    include '../includes/config/tp.config.php';
38
} elseif (file_exists('./includes/config/tp.config.php')) {
39
    include './includes/config/tp.config.php';
40
} else {
41
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
42
}
43
44
// Define Timezone
45
date_default_timezone_set(isset($SETTINGS['timezone']) === true ? $SETTINGS['timezone'] : 'UTC');
46
47
// DO CHECKS
48
require_once $SETTINGS['cpassman_dir'] . '/includes/config/include.php';
49
require_once $SETTINGS['cpassman_dir'] . '/sources/checks.php';
50
$post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING);
51
if (
52
    isset($post_type) === true
53
    && ($post_type === 'ga_generate_qr'
54
        //|| $post_type === 'recovery_send_pw_by_email'
55
        //|| $post_type === 'recovery_generate_new_password'
56
        || $post_type === 'get_teampass_settings')
57
) {
58
    // continue
59
    mainQuery($SETTINGS);
60
} elseif (
61
    isset($_SESSION['user_id']) === true
62
    && checkUser($_SESSION['user_id'], $_SESSION['key'], 'home', $SETTINGS) === false
63
) {
64
    $_SESSION['error']['code'] = ERR_NOT_ALLOWED; //not allowed page
65
    include $SETTINGS['cpassman_dir'] . '/error.php';
66
    exit();
67
} elseif ((isset($_SESSION['user_id']) === true
68
        && isset($_SESSION['key'])) === true
69
    || (isset($post_type) === true
70
        //&& $post_type === 'change_user_language'
71
        && null !== filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES))
72
) {
73
    // continue
74
    mainQuery($SETTINGS);
75
} else {
76
    $_SESSION['error']['code'] = ERR_NOT_ALLOWED; //not allowed page
77
    include $SETTINGS['cpassman_dir'] . '/error.php';
78
    exit();
79
}
80
81
/**
82
 * Undocumented function.
83
 */
84
function mainQuery(array $SETTINGS)
85
{
86
    header('Content-type: text/html; charset=utf-8');
87
    header('Cache-Control: no-cache, must-revalidate');
88
    error_reporting(E_ERROR);
89
90
91
    // Includes
92
    include_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $_SESSION['user_language'] . '.php';
93
    include_once $SETTINGS['cpassman_dir'] . '/includes/config/settings.php';
94
    include_once $SETTINGS['cpassman_dir'] . '/sources/main.functions.php';
95
    include_once $SETTINGS['cpassman_dir'] . '/sources/SplClassLoader.php';
96
97
    // Connect to mysql server
98
    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Database/Meekrodb/db.class.php';
99
100
    DB::$host = DB_HOST;
101
    DB::$user = DB_USER;
102
    DB::$password = defined('DB_PASSWD_CLEAR') === false ? defuseReturnDecrypted(DB_PASSWD, $SETTINGS) : DB_PASSWD_CLEAR;
103
    DB::$dbName = DB_NAME;
104
    DB::$port = DB_PORT;
105
    DB::$encoding = DB_ENCODING;
106
107
    // User's language loading
108
    include_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $_SESSION['user_language'] . '.php';
109
110
    // Prepare post variables
111
    $post_key = filter_input(INPUT_POST, 'key', FILTER_SANITIZE_STRING);
112
    $post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING);
113
    $post_data = filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
114
115
    // Check KEY
116
    if (isset($post_key) === false || empty($post_key) === true) {
117
        echo prepareExchangedData(
118
    $SETTINGS['cpassman_dir'],
119
            array(
120
                'error' => true,
121
                'message' => langHdl('key_is_not_correct'),
122
            ),
123
            'encode'
124
        );
125
        return false;
126
    }
127
128
    // decrypt and retreive data in JSON format
129
    $dataReceived = prepareExchangedData(
130
    $SETTINGS['cpassman_dir'],
131
        $post_data,
132
        'decode'
133
    );
134
    
135
    // Manage type of action asked
136
    switch ($post_type) {
137
        case 'change_pw':
138
            echo changePassword(
139
                (string) filter_var($dataReceived['new_pw'], FILTER_SANITIZE_STRING),
140
                isset($dataReceived['current_pw']) === true ? (string) filter_var($dataReceived['current_pw'], FILTER_SANITIZE_STRING) : '',
141
                (int) filter_var($dataReceived['complexity'], FILTER_SANITIZE_NUMBER_INT),
142
                (string) filter_var($dataReceived['change_request'], FILTER_SANITIZE_STRING),
143
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
144
                $SETTINGS
145
            );
146
            
147
            break;
148
149
        /*
150
         * This will generate the QR Google Authenticator
151
         */
152
        case 'ga_generate_qr':
153
            echo generateQRCode(
154
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
155
                (string) filter_var($dataReceived['demand_origin'], FILTER_SANITIZE_STRING),
156
                (string) filter_var($dataReceived['send_email'], FILTER_SANITIZE_STRING),
157
                (string) filter_var($dataReceived['login'], FILTER_SANITIZE_STRING),
158
                (string) filter_var($dataReceived['pwd'], FILTER_SANITIZE_STRING),
159
                $SETTINGS
160
            );
161
162
            break;
163
        
164
            /*
165
         * Increase the session time of User
166
         */
167
        case 'increase_session_time':
168
            echo increaseSessionDuration(
169
                (int) filter_input(INPUT_POST, 'duration', FILTER_SANITIZE_NUMBER_INT)
170
            );
171
172
            break;
173
        
174
            /*
175
         * Hide maintenance message
176
         */
177
        case 'hide_maintenance':
178
            $_SESSION['hide_maintenance'] = 1;
179
180
            break;
181
        
182
        /*
183
         * Send emails not sent
184
         */
185
        case 'send_waiting_emails':
186
            sendEmailsNotSent(
187
                $SETTINGS
188
            );
189
            
190
            break;
191
192
        /*
193
         * Generate a password generic
194
         */
195
        case 'generate_password':
196
            echo generateGenericPassword(
197
                (int) filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT),
198
                (bool) filter_input(INPUT_POST, 'secure_pwd', FILTER_SANITIZE_STRING),
199
                (bool) filter_input(INPUT_POST, 'lowercase', FILTER_SANITIZE_STRING),
200
                (bool) filter_input(INPUT_POST, 'capitalize', FILTER_SANITIZE_STRING),
201
                (bool) filter_input(INPUT_POST, 'numerals', FILTER_SANITIZE_STRING),
202
                (bool) filter_input(INPUT_POST, 'symbols', FILTER_SANITIZE_NUMBER_INT),
203
                $SETTINGS
204
            );
205
            
206
            break;
207
208
        /*
209
         * Refresh list of last items seen
210
         */
211
        case 'refresh_list_items_seen':
212
            echo refreshUserItemsSeenList(
213
                $SETTINGS
214
            );
215
216
            break;
217
218
        /*
219
         * Generates a KEY with CRYPT
220
         */
221
        case 'generate_new_key':
222
            // load passwordLib library
223
            $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
224
            $pwdlib->register();
225
            $pwdlib = new PasswordLib\PasswordLib();
226
            // generate key
227
            $key = $pwdlib->getRandomToken(filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT));
228
            echo '[{"key" : "' . htmlentities($key, ENT_QUOTES) . '"}]';
229
            break;
230
231
        /*
232
         * Generates a TOKEN with CRYPT
233
         */
234
        case 'save_token':
235
            $token = GenerateCryptKey(
236
                null !== filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT) ? (int) filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT) : 20,
237
                null !== filter_input(INPUT_POST, 'secure', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? filter_input(INPUT_POST, 'secure', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) : false,
238
                null !== filter_input(INPUT_POST, 'numeric', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? filter_input(INPUT_POST, 'numeric', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) : false,
239
                null !== filter_input(INPUT_POST, 'capital', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? filter_input(INPUT_POST, 'capital', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) : false,
240
                null !== filter_input(INPUT_POST, 'symbols', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? filter_input(INPUT_POST, 'symbols', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) : false,
241
                null !== filter_input(INPUT_POST, 'lowercase', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? filter_input(INPUT_POST, 'lowercase', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) : false,
242
                $SETTINGS
243
            );
244
            
245
            // store in DB
246
            DB::insert(
247
                prefixTable('tokens'),
248
                array(
249
                    'user_id' => (int) $_SESSION['user_id'],
250
                    'token' => $token,
251
                    'reason' => filter_input(INPUT_POST, 'reason', FILTER_SANITIZE_STRING),
252
                    'creation_timestamp' => time(),
253
                    'end_timestamp' => time() + filter_input(INPUT_POST, 'duration', FILTER_SANITIZE_NUMBER_INT), // in secs
254
                )
255
            );
256
257
            echo '[{"token" : "' . $token . '"}]';
258
            break;
259
260
261
        /*
262
         * TODO Check if suggestions are existing
263
         */
264
        /*
265
        case 'is_existings_suggestions':
266
            if ($_SESSION['user_manager'] === '1' || $_SESSION['is_admin'] === '1') {
267
                $count = 0;
268
                DB::query('SELECT * FROM ' . prefixTable('items_change'));
269
                $count += DB::count();
270
                DB::query('SELECT * FROM ' . prefixTable('suggestion'));
271
                $count += DB::count();
272
273
                echo '[ { "error" : "" , "count" : "' . $count . '" , "show_sug_in_menu" : "0"} ]';
274
                break;
275
            }
276
            
277
            if (isset($_SESSION['nb_item_change_proposals']) && $_SESSION['nb_item_change_proposals'] > 0) {
278
                echo '[ { "error" : "" , "count" : "' . $_SESSION['nb_item_change_proposals'] . '" , "show_sug_in_menu" : "1"} ]';
279
                break;
280
            }
281
            
282
            echo '[ { "error" : "" , "count" : "" , "show_sug_in_menu" : "0"} ]';
283
284
            break;
285
        */
286
287
        /*
288
         * Sending statistics
289
         */
290
        case 'sending_statistics':
291
            sendingStatistics(
292
                $SETTINGS
293
            );
294
295
            break;
296
297
        /*
298
         * delete a file
299
         */
300
        case 'file_deletion':
301
            fileDelete(filter_input(INPUT_POST, 'filename', FILTER_SANITIZE_STRING), $SETTINGS);
302
303
            break;
304
305
        /*
306
         * Generate BUG report
307
         */
308
        case 'generate_bug_report':
309
            echo generateBugReport(
310
                (string) $post_data,
311
                $SETTINGS
312
            );
313
        
314
            break;
315
316
        /*
317
        * get_teampass_settings
318
        */
319
        case 'get_teampass_settings':
320
            // Encrypt data to return
321
            echo prepareExchangedData(
322
    $SETTINGS['cpassman_dir'],$SETTINGS, 'encode');
323
324
            break;
325
326
327
        /*
328
        * test_current_user_password_is_correct
329
        */
330
        case 'test_current_user_password_is_correct':
331
            echo isUserPasswordCorrect(
332
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
333
                (string) filter_var($dataReceived['password'], FILTER_SANITIZE_STRING),
334
                $SETTINGS
335
            );
336
337
            break;
338
339
        /*
340
         * User's public/private keys change
341
         */
342
        case 'change_private_key_encryption_password':
343
            echo changePrivateKeyEncryptionPassword(
344
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
345
                (string) filter_var($dataReceived['current_code'], FILTER_SANITIZE_STRING),
346
                (string) filter_var($dataReceived['new_code'], FILTER_SANITIZE_STRING),
347
                (string) filter_var($dataReceived['action_type'], FILTER_SANITIZE_STRING),
348
                $SETTINGS
349
            );
350
        
351
            break;
352
353
        /*
354
         * User's password has to be initialized
355
         */
356
        case 'initialize_user_password':
357
            echo initializeUserPassword(
358
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
359
                (string) filter_var($dataReceived['special'], FILTER_SANITIZE_STRING),
360
                (string) filter_var($dataReceived['password'], FILTER_SANITIZE_STRING),
361
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
362
                $SETTINGS
363
            );
364
365
            break;
366
367
        /*
368
        * CASE
369
        * Send email
370
        */
371
        case 'mail_me':
372
            echo sendMailToUser(
373
                filter_var($dataReceived['receipt'], FILTER_SANITIZE_STRING),
374
                $dataReceived['body'],
375
                (string) filter_var($dataReceived['subject'], FILTER_SANITIZE_STRING),
376
                (array) filter_var_array(
377
                    $dataReceived['pre_replace'],
378
                    FILTER_SANITIZE_STRING
379
                ),
380
                $SETTINGS
381
            );
382
383
            break;
384
385
        /*
386
        * Generate a temporary encryption key for user
387
        */
388
        case 'generate_temporary_encryption_key':
389
            echo generateOneTimeCode(
390
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
391
                $SETTINGS
392
            );
393
394
            break;
395
396
        /*
397
        * user_sharekeys_reencryption_start
398
        */
399
        case 'user_sharekeys_reencryption_start':
400
            echo startReEncryptingUserSharekeys(
401
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
402
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
403
                $SETTINGS
404
            );
405
406
            break;
407
408
        /*
409
        * user_sharekeys_reencryption_next
410
        */
411
        case 'user_sharekeys_reencryption_next':
412
            echo continueReEncryptingUserSharekeys(
413
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
414
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
415
                (string) filter_var($dataReceived['action'], FILTER_SANITIZE_STRING),
416
                (int) filter_var($dataReceived['start'], FILTER_SANITIZE_NUMBER_INT),
417
                (int) filter_var($dataReceived['length'], FILTER_SANITIZE_NUMBER_INT),
418
                $SETTINGS
419
            );
420
421
            break;
422
423
        /*
424
        * user_psk_reencryption
425
        */
426
        case 'user_psk_reencryption':
427
            echo migrateTo3_DoUserPersonalItemsEncryption(
428
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
429
                (int) filter_var($dataReceived['start'], FILTER_SANITIZE_NUMBER_INT),
430
                (int) filter_var($dataReceived['length'], FILTER_SANITIZE_NUMBER_INT),
431
                (string) filter_var($dataReceived['userPsk'], FILTER_SANITIZE_STRING),
432
                $SETTINGS
433
            );
434
        
435
            break;
436
437
        /*
438
        * Get info 
439
        */
440
        case 'get_user_info':
441
            echo getUserInfo(
442
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
443
                (string) filter_var($dataReceived['fields'], FILTER_SANITIZE_STRING),
444
                $SETTINGS
445
            );
446
447
            break;
448
449
        /*
450
        * Change user's authenticataion password
451
        */
452
        case 'change_user_auth_password':
453
            echo changeUserAuthenticationPassword(
454
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
455
                (string) filter_var($dataReceived['old_password'], FILTER_SANITIZE_STRING),
456
                (string) filter_var($dataReceived['new_password'], FILTER_SANITIZE_STRING),
457
                $SETTINGS
458
            );
459
460
            break;
461
462
463
        /*
464
        * User's authenticataion password in LDAP has changed
465
        */
466
        case 'change_user_ldap_auth_password':
467
            echo /** @scrutinizer ignore-call */ changeUserLDAPAuthenticationPassword(
468
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
469
                filter_var($dataReceived['previous_password'], FILTER_SANITIZE_STRING),
470
                filter_var($dataReceived['current_password'], FILTER_SANITIZE_STRING),
471
                $SETTINGS
472
            );
473
474
            break;
475
476
477
        /*
478
        * How many items for this user
479
        */
480
        case 'get_number_of_items_to_treat':
481
            echo getNumberOfItemsToTreat(
482
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
483
                $SETTINGS
484
            );
485
486
            break;
487
    }
488
}
489
490
491
/**
492
 * Provides the number of items
493
 *
494
 * @param int   $userId     User ID
495
 * @param array $SETTINGS   TeampassSettings
496
 *
497
 * @return string
498
 */
499
function getNumberOfItemsToTreat(
500
    int $userId,
501
    array $SETTINGS
502
): string
503
{
504
    // get number of items
505
    DB::queryFirstRow(
506
        'SELECT increment_id
507
        FROM ' . prefixTable('sharekeys_items') .
508
        ' WHERE user_id = %i',
509
        $userId
510
    );
511
512
    // Send back
513
    return prepareExchangedData(
514
    $SETTINGS['cpassman_dir'],
515
        array(
516
            'error' => false,
517
            'nbItems' => DB::count(),
518
        ),
519
        'encode'
520
    );
521
}
522
523
524
/**
525
 * 
526
 */
527
function changePassword(
528
    string $post_new_password,
529
    string $post_current_password,
530
    int $post_password_complexity,
531
    string $post_change_request,
532
    int $post_user_id,
533
    array $SETTINGS
534
): string
535
{
536
    // load passwordLib library
537
    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
538
    $pwdlib->register();
539
    $pwdlib = new PasswordLib\PasswordLib();
540
541
    // Prepare variables
542
    $post_new_password_hashed = $pwdlib->createPasswordHash($post_new_password);
543
544
    // User has decided to change is PW
545
    if ($post_change_request === 'reset_user_password_expected'
546
        || $post_change_request === 'user_decides_to_change_password'
547
    ) {
548
        // Check that current user is correct
549
        if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
550
            return prepareExchangedData(
551
    $SETTINGS['cpassman_dir'],
552
                array(
553
                    'error' => true,
554
                    'message' => langHdl('error_not_allowed_to'),
555
                ),
556
                'encode'
557
            );
558
        }
559
560
        // check if expected security level is reached
561
        $dataUser = DB::queryfirstrow(
562
            'SELECT *
563
            FROM ' . prefixTable('users') . ' WHERE id = %i',
564
            $post_user_id
565
        );
566
567
        // check if badly written
568
        $dataUser['fonction_id'] = array_filter(
569
            explode(',', str_replace(';', ',', $dataUser['fonction_id']))
570
        );
571
        $dataUser['fonction_id'] = implode(',', $dataUser['fonction_id']);
572
        DB::update(
573
            prefixTable('users'),
574
            array(
575
                'fonction_id' => $dataUser['fonction_id'],
576
            ),
577
            'id = %i',
578
            $post_user_id
579
        );
580
581
        if (empty($dataUser['fonction_id']) === false) {
582
            $data = DB::queryFirstRow(
583
                'SELECT complexity
584
                FROM ' . prefixTable('roles_title') . '
585
                WHERE id IN (' . $dataUser['fonction_id'] . ')
586
                ORDER BY complexity DESC'
587
            );
588
        } else {
589
            // In case user has no roles yet
590
            $data = array();
591
            $data['complexity'] = 0;
592
        }
593
594
        if ((int) $post_password_complexity < (int) $data['complexity']) {
595
            return prepareExchangedData(
596
    $SETTINGS['cpassman_dir'],
597
                array(
598
                    'error' => true,
599
                    'message' => '<div style="margin:10px 0 10px 15px;">' . langHdl('complexity_level_not_reached') . '.<br>' .
600
                        langHdl('expected_complexity_level') . ': <b>' . TP_PW_COMPLEXITY[$data['complexity']][1] . '</b></div>',
601
                ),
602
                'encode'
603
            );
604
        }
605
606
        // Check that the 2 passwords are differents
607
        if ($post_current_password === $post_new_password) {
608
            return prepareExchangedData(
609
    $SETTINGS['cpassman_dir'],
610
                array(
611
                    'error' => true,
612
                    'message' => langHdl('password_already_used'),
613
                ),
614
                'encode'
615
            );
616
        }
617
618
        // update sessions
619
        $_SESSION['last_pw_change'] = mktime(0, 0, 0, (int) date('m'), (int) date('d'), (int) date('y'));
620
        $_SESSION['validite_pw'] = true;
621
622
        // BEfore updating, check that the pwd is correct
623
        if ($pwdlib->verifyPasswordHash($post_new_password, $post_new_password_hashed) === true && empty($dataUser['private_key']) === false) {
624
            $special_action = 'none';
625
            if ($post_change_request === 'reset_user_password_expected') {
626
                $_SESSION['user']['private_key'] = decryptPrivateKey($post_current_password, $dataUser['private_key']);
627
            }
628
629
            // update DB
630
            DB::update(
631
                prefixTable('users'),
632
                array(
633
                    'pw' => $post_new_password_hashed,
634
                    'last_pw_change' => mktime(0, 0, 0, (int) date('m'), (int) date('d'), (int) date('y')),
635
                    'last_pw' => $post_current_password,
636
                    'special' => $special_action,
637
                    'private_key' => encryptPrivateKey($post_new_password, $_SESSION['user']['private_key']),
638
                ),
639
                'id = %i',
640
                $post_user_id
641
            );
642
            // update LOG
643
            logEvents($SETTINGS, 'user_mngt', 'at_user_pwd_changed', (string) $_SESSION['user_id'], $_SESSION['login'], $post_user_id);
644
645
            // Send back
646
            return prepareExchangedData(
647
    $SETTINGS['cpassman_dir'],
648
                array(
649
                    'error' => false,
650
                    'message' => '',
651
                ),
652
                'encode'
653
            );
654
        }
655
        // Send back
656
        return prepareExchangedData(
657
    $SETTINGS['cpassman_dir'],
658
            array(
659
                'error' => true,
660
                'message' => langHdl('pwd_hash_not_correct'),
661
            ),
662
            'encode'
663
        );
664
    }
665
    return prepareExchangedData(
666
    $SETTINGS['cpassman_dir'],
667
        array(
668
            'error' => true,
669
            'message' => langHdl('error_not_allowed_to'),
670
        ),
671
        'encode'
672
    );
673
}
674
675
676
677
function generateQRCode(
678
    $post_id,
679
    $post_demand_origin,
680
    $post_send_mail,
681
    $post_login,
682
    $post_pwd,
683
    array $SETTINGS
684
): string
685
{
686
    // is this allowed by setting
687
    if ((isset($SETTINGS['ga_reset_by_user']) === false || (int) $SETTINGS['ga_reset_by_user'] !== 1)
688
        && (null === $post_demand_origin || $post_demand_origin !== 'users_management_list')
689
    ) {
690
        // User cannot ask for a new code
691
        return prepareExchangedData(
692
    $SETTINGS['cpassman_dir'],
693
            array(
694
                'error' => true,
695
                'message' => langHdl('error_not_allowed_to'),
696
            ),
697
            'encode'
698
        );
699
    }
700
701
    // Check if user exists
702
    if (null === $post_id || empty($post_id) === true) {
703
        // Get data about user
704
        $data = DB::queryfirstrow(
705
            'SELECT id, email, pw
706
            FROM ' . prefixTable('users') . '
707
            WHERE login = %s',
708
            $post_login
709
        );
710
    } else {
711
        $data = DB::queryfirstrow(
712
            'SELECT id, login, email, pw
713
            FROM ' . prefixTable('users') . '
714
            WHERE id = %i',
715
            $post_id
716
        );
717
        $post_login = $data['login'];
718
    }
719
    // Get number of returned users
720
    $counter = DB::count();
721
722
    // load passwordLib library
723
    $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'] . '/includes/libraries');
724
    $pwdlib->register();
725
    $pwdlib = new PasswordLib\PasswordLib();
726
727
    // Do treatment
728
    if ($counter === 0) {
729
        // Not a registered user !
730
        logEvents($SETTINGS, 'failed_auth', 'user_not_exists', '', stripslashes($post_login), stripslashes($post_login));
731
        return prepareExchangedData(
732
    $SETTINGS['cpassman_dir'],
733
            array(
734
                'error' => true,
735
                'message' => langHdl('no_user'),
736
                'tst' => 1,
737
            ),
738
            'encode'
739
        );
740
    }
741
742
    if (
743
        isset($post_pwd) === true
744
        && isset($data['pw']) === true
745
        && $pwdlib->verifyPasswordHash($post_pwd, $data['pw']) === false
746
        && $post_demand_origin !== 'users_management_list'
747
    ) {
748
        // checked the given password
749
        logEvents($SETTINGS, 'failed_auth', 'password_is_not_correct', '', stripslashes($post_login), stripslashes($post_login));
750
        return prepareExchangedData(
751
    $SETTINGS['cpassman_dir'],
752
            array(
753
                'error' => true,
754
                'message' => langHdl('no_user'),
755
                'tst' => $post_demand_origin,
756
            ),
757
            'encode'
758
        );
759
    }
760
    
761
    if (empty($data['email']) === true) {
762
        return prepareExchangedData(
763
    $SETTINGS['cpassman_dir'],
764
            array(
765
                'error' => true,
766
                'message' => langHdl('no_email'),
767
            ),
768
            'encode'
769
        );
770
    }
771
    
772
    // generate new GA user code
773
    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Authentication/TwoFactorAuth/TwoFactorAuth.php';
774
    $tfa = new Authentication\TwoFactorAuth\TwoFactorAuth($SETTINGS['ga_website_name']);
775
    $gaSecretKey = $tfa->createSecret();
776
    $gaTemporaryCode = GenerateCryptKey(12, false, true, true, false, true, $SETTINGS);
777
778
    DB::update(
779
        prefixTable('users'),
780
        [
781
            'ga' => $gaSecretKey,
782
            'ga_temporary_code' => $gaTemporaryCode,
783
        ],
784
        'id = %i',
785
        $data['id']
786
    );
787
788
    // Log event
789
    logEvents($SETTINGS, 'user_connection', 'at_2fa_google_code_send_by_email', (string) $data['id'], stripslashes($post_login), stripslashes($post_login));
790
791
    // send mail?
792
    if ((int) $post_send_mail === 1) {
793
        sendEmail(
794
            langHdl('email_ga_subject'),
795
            str_replace(
796
                '#2FACode#',
797
                $gaTemporaryCode,
798
                langHdl('email_ga_text')
799
            ),
800
            $data['email'],
801
            $SETTINGS
802
        );
803
804
        // send back
805
        return prepareExchangedData(
806
    $SETTINGS['cpassman_dir'],
807
            array(
808
                'error' => false,
809
                'message' => $post_send_mail,
810
                'email' => $data['email'],
811
                'email_result' => str_replace(
812
                    '#email#',
813
                    '<b>' . obfuscateEmail($data['email']) . '</b>',
814
                    addslashes(langHdl('admin_email_result_ok'))
815
                ),
816
            ),
817
            'encode'
818
        );
819
    }
820
    
821
    // send back
822
    return prepareExchangedData(
823
    $SETTINGS['cpassman_dir'],
824
        array(
825
            'error' => false,
826
            'message' => '',
827
            'email' => $data['email'],
828
            'email_result' => str_replace(
829
                '#email#',
830
                '<b>' . obfuscateEmail($data['email']) . '</b>',
831
                addslashes(langHdl('admin_email_result_ok'))
832
            ),
833
        ),
834
        'encode'
835
    );
836
}
837
838
function sendEmailsNotSent(
839
    array $SETTINGS
840
)
841
{
842
    if (isset($SETTINGS['enable_send_email_on_user_login'])
843
        && (int) $SETTINGS['enable_send_email_on_user_login'] === 1
844
    ) {
845
        $row = DB::queryFirstRow(
846
            'SELECT valeur FROM ' . prefixTable('misc') . ' WHERE type = %s AND intitule = %s',
847
            'cron',
848
            'sending_emails'
849
        );
850
851
        if ((int) (time() - $row['valeur']) >= 300 || (int) $row['valeur'] === 0) {
852
            $rows = DB::query(
853
                'SELECT *
854
                FROM ' . prefixTable('emails') .
855
                ' WHERE status != %s',
856
                'sent'
857
            );
858
            foreach ($rows as $record) {
859
                //echo $record['increment_id'] . " >> ";
860
                // Send email
861
                $ret = json_decode(
862
                    sendEmail(
863
                        $record['subject'],
864
                        $record['body'],
865
                        $record['receivers'],
866
                        $SETTINGS
867
                    ),
868
                    true
869
                );
870
871
                // update item_id in files table
872
                DB::update(
873
                    prefixTable('emails'),
874
                    array(
875
                        'status' => $ret['error'] === 'error_mail_not_send' ? 'not_sent' : 'sent',
876
                    ),
877
                    'timestamp = %s',
878
                    $record['timestamp']
879
                );
880
            }
881
        }
882
        // update cron time
883
        DB::update(
884
            prefixTable('misc'),
885
            array(
886
                'valeur' => time(),
887
            ),
888
            'intitule = %s AND type = %s',
889
            'sending_emails',
890
            'cron'
891
        );
892
    }
893
}
894
895
function generateGenericPassword(
896
    int $size,
897
    bool $secure,
898
    bool $lowercase,
899
    bool $capitalize,
900
    bool $numerals,
901
    bool $symbols,
902
    array $SETTINGS
903
): string
904
{
905
    if ((int) $size > (int) $SETTINGS['pwd_maximum_length']) {
906
        return prepareExchangedData(
907
    $SETTINGS['cpassman_dir'],
908
            array(
909
                'error_msg' => 'Password length is too long! ',
910
                'error' => 'true',
911
            ),
912
            'encode'
913
        );
914
    }
915
916
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
917
    $generator->register();
918
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
919
920
    // Is PHP7 being used?
921
    if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
922
        $php7generator = new SplClassLoader('PasswordGenerator\RandomGenerator', '../includes/libraries');
923
        $php7generator->register();
924
        $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
925
    }
926
927
    // Manage size
928
    $generator->setLength(($size <= 0) ? 10 : $size);
929
930
    if ($secure === true) {
931
        $generator->setSymbols(true);
932
        $generator->setLowercase(true);
933
        $generator->setUppercase(true);
934
        $generator->setNumbers(true);
935
    } else {
936
        $generator->setLowercase($lowercase);
937
        $generator->setUppercase($capitalize);
938
        $generator->setNumbers($numerals);
939
        $generator->setSymbols($symbols);
940
    }
941
942
    return prepareExchangedData(
943
    $SETTINGS['cpassman_dir'],
944
        array(
945
            'key' => $generator->generatePasswords(),
946
            'error' => '',
947
        ),
948
        'encode'
949
    );
950
}
951
952
function refreshUserItemsSeenList(
953
    array $SETTINGS
954
): string
955
{
956
    // get list of last items seen
957
    $arr_html = array();
958
    $rows = DB::query(
959
        'SELECT i.id AS id, i.label AS label, i.id_tree AS id_tree, l.date, i.perso AS perso, i.restricted_to AS restricted
960
        FROM ' . prefixTable('log_items') . ' AS l
961
        RIGHT JOIN ' . prefixTable('items') . ' AS i ON (l.id_item = i.id)
962
        WHERE l.action = %s AND l.id_user = %i
963
        ORDER BY l.date DESC
964
        LIMIT 0, 100',
965
        'at_shown',
966
        $_SESSION['user_id']
967
    );
968
    if (DB::count() > 0) {
969
        foreach ($rows as $record) {
970
            if (in_array($record['id']->id, array_column($arr_html, 'id')) === false) {
971
                array_push(
972
                    $arr_html,
973
                    array(
974
                        'id' => $record['id'],
975
                        'label' => htmlspecialchars(stripslashes(htmlspecialchars_decode($record['label'], ENT_QUOTES)), ENT_QUOTES),
976
                        'tree_id' => $record['id_tree'],
977
                        'perso' => $record['perso'],
978
                        'restricted' => $record['restricted'],
979
                    )
980
                );
981
                if (count($arr_html) >= (int) $SETTINGS['max_latest_items']) {
982
                    break;
983
                }
984
            }
985
        }
986
    }
987
988
    // get wainting suggestions
989
    $nb_suggestions_waiting = 0;
990
    if (
991
        isset($SETTINGS['enable_suggestion']) === true && (int) $SETTINGS['enable_suggestion'] === 1
992
        && ((int) $_SESSION['user_admin'] === 1 || (int) $_SESSION['user_manager'] === 1)
993
    ) {
994
        DB::query('SELECT * FROM ' . prefixTable('suggestion'));
995
        $nb_suggestions_waiting = DB::count();
996
    }
997
998
    return json_encode(
999
        array(
1000
            'error' => '',
1001
            'existing_suggestions' => $nb_suggestions_waiting,
1002
            'html_json' => $arr_html,
1003
        ),
1004
        JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1005
    );
1006
}
1007
1008
function sendingStatistics(
1009
    array $SETTINGS
1010
): void
1011
{
1012
    if (
1013
        isset($SETTINGS['send_statistics_items']) === true
1014
        && isset($SETTINGS['send_stats']) === true
1015
        && isset($SETTINGS['send_stats_time']) === true
1016
        && (int) $SETTINGS['send_stats'] === 1
1017
        && (int) ($SETTINGS['send_stats_time'] + TP_ONE_DAY_SECONDS) > time()
1018
    ) {
1019
        // get statistics data
1020
        $stats_data = getStatisticsData($SETTINGS);
1021
1022
        // get statistics items to share
1023
        $statsToSend = [];
1024
        $statsToSend['ip'] = $_SERVER['SERVER_ADDR'];
1025
        $statsToSend['timestamp'] = time();
1026
        foreach (array_filter(explode(';', $SETTINGS['send_statistics_items'])) as $data) {
1027
            if ($data === 'stat_languages') {
1028
                $tmp = '';
1029
                foreach ($stats_data[$data] as $key => $value) {
1030
                    $tmp .= $tmp === '' ? $key . '-' . $value : ',' . $key . '-' . $value;
1031
                }
1032
                $statsToSend[$data] = $tmp;
1033
            } elseif ($data === 'stat_country') {
1034
                $tmp = '';
1035
                foreach ($stats_data[$data] as $key => $value) {
1036
                    $tmp .= $tmp === '' ? $key . '-' . $value : ',' . $key . '-' . $value;
1037
                }
1038
                $statsToSend[$data] = $tmp;
1039
            } else {
1040
                $statsToSend[$data] = $stats_data[$data];
1041
            }
1042
        }
1043
1044
        // connect to Teampass Statistics database
1045
        $link2 = new MeekroDB(
1046
            'teampass.pw',
1047
            'teampass_user',
1048
            'ZMlEfRzKzFLZNzie',
1049
            'teampass_followup',
1050
            '3306',
1051
            'utf8'
1052
        );
1053
1054
        $link2->insert(
1055
            'statistics',
1056
            $statsToSend
1057
        );
1058
1059
        // update table misc with current timestamp
1060
        DB::update(
1061
            prefixTable('misc'),
1062
            array(
1063
                'valeur' => time(),
1064
            ),
1065
            'type = %s AND intitule = %s',
1066
            'admin',
1067
            'send_stats_time'
1068
        );
1069
1070
        //permits to test only once by session
1071
        $_SESSION['temporary']['send_stats_done'] = true;
1072
        $SETTINGS['send_stats_time'] = time();
1073
1074
        // save change in config file
1075
        handleConfigFile('update', $SETTINGS, 'send_stats_time', $SETTINGS['send_stats_time']);
1076
    }
1077
}
1078
1079
function generateBugReport(
1080
    string $data,
1081
    array $SETTINGS
1082
): string
1083
{
1084
    $config_exclude_vars = array(
1085
        'bck_script_passkey',
1086
        'email_smtp_server',
1087
        'email_auth_username',
1088
        'email_auth_pwd',
1089
        'email_from',
1090
    );
1091
1092
    // Get data
1093
    $post_data = json_decode($data, true);
1094
1095
    // Read config file
1096
    $list_of_options = '';
1097
    $url_found = '';
1098
    $anonym_url = '';
1099
    $tp_config_file = '../includes/config/tp.config.php';
1100
    $data = file($tp_config_file);
1101
    foreach ($data as $line) {
1102
        if (substr($line, 0, 4) === '    ') {
1103
            // Remove extra spaces
1104
            $line = str_replace('    ', '', $line);
1105
1106
            // Identify url to anonymize it
1107
            if (strpos($line, 'cpassman_url') > 0 && empty($url_found) === true) {
1108
                $url_found = substr($line, 19, strlen($line) - 22);
1109
                $tmp = parse_url($url_found);
1110
                $anonym_url = $tmp['scheme'] . '://<anonym_url>' . $tmp['path'];
1111
                $line = "'cpassman_url' => '" . $anonym_url . "\n";
1112
            }
1113
1114
            // Anonymize all urls
1115
            if (empty($anonym_url) === false) {
1116
                $line = str_replace($url_found, $anonym_url, $line);
1117
            }
1118
1119
            // Clear some vars
1120
            foreach ($config_exclude_vars as $var) {
1121
                if (strpos($line, $var) > 0) {
1122
                    $line = "'".$var."' => '<removed>'\n";
1123
                }
1124
            }
1125
1126
            // Complete line to display
1127
            $list_of_options .= $line;
1128
        }
1129
    }
1130
1131
    // Get error
1132
    $err = error_get_last();
1133
1134
    // Get 10 latest errors in Teampass
1135
    $teampass_errors = '';
1136
    $rows = DB::query(
1137
        'SELECT label, date AS error_date
1138
        FROM ' . prefixTable('log_system') . "
1139
        WHERE `type` LIKE 'error'
1140
        ORDER BY `date` DESC
1141
        LIMIT 0, 10"
1142
    );
1143
    if (DB::count() > 0) {
1144
        foreach ($rows as $record) {
1145
            if (empty($teampass_errors) === true) {
1146
                $teampass_errors = ' * ' . date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['error_date']) . ' - ' . $record['label'];
1147
            } else {
1148
                $teampass_errors .= ' * ' . date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['error_date']) . ' - ' . $record['label'];
1149
            }
1150
        }
1151
    }
1152
1153
    $link = mysqli_connect(DB_HOST, DB_USER, DB_PASSWD_CLEAR, DB_NAME, (int) DB_PORT, null);
1154
1155
    // Now prepare text
1156
    $txt = '### Page on which it happened
1157
' . $post_data['current_page'] . '
1158
1159
### Steps to reproduce
1160
1.
1161
2.
1162
3.
1163
1164
### Expected behaviour
1165
Tell us what should happen
1166
1167
1168
### Actual behaviour
1169
Tell us what happens instead
1170
1171
### Server configuration
1172
**Operating system**: ' . php_uname() . '
1173
1174
**Web server:** ' . $_SERVER['SERVER_SOFTWARE'] . '
1175
1176
**Database:** ' . ($link === false ? langHdl('undefined') : mysqli_get_server_info($link)) . '
1177
1178
**PHP version:** ' . PHP_VERSION . '
1179
1180
**Teampass version:** ' . TP_VERSION_FULL . '
1181
1182
**Teampass configuration file:**
1183
```
1184
' . $list_of_options . '
1185
```
1186
1187
**Updated from an older Teampass or fresh install:**
1188
1189
### Client configuration
1190
1191
**Browser:** ' . $post_data['browser_name'] . ' - ' . $post_data['browser_version'] . '
1192
1193
**Operating system:** ' . $post_data['os'] . ' - ' . $post_data['os_archi'] . 'bits
1194
1195
### Logs
1196
1197
#### Web server error log
1198
```
1199
' . $err['message'] . ' - ' . $err['file'] . ' (' . $err['line'] . ')
1200
```
1201
1202
#### Teampass 10 last system errors
1203
```
1204
' . $teampass_errors . '
1205
```
1206
1207
#### Log from the web-browser developer console (CTRL + SHIFT + i)
1208
```
1209
Insert the log here and especially the answer of the query that failed.
1210
```
1211
';
1212
1213
    return prepareExchangedData(
1214
    $SETTINGS['cpassman_dir'],
1215
        array(
1216
            'html' => $txt,
1217
            'error' => '',
1218
        ),
1219
        'encode'
1220
    );
1221
}
1222
1223
function isUserPasswordCorrect(
1224
    int $post_user_id,
1225
    string $post_user_password,
1226
    array $SETTINGS
1227
): string
1228
{
1229
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1230
        // Check if user exists
1231
        $userInfo = DB::queryFirstRow(
1232
            'SELECT public_key, private_key, pw, auth_type
1233
            FROM ' . prefixTable('users') . '
1234
            WHERE id = %i',
1235
            $post_user_id
1236
        );
1237
        if (DB::count() > 0 && empty($userInfo['private_key']) === false) {
1238
            // Get one item
1239
            $record = DB::queryFirstRow(
1240
                'SELECT object_id
1241
                FROM ' . prefixTable('sharekeys_items') . '
1242
                WHERE user_id = %i',
1243
                $post_user_id
1244
            );
1245
1246
            // Get itemKey from current user
1247
            $currentUserKey = DB::queryFirstRow(
1248
                'SELECT share_key, increment_id
1249
                FROM ' . prefixTable('sharekeys_items') . '
1250
                WHERE object_id = %i AND user_id = %i',
1251
                $record['object_id'],
1252
                $post_user_id
1253
            );
1254
1255
            if ($currentUserKey !== null) {
1256
                // Decrypt itemkey with user key
1257
                // use old password to decrypt private_key
1258
                $_SESSION['user']['private_key'] = decryptPrivateKey($post_user_password, $userInfo['private_key']);
1259
                $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1260
1261
                if (empty(base64_decode($itemKey)) === false) {
1262
                    // GOOD password
1263
                    return prepareExchangedData(
1264
    $SETTINGS['cpassman_dir'],
1265
                        array(
1266
                            'error' => false,
1267
                            'message' => '',
1268
                            'debug' => '',
1269
                        ),
1270
                        'encode'
1271
                    );
1272
                }
1273
            }
1274
            
1275
            // Use the password check
1276
            // load passwordLib library
1277
            $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'] . '/includes/libraries');
1278
            $pwdlib->register();
1279
            $pwdlib = new PasswordLib\PasswordLib();
1280
            
1281
            if ($pwdlib->verifyPasswordHash(htmlspecialchars_decode($post_user_password), $userInfo['pw']) === true) {
1282
                // GOOD password
1283
                return prepareExchangedData(
1284
    $SETTINGS['cpassman_dir'],
1285
                    array(
1286
                        'error' => false,
1287
                        'message' => '',
1288
                        'debug' => '',
1289
                    ),
1290
                    'encode'
1291
                );
1292
            }
1293
        }
1294
    }
1295
1296
    return prepareExchangedData(
1297
    $SETTINGS['cpassman_dir'],
1298
        array(
1299
            'error' => true,
1300
            'message' => langHdl('password_is_not_correct'),
1301
            'debug' => isset($itemKey) === true ? base64_decode($itemKey) : '',
1302
        ),
1303
        'encode'
1304
    );
1305
}
1306
1307
function changePrivateKeyEncryptionPassword(
1308
    int $post_user_id,
1309
    string $post_current_code,
1310
    string $post_new_code,
1311
    string $post_action_type,
1312
    array $SETTINGS
1313
): string
1314
{
1315
    if (empty($post_new_code) === true) {
1316
        if (empty($_SESSION['user_pwd']) === false) {
1317
            $post_new_code = $_SESSION['user_pwd'];
1318
        } else {
1319
            // no user password???
1320
            return prepareExchangedData(
1321
    $SETTINGS['cpassman_dir'],
1322
                array(
1323
                    'error' => true,
1324
                    'message' => langHdl('error_no_user_password_exists'),
1325
                    'debug' => '',
1326
                ),
1327
                'encode'
1328
            );
1329
        }
1330
    }
1331
1332
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1333
        // Get user info
1334
        $userData = DB::queryFirstRow(
1335
            'SELECT private_key
1336
            FROM ' . prefixTable('users') . '
1337
            WHERE id = %i',
1338
            $post_user_id
1339
        );
1340
        if (DB::count() > 0 && empty($userData['private_key']) === false) {
1341
            if ($post_action_type === 'encrypt_privkey_with_user_password') {
1342
                // Here the user has his private key encrypted with an OTC.
1343
                // We need to encrypt it with his real password
1344
                $privateKey = decryptPrivateKey($post_new_code, $userData['private_key']);
1345
                $hashedPrivateKey = encryptPrivateKey($post_current_code, $privateKey);
1346
            } else {
1347
                $privateKey = decryptPrivateKey($post_current_code, $userData['private_key']);
1348
                $hashedPrivateKey = encryptPrivateKey($post_new_code, $privateKey);
1349
            }
1350
1351
            // Update user account
1352
            DB::update(
1353
                prefixTable('users'),
1354
                array(
1355
                    'private_key' => $hashedPrivateKey,
1356
                    'special' => 'none',
1357
                ),
1358
                'id = %i',
1359
                $post_user_id
1360
            );
1361
1362
            // Load superGlobals
1363
            include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1364
            $superGlobal = new protect\SuperGlobal\SuperGlobal();
1365
1366
            $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
1367
        }
1368
1369
        // Return
1370
        return prepareExchangedData(
1371
    $SETTINGS['cpassman_dir'],
1372
            array(
1373
                'error' => false,
1374
                'message' => '',
1375
            ),
1376
            'encode'
1377
        );
1378
    }
1379
    
1380
    return prepareExchangedData(
1381
    $SETTINGS['cpassman_dir'],
1382
        array(
1383
            'error' => true,
1384
            'message' => langHdl('error_no_user'),
1385
            'debug' => '',
1386
        ),
1387
        'encode'
1388
    );
1389
}
1390
1391
function initializeUserPassword(
1392
    int $post_user_id,
1393
    string $post_special,
1394
    string $post_user_password,
1395
    bool $post_self_change,
1396
    array $SETTINGS
1397
): string
1398
{
1399
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1400
        // Get user info
1401
        $userData = DB::queryFirstRow(
1402
            'SELECT email, auth_type, login
1403
            FROM ' . prefixTable('users') . '
1404
            WHERE id = %i',
1405
            $post_user_id
1406
        );
1407
        if (DB::count() > 0 && empty($userData['email']) === false) {
1408
            // If user pwd is empty then generate a new one and send it to user
1409
            if (isset($post_user_password) === false || empty($post_user_password) === true) {
1410
                // Generate new password
1411
                $post_user_password = generateQuickPassword();
1412
            }
1413
1414
            // If LDAP enabled, then
1415
            // check that this password is correct
1416
            $continue = true;
1417
            if ($userData['auth_type'] === 'ldap' && (int) $SETTINGS['ldap_mode'] === 1) {
1418
                $continue = ldapCheckUserPassword(
1419
                    $userData['login'],
1420
                    $post_user_password,
1421
                    $SETTINGS
1422
                );
1423
            }
1424
1425
            if ($continue === true) {
1426
                // Only change if email is successfull
1427
                // GEnerate new keys
1428
                $userKeys = generateUserKeys($post_user_password);
1429
1430
                // load passwordLib library
1431
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1432
                $pwdlib->register();
1433
                $pwdlib = new PasswordLib\PasswordLib();
1434
1435
                // Update user account
1436
                DB::update(
1437
                    prefixTable('users'),
1438
                    array(
1439
                        'special' => $post_special,
1440
                        'pw' => $pwdlib->createPasswordHash($post_user_password),
1441
                        'public_key' => $userKeys['public_key'],
1442
                        'private_key' => $userKeys['private_key'],
1443
                        'last_pw_change' => time(),
1444
                    ),
1445
                    'id = %i',
1446
                    $post_user_id
1447
                );
1448
1449
                // Return
1450
                return prepareExchangedData(
1451
    $SETTINGS['cpassman_dir'],
1452
                    array(
1453
                        'error' => false,
1454
                        'message' => '',
1455
                        'user_pwd' => $post_user_password,
1456
                        'user_email' => $userData['email'],
1457
                    ),
1458
                    'encode'
1459
                );
1460
            }
1461
            // Return error
1462
            return prepareExchangedData(
1463
    $SETTINGS['cpassman_dir'],
1464
                array(
1465
                    'error' => true,
1466
                    'message' => langHdl('no_email_set'),
1467
                    'debug' => '',
1468
                    'self_change' => $post_self_change,
1469
                ),
1470
                'encode'
1471
            );
1472
        }
1473
1474
        // Error
1475
        return prepareExchangedData(
1476
    $SETTINGS['cpassman_dir'],
1477
            array(
1478
                'error' => true,
1479
                'message' => langHdl('no_email_set'),
1480
                'debug' => '',
1481
            ),
1482
            'encode'
1483
        );
1484
    }
1485
    
1486
    return prepareExchangedData(
1487
    $SETTINGS['cpassman_dir'],
1488
        array(
1489
            'error' => true,
1490
            'message' => langHdl('error_no_user'),
1491
            'debug' => '',
1492
        ),
1493
        'encode'
1494
    );
1495
}
1496
1497
function sendMailToUser(
1498
    string $post_receipt,
1499
    string $post_body,
1500
    string $post_subject,
1501
    array $post_replace,
1502
    array $SETTINGS
1503
): string
1504
{
1505
    if (count($post_replace) > 0 && is_null($post_replace) === false) {
1506
        $post_body = str_replace(
1507
            array_keys($post_replace),
1508
            array_values($post_replace),
1509
            $post_body
1510
        );
1511
    }
1512
    
1513
    $ret = sendEmail(
1514
        $post_subject,
1515
        $post_body,
1516
        $post_receipt,
1517
        $SETTINGS,
1518
        '',
1519
        false
1520
    );
1521
1522
    $ret = json_decode($ret, true);
1523
1524
    return prepareExchangedData(
1525
    $SETTINGS['cpassman_dir'],
1526
        array(
1527
            'error' => empty($ret['error']) === true ? false : true,
1528
            'message' => $ret['message'],
1529
        ),
1530
        'encode'
1531
    );
1532
}
1533
1534
function generateOneTimeCode(
1535
    int $post_user_id,
1536
    array $SETTINGS
1537
): string
1538
{
1539
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1540
        // Get user info
1541
        $userData = DB::queryFirstRow(
1542
            'SELECT email, auth_type, login
1543
            FROM ' . prefixTable('users') . '
1544
            WHERE id = %i',
1545
            $post_user_id
1546
        );
1547
        if (DB::count() > 0 && empty($userData['email']) === false) {
1548
            // Generate pwd
1549
            $password = generateQuickPassword();
1550
1551
            // GEnerate new keys
1552
            $userKeys = generateUserKeys($password);
1553
1554
            // Save in DB
1555
            DB::update(
1556
                prefixTable('users'),
1557
                array(
1558
                    'public_key' => $userKeys['public_key'],
1559
                    'private_key' => $userKeys['private_key'],
1560
                    'special' => 'generate-keys',
1561
                ),
1562
                'id=%i',
1563
                $post_user_id
1564
            );
1565
1566
            return prepareExchangedData(
1567
    $SETTINGS['cpassman_dir'],
1568
                array(
1569
                    'error' => false,
1570
                    'message' => '',
1571
                    'userTemporaryCode' => $password,
1572
                ),
1573
                'encode'
1574
            );
1575
        }
1576
        
1577
        return prepareExchangedData(
1578
    $SETTINGS['cpassman_dir'],
1579
            array(
1580
                'error' => true,
1581
                'message' => langHdl('no_email_set'),
1582
            ),
1583
            'encode'
1584
        );
1585
    }
1586
        
1587
    return prepareExchangedData(
1588
    $SETTINGS['cpassman_dir'],
1589
        array(
1590
            'error' => true,
1591
            'message' => langHdl('error_no_user'),
1592
        ),
1593
        'encode'
1594
    );
1595
}
1596
1597
function startReEncryptingUserSharekeys(
1598
    int $post_user_id,
1599
    bool $post_self_change,
1600
    array $SETTINGS
1601
): string
1602
{
1603
    //$post_user_id = is_null($post_user_id) === true ? $_SESSION['user_id'] : $post_user_id;
1604
1605
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1606
        // Check if user exists
1607
        DB::queryFirstRow(
1608
            'SELECT *
1609
            FROM ' . prefixTable('users') . '
1610
            WHERE id = %i',
1611
            $post_user_id
1612
        );
1613
        if (DB::count() > 0) {
1614
            // Include libraries
1615
            include_once $SETTINGS['cpassman_dir'] . '/sources/aes.functions.php';
1616
1617
            // CLear old sharekeys
1618
            if ($post_self_change === false) {
1619
                deleteUserObjetsKeys($post_user_id, $SETTINGS);
1620
            }
1621
1622
            // Continu with next step
1623
            return prepareExchangedData(
1624
    $SETTINGS['cpassman_dir'],
1625
                array(
1626
                    'error' => false,
1627
                    'message' => '',
1628
                    'step' => 'step1',
1629
                    'userId' => $post_user_id,
1630
                    'start' => 0,
1631
                    'self_change' => $post_self_change,
1632
                ),
1633
                'encode'
1634
            );
1635
        }
1636
        // Nothing to do
1637
        return prepareExchangedData(
1638
    $SETTINGS['cpassman_dir'],
1639
            array(
1640
                'error' => true,
1641
                'message' => langHdl('error_no_user'),
1642
            ),
1643
            'encode'
1644
        );
1645
    }
1646
1647
    return prepareExchangedData(
1648
    $SETTINGS['cpassman_dir'],
1649
        array(
1650
            'error' => true,
1651
            'message' => langHdl('error_no_user'),
1652
        ),
1653
        'encode'
1654
    );
1655
}
1656
1657
function continueReEncryptingUserSharekeys(
1658
    int $post_user_id,
1659
    bool $post_self_change,
1660
    string $post_action,
1661
    int $post_start,
1662
    int $post_length,
1663
    array $SETTINGS
1664
): string
1665
{
1666
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1667
        // Check if user exists
1668
        $userInfo = DB::queryFirstRow(
1669
            'SELECT public_key
1670
            FROM ' . prefixTable('users') . '
1671
            WHERE id = %i',
1672
            $post_user_id
1673
        );
1674
        if (isset($userInfo['public_key']) === true) {
1675
            // Init
1676
            $next_start = '';
1677
            $next_action = '';
1678
1679
            // Include libraries
1680
            include_once $SETTINGS['cpassman_dir'] . '/sources/aes.functions.php';
1681
1682
            // WHAT STEP TO PERFORM?
1683
            if ($post_action === 'step0') {
1684
                // CLear old sharekeys
1685
                if ($post_self_change === false) {
1686
                    deleteUserObjetsKeys($post_user_id, $SETTINGS);
1687
                }
1688
1689
                $next_action = 'step1';
1690
            }
1691
            
1692
            // STEP 1 - ITEMS
1693
            elseif ($post_action === 'step1') {
1694
                $return = continueReEncryptingUserSharekeysStep1(
1695
                    $post_user_id,
1696
                    $post_self_change,
1697
                    $post_action,
1698
                    $post_start,
1699
                    $post_length,
1700
                    $userInfo['public_key'],
1701
                    $SETTINGS
1702
                );
1703
1704
                $next_start = $return['next_start'];
1705
                $next_action = $return['post_action'];
1706
            }
1707
1708
            // STEP 2 - LOGS
1709
            elseif ($post_action === 'step2') {
1710
                $return = continueReEncryptingUserSharekeysStep2(
1711
                    $post_user_id,
1712
                    $post_self_change,
1713
                    $post_action,
1714
                    $post_start,
1715
                    $post_length,
1716
                    $userInfo['public_key'],
1717
                    $SETTINGS
1718
                );
1719
1720
                $next_start = $return['next_start'];
1721
                $next_action = $return['post_action'];
1722
            }
1723
1724
            // STEP 3 - FIELDS
1725
            elseif ($post_action === 'step3') {
1726
                $return = continueReEncryptingUserSharekeysStep3(
1727
                    $post_user_id,
1728
                    $post_self_change,
1729
                    $post_action,
1730
                    $post_start,
1731
                    $post_length,
1732
                    $userInfo['public_key'],
1733
                    $SETTINGS
1734
                );
1735
1736
                $next_start = $return['next_start'];
1737
                $next_action = $return['post_action'];
1738
            }
1739
            
1740
            // STEP 4 - SUGGESTIONS
1741
            elseif ($post_action === 'step4') {
1742
                $return = continueReEncryptingUserSharekeysStep4(
1743
                    $post_user_id,
1744
                    $post_self_change,
1745
                    $post_action,
1746
                    $post_start,
1747
                    $post_length,
1748
                    $userInfo['public_key'],
1749
                    $SETTINGS
1750
                );
1751
1752
                $next_start = $return['next_start'];
1753
                $next_action = $return['post_action'];
1754
            }
1755
            
1756
            // STEP 5 - FILES
1757
            elseif ($post_action === 'step5') {
1758
                $return = continueReEncryptingUserSharekeysStep5(
1759
                    $post_user_id,
1760
                    $post_self_change,
1761
                    $post_action,
1762
                    $post_start,
1763
                    $post_length,
1764
                    $userInfo['public_key'],
1765
                    $SETTINGS
1766
                );
1767
1768
                $next_start = $return['next_start'];
1769
                $next_action = $return['post_action'];
1770
            }
1771
            
1772
            // STEP 6 - PERSONAL ITEMS
1773
            elseif ($post_action === 'step6') {
1774
                $return = continueReEncryptingUserSharekeysStep6(
1775
                    $post_user_id,
1776
                    $post_self_change,
1777
                    $post_action,
1778
                    $post_start,
1779
                    $post_length,
1780
                    $userInfo['public_key'],
1781
                    $SETTINGS
1782
                );
1783
1784
                $next_start = $return['next_start'];
1785
                $next_action = $return['post_action'];
1786
            }
1787
            
1788
            // Continu with next step
1789
            return prepareExchangedData(
1790
    $SETTINGS['cpassman_dir'],
1791
                array(
1792
                    'error' => false,
1793
                    'message' => '',
1794
                    'step' => isset($next_action) === true ? $next_action : '',
1795
                    'start' => isset($next_start) === true ? $next_start : 0,
1796
                    'userId' => $post_user_id,
1797
                    'self_change' => $post_self_change,
1798
                ),
1799
                'encode'
1800
            );
1801
        }
1802
        
1803
        // Nothing to do
1804
        return prepareExchangedData(
1805
    $SETTINGS['cpassman_dir'],
1806
            array(
1807
                'error' => false,
1808
                'message' => '',
1809
                'step' => 'finished',
1810
                'start' => 0,
1811
                'userId' => $post_user_id,
1812
                'self_change' => $post_self_change,
1813
            ),
1814
            'encode'
1815
        );
1816
    }
1817
    
1818
    // Nothing to do
1819
    return prepareExchangedData(
1820
    $SETTINGS['cpassman_dir'],
1821
        array(
1822
            'error' => true,
1823
            'message' => langHdl('error_no_user'),
1824
            'extra' => $post_user_id,
1825
        ),
1826
        'encode'
1827
    );
1828
}
1829
1830
function continueReEncryptingUserSharekeysStep1(
1831
    int $post_user_id,
1832
    bool $post_self_change,
1833
    string $post_action,
1834
    int $post_start,
1835
    int $post_length,
1836
    string $user_public_key,
1837
    array $SETTINGS
1838
): array 
1839
{
1840
    // Loop on items
1841
    $rows = DB::query(
1842
        'SELECT id, pw
1843
        FROM ' . prefixTable('items') . '
1844
        WHERE perso = 0
1845
        LIMIT ' . $post_start . ', ' . $post_length
1846
    );
1847
    foreach ($rows as $record) {
1848
        // Get itemKey from current user
1849
        $currentUserKey = DB::queryFirstRow(
1850
            'SELECT share_key, increment_id
1851
            FROM ' . prefixTable('sharekeys_items') . '
1852
            WHERE object_id = %i AND user_id = %i',
1853
            $record['id'],
1854
            $_SESSION['user_id']
1855
        );
1856
        if ($currentUserKey === null || count($currentUserKey) === 0) continue;
1857
1858
        // Decrypt itemkey with admin key
1859
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1860
        
1861
        // Encrypt Item key
1862
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
1863
        
1864
        // Save the key in DB
1865
        if ($post_self_change === false) {
1866
            DB::insert(
1867
                prefixTable('sharekeys_items'),
1868
                array(
1869
                    'object_id' => (int) $record['id'],
1870
                    'user_id' => (int) $post_user_id,
1871
                    'share_key' => $share_key_for_item,
1872
                )
1873
            );
1874
        } else {
1875
            // Get itemIncrement from selected user
1876
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
1877
                $currentUserKey = DB::queryFirstRow(
1878
                    'SELECT increment_id
1879
                    FROM ' . prefixTable('sharekeys_items') . '
1880
                    WHERE object_id = %i AND user_id = %i',
1881
                    $record['id'],
1882
                    $post_user_id
1883
                );
1884
1885
                if (DB::count() > 0) {
1886
                    // NOw update
1887
                    DB::update(
1888
                        prefixTable('sharekeys_items'),
1889
                        array(
1890
                            'share_key' => $share_key_for_item,
1891
                        ),
1892
                        'increment_id = %i',
1893
                        $currentUserKey['increment_id']
1894
                    );
1895
                } else {
1896
                    DB::insert(
1897
                        prefixTable('sharekeys_items'),
1898
                        array(
1899
                            'object_id' => (int) $record['id'],
1900
                            'user_id' => (int) $post_user_id,
1901
                            'share_key' => $share_key_for_item,
1902
                        )
1903
                    );
1904
                }
1905
            }
1906
        }
1907
    }
1908
1909
    // SHould we change step?
1910
    DB::query(
1911
        'SELECT *
1912
        FROM ' . prefixTable('items') . '
1913
        WHERE perso = 0'
1914
    );
1915
1916
    $next_start = (int) $post_start + (int) $post_length;
1917
    return [
1918
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
1919
        'post_action' => $next_start > DB::count() ? 'step2' : 'step1',
1920
    ];
1921
}
1922
1923
function continueReEncryptingUserSharekeysStep2(
1924
    int $post_user_id,
1925
    bool $post_self_change,
1926
    string $post_action,
1927
    int $post_start,
1928
    int $post_length,
1929
    string $user_public_key,
1930
    array $SETTINGS
1931
): array
1932
{
1933
    // Loop on logs
1934
    $rows = DB::query(
1935
        'SELECT increment_id
1936
        FROM ' . prefixTable('log_items') . '
1937
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"
1938
        LIMIT ' . $post_start . ', ' . $post_length
1939
    );
1940
    foreach ($rows as $record) {
1941
        // Get itemKey from current user
1942
        $currentUserKey = DB::queryFirstRow(
1943
            'SELECT share_key
1944
            FROM ' . prefixTable('sharekeys_logs') . '
1945
            WHERE object_id = %i AND user_id = %i',
1946
            $record['increment_id'],
1947
            $_SESSION['user_id']
1948
        );
1949
1950
        // Decrypt itemkey with admin key
1951
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1952
1953
        // Encrypt Item key
1954
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
1955
1956
        // Save the key in DB
1957
        if ($post_self_change === false) {
1958
            DB::insert(
1959
                prefixTable('sharekeys_logs'),
1960
                array(
1961
                    'object_id' => (int) $record['increment_id'],
1962
                    'user_id' => (int) $post_user_id,
1963
                    'share_key' => $share_key_for_item,
1964
                )
1965
            );
1966
        } else {
1967
            // Get itemIncrement from selected user
1968
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
1969
                $currentUserKey = DB::queryFirstRow(
1970
                    'SELECT increment_id
1971
                    FROM ' . prefixTable('sharekeys_items') . '
1972
                    WHERE object_id = %i AND user_id = %i',
1973
                    $record['id'],
1974
                    $post_user_id
1975
                );
1976
            }
1977
1978
            // NOw update
1979
            DB::update(
1980
                prefixTable('sharekeys_logs'),
1981
                array(
1982
                    'share_key' => $share_key_for_item,
1983
                ),
1984
                'increment_id = %i',
1985
                $currentUserKey['increment_id']
1986
            );
1987
        }
1988
    }
1989
1990
    // SHould we change step?
1991
    DB::query(
1992
        'SELECT increment_id
1993
        FROM ' . prefixTable('log_items') . '
1994
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"'
1995
    );
1996
1997
    $next_start = (int) $post_start + (int) $post_length;
1998
    return [
1999
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2000
        'post_action' => $next_start > DB::count() ? 'step3' : 'step2',
2001
    ];
2002
}
2003
2004
function continueReEncryptingUserSharekeysStep3(
2005
    int $post_user_id,
2006
    bool $post_self_change,
2007
    string $post_action,
2008
    int $post_start,
2009
    int $post_length,
2010
    string $user_public_key,
2011
    array $SETTINGS
2012
): array
2013
{
2014
    // Loop on fields
2015
    $rows = DB::query(
2016
        'SELECT id
2017
        FROM ' . prefixTable('categories_items') . '
2018
        WHERE encryption_type = "teampass_aes"
2019
        LIMIT ' . $post_start . ', ' . $post_length
2020
    );
2021
    foreach ($rows as $record) {
2022
        // Get itemKey from current user
2023
        $currentUserKey = DB::queryFirstRow(
2024
            'SELECT share_key
2025
            FROM ' . prefixTable('sharekeys_fields') . '
2026
            WHERE object_id = %i AND user_id = %i',
2027
            $record['id'],
2028
            $_SESSION['user_id']
2029
        );
2030
2031
        // Decrypt itemkey with admin key
2032
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2033
2034
        // Encrypt Item key
2035
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2036
2037
        // Save the key in DB
2038
        if ($post_self_change === false) {
2039
            DB::insert(
2040
                prefixTable('sharekeys_fields'),
2041
                array(
2042
                    'object_id' => (int) $record['id'],
2043
                    'user_id' => (int) $post_user_id,
2044
                    'share_key' => $share_key_for_item,
2045
                )
2046
            );
2047
        } else {
2048
            // Get itemIncrement from selected user
2049
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2050
                $currentUserKey = DB::queryFirstRow(
2051
                    'SELECT increment_id
2052
                    FROM ' . prefixTable('sharekeys_items') . '
2053
                    WHERE object_id = %i AND user_id = %i',
2054
                    $record['id'],
2055
                    $post_user_id
2056
                );
2057
            }
2058
2059
            // NOw update
2060
            DB::update(
2061
                prefixTable('sharekeys_fields'),
2062
                array(
2063
                    'share_key' => $share_key_for_item,
2064
                ),
2065
                'increment_id = %i',
2066
                $currentUserKey['increment_id']
2067
            );
2068
        }
2069
    }
2070
2071
    // SHould we change step?
2072
    DB::query(
2073
        'SELECT *
2074
        FROM ' . prefixTable('categories_items') . '
2075
        WHERE encryption_type = "teampass_aes"'
2076
    );
2077
2078
    $next_start = (int) $post_start + (int) $post_length;
2079
    return [
2080
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2081
        'post_action' => $next_start > DB::count() ? 'step4' : 'step3',
2082
    ];
2083
}
2084
2085
function continueReEncryptingUserSharekeysStep4(
2086
    int $post_user_id,
2087
    bool $post_self_change,
2088
    string $post_action,
2089
    int $post_start,
2090
    int $post_length,
2091
    string $user_public_key,
2092
    array $SETTINGS
2093
): array
2094
{
2095
    // Loop on suggestions
2096
    $rows = DB::query(
2097
        'SELECT id
2098
        FROM ' . prefixTable('suggestion') . '
2099
        LIMIT ' . $post_start . ', ' . $post_length
2100
    );
2101
    foreach ($rows as $record) {
2102
        // Get itemKey from current user
2103
        $currentUserKey = DB::queryFirstRow(
2104
            'SELECT share_key
2105
            FROM ' . prefixTable('sharekeys_suggestions') . '
2106
            WHERE object_id = %i AND user_id = %i',
2107
            $record['id'],
2108
            $_SESSION['user_id']
2109
        );
2110
2111
        // Decrypt itemkey with admin key
2112
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2113
2114
        // Encrypt Item key
2115
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2116
2117
        // Save the key in DB
2118
        if ($post_self_change === false) {
2119
            DB::insert(
2120
                prefixTable('sharekeys_suggestions'),
2121
                array(
2122
                    'object_id' => (int) $record['id'],
2123
                    'user_id' => (int) $post_user_id,
2124
                    'share_key' => $share_key_for_item,
2125
                )
2126
            );
2127
        } else {
2128
            // Get itemIncrement from selected user
2129
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2130
                $currentUserKey = DB::queryFirstRow(
2131
                    'SELECT increment_id
2132
                    FROM ' . prefixTable('sharekeys_items') . '
2133
                    WHERE object_id = %i AND user_id = %i',
2134
                    $record['id'],
2135
                    $post_user_id
2136
                );
2137
            }
2138
2139
            // NOw update
2140
            DB::update(
2141
                prefixTable('sharekeys_suggestions'),
2142
                array(
2143
                    'share_key' => $share_key_for_item,
2144
                ),
2145
                'increment_id = %i',
2146
                $currentUserKey['increment_id']
2147
            );
2148
        }
2149
    }
2150
2151
    // SHould we change step?
2152
    DB::query(
2153
        'SELECT *
2154
        FROM ' . prefixTable('suggestion')
2155
    );
2156
2157
    $next_start = (int) $post_start + (int) $post_length;
2158
    return [
2159
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2160
        'post_action' => $next_start > DB::count() ? 'step5' : 'step4',
2161
    ];
2162
}
2163
2164
function continueReEncryptingUserSharekeysStep5(
2165
    int $post_user_id,
2166
    bool $post_self_change,
2167
    string $post_action,
2168
    int $post_start,
2169
    int $post_length,
2170
    string $user_public_key,
2171
    array $SETTINGS
2172
): array
2173
{
2174
    // Loop on files
2175
    $rows = DB::query(
2176
        'SELECT id
2177
        FROM ' . prefixTable('files') . '
2178
        WHERE status = "' . TP_ENCRYPTION_NAME . '"
2179
        LIMIT ' . $post_start . ', ' . $post_length
2180
    ); //aes_encryption
2181
    foreach ($rows as $record) {
2182
        // Get itemKey from current user
2183
        $currentUserKey = DB::queryFirstRow(
2184
            'SELECT share_key
2185
            FROM ' . prefixTable('sharekeys_files') . '
2186
            WHERE object_id = %i AND user_id = %i',
2187
            $record['id'],
2188
            $_SESSION['user_id']
2189
        );
2190
2191
        // Decrypt itemkey with admin key
2192
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2193
2194
        // Encrypt Item key
2195
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2196
2197
        // Save the key in DB
2198
        if ($post_self_change === false) {
2199
            DB::insert(
2200
                prefixTable('sharekeys_files'),
2201
                array(
2202
                    'object_id' => (int) $record['id'],
2203
                    'user_id' => (int) $post_user_id,
2204
                    'share_key' => $share_key_for_item,
2205
                )
2206
            );
2207
        } else {
2208
            // Get itemIncrement from selected user
2209
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2210
                $currentUserKey = DB::queryFirstRow(
2211
                    'SELECT increment_id
2212
                    FROM ' . prefixTable('sharekeys_items') . '
2213
                    WHERE object_id = %i AND user_id = %i',
2214
                    $record['id'],
2215
                    $post_user_id
2216
                );
2217
            }
2218
2219
            // NOw update
2220
            DB::update(
2221
                prefixTable('sharekeys_files'),
2222
                array(
2223
                    'share_key' => $share_key_for_item,
2224
                ),
2225
                'increment_id = %i',
2226
                $currentUserKey['increment_id']
2227
            );
2228
        }
2229
    }
2230
2231
    // SHould we change step?
2232
    DB::query(
2233
        'SELECT *
2234
        FROM ' . prefixTable('files') . '
2235
        WHERE status = "' . TP_ENCRYPTION_NAME . '"'
2236
    );
2237
2238
    $next_start = (int) $post_start + (int) $post_length;
2239
    return [
2240
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2241
        'post_action' => $next_start > DB::count() ? 'step6' : 'step5',
2242
    ];
2243
}
2244
2245
function continueReEncryptingUserSharekeysStep6(
2246
    int $post_user_id,
2247
    bool $post_self_change,
2248
    string $post_action,
2249
    int $post_start,
2250
    int $post_length,
2251
    string $user_public_key,
2252
    array $SETTINGS
2253
): array
2254
{
2255
    // IF USER IS NOT THE SAME
2256
    if ((int) $post_user_id === (int) $_SESSION['user_id']) {
2257
        return [
2258
            'next_start' => 0,
2259
            'post_action' => 'finished',
2260
        ];
2261
    }
2262
    
2263
    // Loop on persoanl items
2264
    if (count($_SESSION['personal_folders']) > 0) {
2265
        $rows = DB::query(
2266
            'SELECT id, pw
2267
            FROM ' . prefixTable('items') . '
2268
            WHERE perso = 1 AND id_tree IN %ls
2269
            LIMIT ' . $post_start . ', ' . $post_length,
2270
            $_SESSION['personal_folders']
2271
        );
2272
        foreach ($rows as $record) {
2273
            // Get itemKey from current user
2274
            $currentUserKey = DB::queryFirstRow(
2275
                'SELECT share_key, increment_id
2276
                FROM ' . prefixTable('sharekeys_items') . '
2277
                WHERE object_id = %i AND user_id = %i',
2278
                $record['id'],
2279
                $_SESSION['user_id']
2280
            );
2281
2282
            // Decrypt itemkey with admin key
2283
            $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2284
2285
            // Encrypt Item key
2286
            $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2287
2288
            // Save the key in DB
2289
            if ($post_self_change === false) {
2290
                DB::insert(
2291
                    prefixTable('sharekeys_items'),
2292
                    array(
2293
                        'object_id' => (int) $record['id'],
2294
                        'user_id' => (int) $post_user_id,
2295
                        'share_key' => $share_key_for_item,
2296
                    )
2297
                );
2298
            } else {
2299
                // Get itemIncrement from selected user
2300
                if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2301
                    $currentUserKey = DB::queryFirstRow(
2302
                        'SELECT increment_id
2303
                        FROM ' . prefixTable('sharekeys_items') . '
2304
                        WHERE object_id = %i AND user_id = %i',
2305
                        $record['id'],
2306
                        $post_user_id
2307
                    );
2308
                }
2309
2310
                // NOw update
2311
                DB::update(
2312
                    prefixTable('sharekeys_items'),
2313
                    array(
2314
                        'share_key' => $share_key_for_item,
2315
                    ),
2316
                    'increment_id = %i',
2317
                    $currentUserKey['increment_id']
2318
                );
2319
            }
2320
        }
2321
    }
2322
2323
    // SHould we change step?
2324
    DB::query(
2325
        'SELECT *
2326
        FROM ' . prefixTable('items') . '
2327
        WHERE perso = 0'
2328
    );
2329
2330
    $next_start = (int) $post_start + (int) $post_length;
2331
    return [
2332
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2333
        'post_action' => $next_start > DB::count() ? 'finished' : 'step6',
2334
    ];
2335
}
2336
2337
function migrateTo3_DoUserPersonalItemsEncryption(
2338
    int $post_user_id,
2339
    int $post_start,
2340
    int $post_length,
2341
    string $post_user_psk,
2342
    array $SETTINGS
2343
) {
2344
    $next_step = '';
2345
2346
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
2347
        // Check if user exists
2348
        $userInfo = DB::queryFirstRow(
2349
            'SELECT public_key, encrypted_psk
2350
            FROM ' . prefixTable('users') . '
2351
            WHERE id = %i',
2352
            $post_user_id
2353
        );
2354
        if (DB::count() > 0) {
2355
            // check if psk is correct.
2356
            if (empty($userInfo['encrypted_psk']) === false) {
2357
                $user_key_encoded = defuse_validate_personal_key(
2358
                    $post_user_psk,
2359
                    $userInfo['encrypted_psk']
2360
                );
2361
2362
                if (strpos($user_key_encoded, "Error ") !== false) {
2363
                    return prepareExchangedData(
2364
    $SETTINGS['cpassman_dir'],
2365
                        array(
2366
                            'error' => true,
2367
                            'message' => langHdl('bad_psk'),
2368
                        ),
2369
                        'encode'
2370
                    );
2371
                }
2372
2373
                // Loop on persoanl items
2374
                $rows = DB::query(
2375
                    'SELECT id, pw
2376
                    FROM ' . prefixTable('items') . '
2377
                    WHERE perso = 1 AND id_tree IN %ls
2378
                    LIMIT ' . $post_start . ', ' . $post_length,
2379
                    $_SESSION['personal_folders']
2380
                );
2381
                $countUserPersonalItems = DB::count();
2382
                foreach ($rows as $record) {
2383
                    if ($record['encryption_type'] !== 'teampass_aes') {
2384
                        // Decrypt with Defuse
2385
                        $passwd = cryption(
2386
                            $record['pw'],
2387
                            $user_key_encoded,
2388
                            'decrypt',
2389
                            $SETTINGS
2390
                        );
2391
2392
                        // Encrypt with Object Key
2393
                        $cryptedStuff = doDataEncryption($passwd['string']);
2394
2395
                        // Store new password in DB
2396
                        DB::update(
2397
                            prefixTable('items'),
2398
                            array(
2399
                                'pw' => $cryptedStuff['encrypted'],
2400
                                'encryption_type' => 'teampass_aes',
2401
                            ),
2402
                            'id = %i',
2403
                            $record['id']
2404
                        );
2405
2406
                        // Insert in DB the new object key for this item by user
2407
                        DB::insert(
2408
                            prefixTable('sharekeys_items'),
2409
                            array(
2410
                                'object_id' => (int) $record['id'],
2411
                                'user_id' => (int) $post_user_id,
2412
                                'share_key' => encryptUserObjectKey($cryptedStuff['objectKey'], $userInfo['public_key']),
2413
                            )
2414
                        );
2415
2416
2417
                        // Does this item has Files?
2418
                        // Loop on files
2419
                        $rows = DB::query(
2420
                            'SELECT id, file
2421
                            FROM ' . prefixTable('files') . '
2422
                            WHERE status != %s
2423
                            AND id_item = %i',
2424
                            TP_ENCRYPTION_NAME,
2425
                            $record['id']
2426
                        );
2427
                        //aes_encryption
2428
                        foreach ($rows as $record2) {
2429
                            // Now decrypt the file
2430
                            prepareFileWithDefuse(
2431
                                'decrypt',
2432
                                $SETTINGS['path_to_upload_folder'] . '/' . $record2['file'],
2433
                                $SETTINGS['path_to_upload_folder'] . '/' . $record2['file'] . '.delete',
2434
                                $SETTINGS,
2435
                                $post_user_psk
2436
                            );
2437
2438
                            // Encrypt the file
2439
                            $encryptedFile = encryptFile($record2['file'] . '.delete', $SETTINGS['path_to_upload_folder']);
2440
2441
                            DB::update(
2442
                                prefixTable('files'),
2443
                                array(
2444
                                    'file' => $encryptedFile['fileHash'],
2445
                                    'status' => TP_ENCRYPTION_NAME,
2446
                                ),
2447
                                'id = %i',
2448
                                $record2['id']
2449
                            );
2450
2451
                            // Save key
2452
                            DB::insert(
2453
                                prefixTable('sharekeys_files'),
2454
                                array(
2455
                                    'object_id' => (int) $record2['id'],
2456
                                    'user_id' => (int) $_SESSION['user_id'],
2457
                                    'share_key' => encryptUserObjectKey($encryptedFile['objectKey'], $_SESSION['user']['public_key']),
2458
                                )
2459
                            );
2460
2461
                            // Unlink original file
2462
                            unlink($SETTINGS['path_to_upload_folder'] . '/' . $record2['file']);
2463
                        }
2464
                    }
2465
                }
2466
2467
                // SHould we change step?
2468
                $next_start = (int) $post_start + (int) $post_length;
2469
                if ($next_start > $countUserPersonalItems) {
2470
                    // Now update user
2471
                    DB::update(
2472
                        prefixTable('users'),
2473
                        array(
2474
                            'special' => 'none',
2475
                            'upgrade_needed' => 0,
2476
                            'encrypted_psk' => '',
2477
                        ),
2478
                        'id = %i',
2479
                        $post_user_id
2480
                    );
2481
2482
                    $next_step = 'finished';
2483
                    $next_start = 0;
2484
                }
2485
2486
                // Continu with next step
2487
                return prepareExchangedData(
2488
    $SETTINGS['cpassman_dir'],
2489
                    array(
2490
                        'error' => false,
2491
                        'message' => '',
2492
                        'step' => $next_step,
2493
                        'start' => $next_start,
2494
                        'userId' => $post_user_id
2495
                    ),
2496
                    'encode'
2497
                );
2498
            }
2499
        }
2500
        
2501
        // Nothing to do
2502
        return prepareExchangedData(
2503
    $SETTINGS['cpassman_dir'],
2504
            array(
2505
                'error' => true,
2506
                'message' => langHdl('error_no_user'),
2507
            ),
2508
            'encode'
2509
        );
2510
    }
2511
    
2512
    // Nothing to do
2513
    return prepareExchangedData(
2514
    $SETTINGS['cpassman_dir'],
2515
        array(
2516
            'error' => true,
2517
            'message' => langHdl('error_no_user'),
2518
        ),
2519
        'encode'
2520
    );
2521
}
2522
2523
2524
function getUserInfo(
2525
    int $post_user_id,
2526
    string $post_fields,
2527
    array $SETTINGS
2528
)
2529
{
2530
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
2531
        // Get user info
2532
        $userData = DB::queryFirstRow(
2533
            'SELECT '.$post_fields.'
2534
            FROM ' . prefixTable('users') . '
2535
            WHERE id = %i',
2536
            $post_user_id
2537
        );
2538
        if (DB::count() > 0) {
2539
            return prepareExchangedData(
2540
    $SETTINGS['cpassman_dir'],
2541
                array(
2542
                    'error' => false,
2543
                    'message' => '',
2544
                    'queryResults' => $userData,
2545
                ),
2546
                'encode'
2547
            );
2548
        }
2549
    }
2550
    return prepareExchangedData(
2551
    $SETTINGS['cpassman_dir'],
2552
        array(
2553
            'error' => true,
2554
            'message' => langHdl('error_no_user'),
2555
        ),
2556
        'encode'
2557
    );
2558
}
2559
2560
function changeUserAuthenticationPassword(
2561
    int $post_user_id,
2562
    string $post_current_pwd,
2563
    string $post_new_pwd,
2564
    array $SETTINGS
2565
)
2566
{
2567
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
2568
        // Get user info
2569
        $userData = DB::queryFirstRow(
2570
            'SELECT auth_type, login, private_key
2571
            FROM ' . prefixTable('users') . '
2572
            WHERE id = %i',
2573
            $post_user_id
2574
        );
2575
        if (DB::count() > 0 && empty($userData['private_key']) === false) {
2576
            // Now check if current password is correct
2577
            // For this, just check if it is possible to decrypt the privatekey
2578
            // And compare it to the one in session
2579
            $privateKey = decryptPrivateKey($post_current_pwd, $userData['private_key']);
2580
2581
            // Load superGlobals
2582
            include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2583
            $superGlobal = new protect\SuperGlobal\SuperGlobal();
2584
2585
            if ($superGlobal->get('private_key', 'SESSION', 'user') === $privateKey) {
2586
                // Encrypt it with new password
2587
                $hashedPrivateKey = encryptPrivateKey($post_new_pwd, $privateKey);
2588
2589
                // Generate new hash for auth password
2590
                // load passwordLib library
2591
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2592
                $pwdlib->register();
2593
                $pwdlib = new PasswordLib\PasswordLib();
2594
2595
                // Prepare variables
2596
                $newPw = $pwdlib->createPasswordHash($post_new_pwd);
2597
2598
                // Update user account
2599
                DB::update(
2600
                    prefixTable('users'),
2601
                    array(
2602
                        'private_key' => $hashedPrivateKey,
2603
                        'pw' => $newPw,
2604
                        'special' => 'none',
2605
                    ),
2606
                    'id = %i',
2607
                    $post_user_id
2608
                );
2609
2610
                $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2611
2612
                return prepareExchangedData(
2613
    $SETTINGS['cpassman_dir'],
2614
                    array(
2615
                        'error' => false,
2616
                        'message' => langHdl('done'),'',
2617
                    ),
2618
                    'encode'
2619
                );
2620
            }
2621
            
2622
            // ERROR
2623
            return prepareExchangedData(
2624
    $SETTINGS['cpassman_dir'],
2625
                array(
2626
                    'error' => true,
2627
                    'message' => langHdl('bad_password'),
2628
                ),
2629
                'encode'
2630
            );
2631
        }
2632
    }
2633
        
2634
    return prepareExchangedData(
2635
    $SETTINGS['cpassman_dir'],
2636
        array(
2637
            'error' => true,
2638
            'message' => langHdl('error_no_user'),
2639
        ),
2640
        'encode'
2641
    );
2642
}
2643
2644
            
2645
function changeUserLDAPAuthenticationPassword(
2646
    int $post_user_id,
2647
    string $post_previous_pwd,
2648
    string $post_current_pwd,
2649
    array $SETTINGS
2650
)
2651
{
2652
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
2653
        // Get user info
2654
        $userData = DB::queryFirstRow(
2655
            'SELECT auth_type, login, private_key, special
2656
            FROM ' . prefixTable('users') . '
2657
            WHERE id = %i',
2658
            $post_user_id
2659
        );
2660
        
2661
        if (DB::count() > 0 && empty($userData['private_key']) === false) {
2662
            // Now check if current password is correct (only if not ldap)
2663
            if ($userData['auth_type'] === 'ldap' && $userData['special'] === 'auth-pwd-change') {
2664
                // As it is a change for an LDAP user
2665
                
2666
                // Now check if current password is correct
2667
                // For this, just check if it is possible to decrypt the privatekey
2668
                // And compare it to the one in session
2669
                $privateKey = decryptPrivateKey($post_previous_pwd, $userData['private_key']);
2670
2671
                // Encrypt it with new password
2672
                $hashedPrivateKey = encryptPrivateKey($post_current_pwd, $privateKey);
2673
2674
                // Update user account
2675
                DB::update(
2676
                    prefixTable('users'),
2677
                    array(
2678
                        'private_key' => $hashedPrivateKey,
2679
                        'special' => 'none',
2680
                    ),
2681
                    'id = %i',
2682
                    $post_user_id
2683
                );
2684
2685
                // Load superGlobals
2686
                include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2687
                $superGlobal = new protect\SuperGlobal\SuperGlobal();
2688
                $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2689
2690
                return prepareExchangedData(
2691
    $SETTINGS['cpassman_dir'],
2692
                    array(
2693
                        'error' => false,
2694
                        'message' => langHdl('done'),'',
2695
                    ),
2696
                    'encode'
2697
                );
2698
            }
2699
2700
            // For this, just check if it is possible to decrypt the privatekey
2701
            // And try to decrypt one existing key
2702
            $privateKey = decryptPrivateKey($post_previous_pwd, $userData['private_key']);
2703
2704
            if (empty($privateKey) === true) {
2705
                return prepareExchangedData(
2706
    $SETTINGS['cpassman_dir'],
2707
                    array(
2708
                        'error' => true,
2709
                        'message' => langHdl('password_is_not_correct'),
2710
                    ),
2711
                    'encode'
2712
                );
2713
            }
2714
2715
            // Test if possible to decvrypt one key
2716
            // Get one item
2717
            $record = DB::queryFirstRow(
2718
                'SELECT id, pw
2719
                FROM ' . prefixTable('items') . '
2720
                WHERE perso = 0'
2721
            );
2722
2723
            // Get itemKey from current user
2724
            $currentUserKey = DB::queryFirstRow(
2725
                'SELECT share_key, increment_id
2726
                FROM ' . prefixTable('sharekeys_items') . '
2727
                WHERE object_id = %i AND user_id = %i',
2728
                $record['id'],
2729
                $post_user_id
2730
            );
2731
2732
            if (count($currentUserKey) > 0) {
2733
                // Decrypt itemkey with user key
2734
                // use old password to decrypt private_key
2735
                $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $privateKey);
2736
                
2737
                if (empty(base64_decode($itemKey)) === false) {
2738
                    // GOOD password
2739
                    // Encrypt it with current password
2740
                    $hashedPrivateKey = encryptPrivateKey($post_current_pwd, $privateKey);
2741
                    
2742
                    // Update user account
2743
                    DB::update(
2744
                        prefixTable('users'),
2745
                        array(
2746
                            'private_key' => $hashedPrivateKey,
2747
                            'special' => 'none',
2748
                        ),
2749
                        'id = %i',
2750
                        $post_user_id
2751
                    );
2752
                    
2753
                    // Load superGlobals
2754
                    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2755
                    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2756
                    $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2757
2758
                    return prepareExchangedData(
2759
    $SETTINGS['cpassman_dir'],
2760
                        array(
2761
                            'error' => false,
2762
                            'message' => langHdl('done'),
2763
                        ),
2764
                        'encode'
2765
                    );
2766
                }
2767
            }
2768
            
2769
            // ERROR
2770
            return prepareExchangedData(
2771
    $SETTINGS['cpassman_dir'],
2772
                array(
2773
                    'error' => true,
2774
                    'message' => langHdl('bad_password'),
2775
                ),
2776
                'encode'
2777
            );
2778
        }
2779
    }
2780
2781
    // ERROR
2782
    return prepareExchangedData(
2783
    $SETTINGS['cpassman_dir'],
2784
        array(
2785
            'error' => true,
2786
            'message' => langHdl('error_no_user'),
2787
        ),
2788
        'encode'
2789
    );
2790
}
2791
2792
2793
function increaseSessionDuration(
2794
    int $duration
2795
): string
2796
{
2797
    // check if session is not already expired.
2798
    if ($_SESSION['sessionDuration'] > time()) {
2799
        // Calculate end of session
2800
        $_SESSION['sessionDuration'] = (int) ($_SESSION['sessionDuration'] + $duration);
2801
        // Update table
2802
        DB::update(
2803
            prefixTable('users'),
2804
            array(
2805
                'session_end' => $_SESSION['sessionDuration'],
2806
            ),
2807
            'id = %i',
2808
            $_SESSION['user_id']
2809
        );
2810
        // Return data
2811
        return '[{"new_value":"' . $_SESSION['sessionDuration'] . '"}]';
2812
    }
2813
    
2814
    return '[{"new_value":"expired"}]';
2815
}