Passed
Push — teampass_3.0 ( c4785d...0b1c1e )
by Nils
04:24
created

increaseSessionDuration()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 10
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 22
rs 9.9332
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-2021 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
            array(
119
                'error' => true,
120
                'message' => langHdl('key_is_not_correct'),
121
            ),
122
            'encode'
123
        );
124
        return false;
125
    }
126
127
    // Ensure Complexity levels are translated
128
    if (defined('TP_PW_COMPLEXITY') === false) {
129
        define(
130
            'TP_PW_COMPLEXITY',
131
            array(
132
                0 => array(0, langHdl('complex_level0'), 'fas fa-bolt text-danger'),
133
                25 => array(25, langHdl('complex_level1'), 'fas fa-thermometer-empty text-danger'),
134
                50 => array(50, langHdl('complex_level2'), 'fas fa-thermometer-quarter text-warning'),
135
                60 => array(60, langHdl('complex_level3'), 'fas fa-thermometer-half text-warning'),
136
                70 => array(70, langHdl('complex_level4'), 'fas fa-thermometer-three-quarters text-success'),
137
                80 => array(80, langHdl('complex_level5'), 'fas fa-thermometer-full text-success'),
138
                90 => array(90, langHdl('complex_level6'), 'far fa-gem text-success'),
139
            )
140
        );
141
    }
142
143
    // decrypt and retreive data in JSON format
144
    $dataReceived = prepareExchangedData(
145
        $post_data,
146
        'decode'
147
    );
148
    
149
    // Manage type of action asked
150
    switch ($post_type) {
151
        case 'change_pw':
152
            $return = changePassword(
153
                (string) filter_var($dataReceived['new_pw'], FILTER_SANITIZE_STRING),
154
                isset($dataReceived['current_pw']) === true ? (string) filter_var($dataReceived['current_pw'], FILTER_SANITIZE_STRING) : '',
155
                (int) filter_var($dataReceived['complexity'], FILTER_SANITIZE_NUMBER_INT),
156
                (string) filter_var($dataReceived['change_request'], FILTER_SANITIZE_STRING),
157
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
158
                $SETTINGS
159
            );
160
161
            echo $return;
162
            
163
            break;
164
165
        /*
166
         * This will generate the QR Google Authenticator
167
         */
168
        case 'ga_generate_qr':
169
            $return = generateQRCode(
170
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
171
                (string) filter_var($dataReceived['demand_origin'], FILTER_SANITIZE_STRING),
172
                (string) filter_var($dataReceived['send_email'], FILTER_SANITIZE_STRING),
173
                (string) filter_var($dataReceived['login'], FILTER_SANITIZE_STRING),
174
                (string) filter_var($dataReceived['pwd'], FILTER_SANITIZE_STRING),
175
                $SETTINGS
176
            );
177
178
            echo $return;
179
180
            break;
181
        
182
            /*
183
         * Increase the session time of User
184
         */
185
        case 'increase_session_time':
186
            $return = increaseSessionDuration(
187
                (int) filter_input(INPUT_POST, 'duration', FILTER_SANITIZE_NUMBER_INT)
188
            );
189
190
            echo $return;
191
192
            break;
193
        
194
            /*
195
         * Hide maintenance message
196
         */
197
        case 'hide_maintenance':
198
            $_SESSION['hide_maintenance'] = 1;
199
200
            break;
201
        
202
        /*
203
         * Send emails not sent
204
         */
205
        case 'send_waiting_emails':
206
            sendEmailsNotSent(
207
                $SETTINGS
208
            );
209
            
210
            break;
211
212
        /*
213
         * Generate a password generic
214
         */
215
        case 'generate_password':
216
            $return = generateGenericPassword(
217
                (int) filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT),
218
                (bool) filter_input(INPUT_POST, 'secure_pwd', FILTER_SANITIZE_STRING),
219
                (bool) filter_input(INPUT_POST, 'lowercase', FILTER_SANITIZE_STRING),
220
                (bool) filter_input(INPUT_POST, 'capitalize', FILTER_SANITIZE_STRING),
221
                (bool) filter_input(INPUT_POST, 'numerals', FILTER_SANITIZE_STRING),
222
                (bool) filter_input(INPUT_POST, 'symbols', FILTER_SANITIZE_NUMBER_INT),
223
                $SETTINGS
224
            );
225
226
            echo $return;
227
            
228
            break;
229
230
        /*
231
         * Refresh list of last items seen
232
         */
233
        case 'refresh_list_items_seen':
234
            $return = refreshUserItemsSeenList(
235
                $SETTINGS
236
            );
237
238
            echo $return;
239
240
            break;
241
242
        /*
243
         * Generates a KEY with CRYPT
244
         */
245
        case 'generate_new_key':
246
            // load passwordLib library
247
            $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
248
            $pwdlib->register();
249
            $pwdlib = new PasswordLib\PasswordLib();
250
            // generate key
251
            $key = $pwdlib->getRandomToken(filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT));
252
            echo '[{"key" : "' . htmlentities($key, ENT_QUOTES) . '"}]';
253
            break;
254
255
        /*
256
         * Generates a TOKEN with CRYPT
257
         */
258
        case 'save_token':
259
            $token = GenerateCryptKey(
260
                null !== filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT) ? (int) filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT) : 20,
261
                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,
262
                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,
263
                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,
264
                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,
265
                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,
266
                $SETTINGS
267
            );
268
269
            // store in DB
270
            DB::insert(
271
                prefixTable('tokens'),
272
                array(
273
                    'user_id' => (int) $_SESSION['user_id'],
274
                    'token' => $token,
275
                    'reason' => filter_input(INPUT_POST, 'reason', FILTER_SANITIZE_STRING),
276
                    'creation_timestamp' => time(),
277
                    'end_timestamp' => time() + filter_input(INPUT_POST, 'duration', FILTER_SANITIZE_NUMBER_INT), // in secs
278
                )
279
            );
280
281
            echo '[{"token" : "' . $token . '"}]';
282
            break;
283
284
285
        /*
286
         * TODO Check if suggestions are existing
287
         */
288
        /*
289
        case 'is_existings_suggestions':
290
            if ($_SESSION['user_manager'] === '1' || $_SESSION['is_admin'] === '1') {
291
                $count = 0;
292
                DB::query('SELECT * FROM ' . prefixTable('items_change'));
293
                $count += DB::count();
294
                DB::query('SELECT * FROM ' . prefixTable('suggestion'));
295
                $count += DB::count();
296
297
                echo '[ { "error" : "" , "count" : "' . $count . '" , "show_sug_in_menu" : "0"} ]';
298
                break;
299
            }
300
            
301
            if (isset($_SESSION['nb_item_change_proposals']) && $_SESSION['nb_item_change_proposals'] > 0) {
302
                echo '[ { "error" : "" , "count" : "' . $_SESSION['nb_item_change_proposals'] . '" , "show_sug_in_menu" : "1"} ]';
303
                break;
304
            }
305
            
306
            echo '[ { "error" : "" , "count" : "" , "show_sug_in_menu" : "0"} ]';
307
308
            break;
309
        */
310
311
        /*
312
         * Sending statistics
313
         */
314
        case 'sending_statistics':
315
            sendingStatistics(
316
                $SETTINGS
317
            );
318
319
            break;
320
321
        /*
322
         * delete a file
323
         */
324
        case 'file_deletion':
325
            fileDelete(filter_input(INPUT_POST, 'filename', FILTER_SANITIZE_STRING), $SETTINGS);
326
327
            break;
328
329
        /*
330
         * Generate BUG report
331
         */
332
        case 'generate_bug_report':
333
            $return = generateBugReport(
334
                (string) $post_data,
335
                $SETTINGS
336
            );
337
338
            echo $return;
339
        
340
            break;
341
342
        /**
343
         * 
344
         */
345
        case 'update_user_field':
346
            // Prepare variables
347
            DB::update(
348
                prefixTable('users'),
349
                array(
350
                    noHTML(htmlspecialchars_decode($dataReceived['field'])) => noHTML(htmlspecialchars_decode($dataReceived['new_value'])),
351
                ),
352
                'id = %i',
353
                (int) $dataReceived['user_id']
354
            );
355
356
            // Update session
357
            if ($field === 'user_api_key') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $field seems to be never defined.
Loading history...
358
                $_SESSION['user']['api-key'] = $new_value;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $new_value seems to be never defined.
Loading history...
359
            }
360
            break;
361
362
        /*
363
        * get_teampass_settings
364
        */
365
        case 'get_teampass_settings':
366
            // Encrypt data to return
367
            echo prepareExchangedData($SETTINGS, 'encode');
368
369
            break;
370
371
372
        /*
373
        * test_current_user_password_is_correct
374
        */
375
        case 'test_current_user_password_is_correct':
376
            $return = isUserPasswordCorrect(
377
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
378
                (string) filter_var($dataReceived['password'], FILTER_SANITIZE_STRING),
379
                $SETTINGS
380
            );
381
382
            echo $return;
383
384
            break;
385
386
        /*
387
         * User's public/private keys change
388
         */
389
        case 'change_private_key_encryption_password':
390
            $return = changePrivateKeyEncryptionPassword(
391
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
392
                (string) filter_var($dataReceived['current_code'], FILTER_SANITIZE_STRING),
393
                (string) filter_var($dataReceived['new_code'], FILTER_SANITIZE_STRING),
394
                (string) filter_var($dataReceived['action_type'], FILTER_SANITIZE_STRING),
395
                $SETTINGS
396
            );
397
398
            echo $return;
399
        
400
            break;
401
402
        /*
403
         * User's password has to be initialized
404
         */
405
        case 'initialize_user_password':
406
            $return = initializeUserPassword(
407
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
408
                (string) filter_var($dataReceived['special'], FILTER_SANITIZE_STRING),
409
                (string) filter_var($dataReceived['password'], FILTER_SANITIZE_STRING),
410
                (string) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
411
                $SETTINGS
412
            );
413
414
            echo $return;
415
416
            break;
417
418
        /*
419
        * CASE
420
        * Send email
421
        */
422
        case 'mail_me':
423
            $return = sendMailToUser(
424
                filter_var($dataReceived['receipt'], FILTER_SANITIZE_NUMBER_INT),
425
                $dataReceived['body'],
426
                (string) filter_var($dataReceived['subject'], FILTER_SANITIZE_STRING),
427
                (array) filter_var($dataReceived['pre_replace'], FILTER_SANITIZE_STRING),
428
                $SETTINGS
429
            );
430
431
            echo $return;
432
433
            break;
434
435
        /*
436
        * Generate a temporary encryption key for user
437
        */
438
        case 'generate_temporary_encryption_key':
439
            $return = generateOneTimeCode(
440
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
441
                $SETTINGS
442
            );
443
            
444
            echo $return;
445
446
            break;
447
448
        /*
449
        * user_sharekeys_reencryption_start
450
        */
451
        case 'user_sharekeys_reencryption_start':
452
            $return = startReEncryptingUserSharekeys(
453
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
454
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
455
                $SETTINGS
456
            );
457
            
458
            echo $return;
459
460
            break;
461
462
        /*
463
        * user_sharekeys_reencryption_next
464
        */
465
        case 'user_sharekeys_reencryption_next':
466
            $return = continueReEncryptingUserSharekeys(
467
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
468
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
469
                (string) filter_var($dataReceived['action'], FILTER_SANITIZE_STRING),
470
                (int) filter_var($dataReceived['start'], FILTER_SANITIZE_NUMBER_INT),
471
                (int) filter_var($dataReceived['length'], FILTER_SANITIZE_NUMBER_INT),
472
                $SETTINGS
473
            );
474
            
475
            echo $return;
476
477
            break;
478
479
        /*
480
        * user_psk_reencryption
481
        */
482
        case 'user_psk_reencryption':
483
            $return = migrateTo3_DoUserPersonalItemsEncryption(
484
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
485
                (int) filter_var($dataReceived['start'], FILTER_SANITIZE_NUMBER_INT),
486
                (int) filter_var($dataReceived['length'], FILTER_SANITIZE_NUMBER_INT),
487
                (string) filter_var($dataReceived['userPsk'], FILTER_SANITIZE_STRING),
488
                $SETTINGS
489
            );
490
            
491
            echo $return;
492
        
493
            break;
494
495
        /*
496
        * Get info 
497
        */
498
        case 'get_user_info':
499
            $return = getUserInfo(
500
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
501
                (string) filter_var($dataReceived['fields'], FILTER_SANITIZE_STRING),
502
                $SETTINGS
503
            );
504
            
505
            echo $return;
506
507
            break;
508
509
        /*
510
        * Change user's authenticataion password
511
        */
512
        case 'change_user_auth_password':
513
            $return = changeUserAuthenticationPassword(
514
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
515
                (string) filter_var($dataReceived['old_password'], FILTER_SANITIZE_STRING),
516
                (string) filter_var($dataReceived['new_password'], FILTER_SANITIZE_STRING),
517
                $SETTINGS
518
            );
519
            
520
            echo $return;
521
522
            break;
523
524
525
        /*
526
        * User's authenticataion password in LDAP has changed
527
        */
528
        case 'change_user_ldap_auth_password':
529
            $return = /** @scrutinizer ignore-call */ changeUserLDAPAuthenticationPassword(
530
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
531
                filter_var($dataReceived['previous_password'], FILTER_SANITIZE_STRING),
532
                filter_var($dataReceived['current_password'], FILTER_SANITIZE_STRING),
533
                $SETTINGS
534
            );
535
            
536
            echo $return;
537
538
            break;
539
    }
540
}
541
542
543
/**
544
 * 
545
 */
546
function changePassword(
547
    string $post_new_password,
548
    string $post_current_password,
549
    int $post_password_complexity,
550
    string $post_change_request,
551
    int $post_user_id,
552
    array $SETTINGS
553
): string
554
{
555
    // load passwordLib library
556
    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
557
    $pwdlib->register();
558
    $pwdlib = new PasswordLib\PasswordLib();
559
560
    // Prepare variables
561
    $post_new_password_hashed = $pwdlib->createPasswordHash($post_new_password);
562
563
    // User has decided to change is PW
564
    if (
565
        $post_change_request === 'reset_user_password_expected'
566
        || $post_change_request === 'user_decides_to_change_password'
567
    ) {
568
        // Check that current user is correct
569
        if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
570
            return prepareExchangedData(
571
                array(
572
                    'error' => true,
573
                    'message' => '<div style="margin:10px 0 10px 15px;">' . langHdl('error_not_allowed_to') . '</div>',
574
                ),
575
                'encode'
576
            );
577
        }
578
579
        // check if expected security level is reached
580
        $dataUser = DB::queryfirstrow(
581
            'SELECT *
582
            FROM ' . prefixTable('users') . '
583
            WHERE id = %i',
584
            $post_user_id
585
        );
586
587
        // check if badly written
588
        $dataUser['fonction_id'] = array_filter(
589
            explode(',', str_replace(';', ',', $dataUser['fonction_id']))
590
        );
591
        $dataUser['fonction_id'] = implode(',', $dataUser['fonction_id']);
592
        DB::update(
593
            prefixTable('users'),
594
            array(
595
                'fonction_id' => $dataUser['fonction_id'],
596
            ),
597
            'id = %i',
598
            $post_user_id
599
        );
600
601
        if (empty($dataUser['fonction_id']) === false) {
602
            $data = DB::queryFirstRow(
603
                'SELECT complexity
604
                FROM ' . prefixTable('roles_title') . '
605
                WHERE id IN (' . $dataUser['fonction_id'] . ')
606
                ORDER BY complexity DESC'
607
            );
608
        } else {
609
            // In case user has no roles yet
610
            $data = array();
611
            $data['complexity'] = 0;
612
        }
613
614
        if ((int) $post_password_complexity < (int) $data['complexity']) {
615
            return prepareExchangedData(
616
                array(
617
                    'error' => true,
618
                    'message' => '<div style="margin:10px 0 10px 15px;">' . langHdl('complexity_level_not_reached') . '.<br>' .
619
                        langHdl('expected_complexity_level') . ': <b>' . TP_PW_COMPLEXITY[$data['complexity']][1] . '</b></div>',
620
                ),
621
                'encode'
622
            );
623
        }
624
625
        // Check that the 2 passwords are differents
626
        if ($post_current_password === $post_new_password) {
627
            return prepareExchangedData(
628
                array(
629
                    'error' => true,
630
                    'message' => langHdl('password_already_used'),
631
                ),
632
                'encode'
633
            );
634
        }
635
636
        // update sessions
637
        $_SESSION['last_pw_change'] = mktime(0, 0, 0, (int) date('m'), (int) date('d'), (int) date('y'));
638
        $_SESSION['validite_pw'] = true;
639
640
        // BEfore updating, check that the pwd is correct
641
        if ($pwdlib->verifyPasswordHash($post_new_password, $post_new_password_hashed) === true) {
642
            $special_action = 'none';
643
            if ($post_change_request === 'reset_user_password_expected') {
644
                $_SESSION['user']['private_key'] = decryptPrivateKey($post_current_password, $dataUser['private_key']);
645
            }
646
647
            // update DB
648
            DB::update(
649
                prefixTable('users'),
650
                array(
651
                    'pw' => $post_new_password_hashed,
652
                    'last_pw_change' => mktime(0, 0, 0, (int) date('m'), (int) date('d'), (int) date('y')),
653
                    'last_pw' => $post_current_password,
654
                    'special' => $special_action,
655
                    'private_key' => encryptPrivateKey($post_new_password, $_SESSION['user']['private_key']),
656
                ),
657
                'id = %i',
658
                $post_user_id
659
            );
660
            // update LOG
661
            logEvents($SETTINGS, 'user_mngt', 'at_user_pwd_changed', (string) $_SESSION['user_id'], $_SESSION['login'], $post_user_id);
662
663
            // Send back
664
            return prepareExchangedData(
665
                array(
666
                    'error' => false,
667
                    'message' => '',
668
                ),
669
                'encode'
670
            );
671
        }
672
        // Send back
673
        return prepareExchangedData(
674
            array(
675
                'error' => true,
676
                'message' => langHdl('pwd_hash_not_correct'),
677
            ),
678
            'encode'
679
        );
680
    }
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 565 is false. This is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
681
}
682
683
684
685
function generateQRCode(
686
    $post_id,
687
    $post_demand_origin,
688
    $post_send_mail,
689
    $post_login,
690
    $post_pwd,
691
    array $SETTINGS
692
): string
693
{
694
    // is this allowed by setting
695
    if ((isset($SETTINGS['ga_reset_by_user']) === false || (int) $SETTINGS['ga_reset_by_user'] !== 1)
696
        && (null === $post_demand_origin || $post_demand_origin !== 'users_management_list')
697
    ) {
698
        // User cannot ask for a new code
699
        return prepareExchangedData(
700
            array(
701
                'error' => true,
702
                'message' => langHdl('error_not_allowed_to'),
703
            ),
704
            'encode'
705
        );
706
    }
707
708
    // Check if user exists
709
    if (null === $post_id || empty($post_id) === true) {
710
        // Get data about user
711
        $data = DB::queryfirstrow(
712
            'SELECT id, email, pw
713
            FROM ' . prefixTable('users') . '
714
            WHERE login = %s',
715
            $post_login
716
        );
717
    } else {
718
        $data = DB::queryfirstrow(
719
            'SELECT id, login, email, pw
720
            FROM ' . prefixTable('users') . '
721
            WHERE id = %i',
722
            $post_id
723
        );
724
        $post_login = $data['login'];
725
    }
726
    // Get number of returned users
727
    $counter = DB::count();
728
729
    // load passwordLib library
730
    $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'] . '/includes/libraries');
731
    $pwdlib->register();
732
    $pwdlib = new PasswordLib\PasswordLib();
733
734
    // Do treatment
735
    if ($counter === 0) {
736
        // Not a registered user !
737
        logEvents($SETTINGS, 'failed_auth', 'user_not_exists', '', stripslashes($post_login), stripslashes($post_login));
738
        return prepareExchangedData(
739
            array(
740
                'error' => true,
741
                'message' => langHdl('no_user'),
742
                'tst' => 1,
743
            ),
744
            'encode'
745
        );
746
    }
747
748
    if (
749
        isset($post_pwd) === true
750
        && isset($data['pw']) === true
751
        && $pwdlib->verifyPasswordHash($post_pwd, $data['pw']) === false
752
        && $post_demand_origin !== 'users_management_list'
753
    ) {
754
        // checked the given password
755
        logEvents($SETTINGS, 'failed_auth', 'user_password_not_correct', '', stripslashes($post_login), stripslashes($post_login));
756
        return prepareExchangedData(
757
            array(
758
                'error' => true,
759
                'message' => langHdl('no_user'),
760
                'tst' => $post_demand_origin,
761
            ),
762
            'encode'
763
        );
764
    }
765
    
766
    if (empty($data['email']) === true) {
767
        return prepareExchangedData(
768
            array(
769
                'error' => true,
770
                'message' => langHdl('no_email'),
771
            ),
772
            'encode'
773
        );
774
    }
775
    
776
    // generate new GA user code
777
    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Authentication/TwoFactorAuth/TwoFactorAuth.php';
778
    $tfa = new Authentication\TwoFactorAuth\TwoFactorAuth($SETTINGS['ga_website_name']);
779
    $gaSecretKey = $tfa->createSecret();
780
    $gaTemporaryCode = GenerateCryptKey(12, false, true, true, false, true, $SETTINGS);
781
782
    DB::update(
783
        prefixTable('users'),
784
        [
785
            'ga' => $gaSecretKey,
786
            'ga_temporary_code' => $gaTemporaryCode,
787
        ],
788
        'id = %i',
789
        $data['id']
790
    );
791
792
    // Log event
793
    logEvents($SETTINGS, 'user_connection', 'at_2fa_google_code_send_by_email', (string) $data['id'], stripslashes($post_login), stripslashes($post_login));
794
795
    // send mail?
796
    if ((int) $post_send_mail === 1) {
797
        json_decode(
798
            sendEmail(
799
                langHdl('email_ga_subject'),
800
                str_replace(
801
                    '#2FACode#',
802
                    $gaTemporaryCode,
803
                    langHdl('email_ga_text')
804
                ),
805
                $data['email'],
806
                $SETTINGS
807
            ),
808
            true
809
        );
810
811
        // send back
812
        return prepareExchangedData(
813
            array(
814
                'error' => false,
815
                'message' => $post_send_mail,
816
                'email' => $data['email'],
817
                'email_result' => str_replace(
818
                    '#email#',
819
                    '<b>' . obfuscateEmail($data['email']) . '</b>',
820
                    addslashes(langHdl('admin_email_result_ok'))
821
                ),
822
            ),
823
            'encode'
824
        );
825
    }
826
    
827
    // send back
828
    return prepareExchangedData(
829
        array(
830
            'error' => false,
831
            'message' => '',
832
            'email' => $data['email'],
833
            'email_result' => str_replace(
834
                '#email#',
835
                '<b>' . obfuscateEmail($data['email']) . '</b>',
836
                addslashes(langHdl('admin_email_result_ok'))
837
            ),
838
        ),
839
        'encode'
840
    );
841
}
842
843
function sendEmailsNotSent(
844
    array $SETTINGS
845
)
846
{
847
    if (isset($SETTINGS['enable_send_email_on_user_login'])
848
        && (int) $SETTINGS['enable_send_email_on_user_login'] === 1
849
    ) {
850
        $row = DB::queryFirstRow(
851
            'SELECT valeur FROM ' . prefixTable('misc') . ' WHERE type = %s AND intitule = %s',
852
            'cron',
853
            'sending_emails'
854
        );
855
856
        if ((int) (time() - $row['valeur']) >= 300 || (int) $row['valeur'] === 0) {
857
            $rows = DB::query(
858
                'SELECT *
859
                FROM ' . prefixTable('emails') .
860
                ' WHERE status != %s',
861
                'sent'
862
            );
863
            foreach ($rows as $record) {
864
                echo $record['increment_id'] . " >> ";
865
                // Send email
866
                $ret = json_decode(
867
                    sendEmail(
868
                        $record['subject'],
869
                        $record['body'],
870
                        $record['receivers'],
871
                        $SETTINGS
872
                    ),
873
                    true
874
                );
875
876
                // update item_id in files table
877
                DB::update(
878
                    prefixTable('emails'),
879
                    array(
880
                        'status' => $ret['error'] === 'error_mail_not_send' ? 'not_sent' : 'sent',
881
                    ),
882
                    'timestamp = %s',
883
                    $record['timestamp']
884
                );
885
            }
886
        }
887
        // update cron time
888
        DB::update(
889
            prefixTable('misc'),
890
            array(
891
                'valeur' => time(),
892
            ),
893
            'intitule = %s AND type = %s',
894
            'sending_emails',
895
            'cron'
896
        );
897
    }
898
}
899
900
function generateGenericPassword(
901
    int $size,
902
    bool $secure,
903
    bool $lowercase,
904
    bool $capitalize,
905
    bool $numerals,
906
    bool $symbols,
907
    array $SETTINGS
908
): string
909
{
910
    if ((int) $size > (int) $SETTINGS['pwd_maximum_length']) {
911
        return prepareExchangedData(
912
            array(
913
                'error_msg' => 'Password length is too long! ',
914
                'error' => 'true',
915
            ),
916
            'encode'
917
        );
918
    }
919
920
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
921
    $generator->register();
922
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
923
924
    // Is PHP7 being used?
925
    if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
926
        $php7generator = new SplClassLoader('PasswordGenerator\RandomGenerator', '../includes/libraries');
927
        $php7generator->register();
928
        $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
929
    }
930
931
    // Manage size
932
    $generator->setLength(($size <= 0) ? 10 : $size);
933
934
    if ($secure === true) {
935
        $generator->setSymbols(true);
936
        $generator->setLowercase(true);
937
        $generator->setUppercase(true);
938
        $generator->setNumbers(true);
939
    } else {
940
        $generator->setLowercase($lowercase);
941
        $generator->setUppercase($capitalize);
942
        $generator->setNumbers($numerals);
943
        $generator->setSymbols($symbols);
944
    }
945
946
    return prepareExchangedData(
947
        array(
948
            'key' => $generator->generatePasswords(),
949
            'error' => '',
950
        ),
951
        'encode'
952
    );
953
}
954
955
function refreshUserItemsSeenList(
956
    array $SETTINGS
957
): string
958
{
959
    // get list of last items seen
960
    $arr_html = array();
961
    $rows = DB::query(
962
        '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
963
        FROM ' . prefixTable('log_items') . ' AS l
964
        RIGHT JOIN ' . prefixTable('items') . ' AS i ON (l.id_item = i.id)
965
        WHERE l.action = %s AND l.id_user = %i
966
        ORDER BY l.date DESC
967
        LIMIT 0, 100',
968
        'at_shown',
969
        $_SESSION['user_id']
970
    );
971
    if (DB::count() > 0) {
972
        foreach ($rows as $record) {
973
            if (in_array($record['id']->id, array_column($arr_html, 'id')) === false) {
974
                array_push(
975
                    $arr_html,
976
                    array(
977
                        'id' => $record['id'],
978
                        'label' => htmlspecialchars(stripslashes(htmlspecialchars_decode($record['label'], ENT_QUOTES)), ENT_QUOTES),
979
                        'tree_id' => $record['id_tree'],
980
                        'perso' => $record['perso'],
981
                        'restricted' => $record['restricted'],
982
                    )
983
                );
984
                if (count($arr_html) >= (int) $SETTINGS['max_latest_items']) {
985
                    break;
986
                }
987
            }
988
        }
989
    }
990
991
    // get wainting suggestions
992
    $nb_suggestions_waiting = 0;
993
    if (
994
        isset($SETTINGS['enable_suggestion']) === true && (int) $SETTINGS['enable_suggestion'] === 1
995
        && ((int) $_SESSION['user_admin'] === 1 || (int) $_SESSION['user_manager'] === 1)
996
    ) {
997
        DB::query('SELECT * FROM ' . prefixTable('suggestion'));
998
        $nb_suggestions_waiting = DB::count();
999
    }
1000
1001
    return json_encode(
1002
        array(
1003
            'error' => '',
1004
            'existing_suggestions' => $nb_suggestions_waiting,
1005
            'html_json' => $arr_html,
1006
        ),
1007
        JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1008
    );
1009
}
1010
1011
function sendingStatistics(
1012
    array $SETTINGS
1013
): void
1014
{
1015
    if (
1016
        isset($SETTINGS['send_statistics_items']) === true
1017
        && isset($SETTINGS['send_stats']) === true
1018
        && isset($SETTINGS['send_stats_time']) === true
1019
        && (int) $SETTINGS['send_stats'] === 1
1020
        && (int) ($SETTINGS['send_stats_time'] + TP_ONE_DAY_SECONDS) > time()
1021
    ) {
1022
        // get statistics data
1023
        $stats_data = getStatisticsData($SETTINGS);
1024
1025
        // get statistics items to share
1026
        $statsToSend = [];
1027
        $statsToSend['ip'] = $_SERVER['SERVER_ADDR'];
1028
        $statsToSend['timestamp'] = time();
1029
        foreach (array_filter(explode(';', $SETTINGS['send_statistics_items'])) as $data) {
1030
            if ($data === 'stat_languages') {
1031
                $tmp = '';
1032
                foreach ($stats_data[$data] as $key => $value) {
1033
                    $tmp .= $tmp === '' ? $key . '-' . $value : ',' . $key . '-' . $value;
1034
                }
1035
                $statsToSend[$data] = $tmp;
1036
            } elseif ($data === 'stat_country') {
1037
                $tmp = '';
1038
                foreach ($stats_data[$data] as $key => $value) {
1039
                    $tmp .= $tmp === '' ? $key . '-' . $value : ',' . $key . '-' . $value;
1040
                }
1041
                $statsToSend[$data] = $tmp;
1042
            } else {
1043
                $statsToSend[$data] = $stats_data[$data];
1044
            }
1045
        }
1046
1047
        // connect to Teampass Statistics database
1048
        $link2 = new MeekroDB(
1049
            'teampass.pw',
1050
            'teampass_user',
1051
            'ZMlEfRzKzFLZNzie',
1052
            'teampass_followup',
1053
            '3306',
1054
            'utf8'
1055
        );
1056
1057
        $link2->insert(
1058
            'statistics',
1059
            $statsToSend
1060
        );
1061
1062
        // update table misc with current timestamp
1063
        DB::update(
1064
            prefixTable('misc'),
1065
            array(
1066
                'valeur' => time(),
1067
            ),
1068
            'type = %s AND intitule = %s',
1069
            'admin',
1070
            'send_stats_time'
1071
        );
1072
1073
        //permits to test only once by session
1074
        $_SESSION['temporary']['send_stats_done'] = true;
1075
        $SETTINGS['send_stats_time'] = time();
1076
1077
        // save change in config file
1078
        handleConfigFile('update', $SETTINGS, 'send_stats_time', $SETTINGS['send_stats_time']);
1079
    }
1080
}
1081
1082
function generateBugReport(
1083
    string $data,
1084
    array $SETTINGS
1085
): string
1086
{
1087
    $config_exclude_vars = array(
1088
        'bck_script_passkey',
1089
        'email_smtp_server',
1090
        'email_auth_username',
1091
        'email_auth_pwd',
1092
        'email_from',
1093
    );
1094
1095
    // Get data
1096
    $post_data = json_decode($data, true);
1097
1098
    // Read config file
1099
    $list_of_options = '';
1100
    $url_found = '';
1101
    $anonym_url = '';
1102
    $tp_config_file = '../includes/config/tp.config.php';
1103
    $data = file($tp_config_file);
1104
    foreach ($data as $line) {
1105
        if (substr($line, 0, 4) === '    ') {
1106
            // Remove extra spaces
1107
            $line = str_replace('    ', '', $line);
1108
1109
            // Identify url to anonymize it
1110
            if (strpos($line, 'cpassman_url') > 0 && empty($url_found) === true) {
1111
                $url_found = substr($line, 19, strlen($line) - 22);
1112
                $tmp = parse_url($url_found);
1113
                $anonym_url = $tmp['scheme'] . '://<anonym_url>' . $tmp['path'];
1114
                $line = "'cpassman_url' => '" . $anonym_url . "\n";
1115
            }
1116
1117
            // Anonymize all urls
1118
            if (empty($anonym_url) === false) {
1119
                $line = str_replace($url_found, $anonym_url, $line);
1120
            }
1121
1122
            // Clear some vars
1123
            foreach ($config_exclude_vars as $var) {
1124
                if (strpos($line, $var) > 0) {
1125
                    $line = "'".$var."' => '<removed>'\n";
1126
                }
1127
            }
1128
1129
            // Complete line to display
1130
            $list_of_options .= $line;
1131
        }
1132
    }
1133
1134
    // Get error
1135
    $err = error_get_last();
1136
1137
    // Get 10 latest errors in Teampass
1138
    $teampass_errors = '';
1139
    $rows = DB::query(
1140
        'SELECT label, date AS error_date
1141
        FROM ' . prefixTable('log_system') . "
1142
        WHERE `type` LIKE 'error'
1143
        ORDER BY `date` DESC
1144
        LIMIT 0, 10"
1145
    );
1146
    if (DB::count() > 0) {
1147
        foreach ($rows as $record) {
1148
            if (empty($teampass_errors) === true) {
1149
                $teampass_errors = ' * ' . date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['error_date']) . ' - ' . $record['label'];
1150
            } else {
1151
                $teampass_errors .= ' * ' . date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['error_date']) . ' - ' . $record['label'];
1152
            }
1153
        }
1154
    }
1155
1156
    $link = mysqli_connect(DB_HOST, DB_USER, DB_PASSWD_CLEAR, DB_NAME, (int) DB_PORT, null);
1157
1158
    // Now prepare text
1159
    $txt = '### Page on which it happened
1160
' . $post_data['current_page'] . '
1161
1162
### Steps to reproduce
1163
1.
1164
2.
1165
3.
1166
1167
### Expected behaviour
1168
Tell us what should happen
1169
1170
1171
### Actual behaviour
1172
Tell us what happens instead
1173
1174
### Server configuration
1175
**Operating system**: ' . php_uname() . '
1176
1177
**Web server:** ' . $_SERVER['SERVER_SOFTWARE'] . '
1178
1179
**Database:** ' . ($link === false ? langHdl('undefined') : mysqli_get_server_info($link)) . '
1180
1181
**PHP version:** ' . PHP_VERSION . '
1182
1183
**Teampass version:** ' . TP_VERSION_FULL . '
1184
1185
**Teampass configuration file:**
1186
```
1187
' . $list_of_options . '
1188
```
1189
1190
**Updated from an older Teampass or fresh install:**
1191
1192
### Client configuration
1193
1194
**Browser:** ' . $post_data['browser_name'] . ' - ' . $post_data['browser_version'] . '
1195
1196
**Operating system:** ' . $post_data['os'] . ' - ' . $post_data['os_archi'] . 'bits
1197
1198
### Logs
1199
1200
#### Web server error log
1201
```
1202
' . $err['message'] . ' - ' . $err['file'] . ' (' . $err['line'] . ')
1203
```
1204
1205
#### Teampass 10 last system errors
1206
```
1207
' . $teampass_errors . '
1208
```
1209
1210
#### Log from the web-browser developer console (CTRL + SHIFT + i)
1211
```
1212
Insert the log here and especially the answer of the query that failed.
1213
```
1214
';
1215
1216
    return prepareExchangedData(
1217
        array(
1218
            'html' => $txt,
1219
            'error' => '',
1220
        ),
1221
        'encode'
1222
    );
1223
}
1224
1225
function isUserPasswordCorrect(
1226
    int $post_user_id,
1227
    string $post_user_password,
1228
    array $SETTINGS
1229
): string
1230
{
1231
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1232
        // Check if user exists
1233
        $userInfo = DB::queryFirstRow(
1234
            'SELECT public_key, private_key, pw
1235
            FROM ' . prefixTable('users') . '
1236
            WHERE id = %i',
1237
            $post_user_id
1238
        );
1239
        if (DB::count() > 0) {
1240
            // Get one item
1241
            $record = DB::queryFirstRow(
1242
                'SELECT id, pw
1243
                FROM ' . prefixTable('items') . '
1244
                WHERE perso = 0'
1245
            );
1246
1247
            // Get itemKey from current user
1248
            $currentUserKey = DB::queryFirstRow(
1249
                'SELECT share_key, increment_id
1250
                FROM ' . prefixTable('sharekeys_items') . '
1251
                WHERE object_id = %i AND user_id = %i',
1252
                $record['id'],
1253
                $post_user_id
1254
            );
1255
1256
            if (count($currentUserKey) > 0) {
1257
                // Decrypt itemkey with user key
1258
                // use old password to decrypt private_key
1259
                $_SESSION['user']['private_key'] = decryptPrivateKey($post_user_password, $userInfo['private_key']);
1260
                $_SESSION['user']['public_key'] = decryptPrivateKey($post_user_password, $userInfo['public_key']);
1261
                $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1262
1263
                if (empty(base64_decode($itemKey)) === false) {
1264
                    // GOOD password
1265
                    return prepareExchangedData(
1266
                        array(
1267
                            'error' => false,
1268
                            'message' => '',
1269
                            'debug' => '',
1270
                        ),
1271
                        'encode'
1272
                    );
1273
                }
1274
            }
1275
            
1276
            // Use the password check
1277
            // load passwordLib library
1278
            $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'] . '/includes/libraries');
1279
            $pwdlib->register();
1280
            $pwdlib = new PasswordLib\PasswordLib();
1281
            
1282
            if ($pwdlib->verifyPasswordHash(htmlspecialchars_decode($post_user_password), $userInfo['pw']) === true) {
1283
                // GOOD password
1284
                return prepareExchangedData(
1285
                    array(
1286
                        'error' => false,
1287
                        'message' => '',
1288
                        'debug' => '',
1289
                    ),
1290
                    'encode'
1291
                );
1292
            }
1293
        }
1294
    }
1295
1296
    return prepareExchangedData(
1297
        array(
1298
            'error' => true,
1299
            'message' => langHdl('password_is_not_correct'),
1300
            'debug' => isset($itemKey) === true ? base64_decode($itemKey) : '',
1301
        ),
1302
        'encode'
1303
    );
1304
}
1305
1306
function changePrivateKeyEncryptionPassword(
1307
    int $post_user_id,
1308
    string $post_current_code,
1309
    string $post_new_code,
1310
    string $post_action_type,
1311
    array $SETTINGS
1312
): string
1313
{
1314
    if (empty($post_new_code) === true) {
1315
        $post_new_code = $_SESSION['user_pwd'];
1316
    }
1317
1318
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1319
        // Get user info
1320
        $userData = DB::queryFirstRow(
1321
            'SELECT private_key
1322
            FROM ' . prefixTable('users') . '
1323
            WHERE id = %i',
1324
            $post_user_id
1325
        );
1326
        if (DB::count() > 0) {
1327
            if ($post_action_type === 'encrypt_privkey_with_user_password') {
1328
                // Here the user has his private key encrypted with an OTC.
1329
                // We need to encrypt it with his real password
1330
                $privateKey = decryptPrivateKey($post_new_code, $userData['private_key']);
1331
                $hashedPrivateKey = encryptPrivateKey($post_current_code, $privateKey);
1332
            } else {
1333
                $privateKey = decryptPrivateKey($post_current_code, $userData['private_key']);
1334
                $hashedPrivateKey = encryptPrivateKey($post_new_code, $privateKey);
1335
            }
1336
1337
            // Update user account
1338
            DB::update(
1339
                prefixTable('users'),
1340
                array(
1341
                    'private_key' => $hashedPrivateKey,
1342
                    'special' => 'none',
1343
                ),
1344
                'id = %i',
1345
                $post_user_id
1346
            );
1347
1348
            // Load superGlobals
1349
            include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1350
            $superGlobal = new protect\SuperGlobal\SuperGlobal();
1351
1352
            $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
1353
        }
1354
1355
        // Return
1356
        return prepareExchangedData(
1357
            array(
1358
                'error' => false,
1359
                'message' => '',
1360
            ),
1361
            'encode'
1362
        );
1363
    }
1364
    
1365
    return prepareExchangedData(
1366
        array(
1367
            'error' => true,
1368
            'message' => langHdl('error_no_user'),
1369
            'debug' => '',
1370
        ),
1371
        'encode'
1372
    );
1373
}
1374
1375
function initializeUserPassword(
1376
    int $post_user_id,
1377
    string $post_special,
1378
    string $post_user_password,
1379
    string $post_self_change,
1380
    array $SETTINGS
1381
): string
1382
{
1383
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1384
        // Get user info
1385
        $userData = DB::queryFirstRow(
1386
            'SELECT email, auth_type, login
1387
            FROM ' . prefixTable('users') . '
1388
            WHERE id = %i',
1389
            $post_user_id
1390
        );
1391
        if (DB::count() > 0 && empty($userData['email']) === false) {
1392
            // If user pwd is empty then generate a new one and send it to user
1393
            if (isset($post_user_password) === false || empty($post_user_password) === true) {
1394
                // Generate new password
1395
                $post_user_password = generateQuickPassword();
1396
            }
1397
1398
            // If LDAP enabled, then
1399
            // check that this password is correct
1400
            $continue = false;
1401
            if ($userData['auth_type'] === 'ldap' && (int) $SETTINGS['ldap_mode'] === 1) {
1402
                $continue = ldapCheckUserPassword(
1403
                    $userData['login'],
1404
                    $post_user_password,
1405
                    $SETTINGS
1406
                );
1407
            }
1408
1409
            if ($continue === true) {
1410
                // Only change if email is successfull
1411
                // GEnerate new keys
1412
                $userKeys = generateUserKeys($post_user_password);
1413
1414
                // load passwordLib library
1415
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1416
                $pwdlib->register();
1417
                $pwdlib = new PasswordLib\PasswordLib();
1418
1419
                // Update user account
1420
                DB::update(
1421
                    prefixTable('users'),
1422
                    array(
1423
                        'special' => $post_special,
1424
                        'pw' => $pwdlib->createPasswordHash($post_user_password),
1425
                        'public_key' => $userKeys['public_key'],
1426
                        'private_key' => $userKeys['private_key'],
1427
                        'last_pw_change' => time(),
1428
                    ),
1429
                    'id = %i',
1430
                    $post_user_id
1431
                );
1432
1433
                // Return
1434
                return prepareExchangedData(
1435
                    array(
1436
                        'error' => false,
1437
                        'message' => '',
1438
                        'user_pwd' => $post_user_password,
1439
                        'user_email' => $userData['email'],
1440
                    ),
1441
                    'encode'
1442
                );
1443
            }
1444
            // Return error
1445
            return prepareExchangedData(
1446
                array(
1447
                    'error' => true,
1448
                    'message' => $continue === false ? langHdl('password_doesnot_correspond_to_ldap_one') : $emailError,
0 ignored issues
show
introduced by
The condition $continue === false is always true.
Loading history...
Comprehensibility Best Practice introduced by
The variable $emailError seems to be never defined.
Loading history...
1449
                    'debug' => '',
1450
                    'self_change' => $post_self_change,
1451
                ),
1452
                'encode'
1453
            );
1454
        }
1455
1456
        // Error
1457
        return prepareExchangedData(
1458
            array(
1459
                'error' => true,
1460
                'message' => langHdl('no_email_set'),
1461
                'debug' => '',
1462
            ),
1463
            'encode'
1464
        );
1465
    }
1466
    
1467
    return prepareExchangedData(
1468
        array(
1469
            'error' => true,
1470
            'message' => langHdl('error_no_user'),
1471
            'debug' => '',
1472
        ),
1473
        'encode'
1474
    );
1475
}
1476
1477
function sendMailToUser(
1478
    string $post_receipt,
1479
    string $post_body,
1480
    string $post_subject,
1481
    array $post_replace,
1482
    array $SETTINGS
1483
): string
1484
{
1485
    if (count($post_replace) > 0 && is_null($post_replace) === false) {
1486
        $post_body = str_replace(
1487
            array_keys($post_replace),
1488
            array_values($post_replace),
1489
            $post_body
1490
        );
1491
    }
1492
    $ret = sendEmail(
1493
        $post_subject,
1494
        $post_body,
1495
        $post_receipt,
1496
        $SETTINGS,
1497
        '',
1498
        false
1499
    );
1500
1501
    $ret = json_decode($ret, true);
1502
1503
    return prepareExchangedData(
1504
        array(
1505
            'error' => empty($ret['error']) === true ? false : true,
1506
            'message' => $ret['message'],
1507
        ),
1508
        'encode'
1509
    );
1510
}
1511
1512
function generateOneTimeCode(
1513
    int $post_user_id,
1514
    array $SETTINGS
1515
): string
1516
{
1517
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1518
        // Get user info
1519
        $userData = DB::queryFirstRow(
1520
            'SELECT email, auth_type, login
1521
            FROM ' . prefixTable('users') . '
1522
            WHERE id = %i',
1523
            $post_user_id
1524
        );
1525
        if (DB::count() > 0 && empty($userData['email']) === false) {
1526
            // Generate pwd
1527
            $password = generateQuickPassword();
1528
1529
            // GEnerate new keys
1530
            $userKeys = generateUserKeys($password);
1531
1532
            // Save in DB
1533
            DB::update(
1534
                prefixTable('users'),
1535
                array(
1536
                    'public_key' => $userKeys['public_key'],
1537
                    'private_key' => $userKeys['private_key'],
1538
                    'special' => 'generate-keys',
1539
                ),
1540
                'id=%i',
1541
                $post_user_id
1542
            );
1543
1544
            return prepareExchangedData(
1545
                array(
1546
                    'error' => false,
1547
                    'message' => '',
1548
                    'userTemporaryCode' => $password,
1549
                ),
1550
                'encode'
1551
            );
1552
        }
1553
        
1554
        return prepareExchangedData(
1555
            array(
1556
                'error' => true,
1557
                'message' => langHdl('no_email_set'),
1558
            ),
1559
            'encode'
1560
        );
1561
    }
1562
        
1563
    return prepareExchangedData(
1564
        array(
1565
            'error' => true,
1566
            'message' => langHdl('error_no_user'),
1567
        ),
1568
        'encode'
1569
    );
1570
}
1571
1572
function startReEncryptingUserSharekeys(
1573
    int $post_user_id,
1574
    bool $post_self_change,
1575
    array $SETTINGS
1576
): string
1577
{
1578
    $post_user_id = is_null($post_user_id) === true ? $_SESSION['user_id'] : $post_user_id;
0 ignored issues
show
introduced by
The condition is_null($post_user_id) === true is always false.
Loading history...
1579
1580
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1581
        // Check if user exists
1582
        DB::queryFirstRow(
1583
            'SELECT *
1584
            FROM ' . prefixTable('users') . '
1585
            WHERE id = %i',
1586
            $post_user_id
1587
        );
1588
        if (DB::count() > 0) {
1589
            // Include libraries
1590
            include_once $SETTINGS['cpassman_dir'] . '/sources/aes.functions.php';
1591
1592
            // CLear old sharekeys
1593
            if ($post_self_change === false) {
1594
                deleteUserObjetsKeys($post_user_id, $SETTINGS);
1595
            }
1596
1597
            // Continu with next step
1598
            return prepareExchangedData(
1599
                array(
1600
                    'error' => false,
1601
                    'message' => '',
1602
                    'step' => 'step1',
1603
                    'userId' => $post_user_id,
1604
                    'start' => 0,
1605
                    'self_change' => $post_self_change,
1606
                ),
1607
                'encode'
1608
            );
1609
        }
1610
        // Nothing to do
1611
        return prepareExchangedData(
1612
            array(
1613
                'error' => true,
1614
                'message' => langHdl('error_no_user'),
1615
            ),
1616
            'encode'
1617
        );
1618
    }
1619
1620
    return prepareExchangedData(
1621
        array(
1622
            'error' => true,
1623
            'message' => langHdl('error_no_user'),
1624
        ),
1625
        'encode'
1626
    );
1627
}
1628
1629
function continueReEncryptingUserSharekeys(
1630
    int $post_user_id,
1631
    bool $post_self_change,
1632
    string $post_action,
1633
    int $post_start,
1634
    int $post_length,
1635
    array $SETTINGS
1636
): string
1637
{
1638
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
1639
        // Check if user exists
1640
        $userInfo = DB::queryFirstRow(
1641
            'SELECT public_key
1642
            FROM ' . prefixTable('users') . '
1643
            WHERE id = %i',
1644
            $post_user_id
1645
        );
1646
        if (DB::count() > 0) {
1647
            // Include libraries
1648
            include_once $SETTINGS['cpassman_dir'] . '/sources/aes.functions.php';
1649
1650
            // WHAT STEP TO PERFORM?
1651
            if ($post_action === 'step0') {
1652
                // CLear old sharekeys
1653
                if ($post_self_change === false) {
1654
                    deleteUserObjetsKeys($post_user_id, $SETTINGS);
1655
                }
1656
1657
                $post_action = 'step1';
1658
            }
1659
1660
            // STEP 1 - ITEMS
1661
            if ($post_action === 'step1') {
1662
                $return = continueReEncryptingUserSharekeysStep1(
1663
                    $post_user_id,
1664
                    $post_self_change,
0 ignored issues
show
Bug introduced by
$post_self_change of type boolean is incompatible with the type string expected by parameter $post_self_change of continueReEncryptingUserSharekeysStep1(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1664
                    /** @scrutinizer ignore-type */ $post_self_change,
Loading history...
1665
                    $post_action,
1666
                    $post_start,
1667
                    $post_length,
1668
                    $userInfo['public_key'],
1669
                    $SETTINGS
1670
                );
1671
1672
                $next_start = $return['next_start'];
1673
                $post_action = $return['post_action'];
1674
            }
1675
1676
            // STEP 2 - LOGS
1677
            if ($post_action === 'step2') {
1678
                $return = continueReEncryptingUserSharekeysStep2(
1679
                    $post_user_id,
1680
                    $post_self_change,
0 ignored issues
show
Bug introduced by
$post_self_change of type boolean is incompatible with the type string expected by parameter $post_self_change of continueReEncryptingUserSharekeysStep2(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1680
                    /** @scrutinizer ignore-type */ $post_self_change,
Loading history...
1681
                    $post_action,
1682
                    $post_start,
1683
                    $post_length,
1684
                    $userInfo['public_key'],
1685
                    $SETTINGS
1686
                );
1687
1688
                $next_start = $return['next_start'];
1689
                $post_action = $return['post_action'];
1690
            }
1691
1692
            // STEP 3 - FIELDS
1693
            if ($post_action === 'step3') {
1694
                $return = continueReEncryptingUserSharekeysStep3(
1695
                    $post_user_id,
1696
                    $post_self_change,
0 ignored issues
show
Bug introduced by
$post_self_change of type boolean is incompatible with the type string expected by parameter $post_self_change of continueReEncryptingUserSharekeysStep3(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1696
                    /** @scrutinizer ignore-type */ $post_self_change,
Loading history...
1697
                    $post_action,
1698
                    $post_start,
1699
                    $post_length,
1700
                    $userInfo['public_key'],
1701
                    $SETTINGS
1702
                );
1703
1704
                $next_start = $return['next_start'];
1705
                $post_action = $return['post_action'];
1706
            }
1707
            
1708
            // STEP 4 - SUGGESTIONS
1709
            if ($post_action === 'step4') {
1710
                $return = continueReEncryptingUserSharekeysStep4(
1711
                    $post_user_id,
1712
                    $post_self_change,
0 ignored issues
show
Bug introduced by
$post_self_change of type boolean is incompatible with the type string expected by parameter $post_self_change of continueReEncryptingUserSharekeysStep4(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1712
                    /** @scrutinizer ignore-type */ $post_self_change,
Loading history...
1713
                    $post_action,
1714
                    $post_start,
1715
                    $post_length,
1716
                    $userInfo['public_key'],
1717
                    $SETTINGS
1718
                );
1719
1720
                $next_start = $return['next_start'];
1721
                $post_action = $return['post_action'];
1722
            }
1723
            
1724
            // STEP 5 - FILES
1725
            if ($post_action === 'step5') {
1726
                $return = continueReEncryptingUserSharekeysStep5(
1727
                    $post_user_id,
1728
                    $post_self_change,
0 ignored issues
show
Bug introduced by
$post_self_change of type boolean is incompatible with the type string expected by parameter $post_self_change of continueReEncryptingUserSharekeysStep5(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1728
                    /** @scrutinizer ignore-type */ $post_self_change,
Loading history...
1729
                    $post_action,
1730
                    $post_start,
1731
                    $post_length,
1732
                    $userInfo['public_key'],
1733
                    $SETTINGS
1734
                );
1735
1736
                $next_start = $return['next_start'];
1737
                $post_action = $return['post_action'];
1738
            }
1739
            
1740
            // STEP 6 - PERSONAL ITEMS
1741
            if ($post_action === 'step6') {
1742
                $return = continueReEncryptingUserSharekeysStep6(
1743
                    $post_user_id,
1744
                    $post_self_change,
0 ignored issues
show
Bug introduced by
$post_self_change of type boolean is incompatible with the type string expected by parameter $post_self_change of continueReEncryptingUserSharekeysStep6(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1744
                    /** @scrutinizer ignore-type */ $post_self_change,
Loading history...
1745
                    $post_action,
1746
                    $post_start,
1747
                    $post_length,
1748
                    $userInfo['public_key'],
1749
                    $SETTINGS
1750
                );
1751
1752
                $next_start = $return['next_start'];
1753
                $post_action = $return['post_action'];
1754
            }
1755
1756
            // Continu with next step
1757
            return prepareExchangedData(
1758
                array(
1759
                    'error' => false,
1760
                    'message' => '',
1761
                    'step' => $post_action,
1762
                    'start' => isset($next_start) === true ? $next_start : 0,
1763
                    'userId' => $post_user_id,
1764
                    'self_change' => $post_self_change,
1765
                ),
1766
                'encode'
1767
            );
1768
        }
1769
        
1770
        // Nothing to do
1771
        return prepareExchangedData(
1772
            array(
1773
                'error' => false,
1774
                'message' => '',
1775
                'step' => 'finished',
1776
                'start' => 0,
1777
                'userId' => $post_user_id,
1778
                'self_change' => $post_self_change,
1779
            ),
1780
            'encode'
1781
        );
1782
    }
1783
    
1784
    // Nothing to do
1785
    return prepareExchangedData(
1786
        array(
1787
            'error' => true,
1788
            'message' => langHdl('error_no_user'),
1789
        ),
1790
        'encode'
1791
    );
1792
}
1793
1794
function continueReEncryptingUserSharekeysStep1(
1795
    int $post_user_id,
1796
    string $post_self_change,
1797
    string $post_action,
1798
    int $post_start,
1799
    int $post_length,
1800
    string $user_public_key,
1801
    array $SETTINGS
1802
): string
1803
{
1804
    // Loop on items
1805
    $rows = DB::query(
1806
        'SELECT id, pw
1807
        FROM ' . prefixTable('items') . '
1808
        WHERE perso = 0
1809
        LIMIT ' . $post_start . ', ' . $post_length
1810
    );
1811
    foreach ($rows as $record) {
1812
        // Get itemKey from current user
1813
        $currentUserKey = DB::queryFirstRow(
1814
            'SELECT share_key, increment_id
1815
            FROM ' . prefixTable('sharekeys_items') . '
1816
            WHERE object_id = %i AND user_id = %i',
1817
            $record['id'],
1818
            $_SESSION['user_id']
1819
        );
1820
        if (count($currentUserKey) === 0) continue;
1821
1822
        // Decrypt itemkey with admin key
1823
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1824
        
1825
        // Encrypt Item key
1826
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
1827
        
1828
        // Save the key in DB
1829
        if ($post_self_change === false) {
1830
            DB::insert(
1831
                prefixTable('sharekeys_items'),
1832
                array(
1833
                    'object_id' => (int) $record['id'],
1834
                    'user_id' => (int) $post_user_id,
1835
                    'share_key' => $share_key_for_item,
1836
                )
1837
            );
1838
        } else {
1839
            // Get itemIncrement from selected user
1840
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
1841
                $currentUserKey = DB::queryFirstRow(
1842
                    'SELECT increment_id
1843
                    FROM ' . prefixTable('sharekeys_items') . '
1844
                    WHERE object_id = %i AND user_id = %i',
1845
                    $record['id'],
1846
                    $post_user_id
1847
                );
1848
1849
                if (DB::count() > 0) {
1850
                    // NOw update
1851
                    DB::update(
1852
                        prefixTable('sharekeys_items'),
1853
                        array(
1854
                            'share_key' => $share_key_for_item,
1855
                        ),
1856
                        'increment_id = %i',
1857
                        $currentUserKey['increment_id']
1858
                    );
1859
                } else {
1860
                    DB::insert(
1861
                        prefixTable('sharekeys_items'),
1862
                        array(
1863
                            'object_id' => (int) $record['id'],
1864
                            'user_id' => (int) $post_user_id,
1865
                            'share_key' => $share_key_for_item,
1866
                        )
1867
                    );
1868
                }
1869
            }
1870
        }
1871
    }
1872
1873
    // SHould we change step?
1874
    DB::query(
1875
        'SELECT *
1876
        FROM ' . prefixTable('items') . '
1877
        WHERE perso = 0'
1878
    );
1879
1880
    $next_start = (int) $post_start + (int) $post_length;
1881
    return [
0 ignored issues
show
Bug Best Practice introduced by
The expression return array('next_start...() ? 'step2' : 'step1') returns the type array<string,integer|string> which is incompatible with the type-hinted return string.
Loading history...
1882
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
1883
        'post_action' => $next_start > DB::count() ? 'step2' : 'step1',
1884
    ];
1885
}
1886
1887
function continueReEncryptingUserSharekeysStep2(
1888
    int $post_user_id,
1889
    string $post_self_change,
1890
    string $post_action,
1891
    int $post_start,
1892
    int $post_length,
1893
    string $user_public_key,
1894
    array $SETTINGS
1895
): array
1896
{
1897
    // Loop on logs
1898
    $rows = DB::query(
1899
        'SELECT increment_id
1900
        FROM ' . prefixTable('log_items') . '
1901
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"
1902
        LIMIT ' . $post_start . ', ' . $post_length
1903
    );
1904
    foreach ($rows as $record) {
1905
        // Get itemKey from current user
1906
        $currentUserKey = DB::queryFirstRow(
1907
            'SELECT share_key
1908
            FROM ' . prefixTable('sharekeys_logs') . '
1909
            WHERE object_id = %i AND user_id = %i',
1910
            $record['increment_id'],
1911
            $_SESSION['user_id']
1912
        );
1913
1914
        // Decrypt itemkey with admin key
1915
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1916
1917
        // Encrypt Item key
1918
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
1919
1920
        // Save the key in DB
1921
        if ($post_self_change === false) {
1922
            DB::insert(
1923
                prefixTable('sharekeys_logs'),
1924
                array(
1925
                    'object_id' => (int) $record['increment_id'],
1926
                    'user_id' => (int) $post_user_id,
1927
                    'share_key' => $share_key_for_item,
1928
                )
1929
            );
1930
        } else {
1931
            // Get itemIncrement from selected user
1932
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
1933
                $currentUserKey = DB::queryFirstRow(
1934
                    'SELECT increment_id
1935
                    FROM ' . prefixTable('sharekeys_items') . '
1936
                    WHERE object_id = %i AND user_id = %i',
1937
                    $record['id'],
1938
                    $post_user_id
1939
                );
1940
            }
1941
1942
            // NOw update
1943
            DB::update(
1944
                prefixTable('sharekeys_logs'),
1945
                array(
1946
                    'share_key' => $share_key_for_item,
1947
                ),
1948
                'increment_id = %i',
1949
                $currentUserKey['increment_id']
1950
            );
1951
        }
1952
    }
1953
1954
    // SHould we change step?
1955
    DB::query(
1956
        'SELECT increment_id
1957
        FROM ' . prefixTable('log_items') . '
1958
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"'
1959
    );
1960
1961
    $next_start = (int) $post_start + (int) $post_length;
1962
    return [
1963
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
1964
        'post_action' => $next_start > DB::count() ? 'step3' : 'step2',
1965
    ];
1966
}
1967
1968
function continueReEncryptingUserSharekeysStep3(
1969
    int $post_user_id,
1970
    string $post_self_change,
1971
    string $post_action,
1972
    int $post_start,
1973
    int $post_length,
1974
    string $user_public_key,
1975
    array $SETTINGS
1976
): array
1977
{
1978
    // Loop on fields
1979
    $rows = DB::query(
1980
        'SELECT id
1981
        FROM ' . prefixTable('categories_items') . '
1982
        WHERE encryption_type = "teampass_aes"
1983
        LIMIT ' . $post_start . ', ' . $post_length
1984
    );
1985
    foreach ($rows as $record) {
1986
        // Get itemKey from current user
1987
        $currentUserKey = DB::queryFirstRow(
1988
            'SELECT share_key
1989
            FROM ' . prefixTable('sharekeys_fields') . '
1990
            WHERE object_id = %i AND user_id = %i',
1991
            $record['id'],
1992
            $_SESSION['user_id']
1993
        );
1994
1995
        // Decrypt itemkey with admin key
1996
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1997
1998
        // Encrypt Item key
1999
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2000
2001
        // Save the key in DB
2002
        if ($post_self_change === false) {
2003
            DB::insert(
2004
                prefixTable('sharekeys_fields'),
2005
                array(
2006
                    'object_id' => (int) $record['id'],
2007
                    'user_id' => (int) $post_user_id,
2008
                    'share_key' => $share_key_for_item,
2009
                )
2010
            );
2011
        } else {
2012
            // Get itemIncrement from selected user
2013
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2014
                $currentUserKey = DB::queryFirstRow(
2015
                    'SELECT increment_id
2016
                    FROM ' . prefixTable('sharekeys_items') . '
2017
                    WHERE object_id = %i AND user_id = %i',
2018
                    $record['id'],
2019
                    $post_user_id
2020
                );
2021
            }
2022
2023
            // NOw update
2024
            DB::update(
2025
                prefixTable('sharekeys_fields'),
2026
                array(
2027
                    'share_key' => $share_key_for_item,
2028
                ),
2029
                'increment_id = %i',
2030
                $currentUserKey['increment_id']
2031
            );
2032
        }
2033
    }
2034
2035
    // SHould we change step?
2036
    DB::query(
2037
        'SELECT *
2038
        FROM ' . prefixTable('categories_items') . '
2039
        WHERE encryption_type = "teampass_aes"'
2040
    );
2041
2042
    $next_start = (int) $post_start + (int) $post_length;
2043
    return [
2044
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2045
        'post_action' => $next_start > DB::count() ? 'step4' : 'step3',
2046
    ];
2047
}
2048
2049
function continueReEncryptingUserSharekeysStep4(
2050
    int $post_user_id,
2051
    string $post_self_change,
2052
    string $post_action,
2053
    int $post_start,
2054
    int $post_length,
2055
    string $user_public_key,
2056
    array $SETTINGS
2057
): array
2058
{
2059
    // Loop on suggestions
2060
    $rows = DB::query(
2061
        'SELECT id
2062
        FROM ' . prefixTable('suggestion') . '
2063
        LIMIT ' . $post_start . ', ' . $post_length
2064
    );
2065
    foreach ($rows as $record) {
2066
        // Get itemKey from current user
2067
        $currentUserKey = DB::queryFirstRow(
2068
            'SELECT share_key
2069
            FROM ' . prefixTable('sharekeys_suggestions') . '
2070
            WHERE object_id = %i AND user_id = %i',
2071
            $record['id'],
2072
            $_SESSION['user_id']
2073
        );
2074
2075
        // Decrypt itemkey with admin key
2076
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2077
2078
        // Encrypt Item key
2079
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2080
2081
        // Save the key in DB
2082
        if ($post_self_change === false) {
2083
            DB::insert(
2084
                prefixTable('sharekeys_suggestions'),
2085
                array(
2086
                    'object_id' => (int) $record['id'],
2087
                    'user_id' => (int) $post_user_id,
2088
                    'share_key' => $share_key_for_item,
2089
                )
2090
            );
2091
        } else {
2092
            // Get itemIncrement from selected user
2093
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2094
                $currentUserKey = DB::queryFirstRow(
2095
                    'SELECT increment_id
2096
                    FROM ' . prefixTable('sharekeys_items') . '
2097
                    WHERE object_id = %i AND user_id = %i',
2098
                    $record['id'],
2099
                    $post_user_id
2100
                );
2101
            }
2102
2103
            // NOw update
2104
            DB::update(
2105
                prefixTable('sharekeys_suggestions'),
2106
                array(
2107
                    'share_key' => $share_key_for_item,
2108
                ),
2109
                'increment_id = %i',
2110
                $currentUserKey['increment_id']
2111
            );
2112
        }
2113
    }
2114
2115
    // SHould we change step?
2116
    DB::query(
2117
        'SELECT *
2118
        FROM ' . prefixTable('suggestion')
2119
    );
2120
2121
    $next_start = (int) $post_start + (int) $post_length;
2122
    return [
2123
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2124
        'post_action' => $next_start > DB::count() ? 'step5' : 'step4',
2125
    ];
2126
}
2127
2128
function continueReEncryptingUserSharekeysStep5(
2129
    int $post_user_id,
2130
    string $post_self_change,
2131
    string $post_action,
2132
    int $post_start,
2133
    int $post_length,
2134
    string $user_public_key,
2135
    array $SETTINGS
2136
): array
2137
{
2138
    // Loop on files
2139
    $rows = DB::query(
2140
        'SELECT id
2141
        FROM ' . prefixTable('files') . '
2142
        WHERE status = "' . TP_ENCRYPTION_NAME . '"
2143
        LIMIT ' . $post_start . ', ' . $post_length
2144
    ); //aes_encryption
2145
    foreach ($rows as $record) {
2146
        // Get itemKey from current user
2147
        $currentUserKey = DB::queryFirstRow(
2148
            'SELECT share_key
2149
            FROM ' . prefixTable('sharekeys_files') . '
2150
            WHERE object_id = %i AND user_id = %i',
2151
            $record['id'],
2152
            $_SESSION['user_id']
2153
        );
2154
2155
        // Decrypt itemkey with admin key
2156
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2157
2158
        // Encrypt Item key
2159
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2160
2161
        // Save the key in DB
2162
        if ($post_self_change === false) {
2163
            DB::insert(
2164
                prefixTable('sharekeys_files'),
2165
                array(
2166
                    'object_id' => (int) $record['id'],
2167
                    'user_id' => (int) $post_user_id,
2168
                    'share_key' => $share_key_for_item,
2169
                )
2170
            );
2171
        } else {
2172
            // Get itemIncrement from selected user
2173
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2174
                $currentUserKey = DB::queryFirstRow(
2175
                    'SELECT increment_id
2176
                    FROM ' . prefixTable('sharekeys_items') . '
2177
                    WHERE object_id = %i AND user_id = %i',
2178
                    $record['id'],
2179
                    $post_user_id
2180
                );
2181
            }
2182
2183
            // NOw update
2184
            DB::update(
2185
                prefixTable('sharekeys_files'),
2186
                array(
2187
                    'share_key' => $share_key_for_item,
2188
                ),
2189
                'increment_id = %i',
2190
                $currentUserKey['increment_id']
2191
            );
2192
        }
2193
    }
2194
2195
    // SHould we change step?
2196
    DB::query(
2197
        'SELECT *
2198
        FROM ' . prefixTable('files') . '
2199
        WHERE status = "' . TP_ENCRYPTION_NAME . '"'
2200
    );
2201
2202
    $next_start = (int) $post_start + (int) $post_length;
2203
    return [
2204
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2205
        'post_action' => $next_start > DB::count() ? 'step6' : 'step5',
2206
    ];
2207
}
2208
2209
function continueReEncryptingUserSharekeysStep6(
2210
    int $post_user_id,
2211
    string $post_self_change,
2212
    string $post_action,
2213
    int $post_start,
2214
    int $post_length,
2215
    string $user_public_key,
2216
    array $SETTINGS
2217
): array
2218
{
2219
    // IF USER IS NOT THE SAME
2220
    if ((int) $post_user_id === (int) $_SESSION['user_id']) {
2221
        return [
2222
            'next_start' => 0,
2223
            'post_action' => 'finished',
2224
        ];
2225
    }
2226
    
2227
    // Loop on persoanl items
2228
    if (count($_SESSION['personal_folders']) > 0) {
2229
        $rows = DB::query(
2230
            'SELECT id, pw
2231
            FROM ' . prefixTable('items') . '
2232
            WHERE perso = 1 AND id_tree IN %ls
2233
            LIMIT ' . $post_start . ', ' . $post_length,
2234
            $_SESSION['personal_folders']
2235
        );
2236
        foreach ($rows as $record) {
2237
            // Get itemKey from current user
2238
            $currentUserKey = DB::queryFirstRow(
2239
                'SELECT share_key, increment_id
2240
                FROM ' . prefixTable('sharekeys_items') . '
2241
                WHERE object_id = %i AND user_id = %i',
2242
                $record['id'],
2243
                $_SESSION['user_id']
2244
            );
2245
2246
            // Decrypt itemkey with admin key
2247
            $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2248
2249
            // Encrypt Item key
2250
            $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2251
2252
            // Save the key in DB
2253
            if ($post_self_change === false) {
2254
                DB::insert(
2255
                    prefixTable('sharekeys_items'),
2256
                    array(
2257
                        'object_id' => (int) $record['id'],
2258
                        'user_id' => (int) $post_user_id,
2259
                        'share_key' => $share_key_for_item,
2260
                    )
2261
                );
2262
            } else {
2263
                // Get itemIncrement from selected user
2264
                if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2265
                    $currentUserKey = DB::queryFirstRow(
2266
                        'SELECT increment_id
2267
                        FROM ' . prefixTable('sharekeys_items') . '
2268
                        WHERE object_id = %i AND user_id = %i',
2269
                        $record['id'],
2270
                        $post_user_id
2271
                    );
2272
                }
2273
2274
                // NOw update
2275
                DB::update(
2276
                    prefixTable('sharekeys_items'),
2277
                    array(
2278
                        'share_key' => $share_key_for_item,
2279
                    ),
2280
                    'increment_id = %i',
2281
                    $currentUserKey['increment_id']
2282
                );
2283
            }
2284
        }
2285
    }
2286
2287
    // SHould we change step?
2288
    DB::query(
2289
        'SELECT *
2290
        FROM ' . prefixTable('items') . '
2291
        WHERE perso = 0'
2292
    );
2293
2294
    $next_start = (int) $post_start + (int) $post_length;
2295
    return [
2296
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2297
        'post_action' => $next_start > DB::count() ? 'finished' : 'step6',
2298
    ];
2299
}
2300
2301
function migrateTo3_DoUserPersonalItemsEncryption(
2302
    int $post_user_id,
2303
    int $post_start,
2304
    int $post_length,
2305
    string $post_user_psk,
2306
    array $SETTINGS
2307
) {
2308
    $next_step = '';
2309
2310
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
2311
        // Check if user exists
2312
        $userInfo = DB::queryFirstRow(
2313
            'SELECT public_key, encrypted_psk
2314
            FROM ' . prefixTable('users') . '
2315
            WHERE id = %i',
2316
            $post_user_id
2317
        );
2318
        if (DB::count() > 0) {
2319
            // check if psk is correct.
2320
            if (empty($userInfo['encrypted_psk']) === false) {
2321
                $user_key_encoded = defuse_validate_personal_key(
2322
                    $post_user_psk,
2323
                    $userInfo['encrypted_psk']
2324
                );
2325
2326
                if (strpos($user_key_encoded, "Error ") !== false) {
2327
                    return prepareExchangedData(
2328
                        array(
2329
                            'error' => true,
2330
                            'message' => langHdl('bad_psk'),
2331
                        ),
2332
                        'encode'
2333
                    );
2334
                }
2335
2336
                // Loop on persoanl items
2337
                $rows = DB::query(
2338
                    'SELECT id, pw
2339
                    FROM ' . prefixTable('items') . '
2340
                    WHERE perso = 1 AND id_tree IN %ls
2341
                    LIMIT ' . $post_start . ', ' . $post_length,
2342
                    $_SESSION['personal_folders']
2343
                );
2344
                $countUserPersonalItems = DB::count();
2345
                foreach ($rows as $record) {
2346
                    if ($record['encryption_type'] !== 'teampass_aes') {
2347
                        // Decrypt with Defuse
2348
                        $passwd = cryption(
2349
                            $record['pw'],
2350
                            $user_key_encoded,
2351
                            'decrypt',
2352
                            $SETTINGS
2353
                        );
2354
2355
                        // Encrypt with Object Key
2356
                        $cryptedStuff = doDataEncryption($passwd['string']);
2357
2358
                        // Store new password in DB
2359
                        DB::update(
2360
                            prefixTable('items'),
2361
                            array(
2362
                                'pw' => $cryptedStuff['encrypted'],
2363
                                'encryption_type' => 'teampass_aes',
2364
                            ),
2365
                            'id = %i',
2366
                            $record['id']
2367
                        );
2368
2369
                        // Insert in DB the new object key for this item by user
2370
                        DB::insert(
2371
                            prefixTable('sharekeys_items'),
2372
                            array(
2373
                                'object_id' => (int) $record['id'],
2374
                                'user_id' => (int) $post_user_id,
2375
                                'share_key' => encryptUserObjectKey($cryptedStuff['objectKey'], $userInfo['public_key']),
2376
                            )
2377
                        );
2378
2379
2380
                        // Does this item has Files?
2381
                        // Loop on files
2382
                        $rows = DB::query(
2383
                            'SELECT id, file
2384
                            FROM ' . prefixTable('files') . '
2385
                            WHERE status != %s
2386
                            AND id_item = %i',
2387
                            TP_ENCRYPTION_NAME,
2388
                            $record['id']
2389
                        );
2390
                        //aes_encryption
2391
                        foreach ($rows as $record2) {
2392
                            // Now decrypt the file
2393
                            prepareFileWithDefuse(
2394
                                'decrypt',
2395
                                $SETTINGS['path_to_upload_folder'] . '/' . $record2['file'],
2396
                                $SETTINGS['path_to_upload_folder'] . '/' . $record2['file'] . '.delete',
2397
                                $SETTINGS,
2398
                                $post_user_psk
2399
                            );
2400
2401
                            // Encrypt the file
2402
                            $encryptedFile = encryptFile($record2['file'] . '.delete', $SETTINGS['path_to_upload_folder']);
2403
2404
                            DB::update(
2405
                                prefixTable('files'),
2406
                                array(
2407
                                    'file' => $encryptedFile['fileHash'],
2408
                                    'status' => TP_ENCRYPTION_NAME,
2409
                                ),
2410
                                'id = %i',
2411
                                $record2['id']
2412
                            );
2413
2414
                            // Save key
2415
                            DB::insert(
2416
                                prefixTable('sharekeys_files'),
2417
                                array(
2418
                                    'object_id' => (int) $record2['id'],
2419
                                    'user_id' => (int) $_SESSION['user_id'],
2420
                                    'share_key' => encryptUserObjectKey($encryptedFile['objectKey'], $_SESSION['user']['public_key']),
2421
                                )
2422
                            );
2423
2424
                            // Unlink original file
2425
                            unlink($SETTINGS['path_to_upload_folder'] . '/' . $record2['file']);
2426
                        }
2427
                    }
2428
                }
2429
2430
                // SHould we change step?
2431
                $next_start = (int) $post_start + (int) $post_length;
2432
                if ($next_start > $countUserPersonalItems) {
2433
                    // Now update user
2434
                    DB::update(
2435
                        prefixTable('users'),
2436
                        array(
2437
                            'special' => 'none',
2438
                            'upgrade_needed' => 0,
2439
                            'encrypted_psk' => '',
2440
                        ),
2441
                        'id = %i',
2442
                        $post_user_id
2443
                    );
2444
2445
                    $next_step = 'finished';
2446
                    $next_start = 0;
2447
                }
2448
2449
                // Continu with next step
2450
                return prepareExchangedData(
2451
                    array(
2452
                        'error' => false,
2453
                        'message' => '',
2454
                        'step' => $next_step,
2455
                        'start' => $next_start,
2456
                        'userId' => $post_user_id
2457
                    ),
2458
                    'encode'
2459
                );
2460
            }
2461
        }
2462
        
2463
        // Nothing to do
2464
        return prepareExchangedData(
2465
            array(
2466
                'error' => true,
2467
                'message' => langHdl('error_no_user'),
2468
            ),
2469
            'encode'
2470
        );
2471
    }
2472
    
2473
    // Nothing to do
2474
    return prepareExchangedData(
2475
        array(
2476
            'error' => true,
2477
            'message' => langHdl('error_no_user'),
2478
        ),
2479
        'encode'
2480
    );
2481
}
2482
2483
2484
function getUserInfo(
2485
    int $post_user_id,
2486
    string $post_fields,
2487
    array $SETTINGS
2488
)
2489
{
2490
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
2491
        // Get user info
2492
        $userData = DB::queryFirstRow(
2493
            'SELECT '.$post_fields.'
2494
            FROM ' . prefixTable('users') . '
2495
            WHERE id = %i',
2496
            $post_user_id
2497
        );
2498
        if (DB::count() > 0) {
2499
            return prepareExchangedData(
2500
                array(
2501
                    'error' => false,
2502
                    'message' => '',
2503
                    'queryResults' => $userData,
2504
                ),
2505
                'encode'
2506
            );
2507
        }
2508
    }
2509
    return prepareExchangedData(
2510
        array(
2511
            'error' => true,
2512
            'message' => langHdl('error_no_user'),
2513
        ),
2514
        'encode'
2515
    );
2516
}
2517
2518
function changeUserAuthenticationPassword(
2519
    int $post_user_id,
2520
    string $post_current_pwd,
2521
    string $post_new_pwd,
2522
    array $SETTINGS
2523
)
2524
{
2525
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
2526
        // Get user info
2527
        $userData = DB::queryFirstRow(
2528
            'SELECT auth_type, login, private_key
2529
            FROM ' . prefixTable('users') . '
2530
            WHERE id = %i',
2531
            $post_user_id
2532
        );
2533
        if (DB::count() > 0) {
2534
            // Now check if current password is correct
2535
            // For this, just check if it is possible to decrypt the privatekey
2536
            // And compare it to the one in session
2537
            $privateKey = decryptPrivateKey($post_current_pwd, $userData['private_key']);
2538
2539
            // Load superGlobals
2540
            include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2541
            $superGlobal = new protect\SuperGlobal\SuperGlobal();
2542
2543
            if ($superGlobal->get('private_key', 'SESSION', 'user') === $privateKey) {
2544
                // Encrypt it with new password
2545
                $hashedPrivateKey = encryptPrivateKey($post_new_pwd, $privateKey);
2546
2547
                // Generate new hash for auth password
2548
                // load passwordLib library
2549
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2550
                $pwdlib->register();
2551
                $pwdlib = new PasswordLib\PasswordLib();
2552
2553
                // Prepare variables
2554
                $newPw = $pwdlib->createPasswordHash($post_new_pwd);
2555
2556
                // Update user account
2557
                DB::update(
2558
                    prefixTable('users'),
2559
                    array(
2560
                        'private_key' => $hashedPrivateKey,
2561
                        'pw' => $newPw,
2562
                        'special' => 'none',
2563
                    ),
2564
                    'id = %i',
2565
                    $post_user_id
2566
                );
2567
2568
                $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2569
2570
                return prepareExchangedData(
2571
                    array(
2572
                        'error' => false,
2573
                        'message' => langHdl('done'),'',
2574
                    ),
2575
                    'encode'
2576
                );
2577
            }
2578
            
2579
            // ERROR
2580
            return prepareExchangedData(
2581
                array(
2582
                    'error' => true,
2583
                    'message' => langHdl('bad_password'),
2584
                ),
2585
                'encode'
2586
            );
2587
        }
2588
    }
2589
        
2590
    return prepareExchangedData(
2591
        array(
2592
            'error' => true,
2593
            'message' => langHdl('error_no_user'),
2594
        ),
2595
        'encode'
2596
    );
2597
}
2598
2599
            
2600
function changeUserLDAPAuthenticationPassword(
2601
    int $post_user_id,
2602
    string $post_previous_pwd,
2603
    string $post_current_pwd,
2604
    array $SETTINGS
2605
)
2606
{
2607
    if (is_null($post_user_id) === false && isset($post_user_id) === true && empty($post_user_id) === false) {
2608
        // Get user info
2609
        $userData = DB::queryFirstRow(
2610
            'SELECT auth_type, login, private_key, special
2611
            FROM ' . prefixTable('users') . '
2612
            WHERE id = %i',
2613
            $post_user_id
2614
        );
2615
        
2616
        if (DB::count() > 0) {
2617
            // Now check if current password is correct (only if not ldap)
2618
            if ($userData['auth_type'] === 'ldap' && $userData['special'] === 'auth-pwd-change') {
2619
                // As it is a change for an LDAP user
2620
                
2621
                // Now check if current password is correct
2622
                // For this, just check if it is possible to decrypt the privatekey
2623
                // And compare it to the one in session
2624
                $privateKey = decryptPrivateKey($post_previous_pwd, $userData['private_key']);
2625
2626
                // Encrypt it with new password
2627
                $hashedPrivateKey = encryptPrivateKey($post_current_pwd, $privateKey);
2628
2629
                // Update user account
2630
                DB::update(
2631
                    prefixTable('users'),
2632
                    array(
2633
                        'private_key' => $hashedPrivateKey,
2634
                        'special' => 'none',
2635
                    ),
2636
                    'id = %i',
2637
                    $post_user_id
2638
                );
2639
2640
                // Load superGlobals
2641
                include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2642
                $superGlobal = new protect\SuperGlobal\SuperGlobal();
2643
                $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2644
2645
                return prepareExchangedData(
2646
                    array(
2647
                        'error' => false,
2648
                        'message' => langHdl('done'),'',
2649
                    ),
2650
                    'encode'
2651
                );
2652
            }
2653
2654
            // For this, just check if it is possible to decrypt the privatekey
2655
            // And try to decrypt one existing key
2656
            $privateKey = decryptPrivateKey($post_previous_pwd, $userData['private_key']);
2657
2658
            if (empty($privateKey) === true) {
2659
                return prepareExchangedData(
2660
                    array(
2661
                        'error' => true,
2662
                        'message' => langHdl('password_is_not_correct'),
2663
                    ),
2664
                    'encode'
2665
                );
2666
            }
2667
2668
            // Test if possible to decvrypt one key
2669
            // Get one item
2670
            $record = DB::queryFirstRow(
2671
                'SELECT id, pw
2672
                FROM ' . prefixTable('items') . '
2673
                WHERE perso = 0'
2674
            );
2675
2676
            // Get itemKey from current user
2677
            $currentUserKey = DB::queryFirstRow(
2678
                'SELECT share_key, increment_id
2679
                FROM ' . prefixTable('sharekeys_items') . '
2680
                WHERE object_id = %i AND user_id = %i',
2681
                $record['id'],
2682
                $post_user_id
2683
            );
2684
2685
            if (count($currentUserKey) > 0) {
2686
                // Decrypt itemkey with user key
2687
                // use old password to decrypt private_key
2688
                $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $privateKey);
2689
                
2690
                if (empty(base64_decode($itemKey)) === false) {
2691
                    // GOOD password
2692
                    // Encrypt it with current password
2693
                    $hashedPrivateKey = encryptPrivateKey($post_current_pwd, $privateKey);
2694
                    
2695
                    // Update user account
2696
                    DB::update(
2697
                        prefixTable('users'),
2698
                        array(
2699
                            'private_key' => $hashedPrivateKey,
2700
                            'special' => 'none',
2701
                        ),
2702
                        'id = %i',
2703
                        $post_user_id
2704
                    );
2705
                    
2706
                    // Load superGlobals
2707
                    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2708
                    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2709
                    $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2710
2711
                    return prepareExchangedData(
2712
                        array(
2713
                            'error' => false,
2714
                            'message' => langHdl('done'),
2715
                        ),
2716
                        'encode'
2717
                    );
2718
                }
2719
            }
2720
            
2721
            // ERROR
2722
            return prepareExchangedData(
2723
                array(
2724
                    'error' => true,
2725
                    'message' => langHdl('bad_password'),
2726
                ),
2727
                'encode'
2728
            );
2729
        }
2730
    }
2731
2732
    // ERROR
2733
    return prepareExchangedData(
2734
        array(
2735
            'error' => true,
2736
            'message' => langHdl('error_no_user'),
2737
        ),
2738
        'encode'
2739
    );
2740
}
2741
2742
2743
function increaseSessionDuration(
2744
    int $duration
2745
): string
2746
{
2747
    // check if session is not already expired.
2748
    if ($_SESSION['sessionDuration'] > time()) {
2749
        // Calculate end of session
2750
        $_SESSION['sessionDuration'] = (int) ($_SESSION['sessionDuration'] + $duration);
2751
        // Update table
2752
        DB::update(
2753
            prefixTable('users'),
2754
            array(
2755
                'session_end' => $_SESSION['sessionDuration'],
2756
            ),
2757
            'id = %i',
2758
            $_SESSION['user_id']
2759
        );
2760
        // Return data
2761
        return '[{"new_value":"' . $_SESSION['sessionDuration'] . '"}]';
2762
    }
2763
    
2764
    return '[{"new_value":"expired"}]';
2765
}