Passed
Push — master ( 5154a4...7dea86 )
by Nils
04:26
created

mainQuery()   B

Complexity

Conditions 8
Paths 14

Size

Total Lines 72
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 46
Bugs 3 Features 0
Metric Value
cc 8
eloc 47
nc 14
nop 1
dl 0
loc 72
rs 7.9119
c 46
b 3
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Teampass - a collaborative passwords manager.
7
 * ---
8
 * This library is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 * ---
12
 * @project   Teampass
13
 * @file      main.queries.php
14
 * ---
15
 * @author    Nils Laumaillé ([email protected])
16
 * @copyright 2009-2022 Teampass.net
17
 * @license   https://spdx.org/licenses/GPL-3.0-only.html#licenseText GPL-3.0
18
 * ---
19
 * @see       https://www.teampass.net
20
 */
21
22
if (isset($_SESSION) === false) {
23
    include_once 'SecureHandler.php';
24
    session_name('teampass_session');
25
    session_start();
26
    $_SESSION['CPM'] = 1;
27
}
28
29
if (isset($_SESSION['CPM']) === false || $_SESSION['CPM'] !== 1) {
30
    $_SESSION['error']['code'] = '1004';
31
    include '../error.php';
32
    exit();
33
}
34
35
// Load config
36
if (file_exists('../includes/config/tp.config.php')) {
37
    include '../includes/config/tp.config.php';
38
} elseif (file_exists('./includes/config/tp.config.php')) {
39
    include './includes/config/tp.config.php';
40
} else {
41
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
42
}
43
44
// Define Timezone
45
date_default_timezone_set(isset($SETTINGS['timezone']) === true ? $SETTINGS['timezone'] : 'UTC');
46
47
// DO CHECKS
48
require_once $SETTINGS['cpassman_dir'] . '/includes/config/include.php';
49
require_once $SETTINGS['cpassman_dir'] . '/sources/checks.php';
50
$post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING);
51
if (
52
    isset($post_type) === true
53
    && ($post_type === 'ga_generate_qr'
54
        //|| $post_type === 'recovery_send_pw_by_email'
55
        //|| $post_type === 'recovery_generate_new_password'
56
        || $post_type === 'get_teampass_settings')
57
) {
58
    // continue
59
    mainQuery($SETTINGS);
60
} elseif (
61
    isset($_SESSION['user_id']) === true
62
    && checkUser($_SESSION['user_id'], $_SESSION['key'], 'home', $SETTINGS) === false
63
) {
64
    $_SESSION['error']['code'] = ERR_NOT_ALLOWED; //not allowed page
65
    include $SETTINGS['cpassman_dir'] . '/error.php';
66
    exit();
67
} elseif ((isset($_SESSION['user_id']) === true
68
        && isset($_SESSION['key'])) === true
69
    || (isset($post_type) === true
70
        //&& $post_type === 'change_user_language'
71
        && null !== filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES))
72
) {
73
    // continue
74
    mainQuery($SETTINGS);
75
} else {
76
    $_SESSION['error']['code'] = ERR_NOT_ALLOWED; //not allowed page
77
    include $SETTINGS['cpassman_dir'] . '/error.php';
78
    exit();
79
}
80
81
/**
82
 * Undocumented function.
83
 */
84
function mainQuery(array $SETTINGS)
85
{
86
    header('Content-type: text/html; charset=utf-8');
87
    header('Cache-Control: no-cache, must-revalidate');
88
    error_reporting(E_ERROR);
89
90
91
    // Includes
92
    include_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $_SESSION['user_language'] . '.php';
93
    include_once $SETTINGS['cpassman_dir'] . '/includes/config/settings.php';
94
    include_once $SETTINGS['cpassman_dir'] . '/sources/main.functions.php';
95
    include_once $SETTINGS['cpassman_dir'] . '/sources/SplClassLoader.php';
96
97
    // Connect to mysql server
98
    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Database/Meekrodb/db.class.php';
99
100
    DB::$host = DB_HOST;
101
    DB::$user = DB_USER;
102
    DB::$password = defined('DB_PASSWD_CLEAR') === false ? defuseReturnDecrypted(DB_PASSWD, $SETTINGS) : DB_PASSWD_CLEAR;
103
    DB::$dbName = DB_NAME;
104
    DB::$port = DB_PORT;
105
    DB::$encoding = DB_ENCODING;
106
107
    // User's language loading
108
    include_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $_SESSION['user_language'] . '.php';
109
110
    // Prepare post variables
111
    $post_key = filter_input(INPUT_POST, 'key', FILTER_SANITIZE_STRING);
112
    $post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING);
113
    $post_type_category = filter_input(INPUT_POST, 'type_category', FILTER_SANITIZE_STRING);
114
    $post_data = filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
115
116
    // Check KEY
117
    if (isValueSetNullEmpty($post_key) === true) {
118
        echo prepareExchangedData(
119
            $SETTINGS['cpassman_dir'],
120
            array(
121
                'error' => true,
122
                'message' => langHdl('key_is_not_correct'),
123
            ),
124
            'encode'
125
        );
126
        return false;
127
    }
128
129
    // decrypt and retreive data in JSON format
130
    $dataReceived = prepareExchangedData(
131
        $SETTINGS['cpassman_dir'],
132
        $post_data,
133
        'decode'
134
    );
135
136
    switch ($post_type_category) {
137
        case 'action_password':
138
            echo passwordHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
It seems like $dataReceived can also be of type resource and string; however, parameter $dataReceived of passwordHandler() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

138
            echo passwordHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
139
            break;
140
141
        case 'action_user':
142
            echo userHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
It seems like $dataReceived can also be of type resource and string; however, parameter $dataReceived of userHandler() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

142
            echo userHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
143
            break;
144
145
        case 'action_mail':
146
            echo mailHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
It seems like $dataReceived can also be of type resource and string; however, parameter $dataReceived of mailHandler() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

146
            echo mailHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
147
            break;
148
149
        case 'action_key':
150
            echo keyHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
It seems like $dataReceived can also be of type resource and string; however, parameter $dataReceived of keyHandler() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

150
            echo keyHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
151
            break;
152
153
        case 'action_system':
154
            echo systemHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
It seems like $dataReceived can also be of type resource and string; however, parameter $dataReceived of systemHandler() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

154
            echo systemHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
155
            break;
156
    }
157
    
158
    // Manage type of action asked
159
    //switch ($post_type) {
160
        /*
161
         * TODO Check if suggestions are existing
162
         */
163
        /*
164
        case 'is_existings_suggestions':
165
            if ($_SESSION['user_manager'] === '1' || $_SESSION['is_admin'] === '1') {
166
                $count = 0;
167
                DB::query('SELECT * FROM ' . prefixTable('items_change'));
168
                $count += DB::count();
169
                DB::query('SELECT * FROM ' . prefixTable('suggestion'));
170
                $count += DB::count();
171
172
                echo '[ { "error" : "" , "count" : "' . $count . '" , "show_sug_in_menu" : "0"} ]';
173
                break;
174
            }
175
            
176
            if (isset($_SESSION['nb_item_change_proposals']) && $_SESSION['nb_item_change_proposals'] > 0) {
177
                echo '[ { "error" : "" , "count" : "' . $_SESSION['nb_item_change_proposals'] . '" , "show_sug_in_menu" : "1"} ]';
178
                break;
179
            }
180
            
181
            echo '[ { "error" : "" , "count" : "" , "show_sug_in_menu" : "0"} ]';
182
183
            break;
184
        */
185
    //}
186
}
187
188
function passwordHandler(string $post_type, array|null $dataReceived, array $SETTINGS)
189
{
190
    switch ($post_type) {
191
        case 'change_pw'://action_password
192
            return changePassword(
193
                (string) filter_var($dataReceived['new_pw'], FILTER_SANITIZE_STRING),
194
                isset($dataReceived['current_pw']) === true ? (string) filter_var($dataReceived['current_pw'], FILTER_SANITIZE_STRING) : '',
195
                (int) filter_var($dataReceived['complexity'], FILTER_SANITIZE_NUMBER_INT),
196
                (string) filter_var($dataReceived['change_request'], FILTER_SANITIZE_STRING),
197
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
198
                $SETTINGS
199
            );            
200
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
201
202
        /*
203
        * Change user's authenticataion password
204
        */
205
        case 'change_user_auth_password'://action_password
206
            return changeUserAuthenticationPassword(
207
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
208
                (string) filter_var($dataReceived['old_password'], FILTER_SANITIZE_STRING),
209
                (string) filter_var($dataReceived['new_password'], FILTER_SANITIZE_STRING),
210
                $SETTINGS
211
            );
212
            break;
213
214
        /*
215
        * User's authenticataion password in LDAP has changed
216
        */
217
        case 'change_user_ldap_auth_password'://action_password
218
            return /** @scrutinizer ignore-call */ changeUserLDAPAuthenticationPassword(
219
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
220
                filter_var($dataReceived['previous_password'], FILTER_SANITIZE_STRING),
221
                filter_var($dataReceived['current_password'], FILTER_SANITIZE_STRING),
222
                $SETTINGS
223
            );
224
            break;
225
226
        /*
227
        * test_current_user_password_is_correct
228
        */
229
        case 'test_current_user_password_is_correct'://action_password
230
            return isUserPasswordCorrect(
231
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
232
                (string) filter_var($dataReceived['password'], FILTER_SANITIZE_STRING),
233
                $SETTINGS
234
            );
235
            break;
236
237
        /*
238
        * User's password has to be initialized
239
        */
240
        case 'initialize_user_password'://action_password
241
            return initializeUserPassword(
242
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
243
                (string) filter_var($dataReceived['special'], FILTER_SANITIZE_STRING),
244
                (string) filter_var($dataReceived['password'], FILTER_SANITIZE_STRING),
245
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
246
                $SETTINGS
247
            );
248
            break;
249
    }
250
}
251
252
253
function userHandler(string $post_type, array|null $dataReceived, array $SETTINGS)
254
{
255
    switch ($post_type) {
256
        /*
257
        * Get info 
258
        */
259
        case 'get_user_info'://action_user
260
            return getUserInfo(
261
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
262
                (string) filter_var($dataReceived['fields'], FILTER_SANITIZE_STRING),
263
                $SETTINGS
264
            );
265
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
266
267
        /*
268
        * Increase the session time of User
269
        */
270
        case 'increase_session_time'://action_user
271
            return increaseSessionDuration(
272
                (int) filter_input(INPUT_POST, 'duration', FILTER_SANITIZE_NUMBER_INT)
273
            );
274
            break;
275
276
        /*
277
        * Generate a password generic
278
        */
279
        case 'generate_password'://action_user
280
            return generateGenericPassword(
281
                (int) filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT),
282
                (bool) filter_input(INPUT_POST, 'secure_pwd', FILTER_VALIDATE_BOOLEAN),
283
                (bool) filter_input(INPUT_POST, 'lowercase', FILTER_VALIDATE_BOOLEAN),
284
                (bool) filter_input(INPUT_POST, 'capitalize', FILTER_VALIDATE_BOOLEAN),
285
                (bool) filter_input(INPUT_POST, 'numerals', FILTER_VALIDATE_BOOLEAN),
286
                (bool) filter_input(INPUT_POST, 'symbols', FILTER_VALIDATE_BOOLEAN),
287
                $SETTINGS
288
            );
289
            break;
290
291
        /*
292
        * Refresh list of last items seen
293
        */
294
        case 'refresh_list_items_seen'://action_user
295
            return refreshUserItemsSeenList(
296
                $SETTINGS
297
            );
298
            break;
299
300
        /*
301
            * This will generate the QR Google Authenticator
302
            */
303
        case 'ga_generate_qr'://action_user
304
            return generateQRCode(
305
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
306
                (string) filter_var($dataReceived['demand_origin'], FILTER_SANITIZE_STRING),
307
                (string) filter_var($dataReceived['send_email'], FILTER_SANITIZE_STRING),
308
                (string) filter_var($dataReceived['login'], FILTER_SANITIZE_STRING),
309
                (string) filter_var($dataReceived['pwd'], FILTER_SANITIZE_STRING),
310
                $SETTINGS
311
            );
312
            break;
313
    }
314
}
315
316
317
function mailHandler(string $post_type, array|null $dataReceived, array $SETTINGS)
318
{
319
    switch ($post_type) {
320
        /*
321
        * CASE
322
        * Send email
323
        */
324
        case 'mail_me'://action_mail
325
            return sendMailToUser(
326
                filter_var($dataReceived['receipt'], FILTER_SANITIZE_STRING),
327
                $dataReceived['body'],
328
                (string) filter_var($dataReceived['subject'], FILTER_SANITIZE_STRING),
329
                (array) filter_var_array(
330
                    $dataReceived['pre_replace'],
331
                    FILTER_SANITIZE_STRING
332
                ),
333
                $SETTINGS
334
            );
335
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
336
        
337
        /*
338
        * Send emails not sent
339
        */
340
        case 'send_waiting_emails'://mail
341
            sendEmailsNotSent(
342
                $SETTINGS
343
            );
344
            echo '';
345
            break;
346
    }
347
}
348
349
350
function keyHandler(string $post_type, array|null $dataReceived, array $SETTINGS)
351
{
352
    switch ($post_type) {
353
        /*
354
        * Generate a temporary encryption key for user
355
        */
356
        case 'generate_temporary_encryption_key'://action_key
357
            return generateOneTimeCode(
358
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
359
                $SETTINGS
360
            );
361
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
362
363
        /*
364
        * user_sharekeys_reencryption_start
365
        */
366
        case 'user_sharekeys_reencryption_start'://action_key
367
            return startReEncryptingUserSharekeys(
368
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
369
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
370
                $SETTINGS
371
            );
372
            break;
373
374
        /*
375
        * user_sharekeys_reencryption_next
376
        */
377
        case 'user_sharekeys_reencryption_next'://action_key
378
            return continueReEncryptingUserSharekeys(
379
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
380
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
381
                (string) filter_var($dataReceived['action'], FILTER_SANITIZE_STRING),
382
                (int) filter_var($dataReceived['start'], FILTER_SANITIZE_NUMBER_INT),
383
                (int) filter_var($dataReceived['length'], FILTER_SANITIZE_NUMBER_INT),
384
                $SETTINGS
385
            );
386
            break;
387
388
        /*
389
        * user_psk_reencryption
390
        */
391
        case 'user_psk_reencryption'://action_key
392
            return migrateTo3_DoUserPersonalItemsEncryption(
393
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
394
                (int) filter_var($dataReceived['start'], FILTER_SANITIZE_NUMBER_INT),
395
                (int) filter_var($dataReceived['length'], FILTER_SANITIZE_NUMBER_INT),
396
                (string) filter_var($dataReceived['userPsk'], FILTER_SANITIZE_STRING),
397
                $SETTINGS
398
            );
399
            break;
400
401
        /*
402
            * User's public/private keys change
403
            */
404
        case 'change_private_key_encryption_password'://action_key
405
            return changePrivateKeyEncryptionPassword(
406
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
407
                (string) filter_var($dataReceived['current_code'], FILTER_SANITIZE_STRING),
408
                (string) filter_var($dataReceived['new_code'], FILTER_SANITIZE_STRING),
409
                (string) filter_var($dataReceived['action_type'], FILTER_SANITIZE_STRING),
410
                $SETTINGS
411
            );
412
            break;
413
414
        /*
415
            * Generates a KEY with CRYPT
416
            */
417
        case 'generate_new_key'://action_key
418
            // load passwordLib library
419
            $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
420
            $pwdlib->register();
421
            $pwdlib = new PasswordLib\PasswordLib();
422
            // generate key
423
            $key = $pwdlib->getRandomToken(filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT));
424
            return '[{"key" : "' . htmlentities($key, ENT_QUOTES) . '"}]';
425
            break;
426
    }
427
}
428
429
430
function systemHandler(string $post_type, array|null $dataReceived, array $SETTINGS)
431
{
432
    switch ($post_type) {
433
        /*
434
        * How many items for this user
435
        */
436
        case 'get_number_of_items_to_treat'://action_system
437
            return getNumberOfItemsToTreat(
438
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
439
                $SETTINGS
440
            );
441
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

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