Passed
Push — master ( 5bf293...ab278b )
by Nils
04:54
created

sendingStatistics()   B

Complexity

Conditions 11
Paths 9

Size

Total Lines 66
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 11
eloc 41
c 1
b 1
f 0
nc 9
nop 1
dl 0
loc 66
rs 7.3166

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 (isKeyExistingAndEqual('ga_reset_by_user', 1, $SETTINGS) === true
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 (isValueSetNullEmpty($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
        isSetArrayOfValues([$post_pwd, $data['pw']]) === true
739
        && $pwdlib->verifyPasswordHash($post_pwd, $data['pw']) === false
740
        && $post_demand_origin !== 'users_management_list'
741
    ) {
742
        // checked the given password
743
        logEvents($SETTINGS, 'failed_auth', 'password_is_not_correct', '', stripslashes($post_login), stripslashes($post_login));
744
        return prepareExchangedData(
745
            $SETTINGS['cpassman_dir'],
746
            array(
747
                'error' => true,
748
                'message' => langHdl('no_user'),
749
                'tst' => $post_demand_origin,
750
            ),
751
            'encode'
752
        );
753
    }
754
    
755
    if (empty($data['email']) === true) {
756
        return prepareExchangedData(
757
            $SETTINGS['cpassman_dir'],
758
            array(
759
                'error' => true,
760
                'message' => langHdl('no_email_set'),
761
            ),
762
            'encode'
763
        );
764
    }
765
    
766
    // generate new GA user code
767
    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Authentication/TwoFactorAuth/TwoFactorAuth.php';
768
    $tfa = new Authentication\TwoFactorAuth\TwoFactorAuth($SETTINGS['ga_website_name']);
769
    $gaSecretKey = $tfa->createSecret();
770
    $gaTemporaryCode = GenerateCryptKey(12, false, true, true, false, true, $SETTINGS);
771
772
    DB::update(
773
        prefixTable('users'),
774
        [
775
            'ga' => $gaSecretKey,
776
            'ga_temporary_code' => $gaTemporaryCode,
777
        ],
778
        'id = %i',
779
        $data['id']
780
    );
781
782
    // Log event
783
    logEvents($SETTINGS, 'user_connection', 'at_2fa_google_code_send_by_email', (string) $data['id'], stripslashes($post_login), stripslashes($post_login));
784
785
    // send mail?
786
    if ((int) $post_send_mail === 1) {
787
        sendEmail(
788
            langHdl('email_ga_subject'),
789
            str_replace(
790
                '#2FACode#',
791
                $gaTemporaryCode,
792
                langHdl('email_ga_text')
793
            ),
794
            $data['email'],
795
            $SETTINGS
796
        );
797
798
        // send back
799
        return prepareExchangedData(
800
            $SETTINGS['cpassman_dir'],
801
            array(
802
                'error' => false,
803
                'message' => $post_send_mail,
804
                'email' => $data['email'],
805
                'email_result' => str_replace(
806
                    '#email#',
807
                    '<b>' . obfuscateEmail($data['email']) . '</b>',
808
                    addslashes(langHdl('admin_email_result_ok'))
809
                ),
810
            ),
811
            'encode'
812
        );
813
    }
814
    
815
    // send back
816
    return prepareExchangedData(
817
        $SETTINGS['cpassman_dir'],
818
        array(
819
            'error' => false,
820
            'message' => '',
821
            'email' => $data['email'],
822
            'email_result' => str_replace(
823
                '#email#',
824
                '<b>' . obfuscateEmail($data['email']) . '</b>',
825
                addslashes(langHdl('admin_email_result_ok'))
826
            ),
827
        ),
828
        'encode'
829
    );
830
}
831
832
function sendEmailsNotSent(
833
    array $SETTINGS
834
)
835
{
836
    if (isKeyExistingAndEqual('enable_send_email_on_user_login', 1, $SETTINGS) === true) {
837
        $row = DB::queryFirstRow(
838
            'SELECT valeur FROM ' . prefixTable('misc') . ' WHERE type = %s AND intitule = %s',
839
            'cron',
840
            'sending_emails'
841
        );
842
843
        if ((int) (time() - $row['valeur']) >= 300 || (int) $row['valeur'] === 0) {
844
            $rows = DB::query(
845
                'SELECT *
846
                FROM ' . prefixTable('emails') .
847
                ' WHERE status != %s',
848
                'sent'
849
            );
850
            foreach ($rows as $record) {
851
                //echo $record['increment_id'] . " >> ";
852
                // Send email
853
                $ret = json_decode(
854
                    sendEmail(
855
                        $record['subject'],
856
                        $record['body'],
857
                        $record['receivers'],
858
                        $SETTINGS
859
                    ),
860
                    true
861
                );
862
863
                // update item_id in files table
864
                DB::update(
865
                    prefixTable('emails'),
866
                    array(
867
                        'status' => $ret['error'] === 'error_mail_not_send' ? 'not_sent' : 'sent',
868
                    ),
869
                    'timestamp = %s',
870
                    $record['timestamp']
871
                );
872
            }
873
        }
874
        // update cron time
875
        DB::update(
876
            prefixTable('misc'),
877
            array(
878
                'valeur' => time(),
879
            ),
880
            'intitule = %s AND type = %s',
881
            'sending_emails',
882
            'cron'
883
        );
884
    }
885
}
886
887
function generateGenericPassword(
888
    int $size,
889
    bool $secure,
890
    bool $lowercase,
891
    bool $capitalize,
892
    bool $numerals,
893
    bool $symbols,
894
    array $SETTINGS
895
): string
896
{
897
    if ((int) $size > (int) $SETTINGS['pwd_maximum_length']) {
898
        return prepareExchangedData(
899
            $SETTINGS['cpassman_dir'],
900
            array(
901
                'error_msg' => 'Password length is too long! ',
902
                'error' => 'true',
903
            ),
904
            'encode'
905
        );
906
    }
907
    
908
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
909
    $generator->register();
910
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
911
912
    // Is PHP7 being used?
913
    if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
914
        $php7generator = new SplClassLoader('PasswordGenerator\RandomGenerator', '../includes/libraries');
915
        $php7generator->register();
916
        $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
917
    }
918
919
    // Manage size
920
    $generator->setLength(($size <= 0) ? 10 : $size);
921
922
    if ($secure === true) {
923
        $generator->setSymbols(true);
924
        $generator->setLowercase(true);
925
        $generator->setUppercase(true);
926
        $generator->setNumbers(true);
927
    } else {
928
        $generator->setLowercase($lowercase);
929
        $generator->setUppercase($capitalize);
930
        $generator->setNumbers($numerals);
931
        $generator->setSymbols($symbols);
932
    }
933
934
    return prepareExchangedData(
935
        $SETTINGS['cpassman_dir'],
936
        array(
937
            'key' => $generator->generatePasswords(),
938
            'error' => '',
939
        ),
940
        'encode'
941
    );
942
}
943
944
function refreshUserItemsSeenList(
945
    array $SETTINGS
946
): string
947
{
948
    // get list of last items seen
949
    $arr_html = array();
950
    $rows = DB::query(
951
        '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
952
        FROM ' . prefixTable('log_items') . ' AS l
953
        RIGHT JOIN ' . prefixTable('items') . ' AS i ON (l.id_item = i.id)
954
        WHERE l.action = %s AND l.id_user = %i
955
        ORDER BY l.date DESC
956
        LIMIT 0, 100',
957
        'at_shown',
958
        $_SESSION['user_id']
959
    );
960
    if (DB::count() > 0) {
961
        foreach ($rows as $record) {
962
            if (in_array($record['id']->id, array_column($arr_html, 'id')) === false) {
963
                array_push(
964
                    $arr_html,
965
                    array(
966
                        'id' => $record['id'],
967
                        'label' => htmlspecialchars(stripslashes(htmlspecialchars_decode($record['label'], ENT_QUOTES)), ENT_QUOTES),
968
                        'tree_id' => $record['id_tree'],
969
                        'perso' => $record['perso'],
970
                        'restricted' => $record['restricted'],
971
                    )
972
                );
973
                if (count($arr_html) >= (int) $SETTINGS['max_latest_items']) {
974
                    break;
975
                }
976
            }
977
        }
978
    }
979
980
    // get wainting suggestions
981
    $nb_suggestions_waiting = 0;
982
    if (isKeyExistingAndEqual('enable_suggestion', 1, $SETTINGS) === true
983
        && ((int) $_SESSION['user_admin'] === 1 || (int) $_SESSION['user_manager'] === 1)
984
    ) {
985
        DB::query('SELECT * FROM ' . prefixTable('suggestion'));
986
        $nb_suggestions_waiting = DB::count();
987
    }
988
989
    return json_encode(
990
        array(
991
            'error' => '',
992
            'existing_suggestions' => $nb_suggestions_waiting,
993
            'html_json' => $arr_html,
994
        ),
995
        JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
996
    );
997
}
998
999
function sendingStatistics(
1000
    array $SETTINGS
1001
): void
1002
{
1003
    if (
1004
        isSetArrayOfValues([$SETTINGS['send_statistics_items'], $dSETTINGS['send_stats_time']]) === true
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dSETTINGS does not exist. Did you maybe mean $SETTINGS?
Loading history...
1005
        && isKeyExistingAndEqual('send_stats', 1, $SETTINGS) === true
1006
        && (int) ($SETTINGS['send_stats_time'] + TP_ONE_DAY_SECONDS) > time()
1007
    ) {
1008
        // get statistics data
1009
        $stats_data = getStatisticsData($SETTINGS);
1010
1011
        // get statistics items to share
1012
        $statsToSend = [];
1013
        $statsToSend['ip'] = $_SERVER['SERVER_ADDR'];
1014
        $statsToSend['timestamp'] = time();
1015
        foreach (array_filter(explode(';', $SETTINGS['send_statistics_items'])) as $data) {
1016
            if ($data === 'stat_languages') {
1017
                $tmp = '';
1018
                foreach ($stats_data[$data] as $key => $value) {
1019
                    $tmp .= $tmp === '' ? $key . '-' . $value : ',' . $key . '-' . $value;
1020
                }
1021
                $statsToSend[$data] = $tmp;
1022
            } elseif ($data === 'stat_country') {
1023
                $tmp = '';
1024
                foreach ($stats_data[$data] as $key => $value) {
1025
                    $tmp .= $tmp === '' ? $key . '-' . $value : ',' . $key . '-' . $value;
1026
                }
1027
                $statsToSend[$data] = $tmp;
1028
            } else {
1029
                $statsToSend[$data] = $stats_data[$data];
1030
            }
1031
        }
1032
1033
        // connect to Teampass Statistics database
1034
        $link2 = new MeekroDB(
1035
            'teampass.pw',
1036
            'teampass_user',
1037
            'ZMlEfRzKzFLZNzie',
1038
            'teampass_followup',
1039
            '3306',
1040
            'utf8'
1041
        );
1042
1043
        $link2->insert(
1044
            'statistics',
1045
            $statsToSend
1046
        );
1047
1048
        // update table misc with current timestamp
1049
        DB::update(
1050
            prefixTable('misc'),
1051
            array(
1052
                'valeur' => time(),
1053
            ),
1054
            'type = %s AND intitule = %s',
1055
            'admin',
1056
            'send_stats_time'
1057
        );
1058
1059
        //permits to test only once by session
1060
        $_SESSION['temporary']['send_stats_done'] = true;
1061
        $SETTINGS['send_stats_time'] = time();
1062
1063
        // save change in config file
1064
        handleConfigFile('update', $SETTINGS, 'send_stats_time', $SETTINGS['send_stats_time']);
1065
    }
1066
}
1067
1068
function generateBugReport(
1069
    string $data,
1070
    array $SETTINGS
1071
): string
1072
{
1073
    $config_exclude_vars = array(
1074
        'bck_script_passkey',
1075
        'email_smtp_server',
1076
        'email_auth_username',
1077
        'email_auth_pwd',
1078
        'email_from',
1079
    );
1080
1081
    // Get data
1082
    $post_data = json_decode($data, true);
1083
1084
    // Read config file
1085
    $list_of_options = '';
1086
    $url_found = '';
1087
    $anonym_url = '';
1088
    $tp_config_file = '../includes/config/tp.config.php';
1089
    $data = file($tp_config_file);
1090
    foreach ($data as $line) {
1091
        if (substr($line, 0, 4) === '    ') {
1092
            // Remove extra spaces
1093
            $line = str_replace('    ', '', $line);
1094
1095
            // Identify url to anonymize it
1096
            if (strpos($line, 'cpassman_url') > 0 && empty($url_found) === true) {
1097
                $url_found = substr($line, 19, strlen($line) - 22);
1098
                if (empty($url_found) === false) {
1099
                    $tmp = parse_url($url_found);
1100
                    $anonym_url = $tmp['scheme'] . '://<anonym_url>' . $tmp['path'];
1101
                    $line = "'cpassman_url' => '" . $anonym_url . "\n";
1102
                } else {
1103
                    $line = "'cpassman_url' => \n";
1104
                }
1105
            }
1106
1107
            // Anonymize all urls
1108
            if (empty($anonym_url) === false) {
1109
                $line = str_replace($url_found, $anonym_url, $line);
1110
            }
1111
1112
            // Clear some vars
1113
            foreach ($config_exclude_vars as $var) {
1114
                if (strpos($line, $var) > 0) {
1115
                    $line = "'".$var."' => '<removed>'\n";
1116
                }
1117
            }
1118
1119
            // Complete line to display
1120
            $list_of_options .= $line;
1121
        }
1122
    }
1123
1124
    // Get error
1125
    $err = error_get_last();
1126
1127
    // Get 10 latest errors in Teampass
1128
    $teampass_errors = '';
1129
    $rows = DB::query(
1130
        'SELECT label, date AS error_date
1131
        FROM ' . prefixTable('log_system') . "
1132
        WHERE `type` LIKE 'error'
1133
        ORDER BY `date` DESC
1134
        LIMIT 0, 10"
1135
    );
1136
    if (DB::count() > 0) {
1137
        foreach ($rows as $record) {
1138
            if (empty($teampass_errors) === true) {
1139
                $teampass_errors = ' * ' . date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['error_date']) . ' - ' . $record['label'];
1140
            } else {
1141
                $teampass_errors .= ' * ' . date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['error_date']) . ' - ' . $record['label'];
1142
            }
1143
        }
1144
    }
1145
1146
    $link = mysqli_connect(DB_HOST, DB_USER, DB_PASSWD_CLEAR, DB_NAME, (int) DB_PORT, null);
1147
1148
    // Now prepare text
1149
    $txt = '### Page on which it happened
1150
' . $post_data['current_page'] . '
1151
1152
### Steps to reproduce
1153
1.
1154
2.
1155
3.
1156
1157
### Expected behaviour
1158
Tell us what should happen
1159
1160
1161
### Actual behaviour
1162
Tell us what happens instead
1163
1164
### Server configuration
1165
**Operating system**: ' . php_uname() . '
1166
1167
**Web server:** ' . $_SERVER['SERVER_SOFTWARE'] . '
1168
1169
**Database:** ' . ($link === false ? langHdl('undefined') : mysqli_get_server_info($link)) . '
1170
1171
**PHP version:** ' . PHP_VERSION . '
1172
1173
**Teampass version:** ' . TP_VERSION_FULL . '
1174
1175
**Teampass configuration file:**
1176
```
1177
' . $list_of_options . '
1178
```
1179
1180
**Updated from an older Teampass or fresh install:**
1181
1182
### Client configuration
1183
1184
**Browser:** ' . $post_data['browser_name'] . ' - ' . $post_data['browser_version'] . '
1185
1186
**Operating system:** ' . $post_data['os'] . ' - ' . $post_data['os_archi'] . 'bits
1187
1188
### Logs
1189
1190
#### Web server error log
1191
```
1192
' . $err['message'] . ' - ' . $err['file'] . ' (' . $err['line'] . ')
1193
```
1194
1195
#### Teampass 10 last system errors
1196
```
1197
' . $teampass_errors . '
1198
```
1199
1200
#### Log from the web-browser developer console (CTRL + SHIFT + i)
1201
```
1202
Insert the log here and especially the answer of the query that failed.
1203
```
1204
';
1205
1206
    return prepareExchangedData(
1207
    $SETTINGS['cpassman_dir'],
1208
        array(
1209
            'html' => $txt,
1210
            'error' => '',
1211
        ),
1212
        'encode'
1213
    );
1214
}
1215
1216
function isUserPasswordCorrect(
1217
    int $post_user_id,
1218
    string $post_user_password,
1219
    array $SETTINGS
1220
): string
1221
{
1222
    if (isUserIdValid($post_user_id) === true) {
1223
        // Check if user exists
1224
        $userInfo = DB::queryFirstRow(
1225
            'SELECT public_key, private_key, pw, auth_type
1226
            FROM ' . prefixTable('users') . '
1227
            WHERE id = %i',
1228
            $post_user_id
1229
        );
1230
        if (DB::count() > 0 && empty($userInfo['private_key']) === false) {
1231
            // Get one item
1232
            $record = DB::queryFirstRow(
1233
                'SELECT object_id
1234
                FROM ' . prefixTable('sharekeys_items') . '
1235
                WHERE user_id = %i',
1236
                $post_user_id
1237
            );
1238
1239
            if (DB::count() === 0) {
1240
                // This user has no items
1241
                // let's consider no items in DB
1242
                return prepareExchangedData(
1243
                    $SETTINGS['cpassman_dir'],
1244
                    array(
1245
                        'error' => false,
1246
                        'message' => '',
1247
                        'debug' => '',
1248
                    ),
1249
                    'encode'
1250
                );
1251
            }
1252
1253
            // Get itemKey from current user
1254
            $currentUserKey = DB::queryFirstRow(
1255
                'SELECT share_key, increment_id
1256
                FROM ' . prefixTable('sharekeys_items') . '
1257
                WHERE object_id = %i AND user_id = %i',
1258
                $record['object_id'],
1259
                $post_user_id
1260
            );
1261
1262
            if ($currentUserKey !== null) {
1263
                // Decrypt itemkey with user key
1264
                // use old password to decrypt private_key
1265
                $_SESSION['user']['private_key'] = decryptPrivateKey($post_user_password, $userInfo['private_key']);
1266
                $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1267
1268
                if (empty(base64_decode($itemKey)) === false) {
1269
                    // GOOD password
1270
                    return prepareExchangedData(
1271
                        $SETTINGS['cpassman_dir'],
1272
                        array(
1273
                            'error' => false,
1274
                            'message' => '',
1275
                            'debug' => '',
1276
                        ),
1277
                        'encode'
1278
                    );
1279
                }
1280
            }
1281
            
1282
            // Use the password check
1283
            // load passwordLib library
1284
            $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'] . '/includes/libraries');
1285
            $pwdlib->register();
1286
            $pwdlib = new PasswordLib\PasswordLib();
1287
            
1288
            if ($pwdlib->verifyPasswordHash(htmlspecialchars_decode($post_user_password), $userInfo['pw']) === true) {
1289
                // GOOD password
1290
                return prepareExchangedData(
1291
                    $SETTINGS['cpassman_dir'],
1292
                    array(
1293
                        'error' => false,
1294
                        'message' => '',
1295
                        'debug' => '',
1296
                    ),
1297
                    'encode'
1298
                );
1299
            }
1300
        }
1301
    }
1302
1303
    return prepareExchangedData(
1304
    $SETTINGS['cpassman_dir'],
1305
        array(
1306
            'error' => true,
1307
            'message' => langHdl('password_is_not_correct'),
1308
            //'debug' => isset($itemKey) === true ? base64_decode($itemKey) : '',
1309
        ),
1310
        'encode'
1311
    );
1312
}
1313
1314
function changePrivateKeyEncryptionPassword(
1315
    int $post_user_id,
1316
    string $post_current_code,
1317
    string $post_new_code,
1318
    string $post_action_type,
1319
    array $SETTINGS
1320
): string
1321
{
1322
    if (empty($post_new_code) === true) {
1323
        if (empty($_SESSION['user_pwd']) === false) {
1324
            $post_new_code = $_SESSION['user_pwd'];
1325
        } else {
1326
            // no user password???
1327
            return prepareExchangedData(
1328
                $SETTINGS['cpassman_dir'],
1329
                array(
1330
                    'error' => true,
1331
                    'message' => langHdl('error_no_user_password_exists'),
1332
                    'debug' => '',
1333
                ),
1334
                'encode'
1335
            );
1336
        }
1337
    }
1338
1339
    if (isUserIdValid($post_user_id) === true) {
1340
        // Get user info
1341
        $userData = DB::queryFirstRow(
1342
            'SELECT private_key
1343
            FROM ' . prefixTable('users') . '
1344
            WHERE id = %i',
1345
            $post_user_id
1346
        );
1347
        if (DB::count() > 0 && empty($userData['private_key']) === false) {
1348
            if ($post_action_type === 'encrypt_privkey_with_user_password') {
1349
                // Here the user has his private key encrypted with an OTC.
1350
                // We need to encrypt it with his real password
1351
                $privateKey = decryptPrivateKey($post_new_code, $userData['private_key']);
1352
                $hashedPrivateKey = encryptPrivateKey($post_current_code, $privateKey);
1353
            } else {
1354
                $privateKey = decryptPrivateKey($post_current_code, $userData['private_key']);
1355
                $hashedPrivateKey = encryptPrivateKey($post_new_code, $privateKey);
1356
            }
1357
1358
            // Update user account
1359
            DB::update(
1360
                prefixTable('users'),
1361
                array(
1362
                    'private_key' => $hashedPrivateKey,
1363
                    'special' => 'none',
1364
                ),
1365
                'id = %i',
1366
                $post_user_id
1367
            );
1368
1369
            // Load superGlobals
1370
            include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1371
            $superGlobal = new protect\SuperGlobal\SuperGlobal();
1372
1373
            $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
1374
        }
1375
1376
        // Return
1377
        return prepareExchangedData(
1378
            $SETTINGS['cpassman_dir'],
1379
            array(
1380
                'error' => false,
1381
                'message' => '',
1382
            ),
1383
            'encode'
1384
        );
1385
    }
1386
    
1387
    return prepareExchangedData(
1388
        $SETTINGS['cpassman_dir'],
1389
        array(
1390
            'error' => true,
1391
            'message' => langHdl('error_no_user'),
1392
            'debug' => '',
1393
        ),
1394
        'encode'
1395
    );
1396
}
1397
1398
function initializeUserPassword(
1399
    int $post_user_id,
1400
    string $post_special,
1401
    string $post_user_password,
1402
    bool $post_self_change,
1403
    array $SETTINGS
1404
): string
1405
{
1406
    if (isUserIdValid($post_user_id) === true) {
1407
        // Get user info
1408
        $userData = DB::queryFirstRow(
1409
            'SELECT email, auth_type, login
1410
            FROM ' . prefixTable('users') . '
1411
            WHERE id = %i',
1412
            $post_user_id
1413
        );
1414
        if (DB::count() > 0 && empty($userData['email']) === false) {
1415
            // If user pwd is empty then generate a new one and send it to user
1416
            if (isset($post_user_password) === false || empty($post_user_password) === true) {
1417
                // Generate new password
1418
                $post_user_password = generateQuickPassword();
1419
            }
1420
1421
            // If LDAP enabled, then
1422
            // check that this password is correct
1423
            $continue = true;
1424
            if ($userData['auth_type'] === 'ldap' && (int) $SETTINGS['ldap_mode'] === 1) {
1425
                $continue = ldapCheckUserPassword(
1426
                    $userData['login'],
1427
                    $post_user_password,
1428
                    $SETTINGS
1429
                );
1430
            }
1431
1432
            if ($continue === true) {
1433
                // Only change if email is successfull
1434
                // GEnerate new keys
1435
                $userKeys = generateUserKeys($post_user_password);
1436
1437
                // load passwordLib library
1438
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1439
                $pwdlib->register();
1440
                $pwdlib = new PasswordLib\PasswordLib();
1441
1442
                // Update user account
1443
                DB::update(
1444
                    prefixTable('users'),
1445
                    array(
1446
                        'special' => $post_special,
1447
                        'pw' => $pwdlib->createPasswordHash($post_user_password),
1448
                        'public_key' => $userKeys['public_key'],
1449
                        'private_key' => $userKeys['private_key'],
1450
                        'last_pw_change' => time(),
1451
                    ),
1452
                    'id = %i',
1453
                    $post_user_id
1454
                );
1455
1456
                // Return
1457
                return prepareExchangedData(
1458
    $SETTINGS['cpassman_dir'],
1459
                    array(
1460
                        'error' => false,
1461
                        'message' => '',
1462
                        'user_pwd' => $post_user_password,
1463
                        'user_email' => $userData['email'],
1464
                    ),
1465
                    'encode'
1466
                );
1467
            }
1468
            // Return error
1469
            return prepareExchangedData(
1470
    $SETTINGS['cpassman_dir'],
1471
                array(
1472
                    'error' => true,
1473
                    'message' => langHdl('no_email_set'),
1474
                    'debug' => '',
1475
                    'self_change' => $post_self_change,
1476
                ),
1477
                'encode'
1478
            );
1479
        }
1480
1481
        // Error
1482
        return prepareExchangedData(
1483
    $SETTINGS['cpassman_dir'],
1484
            array(
1485
                'error' => true,
1486
                'message' => langHdl('no_email_set'),
1487
                'debug' => '',
1488
            ),
1489
            'encode'
1490
        );
1491
    }
1492
    
1493
    return prepareExchangedData(
1494
    $SETTINGS['cpassman_dir'],
1495
        array(
1496
            'error' => true,
1497
            'message' => langHdl('error_no_user'),
1498
            'debug' => '',
1499
        ),
1500
        'encode'
1501
    );
1502
}
1503
1504
function sendMailToUser(
1505
    string $post_receipt,
1506
    string $post_body,
1507
    string $post_subject,
1508
    array $post_replace,
1509
    array $SETTINGS
1510
): string
1511
{
1512
    if (count($post_replace) > 0 && is_null($post_replace) === false) {
1513
        $post_body = str_replace(
1514
            array_keys($post_replace),
1515
            array_values($post_replace),
1516
            $post_body
1517
        );
1518
    }
1519
    
1520
    $ret = sendEmail(
1521
        $post_subject,
1522
        $post_body,
1523
        $post_receipt,
1524
        $SETTINGS,
1525
        '',
1526
        false
1527
    );
1528
1529
    $ret = json_decode($ret, true);
1530
1531
    return prepareExchangedData(
1532
    $SETTINGS['cpassman_dir'],
1533
        array(
1534
            'error' => empty($ret['error']) === true ? false : true,
1535
            'message' => $ret['message'],
1536
        ),
1537
        'encode'
1538
    );
1539
}
1540
1541
function generateOneTimeCode(
1542
    int $post_user_id,
1543
    array $SETTINGS
1544
): string
1545
{
1546
    if (isUserIdValid($post_user_id) === true) {
1547
        // Get user info
1548
        $userData = DB::queryFirstRow(
1549
            'SELECT email, auth_type, login
1550
            FROM ' . prefixTable('users') . '
1551
            WHERE id = %i',
1552
            $post_user_id
1553
        );
1554
        if (DB::count() > 0 && empty($userData['email']) === false) {
1555
            // Generate pwd
1556
            $password = generateQuickPassword();
1557
1558
            // GEnerate new keys
1559
            $userKeys = generateUserKeys($password);
1560
1561
            // Save in DB
1562
            DB::update(
1563
                prefixTable('users'),
1564
                array(
1565
                    'public_key' => $userKeys['public_key'],
1566
                    'private_key' => $userKeys['private_key'],
1567
                    'special' => 'generate-keys',
1568
                ),
1569
                'id=%i',
1570
                $post_user_id
1571
            );
1572
1573
            return prepareExchangedData(
1574
    $SETTINGS['cpassman_dir'],
1575
                array(
1576
                    'error' => false,
1577
                    'message' => '',
1578
                    'userTemporaryCode' => $password,
1579
                ),
1580
                'encode'
1581
            );
1582
        }
1583
        
1584
        return prepareExchangedData(
1585
    $SETTINGS['cpassman_dir'],
1586
            array(
1587
                'error' => true,
1588
                'message' => langHdl('no_email_set'),
1589
            ),
1590
            'encode'
1591
        );
1592
    }
1593
        
1594
    return prepareExchangedData(
1595
    $SETTINGS['cpassman_dir'],
1596
        array(
1597
            'error' => true,
1598
            'message' => langHdl('error_no_user'),
1599
        ),
1600
        'encode'
1601
    );
1602
}
1603
1604
function startReEncryptingUserSharekeys(
1605
    int $post_user_id,
1606
    bool $post_self_change,
1607
    array $SETTINGS
1608
): string
1609
{
1610
    if (isUserIdValid($post_user_id) === true) {
1611
        // Check if user exists
1612
        DB::queryFirstRow(
1613
            'SELECT *
1614
            FROM ' . prefixTable('users') . '
1615
            WHERE id = %i',
1616
            $post_user_id
1617
        );
1618
        if (DB::count() > 0) {
1619
            // Include libraries
1620
            include_once $SETTINGS['cpassman_dir'] . '/sources/aes.functions.php';
1621
1622
            // CLear old sharekeys
1623
            if ($post_self_change === false) {
1624
                deleteUserObjetsKeys($post_user_id, $SETTINGS);
1625
            }
1626
1627
            // Continu with next step
1628
            return prepareExchangedData(
1629
                $SETTINGS['cpassman_dir'],
1630
                array(
1631
                    'error' => false,
1632
                    'message' => '',
1633
                    'step' => 'step1',
1634
                    'userId' => $post_user_id,
1635
                    'start' => 0,
1636
                    'self_change' => $post_self_change,
1637
                ),
1638
                'encode'
1639
            );
1640
        }
1641
        // Nothing to do
1642
        return prepareExchangedData(
1643
            $SETTINGS['cpassman_dir'],
1644
            array(
1645
                'error' => true,
1646
                'message' => langHdl('error_no_user'),
1647
            ),
1648
            'encode'
1649
        );
1650
    }
1651
1652
    return prepareExchangedData(
1653
        $SETTINGS['cpassman_dir'],
1654
        array(
1655
            'error' => true,
1656
            'message' => langHdl('error_no_user'),
1657
        ),
1658
        'encode'
1659
    );
1660
}
1661
1662
/**
1663
 * Permits to encrypt user's keys
1664
 *
1665
 * @param integer $post_user_id
1666
 * @param boolean $post_self_change
1667
 * @param string $post_action
1668
 * @param integer $post_start
1669
 * @param integer $post_length
1670
 * @param array $SETTINGS
1671
 * @return string
1672
 */
1673
function continueReEncryptingUserSharekeys(
1674
    int     $post_user_id,
1675
    bool    $post_self_change,
1676
    string  $post_action,
1677
    int     $post_start,
1678
    int     $post_length,
1679
    array   $SETTINGS
1680
): string
1681
{
1682
    if (isUserIdValid($post_user_id) === true) {
1683
        // Check if user exists
1684
        $userInfo = DB::queryFirstRow(
1685
            'SELECT public_key
1686
            FROM ' . prefixTable('users') . '
1687
            WHERE id = %i',
1688
            $post_user_id
1689
        );
1690
        if (isset($userInfo['public_key']) === true) {
1691
            // Include libraries
1692
            include_once $SETTINGS['cpassman_dir'] . '/sources/aes.functions.php';
1693
            $return = [];
1694
1695
            // WHAT STEP TO PERFORM?
1696
            if ($post_action === 'step0') {
1697
                // CLear old sharekeys
1698
                if ($post_self_change === false) {
1699
                    deleteUserObjetsKeys($post_user_id, $SETTINGS);
1700
                }
1701
1702
                $return['post_action'] = 'step1';
1703
            }
1704
            
1705
            // STEP 1 - ITEMS
1706
            elseif ($post_action === 'step1') {
1707
                $return = continueReEncryptingUserSharekeysStep1(
1708
                    $post_user_id,
1709
                    $post_self_change,
1710
                    $post_action,
1711
                    $post_start,
1712
                    $post_length,
1713
                    $userInfo['public_key'],
1714
                    $SETTINGS
1715
                );
1716
            }
1717
1718
            // STEP 2 - LOGS
1719
            elseif ($post_action === 'step2') {
1720
                $return = continueReEncryptingUserSharekeysStep2(
1721
                    $post_user_id,
1722
                    $post_self_change,
1723
                    $post_action,
1724
                    $post_start,
1725
                    $post_length,
1726
                    $userInfo['public_key'],
1727
                    $SETTINGS
1728
                );
1729
            }
1730
1731
            // STEP 3 - FIELDS
1732
            elseif ($post_action === 'step3') {
1733
                $return = continueReEncryptingUserSharekeysStep3(
1734
                    $post_user_id,
1735
                    $post_self_change,
1736
                    $post_action,
1737
                    $post_start,
1738
                    $post_length,
1739
                    $userInfo['public_key'],
1740
                    $SETTINGS
1741
                );
1742
            }
1743
            
1744
            // STEP 4 - SUGGESTIONS
1745
            elseif ($post_action === 'step4') {
1746
                $return = continueReEncryptingUserSharekeysStep4(
1747
                    $post_user_id,
1748
                    $post_self_change,
1749
                    $post_action,
1750
                    $post_start,
1751
                    $post_length,
1752
                    $userInfo['public_key'],
1753
                    $SETTINGS
1754
                );
1755
            }
1756
            
1757
            // STEP 5 - FILES
1758
            elseif ($post_action === 'step5') {
1759
                $return = continueReEncryptingUserSharekeysStep5(
1760
                    $post_user_id,
1761
                    $post_self_change,
1762
                    $post_action,
1763
                    $post_start,
1764
                    $post_length,
1765
                    $userInfo['public_key'],
1766
                    $SETTINGS
1767
                );
1768
            }
1769
            
1770
            // STEP 6 - PERSONAL ITEMS
1771
            elseif ($post_action === 'step6') {
1772
                $return = continueReEncryptingUserSharekeysStep6(
1773
                    $post_user_id,
1774
                    $post_self_change,
1775
                    $post_action,
1776
                    $post_start,
1777
                    $post_length,
1778
                    $userInfo['public_key'],
1779
                    $SETTINGS
1780
                );
1781
            }
1782
            
1783
            // Continu with next step
1784
            return prepareExchangedData(
1785
                $SETTINGS['cpassman_dir'],
1786
                array(
1787
                    'error' => false,
1788
                    'message' => '',
1789
                    'step' => isset($return['post_action']) === true ? $return['post_action'] : '',
1790
                    'start' => isset($return['next_start']) === true ? $return['next_start'] : 0,
1791
                    'userId' => $post_user_id,
1792
                    'self_change' => $post_self_change,
1793
                ),
1794
                'encode'
1795
            );
1796
        }
1797
        
1798
        // Nothing to do
1799
        return prepareExchangedData(
1800
            $SETTINGS['cpassman_dir'],
1801
            array(
1802
                'error' => false,
1803
                'message' => '',
1804
                'step' => 'finished',
1805
                'start' => 0,
1806
                'userId' => $post_user_id,
1807
                'self_change' => $post_self_change,
1808
            ),
1809
            'encode'
1810
        );
1811
    }
1812
    
1813
    // Nothing to do
1814
    return prepareExchangedData(
1815
        $SETTINGS['cpassman_dir'],
1816
        array(
1817
            'error' => true,
1818
            'message' => langHdl('error_no_user'),
1819
            'extra' => $post_user_id,
1820
        ),
1821
        'encode'
1822
    );
1823
}
1824
1825
function continueReEncryptingUserSharekeysStep1(
1826
    int $post_user_id,
1827
    bool $post_self_change,
1828
    string $post_action,
1829
    int $post_start,
1830
    int $post_length,
1831
    string $user_public_key,
1832
    array $SETTINGS
1833
): array 
1834
{
1835
    // Loop on items
1836
    $rows = DB::query(
1837
        'SELECT id, pw
1838
        FROM ' . prefixTable('items') . '
1839
        WHERE perso = 0
1840
        LIMIT ' . $post_start . ', ' . $post_length
1841
    );
1842
    foreach ($rows as $record) {
1843
        // Get itemKey from current user
1844
        $currentUserKey = DB::queryFirstRow(
1845
            'SELECT share_key, increment_id
1846
            FROM ' . prefixTable('sharekeys_items') . '
1847
            WHERE object_id = %i AND user_id = %i',
1848
            $record['id'],
1849
            $_SESSION['user_id']
1850
        );
1851
        if ($currentUserKey === null || count($currentUserKey) === 0) continue;
1852
1853
        // Decrypt itemkey with admin key
1854
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1855
        
1856
        // Encrypt Item key
1857
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
1858
        
1859
        // Save the key in DB
1860
        if ($post_self_change === false) {
1861
            DB::insert(
1862
                prefixTable('sharekeys_items'),
1863
                array(
1864
                    'object_id' => (int) $record['id'],
1865
                    'user_id' => (int) $post_user_id,
1866
                    'share_key' => $share_key_for_item,
1867
                )
1868
            );
1869
        } else {
1870
            // Get itemIncrement from selected user
1871
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
1872
                $currentUserKey = DB::queryFirstRow(
1873
                    'SELECT increment_id
1874
                    FROM ' . prefixTable('sharekeys_items') . '
1875
                    WHERE object_id = %i AND user_id = %i',
1876
                    $record['id'],
1877
                    $post_user_id
1878
                );
1879
1880
                if (DB::count() > 0) {
1881
                    // NOw update
1882
                    DB::update(
1883
                        prefixTable('sharekeys_items'),
1884
                        array(
1885
                            'share_key' => $share_key_for_item,
1886
                        ),
1887
                        'increment_id = %i',
1888
                        $currentUserKey['increment_id']
1889
                    );
1890
                } else {
1891
                    DB::insert(
1892
                        prefixTable('sharekeys_items'),
1893
                        array(
1894
                            'object_id' => (int) $record['id'],
1895
                            'user_id' => (int) $post_user_id,
1896
                            'share_key' => $share_key_for_item,
1897
                        )
1898
                    );
1899
                }
1900
            }
1901
        }
1902
    }
1903
1904
    // SHould we change step?
1905
    DB::query(
1906
        'SELECT *
1907
        FROM ' . prefixTable('items') . '
1908
        WHERE perso = 0'
1909
    );
1910
1911
    $next_start = (int) $post_start + (int) $post_length;
1912
    return [
1913
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
1914
        'post_action' => $next_start > DB::count() ? 'step2' : 'step1',
1915
    ];
1916
}
1917
1918
function continueReEncryptingUserSharekeysStep2(
1919
    int $post_user_id,
1920
    bool $post_self_change,
1921
    string $post_action,
1922
    int $post_start,
1923
    int $post_length,
1924
    string $user_public_key,
1925
    array $SETTINGS
1926
): array
1927
{
1928
    // Loop on logs
1929
    $rows = DB::query(
1930
        'SELECT increment_id
1931
        FROM ' . prefixTable('log_items') . '
1932
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"
1933
        LIMIT ' . $post_start . ', ' . $post_length
1934
    );
1935
    foreach ($rows as $record) {
1936
        // Get itemKey from current user
1937
        $currentUserKey = DB::queryFirstRow(
1938
            'SELECT share_key
1939
            FROM ' . prefixTable('sharekeys_logs') . '
1940
            WHERE object_id = %i AND user_id = %i',
1941
            $record['increment_id'],
1942
            $_SESSION['user_id']
1943
        );
1944
1945
        // Decrypt itemkey with admin key
1946
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1947
1948
        // Encrypt Item key
1949
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
1950
1951
        // Save the key in DB
1952
        if ($post_self_change === false) {
1953
            DB::insert(
1954
                prefixTable('sharekeys_logs'),
1955
                array(
1956
                    'object_id' => (int) $record['increment_id'],
1957
                    'user_id' => (int) $post_user_id,
1958
                    'share_key' => $share_key_for_item,
1959
                )
1960
            );
1961
        } else {
1962
            // Get itemIncrement from selected user
1963
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
1964
                $currentUserKey = DB::queryFirstRow(
1965
                    'SELECT increment_id
1966
                    FROM ' . prefixTable('sharekeys_items') . '
1967
                    WHERE object_id = %i AND user_id = %i',
1968
                    $record['id'],
1969
                    $post_user_id
1970
                );
1971
            }
1972
1973
            // NOw update
1974
            DB::update(
1975
                prefixTable('sharekeys_logs'),
1976
                array(
1977
                    'share_key' => $share_key_for_item,
1978
                ),
1979
                'increment_id = %i',
1980
                $currentUserKey['increment_id']
1981
            );
1982
        }
1983
    }
1984
1985
    // SHould we change step?
1986
    DB::query(
1987
        'SELECT increment_id
1988
        FROM ' . prefixTable('log_items') . '
1989
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"'
1990
    );
1991
1992
    $next_start = (int) $post_start + (int) $post_length;
1993
    return [
1994
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
1995
        'post_action' => $next_start > DB::count() ? 'step3' : 'step2',
1996
    ];
1997
}
1998
1999
function continueReEncryptingUserSharekeysStep3(
2000
    int $post_user_id,
2001
    bool $post_self_change,
2002
    string $post_action,
2003
    int $post_start,
2004
    int $post_length,
2005
    string $user_public_key,
2006
    array $SETTINGS
2007
): array
2008
{
2009
    // Loop on fields
2010
    $rows = DB::query(
2011
        'SELECT id
2012
        FROM ' . prefixTable('categories_items') . '
2013
        WHERE encryption_type = "teampass_aes"
2014
        LIMIT ' . $post_start . ', ' . $post_length
2015
    );
2016
    foreach ($rows as $record) {
2017
        // Get itemKey from current user
2018
        $currentUserKey = DB::queryFirstRow(
2019
            'SELECT share_key
2020
            FROM ' . prefixTable('sharekeys_fields') . '
2021
            WHERE object_id = %i AND user_id = %i',
2022
            $record['id'],
2023
            $_SESSION['user_id']
2024
        );
2025
2026
        // Decrypt itemkey with admin key
2027
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2028
2029
        // Encrypt Item key
2030
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2031
2032
        // Save the key in DB
2033
        if ($post_self_change === false) {
2034
            DB::insert(
2035
                prefixTable('sharekeys_fields'),
2036
                array(
2037
                    'object_id' => (int) $record['id'],
2038
                    'user_id' => (int) $post_user_id,
2039
                    'share_key' => $share_key_for_item,
2040
                )
2041
            );
2042
        } else {
2043
            // Get itemIncrement from selected user
2044
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2045
                $currentUserKey = DB::queryFirstRow(
2046
                    'SELECT increment_id
2047
                    FROM ' . prefixTable('sharekeys_items') . '
2048
                    WHERE object_id = %i AND user_id = %i',
2049
                    $record['id'],
2050
                    $post_user_id
2051
                );
2052
            }
2053
2054
            // NOw update
2055
            DB::update(
2056
                prefixTable('sharekeys_fields'),
2057
                array(
2058
                    'share_key' => $share_key_for_item,
2059
                ),
2060
                'increment_id = %i',
2061
                $currentUserKey['increment_id']
2062
            );
2063
        }
2064
    }
2065
2066
    // SHould we change step?
2067
    DB::query(
2068
        'SELECT *
2069
        FROM ' . prefixTable('categories_items') . '
2070
        WHERE encryption_type = "teampass_aes"'
2071
    );
2072
2073
    $next_start = (int) $post_start + (int) $post_length;
2074
    return [
2075
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2076
        'post_action' => $next_start > DB::count() ? 'step4' : 'step3',
2077
    ];
2078
}
2079
2080
function continueReEncryptingUserSharekeysStep4(
2081
    int $post_user_id,
2082
    bool $post_self_change,
2083
    string $post_action,
2084
    int $post_start,
2085
    int $post_length,
2086
    string $user_public_key,
2087
    array $SETTINGS
2088
): array
2089
{
2090
    // Loop on suggestions
2091
    $rows = DB::query(
2092
        'SELECT id
2093
        FROM ' . prefixTable('suggestion') . '
2094
        LIMIT ' . $post_start . ', ' . $post_length
2095
    );
2096
    foreach ($rows as $record) {
2097
        // Get itemKey from current user
2098
        $currentUserKey = DB::queryFirstRow(
2099
            'SELECT share_key
2100
            FROM ' . prefixTable('sharekeys_suggestions') . '
2101
            WHERE object_id = %i AND user_id = %i',
2102
            $record['id'],
2103
            $_SESSION['user_id']
2104
        );
2105
2106
        // Decrypt itemkey with admin key
2107
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2108
2109
        // Encrypt Item key
2110
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2111
2112
        // Save the key in DB
2113
        if ($post_self_change === false) {
2114
            DB::insert(
2115
                prefixTable('sharekeys_suggestions'),
2116
                array(
2117
                    'object_id' => (int) $record['id'],
2118
                    'user_id' => (int) $post_user_id,
2119
                    'share_key' => $share_key_for_item,
2120
                )
2121
            );
2122
        } else {
2123
            // Get itemIncrement from selected user
2124
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2125
                $currentUserKey = DB::queryFirstRow(
2126
                    'SELECT increment_id
2127
                    FROM ' . prefixTable('sharekeys_items') . '
2128
                    WHERE object_id = %i AND user_id = %i',
2129
                    $record['id'],
2130
                    $post_user_id
2131
                );
2132
            }
2133
2134
            // NOw update
2135
            DB::update(
2136
                prefixTable('sharekeys_suggestions'),
2137
                array(
2138
                    'share_key' => $share_key_for_item,
2139
                ),
2140
                'increment_id = %i',
2141
                $currentUserKey['increment_id']
2142
            );
2143
        }
2144
    }
2145
2146
    // SHould we change step?
2147
    DB::query(
2148
        'SELECT *
2149
        FROM ' . prefixTable('suggestion')
2150
    );
2151
2152
    $next_start = (int) $post_start + (int) $post_length;
2153
    return [
2154
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2155
        'post_action' => $next_start > DB::count() ? 'step5' : 'step4',
2156
    ];
2157
}
2158
2159
function continueReEncryptingUserSharekeysStep5(
2160
    int $post_user_id,
2161
    bool $post_self_change,
2162
    string $post_action,
2163
    int $post_start,
2164
    int $post_length,
2165
    string $user_public_key,
2166
    array $SETTINGS
2167
): array
2168
{
2169
    // Loop on files
2170
    $rows = DB::query(
2171
        'SELECT id
2172
        FROM ' . prefixTable('files') . '
2173
        WHERE status = "' . TP_ENCRYPTION_NAME . '"
2174
        LIMIT ' . $post_start . ', ' . $post_length
2175
    ); //aes_encryption
2176
    foreach ($rows as $record) {
2177
        // Get itemKey from current user
2178
        $currentUserKey = DB::queryFirstRow(
2179
            'SELECT share_key
2180
            FROM ' . prefixTable('sharekeys_files') . '
2181
            WHERE object_id = %i AND user_id = %i',
2182
            $record['id'],
2183
            $_SESSION['user_id']
2184
        );
2185
2186
        // Decrypt itemkey with admin key
2187
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2188
2189
        // Encrypt Item key
2190
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2191
2192
        // Save the key in DB
2193
        if ($post_self_change === false) {
2194
            DB::insert(
2195
                prefixTable('sharekeys_files'),
2196
                array(
2197
                    'object_id' => (int) $record['id'],
2198
                    'user_id' => (int) $post_user_id,
2199
                    'share_key' => $share_key_for_item,
2200
                )
2201
            );
2202
        } else {
2203
            // Get itemIncrement from selected user
2204
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2205
                $currentUserKey = DB::queryFirstRow(
2206
                    'SELECT increment_id
2207
                    FROM ' . prefixTable('sharekeys_items') . '
2208
                    WHERE object_id = %i AND user_id = %i',
2209
                    $record['id'],
2210
                    $post_user_id
2211
                );
2212
            }
2213
2214
            // NOw update
2215
            DB::update(
2216
                prefixTable('sharekeys_files'),
2217
                array(
2218
                    'share_key' => $share_key_for_item,
2219
                ),
2220
                'increment_id = %i',
2221
                $currentUserKey['increment_id']
2222
            );
2223
        }
2224
    }
2225
2226
    // SHould we change step?
2227
    DB::query(
2228
        'SELECT *
2229
        FROM ' . prefixTable('files') . '
2230
        WHERE status = "' . TP_ENCRYPTION_NAME . '"'
2231
    );
2232
2233
    $next_start = (int) $post_start + (int) $post_length;
2234
    return [
2235
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2236
        'post_action' => $next_start > DB::count() ? 'step6' : 'step5',
2237
    ];
2238
}
2239
2240
function continueReEncryptingUserSharekeysStep6(
2241
    int $post_user_id,
2242
    bool $post_self_change,
2243
    string $post_action,
2244
    int $post_start,
2245
    int $post_length,
2246
    string $user_public_key,
2247
    array $SETTINGS
2248
): array
2249
{
2250
    // IF USER IS NOT THE SAME
2251
    if ((int) $post_user_id === (int) $_SESSION['user_id']) {
2252
        return [
2253
            'next_start' => 0,
2254
            'post_action' => 'finished',
2255
        ];
2256
    }
2257
    
2258
    // Loop on persoanl items
2259
    if (count($_SESSION['personal_folders']) > 0) {
2260
        $rows = DB::query(
2261
            'SELECT id, pw
2262
            FROM ' . prefixTable('items') . '
2263
            WHERE perso = 1 AND id_tree IN %ls
2264
            LIMIT ' . $post_start . ', ' . $post_length,
2265
            $_SESSION['personal_folders']
2266
        );
2267
        foreach ($rows as $record) {
2268
            // Get itemKey from current user
2269
            $currentUserKey = DB::queryFirstRow(
2270
                'SELECT share_key, increment_id
2271
                FROM ' . prefixTable('sharekeys_items') . '
2272
                WHERE object_id = %i AND user_id = %i',
2273
                $record['id'],
2274
                $_SESSION['user_id']
2275
            );
2276
2277
            // Decrypt itemkey with admin key
2278
            $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2279
2280
            // Encrypt Item key
2281
            $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2282
2283
            // Save the key in DB
2284
            if ($post_self_change === false) {
2285
                DB::insert(
2286
                    prefixTable('sharekeys_items'),
2287
                    array(
2288
                        'object_id' => (int) $record['id'],
2289
                        'user_id' => (int) $post_user_id,
2290
                        'share_key' => $share_key_for_item,
2291
                    )
2292
                );
2293
            } else {
2294
                // Get itemIncrement from selected user
2295
                if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2296
                    $currentUserKey = DB::queryFirstRow(
2297
                        'SELECT increment_id
2298
                        FROM ' . prefixTable('sharekeys_items') . '
2299
                        WHERE object_id = %i AND user_id = %i',
2300
                        $record['id'],
2301
                        $post_user_id
2302
                    );
2303
                }
2304
2305
                // NOw update
2306
                DB::update(
2307
                    prefixTable('sharekeys_items'),
2308
                    array(
2309
                        'share_key' => $share_key_for_item,
2310
                    ),
2311
                    'increment_id = %i',
2312
                    $currentUserKey['increment_id']
2313
                );
2314
            }
2315
        }
2316
    }
2317
2318
    // SHould we change step?
2319
    DB::query(
2320
        'SELECT *
2321
        FROM ' . prefixTable('items') . '
2322
        WHERE perso = 0'
2323
    );
2324
2325
    $next_start = (int) $post_start + (int) $post_length;
2326
    return [
2327
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2328
        'post_action' => $next_start > DB::count() ? 'finished' : 'step6',
2329
    ];
2330
}
2331
2332
function migrateTo3_DoUserPersonalItemsEncryption(
2333
    int $post_user_id,
2334
    int $post_start,
2335
    int $post_length,
2336
    string $post_user_psk,
2337
    array $SETTINGS
2338
) {
2339
    $next_step = '';
2340
    
2341
    if (isUserIdValid($post_user_id) === true) {
2342
        // Check if user exists
2343
        $userInfo = DB::queryFirstRow(
2344
            'SELECT public_key, encrypted_psk
2345
            FROM ' . prefixTable('users') . '
2346
            WHERE id = %i',
2347
            $post_user_id
2348
        );
2349
        if (DB::count() > 0) {
2350
            // check if psk is correct.
2351
            if (empty($userInfo['encrypted_psk']) === false) {//echo $post_user_psk." ;; ".$userInfo['encrypted_psk']." ;; ";
2352
                $user_key_encoded = defuse_validate_personal_key(
2353
                    $post_user_psk,
2354
                    $userInfo['encrypted_psk']
2355
                );
2356
2357
                if (strpos($user_key_encoded, "Error ") !== false) {
2358
                    return prepareExchangedData(
2359
                        $SETTINGS['cpassman_dir'],
2360
                        array(
2361
                            'error' => true,
2362
                            'message' => langHdl('bad_psk'),
2363
                        ),
2364
                        'encode'
2365
                    );
2366
                }
2367
2368
                // Loop on persoanl items
2369
                $rows = DB::query(
2370
                    'SELECT id, pw
2371
                    FROM ' . prefixTable('items') . '
2372
                    WHERE perso = 1 AND id_tree IN %ls
2373
                    LIMIT ' . $post_start . ', ' . $post_length,
2374
                    $_SESSION['personal_folders']
2375
                );
2376
                $countUserPersonalItems = DB::count();
2377
                foreach ($rows as $record) {
2378
                    if ($record['encryption_type'] !== 'teampass_aes') {
2379
                        // Decrypt with Defuse
2380
                        $passwd = cryption(
2381
                            $record['pw'],
2382
                            $user_key_encoded,
2383
                            'decrypt',
2384
                            $SETTINGS
2385
                        );
2386
2387
                        // Encrypt with Object Key
2388
                        $cryptedStuff = doDataEncryption($passwd['string']);
2389
2390
                        // Store new password in DB
2391
                        DB::update(
2392
                            prefixTable('items'),
2393
                            array(
2394
                                'pw' => $cryptedStuff['encrypted'],
2395
                                'encryption_type' => 'teampass_aes',
2396
                            ),
2397
                            'id = %i',
2398
                            $record['id']
2399
                        );
2400
2401
                        // Insert in DB the new object key for this item by user
2402
                        DB::insert(
2403
                            prefixTable('sharekeys_items'),
2404
                            array(
2405
                                'object_id' => (int) $record['id'],
2406
                                'user_id' => (int) $post_user_id,
2407
                                'share_key' => encryptUserObjectKey($cryptedStuff['objectKey'], $userInfo['public_key']),
2408
                            )
2409
                        );
2410
2411
2412
                        // Does this item has Files?
2413
                        // Loop on files
2414
                        $rows = DB::query(
2415
                            'SELECT id, file
2416
                            FROM ' . prefixTable('files') . '
2417
                            WHERE status != %s
2418
                            AND id_item = %i',
2419
                            TP_ENCRYPTION_NAME,
2420
                            $record['id']
2421
                        );
2422
                        //aes_encryption
2423
                        foreach ($rows as $record2) {
2424
                            // Now decrypt the file
2425
                            prepareFileWithDefuse(
2426
                                'decrypt',
2427
                                $SETTINGS['path_to_upload_folder'] . '/' . $record2['file'],
2428
                                $SETTINGS['path_to_upload_folder'] . '/' . $record2['file'] . '.delete',
2429
                                $SETTINGS,
2430
                                $post_user_psk
2431
                            );
2432
2433
                            // Encrypt the file
2434
                            $encryptedFile = encryptFile($record2['file'] . '.delete', $SETTINGS['path_to_upload_folder']);
2435
2436
                            DB::update(
2437
                                prefixTable('files'),
2438
                                array(
2439
                                    'file' => $encryptedFile['fileHash'],
2440
                                    'status' => TP_ENCRYPTION_NAME,
2441
                                ),
2442
                                'id = %i',
2443
                                $record2['id']
2444
                            );
2445
2446
                            // Save key
2447
                            DB::insert(
2448
                                prefixTable('sharekeys_files'),
2449
                                array(
2450
                                    'object_id' => (int) $record2['id'],
2451
                                    'user_id' => (int) $_SESSION['user_id'],
2452
                                    'share_key' => encryptUserObjectKey($encryptedFile['objectKey'], $_SESSION['user']['public_key']),
2453
                                )
2454
                            );
2455
2456
                            // Unlink original file
2457
                            unlink($SETTINGS['path_to_upload_folder'] . '/' . $record2['file']);
2458
                        }
2459
                    }
2460
                }
2461
2462
                // SHould we change step?
2463
                $next_start = (int) $post_start + (int) $post_length;
2464
                if ($next_start > $countUserPersonalItems) {
2465
                    // Now update user
2466
                    DB::update(
2467
                        prefixTable('users'),
2468
                        array(
2469
                            'special' => 'none',
2470
                            'upgrade_needed' => 0,
2471
                            'encrypted_psk' => '',
2472
                        ),
2473
                        'id = %i',
2474
                        $post_user_id
2475
                    );
2476
2477
                    $next_step = 'finished';
2478
                    $next_start = 0;
2479
                }
2480
2481
                // Continu with next step
2482
                return prepareExchangedData(
2483
                    $SETTINGS['cpassman_dir'],
2484
                    array(
2485
                        'error' => false,
2486
                        'message' => '',
2487
                        'step' => $next_step,
2488
                        'start' => $next_start,
2489
                        'userId' => $post_user_id
2490
                    ),
2491
                    'encode'
2492
                );
2493
            }
2494
        }
2495
        
2496
        // Nothing to do
2497
        return prepareExchangedData(
2498
            $SETTINGS['cpassman_dir'],
2499
            array(
2500
                'error' => true,
2501
                'message' => langHdl('error_no_user'),
2502
            ),
2503
            'encode'
2504
        );
2505
    }
2506
    
2507
    // Nothing to do
2508
    return prepareExchangedData(
2509
        $SETTINGS['cpassman_dir'],
2510
        array(
2511
            'error' => true,
2512
            'message' => langHdl('error_no_user'),
2513
        ),
2514
        'encode'
2515
    );
2516
}
2517
2518
2519
function getUserInfo(
2520
    int $post_user_id,
2521
    string $post_fields,
2522
    array $SETTINGS
2523
)
2524
{
2525
    if (isUserIdValid($post_user_id) === true) {
2526
        // Get user info
2527
        $userData = DB::queryFirstRow(
2528
            'SELECT '.$post_fields.'
2529
            FROM ' . prefixTable('users') . '
2530
            WHERE id = %i',
2531
            $post_user_id
2532
        );
2533
        if (DB::count() > 0) {
2534
            return prepareExchangedData(
2535
                $SETTINGS['cpassman_dir'],
2536
                array(
2537
                    'error' => false,
2538
                    'message' => '',
2539
                    'queryResults' => $userData,
2540
                ),
2541
                'encode'
2542
            );
2543
        }
2544
    }
2545
    return prepareExchangedData(
2546
        $SETTINGS['cpassman_dir'],
2547
        array(
2548
            'error' => true,
2549
            'message' => langHdl('error_no_user'),
2550
        ),
2551
        'encode'
2552
    );
2553
}
2554
2555
/**
2556
 * Change user auth password
2557
 *
2558
 * @param integer $post_user_id
2559
 * @param string $post_current_pwd
2560
 * @param string $post_new_pwd
2561
 * @param array $SETTINGS
2562
 * @return string
2563
 */
2564
function changeUserAuthenticationPassword(
2565
    int $post_user_id,
2566
    string $post_current_pwd,
2567
    string $post_new_pwd,
2568
    array $SETTINGS
2569
)
2570
{
2571
    if (isUserIdValid($post_user_id) === true) {
2572
        // Get user info
2573
        $userData = DB::queryFirstRow(
2574
            'SELECT auth_type, login, private_key
2575
            FROM ' . prefixTable('users') . '
2576
            WHERE id = %i',
2577
            $post_user_id
2578
        );
2579
        if (DB::count() > 0 && empty($userData['private_key']) === false) {
2580
            // Now check if current password is correct
2581
            // For this, just check if it is possible to decrypt the privatekey
2582
            // And compare it to the one in session
2583
            try {
2584
                $privateKey = decryptPrivateKey($post_current_pwd, $userData['private_key']);
2585
            } catch (Exception $e) {
2586
                return prepareExchangedData(
2587
                    $SETTINGS['cpassman_dir'],
2588
                    array(
2589
                        'error' => true,
2590
                        'message' => langHdl('bad_password'),
2591
                    ),
2592
                    'encode'
2593
                );
2594
            }
2595
2596
            // Load superGlobals
2597
            include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2598
            $superGlobal = new protect\SuperGlobal\SuperGlobal();
2599
2600
            if ($superGlobal->get('private_key', 'SESSION', 'user') === $privateKey) {
2601
                // Encrypt it with new password
2602
                $hashedPrivateKey = encryptPrivateKey($post_new_pwd, $privateKey);
2603
2604
                // Generate new hash for auth password
2605
                // load passwordLib library
2606
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2607
                $pwdlib->register();
2608
                $pwdlib = new PasswordLib\PasswordLib();
2609
2610
                // Prepare variables
2611
                $newPw = $pwdlib->createPasswordHash($post_new_pwd);
2612
2613
                // Update user account
2614
                DB::update(
2615
                    prefixTable('users'),
2616
                    array(
2617
                        'private_key' => $hashedPrivateKey,
2618
                        'pw' => $newPw,
2619
                        'special' => 'none',
2620
                    ),
2621
                    'id = %i',
2622
                    $post_user_id
2623
                );
2624
2625
                $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2626
2627
                return prepareExchangedData(
2628
                    $SETTINGS['cpassman_dir'],
2629
                    array(
2630
                        'error' => false,
2631
                        'message' => langHdl('done'),'',
2632
                    ),
2633
                    'encode'
2634
                );
2635
            }
2636
            
2637
            // ERROR
2638
            return prepareExchangedData(
2639
                $SETTINGS['cpassman_dir'],
2640
                array(
2641
                    'error' => true,
2642
                    'message' => langHdl('bad_password'),
2643
                ),
2644
                'encode'
2645
            );
2646
        }
2647
    }
2648
        
2649
    return prepareExchangedData(
2650
        $SETTINGS['cpassman_dir'],
2651
        array(
2652
            'error' => true,
2653
            'message' => langHdl('error_no_user'),
2654
        ),
2655
        'encode'
2656
    );
2657
}
2658
2659
            
2660
function changeUserLDAPAuthenticationPassword(
2661
    int $post_user_id,
2662
    string $post_previous_pwd,
2663
    string $post_current_pwd,
2664
    array $SETTINGS
2665
)
2666
{
2667
    if (isUserIdValid($post_user_id) === true) {
2668
        // Get user info
2669
        $userData = DB::queryFirstRow(
2670
            'SELECT auth_type, login, private_key, special
2671
            FROM ' . prefixTable('users') . '
2672
            WHERE id = %i',
2673
            $post_user_id
2674
        );
2675
        
2676
        if (DB::count() > 0 && empty($userData['private_key']) === false) {
2677
            // Now check if current password is correct (only if not ldap)
2678
            if ($userData['auth_type'] === 'ldap' && $userData['special'] === 'auth-pwd-change') {
2679
                // As it is a change for an LDAP user
2680
                
2681
                // Now check if current password is correct
2682
                // For this, just check if it is possible to decrypt the privatekey
2683
                // And compare it to the one in session
2684
                $privateKey = decryptPrivateKey($post_previous_pwd, $userData['private_key']);
2685
2686
                // Encrypt it with new password
2687
                $hashedPrivateKey = encryptPrivateKey($post_current_pwd, $privateKey);
2688
2689
                // Update user account
2690
                DB::update(
2691
                    prefixTable('users'),
2692
                    array(
2693
                        'private_key' => $hashedPrivateKey,
2694
                        'special' => 'none',
2695
                    ),
2696
                    'id = %i',
2697
                    $post_user_id
2698
                );
2699
2700
                // Load superGlobals
2701
                include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2702
                $superGlobal = new protect\SuperGlobal\SuperGlobal();
2703
                $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2704
2705
                return prepareExchangedData(
2706
                    $SETTINGS['cpassman_dir'],
2707
                    array(
2708
                        'error' => false,
2709
                        'message' => langHdl('done'),'',
2710
                    ),
2711
                    'encode'
2712
                );
2713
            }
2714
2715
            // For this, just check if it is possible to decrypt the privatekey
2716
            // And try to decrypt one existing key
2717
            $privateKey = decryptPrivateKey($post_previous_pwd, $userData['private_key']);
2718
2719
            if (empty($privateKey) === true) {
2720
                return prepareExchangedData(
2721
                    $SETTINGS['cpassman_dir'],
2722
                    array(
2723
                        'error' => true,
2724
                        'message' => langHdl('password_is_not_correct'),
2725
                    ),
2726
                    'encode'
2727
                );
2728
            }
2729
2730
            // Test if possible to decvrypt one key
2731
            // Get one item
2732
            $record = DB::queryFirstRow(
2733
                'SELECT id, pw
2734
                FROM ' . prefixTable('items') . '
2735
                WHERE perso = 0'
2736
            );
2737
2738
            // Get itemKey from current user
2739
            $currentUserKey = DB::queryFirstRow(
2740
                'SELECT share_key, increment_id
2741
                FROM ' . prefixTable('sharekeys_items') . '
2742
                WHERE object_id = %i AND user_id = %i',
2743
                $record['id'],
2744
                $post_user_id
2745
            );
2746
2747
            if (count($currentUserKey) > 0) {
2748
                // Decrypt itemkey with user key
2749
                // use old password to decrypt private_key
2750
                $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $privateKey);
2751
                
2752
                if (empty(base64_decode($itemKey)) === false) {
2753
                    // GOOD password
2754
                    // Encrypt it with current password
2755
                    $hashedPrivateKey = encryptPrivateKey($post_current_pwd, $privateKey);
2756
                    
2757
                    // Update user account
2758
                    DB::update(
2759
                        prefixTable('users'),
2760
                        array(
2761
                            'private_key' => $hashedPrivateKey,
2762
                            'special' => 'none',
2763
                        ),
2764
                        'id = %i',
2765
                        $post_user_id
2766
                    );
2767
                    
2768
                    // Load superGlobals
2769
                    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2770
                    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2771
                    $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2772
2773
                    return prepareExchangedData(
2774
                        $SETTINGS['cpassman_dir'],
2775
                        array(
2776
                            'error' => false,
2777
                            'message' => langHdl('done'),
2778
                        ),
2779
                        'encode'
2780
                    );
2781
                }
2782
            }
2783
            
2784
            // ERROR
2785
            return prepareExchangedData(
2786
                $SETTINGS['cpassman_dir'],
2787
                array(
2788
                    'error' => true,
2789
                    'message' => langHdl('bad_password'),
2790
                ),
2791
                'encode'
2792
            );
2793
        }
2794
    }
2795
2796
    // ERROR
2797
    return prepareExchangedData(
2798
    $SETTINGS['cpassman_dir'],
2799
        array(
2800
            'error' => true,
2801
            'message' => langHdl('error_no_user'),
2802
        ),
2803
        'encode'
2804
    );
2805
}
2806
2807
2808
function increaseSessionDuration(
2809
    int $duration
2810
): string
2811
{
2812
    // check if session is not already expired.
2813
    if ($_SESSION['sessionDuration'] > time()) {
2814
        // Calculate end of session
2815
        $_SESSION['sessionDuration'] = (int) ($_SESSION['sessionDuration'] + $duration);
2816
        // Update table
2817
        DB::update(
2818
            prefixTable('users'),
2819
            array(
2820
                'session_end' => $_SESSION['sessionDuration'],
2821
            ),
2822
            'id = %i',
2823
            $_SESSION['user_id']
2824
        );
2825
        // Return data
2826
        return '[{"new_value":"' . $_SESSION['sessionDuration'] . '"}]';
2827
    }
2828
    
2829
    return '[{"new_value":"expired"}]';
2830
}