Passed
Push — master ( 3b3500...0bff11 )
by Nils
04:16
created

generateOneTimeCode()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 71
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 5
eloc 43
c 2
b 1
f 0
nc 4
nop 3
dl 0
loc 71
rs 8.9208

How to fix   Long Method   

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