Passed
Push — master ( 64c076...b207d0 )
by Nils
09:35
created

keyHandler()   C

Complexity

Conditions 11
Paths 9

Size

Total Lines 109
Code Lines 62

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
cc 11
eloc 62
c 7
b 0
f 0
nc 9
nop 3
dl 0
loc 109
rs 6.6824

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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