Passed
Push — master ( 2b62aa...b5e3d6 )
by Nils
04:30
created

continueReEncryptingUserSharekeys()   C

Complexity

Conditions 13
Paths 11

Size

Total Lines 149
Code Lines 93

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 2 Features 0
Metric Value
cc 13
eloc 93
c 6
b 2
f 0
nc 11
nop 6
dl 0
loc 149
rs 5.446

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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