Passed
Push — teampass_3.0 ( 5e4b29...ad0650 )
by Nils
05:21
created

continueReEncryptingUserSharekeys()   F

Complexity

Conditions 20
Paths 11

Size

Total Lines 216
Code Lines 142

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 2 Features 0
Metric Value
cc 20
eloc 142
c 4
b 2
f 0
nc 11
nop 6
dl 0
loc 216
rs 3.3333

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