Passed
Push — master ( d9bccd...639079 )
by Nils
11:04
created

userIsReady()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nc 1
nop 1
dl 0
loc 20
rs 9.8333
c 0
b 0
f 0
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
set_time_limit(600);
23
24
if (isset($_SESSION) === false) {
25
    include_once 'SecureHandler.php';
26
    session_name('teampass_session');
27
    session_start();
28
    $_SESSION['CPM'] = 1;
29
}
30
31
if (isset($_SESSION['CPM']) === false || $_SESSION['CPM'] !== 1) {
32
    $_SESSION['error']['code'] = '1004';
33
    include '../error.php';
34
    exit();
35
}
36
37
// Load config
38
if (file_exists('../includes/config/tp.config.php')) {
39
    include '../includes/config/tp.config.php';
40
} elseif (file_exists('./includes/config/tp.config.php')) {
41
    include './includes/config/tp.config.php';
42
} else {
43
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
44
}
45
46
// Define Timezone
47
date_default_timezone_set(isset($SETTINGS['timezone']) === true ? $SETTINGS['timezone'] : 'UTC');
48
49
// DO CHECKS
50
require_once $SETTINGS['cpassman_dir'] . '/includes/config/include.php';
51
require_once $SETTINGS['cpassman_dir'] . '/sources/checks.php';
52
$post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING);
53
if (
54
    isset($post_type) === true
55
    && ($post_type === 'ga_generate_qr'
56
        //|| $post_type === 'recovery_send_pw_by_email'
57
        //|| $post_type === 'recovery_generate_new_password'
58
        || $post_type === 'get_teampass_settings')
59
) {
60
    // continue
61
    mainQuery($SETTINGS);
62
} elseif (
63
    isset($_SESSION['user_id']) === true
64
    && checkUser($_SESSION['user_id'], $_SESSION['key'], 'home', $SETTINGS) === false
65
) {
66
    $_SESSION['error']['code'] = ERR_NOT_ALLOWED; //not allowed page
67
    include $SETTINGS['cpassman_dir'] . '/error.php';
68
    exit();
69
} elseif ((isset($_SESSION['user_id']) === true
70
        && isset($_SESSION['key'])) === true
71
    || (isset($post_type) === true
72
        //&& $post_type === 'change_user_language'
73
        && null !== filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES))
74
) {
75
    // continue
76
    mainQuery($SETTINGS);
77
} else {
78
    $_SESSION['error']['code'] = ERR_NOT_ALLOWED; //not allowed page
79
    include $SETTINGS['cpassman_dir'] . '/error.php';
80
    exit();
81
}
82
83
/**
84
 * Undocumented function.
85
 */
86
function mainQuery(array $SETTINGS)
87
{
88
    header('Content-type: text/html; charset=utf-8');
89
    header('Cache-Control: no-cache, must-revalidate');
90
    error_reporting(E_ERROR);
91
92
93
    // Includes
94
    include_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $_SESSION['user_language'] . '.php';
95
    include_once $SETTINGS['cpassman_dir'] . '/includes/config/settings.php';
96
    include_once $SETTINGS['cpassman_dir'] . '/sources/main.functions.php';
97
    include_once $SETTINGS['cpassman_dir'] . '/sources/SplClassLoader.php';
98
99
    // Connect to mysql server
100
    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Database/Meekrodb/db.class.php';
101
102
    DB::$host = DB_HOST;
103
    DB::$user = DB_USER;
104
    DB::$password = defined('DB_PASSWD_CLEAR') === false ? defuseReturnDecrypted(DB_PASSWD, $SETTINGS) : DB_PASSWD_CLEAR;
105
    DB::$dbName = DB_NAME;
106
    DB::$port = DB_PORT;
107
    DB::$encoding = DB_ENCODING;
108
    DB::$ssl = DB_SSL;
109
    DB::$connect_options = DB_CONNECT_OPTIONS;
110
111
    // User's language loading
112
    include_once $SETTINGS['cpassman_dir'] . '/includes/language/' . $_SESSION['user_language'] . '.php';
113
114
    // Prepare post variables
115
    $post_key = filter_input(INPUT_POST, 'key', FILTER_SANITIZE_STRING);
116
    $post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING);
117
    $post_type_category = filter_input(INPUT_POST, 'type_category', FILTER_SANITIZE_STRING);
118
    $post_data = filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
119
120
    // Check KEY
121
    if (isValueSetNullEmpty($post_key) === true) {
122
        echo prepareExchangedData(
123
            $SETTINGS['cpassman_dir'],
124
            array(
125
                'error' => true,
126
                'message' => langHdl('key_is_not_correct'),
127
            ),
128
            'encode'
129
        );
130
        return false;
131
    }
132
133
    // decrypt and retreive data in JSON format
134
    $dataReceived = prepareExchangedData(
135
        $SETTINGS['cpassman_dir'],
136
        $post_data,
137
        'decode'
138
    );
139
140
    switch ($post_type_category) {
141
        case 'action_password':
142
            echo passwordHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
It seems like $dataReceived can also be of type resource; however, parameter $dataReceived of passwordHandler() does only seem to accept array|null|string, 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 passwordHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
Bug introduced by
Are you sure the usage of passwordHandler($post_ty...ataReceived, $SETTINGS) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
Are you sure passwordHandler($post_ty...ataReceived, $SETTINGS) of type void can be used in echo? ( 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 /** @scrutinizer ignore-type */ passwordHandler($post_type, $dataReceived, $SETTINGS);
Loading history...
143
            break;
144
145
        case 'action_user':
146
            echo userHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
It seems like $dataReceived can also be of type resource; however, parameter $dataReceived of userHandler() does only seem to accept array|null|string, 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 userHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
Bug introduced by
Are you sure the usage of userHandler($post_type, $dataReceived, $SETTINGS) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
Are you sure userHandler($post_type, $dataReceived, $SETTINGS) of type void can be used in echo? ( 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 /** @scrutinizer ignore-type */ userHandler($post_type, $dataReceived, $SETTINGS);
Loading history...
147
            break;
148
149
        case 'action_mail':
150
            echo mailHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
Are you sure mailHandler($post_type, $dataReceived, $SETTINGS) of type void can be used in echo? ( 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 /** @scrutinizer ignore-type */ mailHandler($post_type, $dataReceived, $SETTINGS);
Loading history...
Bug introduced by
It seems like $dataReceived can also be of type resource; however, parameter $dataReceived of mailHandler() does only seem to accept array|null|string, 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 mailHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
Bug introduced by
Are you sure the usage of mailHandler($post_type, $dataReceived, $SETTINGS) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
151
            break;
152
153
        case 'action_key':
154
            echo keyHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
Are you sure keyHandler($post_type, $dataReceived, $SETTINGS) of type void can be used in echo? ( 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 /** @scrutinizer ignore-type */ keyHandler($post_type, $dataReceived, $SETTINGS);
Loading history...
Bug introduced by
It seems like $dataReceived can also be of type resource; however, parameter $dataReceived of keyHandler() does only seem to accept array|null|string, 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 keyHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
Bug introduced by
Are you sure the usage of keyHandler($post_type, $dataReceived, $SETTINGS) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
155
            break;
156
157
        case 'action_system':
158
            echo systemHandler($post_type, $dataReceived, $SETTINGS);
0 ignored issues
show
Bug introduced by
Are you sure systemHandler($post_type...ataReceived, $SETTINGS) of type void can be used in echo? ( Ignorable by Annotation )

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

158
            echo /** @scrutinizer ignore-type */ systemHandler($post_type, $dataReceived, $SETTINGS);
Loading history...
Bug introduced by
Are you sure the usage of systemHandler($post_type...ataReceived, $SETTINGS) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
It seems like $dataReceived can also be of type resource; however, parameter $dataReceived of systemHandler() does only seem to accept array|null|string, 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

158
            echo systemHandler($post_type, /** @scrutinizer ignore-type */ $dataReceived, $SETTINGS);
Loading history...
159
            break;
160
    }
161
    
162
    // Manage type of action asked
163
    //switch ($post_type) {
164
        /*
165
         * TODO Check if suggestions are existing
166
         */
167
        /*
168
        case 'is_existings_suggestions':
169
            if ($_SESSION['user_manager'] === '1' || $_SESSION['is_admin'] === '1') {
170
                $count = 0;
171
                DB::query('SELECT * FROM ' . prefixTable('items_change'));
172
                $count += DB::count();
173
                DB::query('SELECT * FROM ' . prefixTable('suggestion'));
174
                $count += DB::count();
175
176
                echo '[ { "error" : "" , "count" : "' . $count . '" , "show_sug_in_menu" : "0"} ]';
177
                break;
178
            }
179
            
180
            if (isset($_SESSION['nb_item_change_proposals']) && $_SESSION['nb_item_change_proposals'] > 0) {
181
                echo '[ { "error" : "" , "count" : "' . $_SESSION['nb_item_change_proposals'] . '" , "show_sug_in_menu" : "1"} ]';
182
                break;
183
            }
184
            
185
            echo '[ { "error" : "" , "count" : "" , "show_sug_in_menu" : "0"} ]';
186
187
            break;
188
        */
189
    //}
190
}
191
192
/**
193
 * Handler for all password tasks
194
 *
195
 * @param string $post_type
196
 * @param array|null|string $dataReceived
197
 * @param array $SETTINGS
198
 * @return void
199
 */
200
function passwordHandler(string $post_type, /*php8 array|null|string*/ $dataReceived, array $SETTINGS)
201
{
202
    switch ($post_type) {
203
        case 'change_pw'://action_password
204
            return changePassword(
0 ignored issues
show
Bug Best Practice introduced by
The expression return changePassword((s...NUMBER_INT), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
205
                (string) filter_var($dataReceived['new_pw'], FILTER_SANITIZE_STRING),
206
                isset($dataReceived['current_pw']) === true ? (string) filter_var($dataReceived['current_pw'], FILTER_SANITIZE_STRING) : '',
207
                (int) filter_var($dataReceived['complexity'], FILTER_SANITIZE_NUMBER_INT),
208
                (string) filter_var($dataReceived['change_request'], FILTER_SANITIZE_STRING),
209
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
210
                $SETTINGS
211
            );
212
213
        /*
214
        * Change user's authenticataion password
215
        */
216
        case 'change_user_auth_password'://action_password
217
            return changeUserAuthenticationPassword(
0 ignored issues
show
Bug Best Practice introduced by
The expression return changeUserAuthent...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
218
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
219
                (string) filter_var($dataReceived['old_password'], FILTER_SANITIZE_STRING),
220
                (string) filter_var($dataReceived['new_password'], FILTER_SANITIZE_STRING),
221
                $SETTINGS
222
            );
223
224
        /*
225
        * User's authenticataion password in LDAP has changed
226
        */
227
        case 'change_user_ldap_auth_password'://action_password
228
            return /** @scrutinizer ignore-call */ changeUserLDAPAuthenticationPassword(
0 ignored issues
show
Bug Best Practice introduced by
The expression return changeUserLDAPAut...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
229
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
230
                filter_var($dataReceived['previous_password'], FILTER_SANITIZE_STRING),
231
                filter_var($dataReceived['current_password'], FILTER_SANITIZE_STRING),
232
                $SETTINGS
233
            );
234
235
        /*
236
        * test_current_user_password_is_correct
237
        */
238
        case 'test_current_user_password_is_correct'://action_password
239
            return isUserPasswordCorrect(
0 ignored issues
show
Bug Best Practice introduced by
The expression return isUserPasswordCor...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
240
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
241
                (string) filter_var($dataReceived['password'], FILTER_SANITIZE_STRING),
242
                $SETTINGS
243
            );
244
245
        /*
246
        * User's password has to be initialized
247
        */
248
        case 'initialize_user_password'://action_password
249
            return initializeUserPassword(
0 ignored issues
show
Bug Best Practice introduced by
The expression return initializeUserPas...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
250
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
251
                (string) filter_var($dataReceived['special'], FILTER_SANITIZE_STRING),
252
                (string) filter_var($dataReceived['password'], FILTER_SANITIZE_STRING),
253
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
254
                $SETTINGS
255
            );
256
    }
257
}
258
259
/**
260
 * Handler for all user tasks
261
 *
262
 * @param string $post_type
263
 * @param array|null|string $dataReceived
264
 * @param array $SETTINGS
265
 * @return void
266
 */
267
function userHandler(string $post_type, /*php8 array|null|string*/ $dataReceived, array $SETTINGS)
268
{
269
    switch ($post_type) {
270
        /*
271
        * Get info 
272
        */
273
        case 'get_user_info'://action_user
274
            return getUserInfo(
0 ignored issues
show
Bug Best Practice introduced by
The expression return getUserInfo((int)...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
275
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
276
                (string) filter_var($dataReceived['fields'], FILTER_SANITIZE_STRING),
277
                $SETTINGS
278
            );
279
280
        /*
281
        * Increase the session time of User
282
        */
283
        case 'increase_session_time'://action_user
284
            return increaseSessionDuration(
0 ignored issues
show
Bug Best Practice introduced by
The expression return increaseSessionDu...R_SANITIZE_NUMBER_INT)) returns the type string which is incompatible with the documented return type void.
Loading history...
285
                (int) filter_input(INPUT_POST, 'duration', FILTER_SANITIZE_NUMBER_INT)
286
            );
287
288
        /*
289
        * Generate a password generic
290
        */
291
        case 'generate_password'://action_user
292
            return generateGenericPassword(
0 ignored issues
show
Bug Best Practice introduced by
The expression return generateGenericPa...TE_BOOLEAN), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
293
                (int) filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT),
294
                (bool) filter_input(INPUT_POST, 'secure_pwd', FILTER_VALIDATE_BOOLEAN),
295
                (bool) filter_input(INPUT_POST, 'lowercase', FILTER_VALIDATE_BOOLEAN),
296
                (bool) filter_input(INPUT_POST, 'capitalize', FILTER_VALIDATE_BOOLEAN),
297
                (bool) filter_input(INPUT_POST, 'numerals', FILTER_VALIDATE_BOOLEAN),
298
                (bool) filter_input(INPUT_POST, 'symbols', FILTER_VALIDATE_BOOLEAN),
299
                $SETTINGS
300
            );
301
302
        /*
303
        * Refresh list of last items seen
304
        */
305
        case 'refresh_list_items_seen'://action_user
306
            return refreshUserItemsSeenList(
0 ignored issues
show
Bug Best Practice introduced by
The expression return refreshUserItemsSeenList($SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
307
                $SETTINGS
308
            );
309
310
        /*
311
        * This will generate the QR Google Authenticator
312
        */
313
        case 'ga_generate_qr'://action_user
314
            return generateQRCode(
0 ignored issues
show
Bug Best Practice introduced by
The expression return generateQRCode((i...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
315
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
316
                (string) filter_var($dataReceived['demand_origin'], FILTER_SANITIZE_STRING),
317
                (string) filter_var($dataReceived['send_email'], FILTER_SANITIZE_STRING),
318
                (string) filter_var($dataReceived['login'], FILTER_SANITIZE_STRING),
319
                (string) filter_var($dataReceived['pwd'], FILTER_SANITIZE_STRING),
320
                $SETTINGS
321
            );
322
323
        /*
324
        * This will set the user ready
325
        */
326
        case 'user_is_ready'://action_user
327
            return userIsReady(
0 ignored issues
show
Bug Best Practice introduced by
The expression return userIsReady((int)...NUMBER_INT), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
328
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
329
                $SETTINGS
0 ignored issues
show
Unused Code introduced by
The call to userIsReady() has too many arguments starting with $SETTINGS. ( Ignorable by Annotation )

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

329
            return /** @scrutinizer ignore-call */ userIsReady(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
330
            );
331
    }
332
}
333
334
/**
335
 * Handler for all mail tasks
336
 *
337
 * @param string $post_type
338
 * @param array|null|string $dataReceived
339
 * @param array $SETTINGS
340
 * @return void
341
 */
342
function mailHandler(string $post_type, /*php8 array|null|string */$dataReceived, array $SETTINGS)
343
{
344
    switch ($post_type) {
345
        /*
346
        * CASE
347
        * Send email
348
        */
349
        case 'mail_me'://action_mail
350
            return sendMailToUser(
0 ignored issues
show
Bug Best Practice introduced by
The expression return sendMailToUser(fi...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
351
                filter_var($dataReceived['receipt'], FILTER_SANITIZE_STRING),
352
                $dataReceived['body'],
353
                (string) filter_var($dataReceived['subject'], FILTER_SANITIZE_STRING),
354
                (array) filter_var_array(
355
                    $dataReceived['pre_replace'],
356
                    FILTER_SANITIZE_STRING
357
                ),
358
                $SETTINGS
359
            );
360
        
361
        /*
362
        * Send emails not sent
363
        */
364
        case 'send_waiting_emails'://mail
365
            sendEmailsNotSent(
366
                $SETTINGS
367
            );
368
            echo '';
369
            break;
370
    }
371
}
372
373
/**
374
 * Handler for all key related tasks
375
 *
376
 * @param string $post_type
377
 * @param array|null|string $dataReceived
378
 * @param array $SETTINGS
379
 * @return void
380
 */
381
function keyHandler(string $post_type, /*php8 array|null|string */$dataReceived, array $SETTINGS)
382
{
383
    switch ($post_type) {
384
        /*
385
        * Generate a temporary encryption key for user
386
        */
387
        case 'generate_temporary_encryption_key'://action_key
388
            return generateOneTimeCode(
0 ignored issues
show
Bug Best Practice introduced by
The expression return generateOneTimeCo...NUMBER_INT), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
389
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
390
                $SETTINGS
391
            );
392
393
        /*
394
        * user_sharekeys_reencryption_start
395
        */
396
        case 'user_sharekeys_reencryption_start'://action_key
397
            return startReEncryptingUserSharekeys(
0 ignored issues
show
Bug Best Practice introduced by
The expression return startReEncrypting...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
398
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
399
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
400
                $SETTINGS
401
            );
402
403
        /*
404
        * user_sharekeys_reencryption_next
405
        */
406
        case 'user_sharekeys_reencryption_next'://action_key
407
            return continueReEncryptingUserSharekeys(
0 ignored issues
show
Bug Best Practice introduced by
The expression return continueReEncrypt...NUMBER_INT), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
408
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
409
                (bool) filter_var($dataReceived['self_change'], FILTER_SANITIZE_STRING),
410
                (string) filter_var($dataReceived['action'], FILTER_SANITIZE_STRING),
411
                (int) filter_var($dataReceived['start'], FILTER_SANITIZE_NUMBER_INT),
412
                (int) filter_var($dataReceived['length'], FILTER_SANITIZE_NUMBER_INT),
413
                $SETTINGS
414
            );
415
416
        /*
417
        * user_psk_reencryption
418
        */
419
        case 'user_psk_reencryption'://action_key
420
            return migrateTo3_DoUserPersonalItemsEncryption(
0 ignored issues
show
Bug Best Practice introduced by
The expression return migrateTo3_DoUser...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
421
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
422
                (int) filter_var($dataReceived['start'], FILTER_SANITIZE_NUMBER_INT),
423
                (int) filter_var($dataReceived['length'], FILTER_SANITIZE_NUMBER_INT),
424
                (string) filter_var($dataReceived['userPsk'], FILTER_SANITIZE_STRING),
425
                $SETTINGS
426
            );
427
428
        /*
429
            * User's public/private keys change
430
            */
431
        case 'change_private_key_encryption_password'://action_key
432
            return changePrivateKeyEncryptionPassword(
0 ignored issues
show
Bug Best Practice introduced by
The expression return changePrivateKeyE...IZE_STRING), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
433
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
434
                (string) filter_var($dataReceived['current_code'], FILTER_SANITIZE_STRING),
435
                (string) filter_var($dataReceived['new_code'], FILTER_SANITIZE_STRING),
436
                (string) filter_var($dataReceived['action_type'], FILTER_SANITIZE_STRING),
437
                $SETTINGS
438
            );
439
440
        /*
441
            * Generates a KEY with CRYPT
442
            */
443
        case 'generate_new_key'://action_key
444
            // load passwordLib library
445
            $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
446
            $pwdlib->register();
447
            $pwdlib = new PasswordLib\PasswordLib();
448
            // generate key
449
            $key = $pwdlib->getRandomToken(filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT));
450
            return '[{"key" : "' . htmlentities($key, ENT_QUOTES) . '"}]';
0 ignored issues
show
Bug Best Practice introduced by
The expression return '[{"key" : "' . h...ey, ENT_QUOTES) . '"}]' returns the type string which is incompatible with the documented return type void.
Loading history...
451
    }
452
}
453
454
/**
455
 * Handler for all system tasks
456
 *
457
 * @param string $post_type
458
 * @param array|null|string $dataReceived
459
 * @param array $SETTINGS
460
 * @return void
461
 */
462
function systemHandler(string $post_type, /*php8 array|null|string */$dataReceived, array $SETTINGS)
463
{
464
    switch ($post_type) {
465
        /*
466
        * How many items for this user
467
        */
468
        case 'get_number_of_items_to_treat'://action_system
469
            return getNumberOfItemsToTreat(
0 ignored issues
show
Bug Best Practice introduced by
The expression return getNumberOfItemsT...NUMBER_INT), $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
470
                (int) filter_var($dataReceived['user_id'], FILTER_SANITIZE_NUMBER_INT),
471
                $SETTINGS
472
            );
473
            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...
474
475
        /*
476
            * Sending statistics
477
            */
478
        case 'sending_statistics'://action_system
479
            sendingStatistics(
480
                $SETTINGS
481
            );
482
            break;
483
484
        /*
485
            * Generate BUG report
486
            */
487
        case 'generate_bug_report'://action_system
488
            return generateBugReport(
0 ignored issues
show
Bug Best Practice introduced by
The expression return generateBugReport...)$post_data, $SETTINGS) returns the type string which is incompatible with the documented return type void.
Loading history...
489
                (string) $post_data,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $post_data seems to be never defined.
Loading history...
490
                $SETTINGS
491
            );
492
            break;
493
494
        /*
495
        * get_teampass_settings
496
        */
497
        case 'get_teampass_settings'://action_system
498
            // Encrypt data to return
499
            return prepareExchangedData(
0 ignored issues
show
Bug Best Practice introduced by
The expression return prepareExchangedD...], $SETTINGS, 'encode') returns the type string which is incompatible with the documented return type void.
Loading history...
500
                $SETTINGS['cpassman_dir'],
501
                $SETTINGS,
502
                'encode'
503
            );
504
            break;
505
506
        /*
507
            * Generates a TOKEN with CRYPT
508
            */
509
        case 'save_token'://action_system
510
            $token = GenerateCryptKey(
511
                null !== filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT) ? (int) filter_input(INPUT_POST, 'size', FILTER_SANITIZE_NUMBER_INT) : 20,
512
                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,
513
                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,
514
                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,
515
                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,
516
                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,
517
                $SETTINGS
518
            );
519
            
520
            // store in DB
521
            DB::insert(
522
                prefixTable('tokens'),
523
                array(
524
                    'user_id' => (int) $_SESSION['user_id'],
525
                    'token' => $token,
526
                    'reason' => filter_input(INPUT_POST, 'reason', FILTER_SANITIZE_STRING),
527
                    'creation_timestamp' => time(),
528
                    'end_timestamp' => time() + filter_input(INPUT_POST, 'duration', FILTER_SANITIZE_NUMBER_INT), // in secs
529
                )
530
            );
531
532
            return '[{"token" : "' . $token . '"}]';
0 ignored issues
show
Bug Best Practice introduced by
The expression return '[{"token" : "' . $token . '"}]' returns the type string which is incompatible with the documented return type void.
Loading history...
533
            break;
534
    }
535
}
536
537
538
/**
539
 * Permits to set the user ready
540
 *
541
 * @param integer $userid
542
 * @return string
543
 */
544
function userIsReady(int $userid): string
545
{
546
    DB::debugmode(true);
547
    DB::update(
548
        prefixTable('users'),
549
        array(
550
            'is_ready_for_usage' => 1,
551
        ),
552
        'id = %i',
553
        $userid
554
    );
555
    DB::debugmode(false);
556
557
    // Send back
558
    return prepareExchangedData(
559
        $SETTINGS['cpassman_dir'],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $SETTINGS seems to be never defined.
Loading history...
560
            array(
561
                'error' => false,
562
            ),
563
            'encode'
564
        );
565
}
566
567
/**
568
 * Provides the number of items
569
 *
570
 * @param int   $userId     User ID
571
 * @param array $SETTINGS   TeampassSettings
572
 *
573
 * @return string
574
 */
575
function getNumberOfItemsToTreat(
576
    int $userId,
577
    array $SETTINGS
578
): string
579
{
580
    // get number of items
581
    DB::queryFirstRow(
582
        'SELECT increment_id
583
        FROM ' . prefixTable('sharekeys_items') .
584
        ' WHERE user_id = %i',
585
        $userId
586
    );
587
588
    // Send back
589
    return prepareExchangedData(
590
    $SETTINGS['cpassman_dir'],
591
        array(
592
            'error' => false,
593
            'nbItems' => DB::count(),
594
        ),
595
        'encode'
596
    );
597
}
598
599
600
/**
601
 * 
602
 */
603
function changePassword(
604
    string $post_new_password,
605
    string $post_current_password,
606
    int $post_password_complexity,
607
    string $post_change_request,
608
    int $post_user_id,
609
    array $SETTINGS
610
): string
611
{
612
    // load passwordLib library
613
    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
614
    $pwdlib->register();
615
    $pwdlib = new PasswordLib\PasswordLib();
616
617
    // Prepare variables
618
    $post_new_password_hashed = $pwdlib->createPasswordHash($post_new_password);
619
620
    // User has decided to change is PW
621
    if ($post_change_request === 'reset_user_password_expected'
622
        || $post_change_request === 'user_decides_to_change_password'
623
    ) {
624
        // Check that current user is correct
625
        if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
626
            return prepareExchangedData(
627
                $SETTINGS['cpassman_dir'],
628
                array(
629
                    'error' => true,
630
                    'message' => langHdl('error_not_allowed_to'),
631
                ),
632
                'encode'
633
            );
634
        }
635
636
        // check if expected security level is reached
637
        $dataUser = DB::queryfirstrow(
638
            'SELECT *
639
            FROM ' . prefixTable('users') . ' WHERE id = %i',
640
            $post_user_id
641
        );
642
643
        // check if badly written
644
        $dataUser['fonction_id'] = array_filter(
645
            explode(',', str_replace(';', ',', $dataUser['fonction_id']))
646
        );
647
        $dataUser['fonction_id'] = implode(',', $dataUser['fonction_id']);
648
        DB::update(
649
            prefixTable('users'),
650
            array(
651
                'fonction_id' => $dataUser['fonction_id'],
652
            ),
653
            'id = %i',
654
            $post_user_id
655
        );
656
657
        if (empty($dataUser['fonction_id']) === false) {
658
            $data = DB::queryFirstRow(
659
                'SELECT complexity
660
                FROM ' . prefixTable('roles_title') . '
661
                WHERE id IN (' . $dataUser['fonction_id'] . ')
662
                ORDER BY complexity DESC'
663
            );
664
        } else {
665
            // In case user has no roles yet
666
            $data = array();
667
            $data['complexity'] = 0;
668
        }
669
670
        if ((int) $post_password_complexity < (int) $data['complexity']) {
671
            return prepareExchangedData(
672
                $SETTINGS['cpassman_dir'],
673
                array(
674
                    'error' => true,
675
                    'message' => '<div style="margin:10px 0 10px 15px;">' . langHdl('complexity_level_not_reached') . '.<br>' .
676
                        langHdl('expected_complexity_level') . ': <b>' . TP_PW_COMPLEXITY[$data['complexity']][1] . '</b></div>',
677
                ),
678
                'encode'
679
            );
680
        }
681
682
        // Check that the 2 passwords are differents
683
        if ($post_current_password === $post_new_password) {
684
            return prepareExchangedData(
685
                $SETTINGS['cpassman_dir'],
686
                array(
687
                    'error' => true,
688
                    'message' => langHdl('password_already_used'),
689
                ),
690
                'encode'
691
            );
692
        }
693
694
        // update sessions
695
        $_SESSION['last_pw_change'] = mktime(0, 0, 0, (int) date('m'), (int) date('d'), (int) date('y'));
696
        $_SESSION['validite_pw'] = true;
697
698
        // BEfore updating, check that the pwd is correct
699
        if ($pwdlib->verifyPasswordHash($post_new_password, $post_new_password_hashed) === true && empty($dataUser['private_key']) === false) {
700
            $special_action = 'none';
701
            if ($post_change_request === 'reset_user_password_expected') {
702
                $_SESSION['user']['private_key'] = decryptPrivateKey($post_current_password, $dataUser['private_key']);
703
            }
704
705
            // update DB
706
            DB::update(
707
                prefixTable('users'),
708
                array(
709
                    'pw' => $post_new_password_hashed,
710
                    'last_pw_change' => mktime(0, 0, 0, (int) date('m'), (int) date('d'), (int) date('y')),
711
                    'last_pw' => $post_current_password,
712
                    'special' => $special_action,
713
                    'private_key' => encryptPrivateKey($post_new_password, $_SESSION['user']['private_key']),
714
                ),
715
                'id = %i',
716
                $post_user_id
717
            );
718
            // update LOG
719
            logEvents($SETTINGS, 'user_mngt', 'at_user_pwd_changed', (string) $_SESSION['user_id'], $_SESSION['login'], $post_user_id);
720
721
            // Send back
722
            return prepareExchangedData(
723
                $SETTINGS['cpassman_dir'],
724
                array(
725
                    'error' => false,
726
                    'message' => '',
727
                ),
728
                'encode'
729
            );
730
        }
731
        // Send back
732
        return prepareExchangedData(
733
            $SETTINGS['cpassman_dir'],
734
            array(
735
                'error' => true,
736
                'message' => langHdl('pw_hash_not_correct'),
737
            ),
738
            'encode'
739
        );
740
    }
741
    return prepareExchangedData(
742
        $SETTINGS['cpassman_dir'],
743
        array(
744
            'error' => true,
745
            'message' => langHdl('error_not_allowed_to'),
746
        ),
747
        'encode'
748
    );
749
}
750
751
752
753
function generateQRCode(
754
    $post_id,
755
    $post_demand_origin,
756
    $post_send_mail,
757
    $post_login,
758
    $post_pwd,
759
    array $SETTINGS
760
): string
761
{
762
    // is this allowed by setting
763
    if (isKeyExistingAndEqual('ga_reset_by_user', 0, $SETTINGS) === true
764
        && (null === $post_demand_origin || $post_demand_origin !== 'users_management_list')
765
    ) {
766
        // User cannot ask for a new code
767
        return prepareExchangedData(
768
            $SETTINGS['cpassman_dir'],
769
            array(
770
                'error' => true,
771
                'message' => "113 ".langHdl('error_not_allowed_to')." - ".isKeyExistingAndEqual('ga_reset_by_user', 1, $SETTINGS),
772
            ),
773
            'encode'
774
        );
775
    }
776
777
    // Check if user exists
778
    if (isValueSetNullEmpty($post_id) === true) {
779
        // Get data about user
780
        $data = DB::queryfirstrow(
781
            'SELECT id, email, pw
782
            FROM ' . prefixTable('users') . '
783
            WHERE login = %s',
784
            $post_login
785
        );
786
    } else {
787
        $data = DB::queryfirstrow(
788
            'SELECT id, login, email, pw
789
            FROM ' . prefixTable('users') . '
790
            WHERE id = %i',
791
            $post_id
792
        );
793
        $post_login = $data['login'];
794
    }
795
    // Get number of returned users
796
    $counter = DB::count();
797
798
    // load passwordLib library
799
    $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'] . '/includes/libraries');
800
    $pwdlib->register();
801
    $pwdlib = new PasswordLib\PasswordLib();
802
803
    // Do treatment
804
    if ($counter === 0) {
805
        // Not a registered user !
806
        logEvents($SETTINGS, 'failed_auth', 'user_not_exists', '', stripslashes($post_login), stripslashes($post_login));
807
        return prepareExchangedData(
808
            $SETTINGS['cpassman_dir'],
809
            array(
810
                'error' => true,
811
                'message' => langHdl('no_user'),
812
                'tst' => 1,
813
            ),
814
            'encode'
815
        );
816
    }
817
818
    if (
819
        isSetArrayOfValues([$post_pwd, $data['pw']]) === true
820
        && $pwdlib->verifyPasswordHash($post_pwd, $data['pw']) === false
821
        && $post_demand_origin !== 'users_management_list'
822
    ) {
823
        // checked the given password
824
        logEvents($SETTINGS, 'failed_auth', 'password_is_not_correct', '', stripslashes($post_login), stripslashes($post_login));
825
        return prepareExchangedData(
826
            $SETTINGS['cpassman_dir'],
827
            array(
828
                'error' => true,
829
                'message' => langHdl('no_user'),
830
                'tst' => $post_demand_origin,
831
            ),
832
            'encode'
833
        );
834
    }
835
    
836
    if (empty($data['email']) === true) {
837
        return prepareExchangedData(
838
            $SETTINGS['cpassman_dir'],
839
            array(
840
                'error' => true,
841
                'message' => langHdl('no_email_set'),
842
            ),
843
            'encode'
844
        );
845
    }
846
    
847
    // generate new GA user code
848
    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/Authentication/TwoFactorAuth/TwoFactorAuth.php';
849
    $tfa = new Authentication\TwoFactorAuth\TwoFactorAuth($SETTINGS['ga_website_name']);
850
    $gaSecretKey = $tfa->createSecret();
851
    $gaTemporaryCode = GenerateCryptKey(12, false, true, true, false, true, $SETTINGS);
852
853
    DB::update(
854
        prefixTable('users'),
855
        [
856
            'ga' => $gaSecretKey,
857
            'ga_temporary_code' => $gaTemporaryCode,
858
        ],
859
        'id = %i',
860
        $data['id']
861
    );
862
863
    // Log event
864
    logEvents($SETTINGS, 'user_connection', 'at_2fa_google_code_send_by_email', (string) $data['id'], stripslashes($post_login), stripslashes($post_login));
865
866
    // send mail?
867
    if ((int) $post_send_mail === 1) {
868
        sendEmail(
869
            langHdl('email_ga_subject'),
870
            str_replace(
871
                '#2FACode#',
872
                $gaTemporaryCode,
873
                langHdl('email_ga_text')
874
            ),
875
            $data['email'],
876
            $SETTINGS
877
        );
878
879
        // send back
880
        return prepareExchangedData(
881
            $SETTINGS['cpassman_dir'],
882
            array(
883
                'error' => false,
884
                'message' => $post_send_mail,
885
                'email' => $data['email'],
886
                'email_result' => str_replace(
887
                    '#email#',
888
                    '<b>' . obfuscateEmail($data['email']) . '</b>',
889
                    addslashes(langHdl('admin_email_result_ok'))
890
                ),
891
            ),
892
            'encode'
893
        );
894
    }
895
    
896
    // send back
897
    return prepareExchangedData(
898
        $SETTINGS['cpassman_dir'],
899
        array(
900
            'error' => false,
901
            'message' => '',
902
            'email' => $data['email'],
903
            'email_result' => str_replace(
904
                '#email#',
905
                '<b>' . obfuscateEmail($data['email']) . '</b>',
906
                addslashes(langHdl('admin_email_result_ok'))
907
            ),
908
        ),
909
        'encode'
910
    );
911
}
912
913
function sendEmailsNotSent(
914
    array $SETTINGS
915
)
916
{
917
    if (isKeyExistingAndEqual('enable_send_email_on_user_login', 1, $SETTINGS) === true) {
918
        $row = DB::queryFirstRow(
919
            'SELECT valeur FROM ' . prefixTable('misc') . ' WHERE type = %s AND intitule = %s',
920
            'cron',
921
            'sending_emails'
922
        );
923
924
        if ((int) (time() - $row['valeur']) >= 300 || (int) $row['valeur'] === 0) {
925
            $rows = DB::query(
926
                'SELECT *
927
                FROM ' . prefixTable('emails') .
928
                ' WHERE status != %s',
929
                'sent'
930
            );
931
            foreach ($rows as $record) {
932
                //echo $record['increment_id'] . " >> ";
933
                // Send email
934
                $ret = json_decode(
935
                    sendEmail(
936
                        $record['subject'],
937
                        $record['body'],
938
                        $record['receivers'],
939
                        $SETTINGS
940
                    ),
941
                    true
942
                );
943
944
                // update item_id in files table
945
                DB::update(
946
                    prefixTable('emails'),
947
                    array(
948
                        'status' => $ret['error'] === 'error_mail_not_send' ? 'not_sent' : 'sent',
949
                    ),
950
                    'timestamp = %s',
951
                    $record['timestamp']
952
                );
953
            }
954
        }
955
        // update cron time
956
        DB::update(
957
            prefixTable('misc'),
958
            array(
959
                'valeur' => time(),
960
            ),
961
            'intitule = %s AND type = %s',
962
            'sending_emails',
963
            'cron'
964
        );
965
    }
966
}
967
968
function generateGenericPassword(
969
    int $size,
970
    bool $secure,
971
    bool $lowercase,
972
    bool $capitalize,
973
    bool $numerals,
974
    bool $symbols,
975
    array $SETTINGS
976
): string
977
{
978
    if ((int) $size > (int) $SETTINGS['pwd_maximum_length']) {
979
        return prepareExchangedData(
980
            $SETTINGS['cpassman_dir'],
981
            array(
982
                'error_msg' => 'Password length is too long! ',
983
                'error' => 'true',
984
            ),
985
            'encode'
986
        );
987
    }
988
    
989
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
990
    $generator->register();
991
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
992
993
    // Is PHP7 being used?
994
    if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
995
        $php7generator = new SplClassLoader('PasswordGenerator\RandomGenerator', '../includes/libraries');
996
        $php7generator->register();
997
        $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
998
    }
999
1000
    // Manage size
1001
    $generator->setLength(($size <= 0) ? 10 : $size);
1002
1003
    if ($secure === true) {
1004
        $generator->setSymbols(true);
1005
        $generator->setLowercase(true);
1006
        $generator->setUppercase(true);
1007
        $generator->setNumbers(true);
1008
    } else {
1009
        $generator->setLowercase($lowercase);
1010
        $generator->setUppercase($capitalize);
1011
        $generator->setNumbers($numerals);
1012
        $generator->setSymbols($symbols);
1013
    }
1014
1015
    return prepareExchangedData(
1016
        $SETTINGS['cpassman_dir'],
1017
        array(
1018
            'key' => $generator->generatePasswords(),
1019
            'error' => '',
1020
        ),
1021
        'encode'
1022
    );
1023
}
1024
1025
function refreshUserItemsSeenList(
1026
    array $SETTINGS
1027
): string
1028
{
1029
    // get list of last items seen
1030
    $arr_html = array();
1031
    $rows = DB::query(
1032
        '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
1033
        FROM ' . prefixTable('log_items') . ' AS l
1034
        RIGHT JOIN ' . prefixTable('items') . ' AS i ON (l.id_item = i.id)
1035
        WHERE l.action = %s AND l.id_user = %i
1036
        ORDER BY l.date DESC
1037
        LIMIT 0, 100',
1038
        'at_shown',
1039
        $_SESSION['user_id']
1040
    );
1041
    if (DB::count() > 0) {
1042
        foreach ($rows as $record) {
1043
            if (in_array($record['id']->id, array_column($arr_html, 'id')) === false) {
1044
                array_push(
1045
                    $arr_html,
1046
                    array(
1047
                        'id' => $record['id'],
1048
                        'label' => htmlspecialchars(stripslashes(htmlspecialchars_decode($record['label'], ENT_QUOTES)), ENT_QUOTES),
1049
                        'tree_id' => $record['id_tree'],
1050
                        'perso' => $record['perso'],
1051
                        'restricted' => $record['restricted'],
1052
                    )
1053
                );
1054
                if (count($arr_html) >= (int) $SETTINGS['max_latest_items']) {
1055
                    break;
1056
                }
1057
            }
1058
        }
1059
    }
1060
1061
    // get wainting suggestions
1062
    $nb_suggestions_waiting = 0;
1063
    if (isKeyExistingAndEqual('enable_suggestion', 1, $SETTINGS) === true
1064
        && ((int) $_SESSION['user_admin'] === 1 || (int) $_SESSION['user_manager'] === 1)
1065
    ) {
1066
        DB::query('SELECT * FROM ' . prefixTable('suggestion'));
1067
        $nb_suggestions_waiting = DB::count();
1068
    }
1069
1070
    return json_encode(
1071
        array(
1072
            'error' => '',
1073
            'existing_suggestions' => $nb_suggestions_waiting,
1074
            'html_json' => $arr_html,
1075
        ),
1076
        JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1077
    );
1078
}
1079
1080
function sendingStatistics(
1081
    array $SETTINGS
1082
): void
1083
{
1084
    if (
1085
        isSetArrayOfValues([$SETTINGS['send_statistics_items'], $SETTINGS['send_stats_time']]) === true
1086
        && isKeyExistingAndEqual('send_stats', 1, $SETTINGS) === true
1087
        && (int) ($SETTINGS['send_stats_time'] + TP_ONE_DAY_SECONDS) > time()
1088
    ) {
1089
        // get statistics data
1090
        $stats_data = getStatisticsData($SETTINGS);
1091
1092
        // get statistics items to share
1093
        $statsToSend = [];
1094
        $statsToSend['ip'] = $_SERVER['SERVER_ADDR'];
1095
        $statsToSend['timestamp'] = time();
1096
        foreach (array_filter(explode(';', $SETTINGS['send_statistics_items'])) as $data) {
1097
            if ($data === 'stat_languages') {
1098
                $tmp = '';
1099
                foreach ($stats_data[$data] as $key => $value) {
1100
                    $tmp .= $tmp === '' ? $key . '-' . $value : ',' . $key . '-' . $value;
1101
                }
1102
                $statsToSend[$data] = $tmp;
1103
            } elseif ($data === 'stat_country') {
1104
                $tmp = '';
1105
                foreach ($stats_data[$data] as $key => $value) {
1106
                    $tmp .= $tmp === '' ? $key . '-' . $value : ',' . $key . '-' . $value;
1107
                }
1108
                $statsToSend[$data] = $tmp;
1109
            } else {
1110
                $statsToSend[$data] = $stats_data[$data];
1111
            }
1112
        }
1113
1114
        // connect to Teampass Statistics database
1115
        $link2 = new MeekroDB(
1116
            'teampass.pw',
1117
            'teampass_user',
1118
            'ZMlEfRzKzFLZNzie',
1119
            'teampass_followup',
1120
            '3306',
1121
            'utf8'
1122
        );
1123
1124
        $link2->insert(
1125
            'statistics',
1126
            $statsToSend
1127
        );
1128
1129
        // update table misc with current timestamp
1130
        DB::update(
1131
            prefixTable('misc'),
1132
            array(
1133
                'valeur' => time(),
1134
            ),
1135
            'type = %s AND intitule = %s',
1136
            'admin',
1137
            'send_stats_time'
1138
        );
1139
1140
        //permits to test only once by session
1141
        $_SESSION['temporary']['send_stats_done'] = true;
1142
        $SETTINGS['send_stats_time'] = time();
1143
1144
        // save change in config file
1145
        handleConfigFile('update', $SETTINGS, 'send_stats_time', $SETTINGS['send_stats_time']);
1146
    }
1147
}
1148
1149
function generateBugReport(
1150
    string $data,
1151
    array $SETTINGS
1152
): string
1153
{
1154
    $config_exclude_vars = array(
1155
        'bck_script_passkey',
1156
        'email_smtp_server',
1157
        'email_auth_username',
1158
        'email_auth_pwd',
1159
        'email_from',
1160
    );
1161
1162
    // Get data
1163
    $post_data = json_decode($data, true);
1164
1165
    // Read config file
1166
    $list_of_options = '';
1167
    $url_found = '';
1168
    $anonym_url = '';
1169
    $tp_config_file = '../includes/config/tp.config.php';
1170
    $data = file($tp_config_file);
1171
    foreach ($data as $line) {
1172
        if (substr($line, 0, 4) === '    ') {
1173
            // Remove extra spaces
1174
            $line = str_replace('    ', '', $line);
1175
1176
            // Identify url to anonymize it
1177
            if (strpos($line, 'cpassman_url') > 0 && empty($url_found) === true) {
1178
                $url_found = substr($line, 19, strlen($line) - 22);
1179
                if (empty($url_found) === false) {
1180
                    $tmp = parse_url($url_found);
1181
                    $anonym_url = $tmp['scheme'] . '://<anonym_url>' . (isset($tmp['path']) === true ? $tmp['path'] : '');
1182
                    $line = "'cpassman_url' => '" . $anonym_url . "\n";
1183
                } else {
1184
                    $line = "'cpassman_url' => \n";
1185
                }
1186
            }
1187
1188
            // Anonymize all urls
1189
            if (empty($anonym_url) === false) {
1190
                $line = str_replace($url_found, $anonym_url, $line);
1191
            }
1192
1193
            // Clear some vars
1194
            foreach ($config_exclude_vars as $var) {
1195
                if (strpos($line, $var) > 0) {
1196
                    $line = "'".$var."' => '<removed>'\n";
1197
                }
1198
            }
1199
1200
            // Complete line to display
1201
            $list_of_options .= $line;
1202
        }
1203
    }
1204
1205
    // Get error
1206
    $err = error_get_last();
1207
1208
    // Get 10 latest errors in Teampass
1209
    $teampass_errors = '';
1210
    $rows = DB::query(
1211
        'SELECT label, date AS error_date
1212
        FROM ' . prefixTable('log_system') . "
1213
        WHERE `type` LIKE 'error'
1214
        ORDER BY `date` DESC
1215
        LIMIT 0, 10"
1216
    );
1217
    if (DB::count() > 0) {
1218
        foreach ($rows as $record) {
1219
            if (empty($teampass_errors) === true) {
1220
                $teampass_errors = ' * ' . date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['error_date']) . ' - ' . $record['label'];
1221
            } else {
1222
                $teampass_errors .= ' * ' . date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], (int) $record['error_date']) . ' - ' . $record['label'];
1223
            }
1224
        }
1225
    }
1226
1227
    $link = mysqli_connect(DB_HOST, DB_USER, DB_PASSWD_CLEAR, DB_NAME, (int) DB_PORT, null);
1228
1229
    // Now prepare text
1230
    $txt = '### Page on which it happened
1231
' . $post_data['current_page'] . '
1232
1233
### Steps to reproduce
1234
1.
1235
2.
1236
3.
1237
1238
### Expected behaviour
1239
Tell us what should happen
1240
1241
1242
### Actual behaviour
1243
Tell us what happens instead
1244
1245
### Server configuration
1246
**Operating system**: ' . php_uname() . '
1247
1248
**Web server:** ' . $_SERVER['SERVER_SOFTWARE'] . '
1249
1250
**Database:** ' . ($link === false ? langHdl('undefined') : mysqli_get_server_info($link)) . '
1251
1252
**PHP version:** ' . PHP_VERSION . '
1253
1254
**Teampass version:** ' . TP_VERSION_FULL . '
1255
1256
**Teampass configuration file:**
1257
```
1258
' . $list_of_options . '
1259
```
1260
1261
**Updated from an older Teampass or fresh install:**
1262
1263
### Client configuration
1264
1265
**Browser:** ' . $post_data['browser_name'] . ' - ' . $post_data['browser_version'] . '
1266
1267
**Operating system:** ' . $post_data['os'] . ' - ' . $post_data['os_archi'] . 'bits
1268
1269
### Logs
1270
1271
#### Web server error log
1272
```
1273
' . $err['message'] . ' - ' . $err['file'] . ' (' . $err['line'] . ')
1274
```
1275
1276
#### Teampass 10 last system errors
1277
```
1278
' . $teampass_errors . '
1279
```
1280
1281
#### Log from the web-browser developer console (CTRL + SHIFT + i)
1282
```
1283
Insert the log here and especially the answer of the query that failed.
1284
```
1285
';
1286
1287
    return prepareExchangedData(
1288
    $SETTINGS['cpassman_dir'],
1289
        array(
1290
            'html' => $txt,
1291
            'error' => '',
1292
        ),
1293
        'encode'
1294
    );
1295
}
1296
1297
/**
1298
 * Check that the user password is valid
1299
 *
1300
 * @param integer $post_user_id
1301
 * @param string $post_user_password
1302
 * @param array $SETTINGS
1303
 * @return string
1304
 */
1305
function isUserPasswordCorrect(
1306
    int $post_user_id,
1307
    string $post_user_password,
1308
    array $SETTINGS
1309
): string
1310
{
1311
    if (isUserIdValid($post_user_id) === true) {
1312
        // Check if user exists
1313
        $userInfo = DB::queryFirstRow(
1314
            'SELECT public_key, private_key, pw, auth_type
1315
            FROM ' . prefixTable('users') . '
1316
            WHERE id = %i',
1317
            $post_user_id
1318
        );
1319
        if (DB::count() > 0 && empty($userInfo['private_key']) === false) {
1320
            // Get one item
1321
            $record = DB::queryFirstRow(
1322
                'SELECT object_id
1323
                FROM ' . prefixTable('sharekeys_items') . '
1324
                WHERE user_id = %i',
1325
                $post_user_id
1326
            );
1327
1328
            if (DB::count() === 0) {
1329
                // This user has no items
1330
                // let's consider no items in DB
1331
                return prepareExchangedData(
1332
                    $SETTINGS['cpassman_dir'],
1333
                    array(
1334
                        'error' => false,
1335
                        'message' => '',
1336
                        'debug' => '',
1337
                    ),
1338
                    'encode'
1339
                );
1340
            }
1341
1342
            // Get itemKey from current user
1343
            $currentUserKey = DB::queryFirstRow(
1344
                'SELECT share_key, increment_id
1345
                FROM ' . prefixTable('sharekeys_items') . '
1346
                WHERE object_id = %i AND user_id = %i',
1347
                $record['object_id'],
1348
                $post_user_id
1349
            );
1350
1351
            if ($currentUserKey !== null) {
1352
                // Decrypt itemkey with user key
1353
                // use old password to decrypt private_key
1354
                $_SESSION['user']['private_key'] = decryptPrivateKey($post_user_password, $userInfo['private_key']);
1355
                $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1356
1357
                if (empty(base64_decode($itemKey)) === false) {
1358
                    // GOOD password
1359
                    return prepareExchangedData(
1360
                        $SETTINGS['cpassman_dir'],
1361
                        array(
1362
                            'error' => false,
1363
                            'message' => '',
1364
                            'debug' => '',
1365
                        ),
1366
                        'encode'
1367
                    );
1368
                }
1369
            }
1370
            
1371
            // Use the password check
1372
            // load passwordLib library
1373
            $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'] . '/includes/libraries');
1374
            $pwdlib->register();
1375
            $pwdlib = new PasswordLib\PasswordLib();
1376
            
1377
            if ($pwdlib->verifyPasswordHash(htmlspecialchars_decode($post_user_password), $userInfo['pw']) === true) {
1378
                // GOOD password
1379
                return prepareExchangedData(
1380
                    $SETTINGS['cpassman_dir'],
1381
                    array(
1382
                        'error' => false,
1383
                        'message' => '',
1384
                        'debug' => '',
1385
                    ),
1386
                    'encode'
1387
                );
1388
            }
1389
        }
1390
    }
1391
1392
    return prepareExchangedData(
1393
    $SETTINGS['cpassman_dir'],
1394
        array(
1395
            'error' => true,
1396
            'message' => langHdl('password_is_not_correct'),
1397
            //'debug' => isset($itemKey) === true ? base64_decode($itemKey) : '',
1398
        ),
1399
        'encode'
1400
    );
1401
}
1402
1403
function changePrivateKeyEncryptionPassword(
1404
    int $post_user_id,
1405
    string $post_current_code,
1406
    string $post_new_code,
1407
    string $post_action_type,
1408
    array $SETTINGS
1409
): string
1410
{
1411
    if (empty($post_new_code) === true) {
1412
        if (empty($_SESSION['user_pwd']) === false) {
1413
            $post_new_code = $_SESSION['user_pwd'];
1414
        } else {
1415
            // no user password???
1416
            return prepareExchangedData(
1417
                $SETTINGS['cpassman_dir'],
1418
                array(
1419
                    'error' => true,
1420
                    'message' => langHdl('error_no_user_password_exists'),
1421
                    'debug' => '',
1422
                ),
1423
                'encode'
1424
            );
1425
        }
1426
    }
1427
1428
    if (isUserIdValid($post_user_id) === true) {
1429
        // Get user info
1430
        $userData = DB::queryFirstRow(
1431
            'SELECT private_key
1432
            FROM ' . prefixTable('users') . '
1433
            WHERE id = %i',
1434
            $post_user_id
1435
        );
1436
        if (DB::count() > 0 && empty($userData['private_key']) === false) {
1437
            if ($post_action_type === 'encrypt_privkey_with_user_password') {
1438
                // Here the user has his private key encrypted with an OTC.
1439
                // We need to encrypt it with his real password
1440
                $privateKey = decryptPrivateKey($post_new_code, $userData['private_key']);
1441
                $hashedPrivateKey = encryptPrivateKey($post_current_code, $privateKey);
1442
            } else {
1443
                $privateKey = decryptPrivateKey($post_current_code, $userData['private_key']);
1444
                $hashedPrivateKey = encryptPrivateKey($post_new_code, $privateKey);
1445
            }
1446
1447
            // Update user account
1448
            DB::update(
1449
                prefixTable('users'),
1450
                array(
1451
                    'private_key' => $hashedPrivateKey,
1452
                    'special' => 'none',
1453
                ),
1454
                'id = %i',
1455
                $post_user_id
1456
            );
1457
1458
            // Load superGlobals
1459
            include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1460
            $superGlobal = new protect\SuperGlobal\SuperGlobal();
1461
1462
            $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
1463
        }
1464
1465
        // Return
1466
        return prepareExchangedData(
1467
            $SETTINGS['cpassman_dir'],
1468
            array(
1469
                'error' => false,
1470
                'message' => '',
1471
            ),
1472
            'encode'
1473
        );
1474
    }
1475
    
1476
    return prepareExchangedData(
1477
        $SETTINGS['cpassman_dir'],
1478
        array(
1479
            'error' => true,
1480
            'message' => langHdl('error_no_user'),
1481
            'debug' => '',
1482
        ),
1483
        'encode'
1484
    );
1485
}
1486
1487
function initializeUserPassword(
1488
    int $post_user_id,
1489
    string $post_special,
1490
    string $post_user_password,
1491
    bool $post_self_change,
1492
    array $SETTINGS
1493
): string
1494
{
1495
    if (isUserIdValid($post_user_id) === true) {
1496
        // Get user info
1497
        $userData = DB::queryFirstRow(
1498
            'SELECT email, auth_type, login
1499
            FROM ' . prefixTable('users') . '
1500
            WHERE id = %i',
1501
            $post_user_id
1502
        );
1503
        if (DB::count() > 0 && empty($userData['email']) === false) {
1504
            // If user pwd is empty then generate a new one and send it to user
1505
            if (isset($post_user_password) === false || empty($post_user_password) === true) {
1506
                // Generate new password
1507
                $post_user_password = generateQuickPassword();
1508
            }
1509
1510
            // If LDAP enabled, then
1511
            // check that this password is correct
1512
            $continue = true;
1513
            if ($userData['auth_type'] === 'ldap' && (int) $SETTINGS['ldap_mode'] === 1) {
1514
                $continue = ldapCheckUserPassword(
1515
                    $userData['login'],
1516
                    $post_user_password,
1517
                    $SETTINGS
1518
                );
1519
            }
1520
1521
            if ($continue === true) {
1522
                // Only change if email is successfull
1523
                // GEnerate new keys
1524
                $userKeys = generateUserKeys($post_user_password);
1525
1526
                // load passwordLib library
1527
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1528
                $pwdlib->register();
1529
                $pwdlib = new PasswordLib\PasswordLib();
1530
1531
                // Update user account
1532
                DB::update(
1533
                    prefixTable('users'),
1534
                    array(
1535
                        'special' => $post_special,
1536
                        'pw' => $pwdlib->createPasswordHash($post_user_password),
1537
                        'public_key' => $userKeys['public_key'],
1538
                        'private_key' => $userKeys['private_key'],
1539
                        'last_pw_change' => time(),
1540
                    ),
1541
                    'id = %i',
1542
                    $post_user_id
1543
                );
1544
1545
                // Return
1546
                return prepareExchangedData(
1547
    $SETTINGS['cpassman_dir'],
1548
                    array(
1549
                        'error' => false,
1550
                        'message' => '',
1551
                        'user_pwd' => $post_user_password,
1552
                        'user_email' => $userData['email'],
1553
                    ),
1554
                    'encode'
1555
                );
1556
            }
1557
            // Return error
1558
            return prepareExchangedData(
1559
    $SETTINGS['cpassman_dir'],
1560
                array(
1561
                    'error' => true,
1562
                    'message' => langHdl('no_email_set'),
1563
                    'debug' => '',
1564
                    'self_change' => $post_self_change,
1565
                ),
1566
                'encode'
1567
            );
1568
        }
1569
1570
        // Error
1571
        return prepareExchangedData(
1572
    $SETTINGS['cpassman_dir'],
1573
            array(
1574
                'error' => true,
1575
                'message' => langHdl('no_email_set'),
1576
                'debug' => '',
1577
            ),
1578
            'encode'
1579
        );
1580
    }
1581
    
1582
    return prepareExchangedData(
1583
    $SETTINGS['cpassman_dir'],
1584
        array(
1585
            'error' => true,
1586
            'message' => langHdl('error_no_user'),
1587
            'debug' => '',
1588
        ),
1589
        'encode'
1590
    );
1591
}
1592
1593
function sendMailToUser(
1594
    string $post_receipt,
1595
    string $post_body,
1596
    string $post_subject,
1597
    array $post_replace,
1598
    array $SETTINGS
1599
): string
1600
{
1601
    if (count($post_replace) > 0 && is_null($post_replace) === false) {
1602
        $post_body = str_replace(
1603
            array_keys($post_replace),
0 ignored issues
show
Bug introduced by
$post_replace of type null is incompatible with the type array expected by parameter $array of array_keys(). ( Ignorable by Annotation )

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

1603
            array_keys(/** @scrutinizer ignore-type */ $post_replace),
Loading history...
1604
            array_values($post_replace),
0 ignored issues
show
Bug introduced by
$post_replace of type null is incompatible with the type array expected by parameter $array of array_values(). ( Ignorable by Annotation )

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

1604
            array_values(/** @scrutinizer ignore-type */ $post_replace),
Loading history...
1605
            $post_body
1606
        );
1607
    }
1608
    
1609
    $ret = sendEmail(
1610
        $post_subject,
1611
        $post_body,
1612
        $post_receipt,
1613
        $SETTINGS,
1614
        '',
1615
        false
1616
    );
1617
1618
    $ret = json_decode($ret, true);
1619
1620
    return prepareExchangedData(
1621
    $SETTINGS['cpassman_dir'],
1622
        array(
1623
            'error' => empty($ret['error']) === true ? false : true,
1624
            'message' => $ret['message'],
1625
        ),
1626
        'encode'
1627
    );
1628
}
1629
1630
function generateOneTimeCode(
1631
    int $post_user_id,
1632
    array $SETTINGS
1633
): string
1634
{
1635
    if (isUserIdValid($post_user_id) === true) {
1636
        // Get user info
1637
        $userData = DB::queryFirstRow(
1638
            'SELECT email, auth_type, login
1639
            FROM ' . prefixTable('users') . '
1640
            WHERE id = %i',
1641
            $post_user_id
1642
        );
1643
        if (DB::count() > 0 && empty($userData['email']) === false) {
1644
            // Generate pwd
1645
            $password = generateQuickPassword();
1646
1647
            // GEnerate new keys
1648
            $userKeys = generateUserKeys($password);
1649
1650
            // Save in DB
1651
            DB::update(
1652
                prefixTable('users'),
1653
                array(
1654
                    'public_key' => $userKeys['public_key'],
1655
                    'private_key' => $userKeys['private_key'],
1656
                    'special' => 'generate-keys',
1657
                ),
1658
                'id=%i',
1659
                $post_user_id
1660
            );
1661
1662
            return prepareExchangedData(
1663
    $SETTINGS['cpassman_dir'],
1664
                array(
1665
                    'error' => false,
1666
                    'message' => '',
1667
                    'userTemporaryCode' => $password,
1668
                ),
1669
                'encode'
1670
            );
1671
        }
1672
        
1673
        return prepareExchangedData(
1674
    $SETTINGS['cpassman_dir'],
1675
            array(
1676
                'error' => true,
1677
                'message' => langHdl('no_email_set'),
1678
            ),
1679
            'encode'
1680
        );
1681
    }
1682
        
1683
    return prepareExchangedData(
1684
    $SETTINGS['cpassman_dir'],
1685
        array(
1686
            'error' => true,
1687
            'message' => langHdl('error_no_user'),
1688
        ),
1689
        'encode'
1690
    );
1691
}
1692
1693
function startReEncryptingUserSharekeys(
1694
    int $post_user_id,
1695
    bool $post_self_change,
1696
    array $SETTINGS
1697
): string
1698
{
1699
    if (isUserIdValid($post_user_id) === true) {
1700
        // Check if user exists
1701
        DB::queryFirstRow(
1702
            'SELECT *
1703
            FROM ' . prefixTable('users') . '
1704
            WHERE id = %i',
1705
            $post_user_id
1706
        );
1707
        if (DB::count() > 0) {
1708
            // Include libraries
1709
            include_once $SETTINGS['cpassman_dir'] . '/sources/aes.functions.php';
1710
1711
            // CLear old sharekeys
1712
            if ($post_self_change === false) {
1713
                deleteUserObjetsKeys($post_user_id, $SETTINGS);
1714
            }
1715
1716
            // Continu with next step
1717
            return prepareExchangedData(
1718
                $SETTINGS['cpassman_dir'],
1719
                array(
1720
                    'error' => false,
1721
                    'message' => '',
1722
                    'step' => 'step1',
1723
                    'userId' => $post_user_id,
1724
                    'start' => 0,
1725
                    'self_change' => $post_self_change,
1726
                ),
1727
                'encode'
1728
            );
1729
        }
1730
        // Nothing to do
1731
        return prepareExchangedData(
1732
            $SETTINGS['cpassman_dir'],
1733
            array(
1734
                'error' => true,
1735
                'message' => langHdl('error_no_user'),
1736
            ),
1737
            'encode'
1738
        );
1739
    }
1740
1741
    return prepareExchangedData(
1742
        $SETTINGS['cpassman_dir'],
1743
        array(
1744
            'error' => true,
1745
            'message' => langHdl('error_no_user'),
1746
        ),
1747
        'encode'
1748
    );
1749
}
1750
1751
/**
1752
 * Permits to encrypt user's keys
1753
 *
1754
 * @param integer $post_user_id
1755
 * @param boolean $post_self_change
1756
 * @param string $post_action
1757
 * @param integer $post_start
1758
 * @param integer $post_length
1759
 * @param array $SETTINGS
1760
 * @return string
1761
 */
1762
function continueReEncryptingUserSharekeys(
1763
    int     $post_user_id,
1764
    bool    $post_self_change,
1765
    string  $post_action,
1766
    int     $post_start,
1767
    int     $post_length,
1768
    array   $SETTINGS
1769
): string
1770
{
1771
    if (isUserIdValid($post_user_id) === true) {
1772
        // Check if user exists
1773
        $userInfo = DB::queryFirstRow(
1774
            'SELECT public_key
1775
            FROM ' . prefixTable('users') . '
1776
            WHERE id = %i',
1777
            $post_user_id
1778
        );
1779
        if (isset($userInfo['public_key']) === true) {
1780
            // Include libraries
1781
            include_once $SETTINGS['cpassman_dir'] . '/sources/aes.functions.php';
1782
            $return = [];
1783
1784
            // WHAT STEP TO PERFORM?
1785
            if ($post_action === 'step0') {
1786
                // CLear old sharekeys
1787
                if ($post_self_change === false) {
1788
                    deleteUserObjetsKeys($post_user_id, $SETTINGS);
1789
                }
1790
1791
                $return['post_action'] = 'step1';
1792
            }
1793
            
1794
            // STEP 1 - ITEMS
1795
            elseif ($post_action === 'step1') {
1796
                $return = continueReEncryptingUserSharekeysStep1(
1797
                    $post_user_id,
1798
                    $post_self_change,
1799
                    $post_action,
1800
                    $post_start,
1801
                    $post_length,
1802
                    $userInfo['public_key'],
1803
                    $SETTINGS
1804
                );
1805
            }
1806
1807
            // STEP 2 - LOGS
1808
            elseif ($post_action === 'step2') {
1809
                $return = continueReEncryptingUserSharekeysStep2(
1810
                    $post_user_id,
1811
                    $post_self_change,
1812
                    $post_action,
1813
                    $post_start,
1814
                    $post_length,
1815
                    $userInfo['public_key'],
1816
                    $SETTINGS
1817
                );
1818
            }
1819
1820
            // STEP 3 - FIELDS
1821
            elseif ($post_action === 'step3') {
1822
                $return = continueReEncryptingUserSharekeysStep3(
1823
                    $post_user_id,
1824
                    $post_self_change,
1825
                    $post_action,
1826
                    $post_start,
1827
                    $post_length,
1828
                    $userInfo['public_key'],
1829
                    $SETTINGS
1830
                );
1831
            }
1832
            
1833
            // STEP 4 - SUGGESTIONS
1834
            elseif ($post_action === 'step4') {
1835
                $return = continueReEncryptingUserSharekeysStep4(
1836
                    $post_user_id,
1837
                    $post_self_change,
1838
                    $post_action,
1839
                    $post_start,
1840
                    $post_length,
1841
                    $userInfo['public_key'],
1842
                    $SETTINGS
1843
                );
1844
            }
1845
            
1846
            // STEP 5 - FILES
1847
            elseif ($post_action === 'step5') {
1848
                $return = continueReEncryptingUserSharekeysStep5(
1849
                    $post_user_id,
1850
                    $post_self_change,
1851
                    $post_action,
1852
                    $post_start,
1853
                    $post_length,
1854
                    $userInfo['public_key'],
1855
                    $SETTINGS
1856
                );
1857
            }
1858
            
1859
            // STEP 6 - PERSONAL ITEMS
1860
            elseif ($post_action === 'step6') {
1861
                $return = continueReEncryptingUserSharekeysStep6(
1862
                    $post_user_id,
1863
                    $post_self_change,
1864
                    $post_action,
1865
                    $post_start,
1866
                    $post_length,
1867
                    $userInfo['public_key'],
1868
                    $SETTINGS
1869
                );
1870
            }
1871
            
1872
            // Continu with next step
1873
            return prepareExchangedData(
1874
                $SETTINGS['cpassman_dir'],
1875
                array(
1876
                    'error' => false,
1877
                    'message' => '',
1878
                    'step' => isset($return['post_action']) === true ? $return['post_action'] : '',
1879
                    'start' => isset($return['next_start']) === true ? $return['next_start'] : 0,
1880
                    'userId' => $post_user_id,
1881
                    'self_change' => $post_self_change,
1882
                ),
1883
                'encode'
1884
            );
1885
        }
1886
        
1887
        // Nothing to do
1888
        return prepareExchangedData(
1889
            $SETTINGS['cpassman_dir'],
1890
            array(
1891
                'error' => false,
1892
                'message' => '',
1893
                'step' => 'finished',
1894
                'start' => 0,
1895
                'userId' => $post_user_id,
1896
                'self_change' => $post_self_change,
1897
            ),
1898
            'encode'
1899
        );
1900
    }
1901
    
1902
    // Nothing to do
1903
    return prepareExchangedData(
1904
        $SETTINGS['cpassman_dir'],
1905
        array(
1906
            'error' => true,
1907
            'message' => langHdl('error_no_user'),
1908
            'extra' => $post_user_id,
1909
        ),
1910
        'encode'
1911
    );
1912
}
1913
1914
function continueReEncryptingUserSharekeysStep1(
1915
    int $post_user_id,
1916
    bool $post_self_change,
1917
    string $post_action,
1918
    int $post_start,
1919
    int $post_length,
1920
    string $user_public_key,
1921
    array $SETTINGS
1922
): array 
1923
{
1924
    // Loop on items
1925
    $rows = DB::query(
1926
        'SELECT id, pw
1927
        FROM ' . prefixTable('items') . '
1928
        WHERE perso = 0
1929
        LIMIT ' . $post_start . ', ' . $post_length
1930
    );
1931
    foreach ($rows as $record) {
1932
        // Get itemKey from current user
1933
        $currentUserKey = DB::queryFirstRow(
1934
            'SELECT share_key, increment_id
1935
            FROM ' . prefixTable('sharekeys_items') . '
1936
            WHERE object_id = %i AND user_id = %i',
1937
            $record['id'],
1938
            $_SESSION['user_id']
1939
        );
1940
        if ($currentUserKey === null || count($currentUserKey) === 0) continue;
1941
1942
        // Decrypt itemkey with admin key
1943
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
1944
        
1945
        // Encrypt Item key
1946
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
1947
        
1948
        // Save the key in DB
1949
        if ($post_self_change === false) {
1950
            DB::insert(
1951
                prefixTable('sharekeys_items'),
1952
                array(
1953
                    'object_id' => (int) $record['id'],
1954
                    'user_id' => (int) $post_user_id,
1955
                    'share_key' => $share_key_for_item,
1956
                )
1957
            );
1958
        } else {
1959
            // Get itemIncrement from selected user
1960
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
1961
                $currentUserKey = DB::queryFirstRow(
1962
                    'SELECT increment_id
1963
                    FROM ' . prefixTable('sharekeys_items') . '
1964
                    WHERE object_id = %i AND user_id = %i',
1965
                    $record['id'],
1966
                    $post_user_id
1967
                );
1968
1969
                if (DB::count() > 0) {
1970
                    // NOw update
1971
                    DB::update(
1972
                        prefixTable('sharekeys_items'),
1973
                        array(
1974
                            'share_key' => $share_key_for_item,
1975
                        ),
1976
                        'increment_id = %i',
1977
                        $currentUserKey['increment_id']
1978
                    );
1979
                } else {
1980
                    DB::insert(
1981
                        prefixTable('sharekeys_items'),
1982
                        array(
1983
                            'object_id' => (int) $record['id'],
1984
                            'user_id' => (int) $post_user_id,
1985
                            'share_key' => $share_key_for_item,
1986
                        )
1987
                    );
1988
                }
1989
            }
1990
        }
1991
    }
1992
1993
    // SHould we change step?
1994
    DB::query(
1995
        'SELECT *
1996
        FROM ' . prefixTable('items') . '
1997
        WHERE perso = 0'
1998
    );
1999
2000
    $next_start = (int) $post_start + (int) $post_length;
2001
    return [
2002
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2003
        'post_action' => $next_start > DB::count() ? 'step2' : 'step1',
2004
    ];
2005
}
2006
2007
function continueReEncryptingUserSharekeysStep2(
2008
    int $post_user_id,
2009
    bool $post_self_change,
2010
    string $post_action,
2011
    int $post_start,
2012
    int $post_length,
2013
    string $user_public_key,
2014
    array $SETTINGS
2015
): array
2016
{
2017
    // Loop on logs
2018
    $rows = DB::query(
2019
        'SELECT increment_id
2020
        FROM ' . prefixTable('log_items') . '
2021
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"
2022
        LIMIT ' . $post_start . ', ' . $post_length
2023
    );
2024
    foreach ($rows as $record) {
2025
        // Get itemKey from current user
2026
        $currentUserKey = DB::queryFirstRow(
2027
            'SELECT share_key
2028
            FROM ' . prefixTable('sharekeys_logs') . '
2029
            WHERE object_id = %i AND user_id = %i',
2030
            $record['increment_id'],
2031
            $_SESSION['user_id']
2032
        );
2033
2034
        // Decrypt itemkey with admin key
2035
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2036
2037
        // Encrypt Item key
2038
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2039
2040
        // Save the key in DB
2041
        if ($post_self_change === false) {
2042
            DB::insert(
2043
                prefixTable('sharekeys_logs'),
2044
                array(
2045
                    'object_id' => (int) $record['increment_id'],
2046
                    'user_id' => (int) $post_user_id,
2047
                    'share_key' => $share_key_for_item,
2048
                )
2049
            );
2050
        } else {
2051
            // Get itemIncrement from selected user
2052
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2053
                $currentUserKey = DB::queryFirstRow(
2054
                    'SELECT increment_id
2055
                    FROM ' . prefixTable('sharekeys_items') . '
2056
                    WHERE object_id = %i AND user_id = %i',
2057
                    $record['id'],
2058
                    $post_user_id
2059
                );
2060
            }
2061
2062
            // NOw update
2063
            DB::update(
2064
                prefixTable('sharekeys_logs'),
2065
                array(
2066
                    'share_key' => $share_key_for_item,
2067
                ),
2068
                'increment_id = %i',
2069
                $currentUserKey['increment_id']
2070
            );
2071
        }
2072
    }
2073
2074
    // SHould we change step?
2075
    DB::query(
2076
        'SELECT increment_id
2077
        FROM ' . prefixTable('log_items') . '
2078
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"'
2079
    );
2080
2081
    $next_start = (int) $post_start + (int) $post_length;
2082
    return [
2083
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2084
        'post_action' => $next_start > DB::count() ? 'step3' : 'step2',
2085
    ];
2086
}
2087
2088
function continueReEncryptingUserSharekeysStep3(
2089
    int $post_user_id,
2090
    bool $post_self_change,
2091
    string $post_action,
2092
    int $post_start,
2093
    int $post_length,
2094
    string $user_public_key,
2095
    array $SETTINGS
2096
): array
2097
{
2098
    // Loop on fields
2099
    $rows = DB::query(
2100
        'SELECT id
2101
        FROM ' . prefixTable('categories_items') . '
2102
        WHERE encryption_type = "teampass_aes"
2103
        LIMIT ' . $post_start . ', ' . $post_length
2104
    );
2105
    foreach ($rows as $record) {
2106
        // Get itemKey from current user
2107
        $currentUserKey = DB::queryFirstRow(
2108
            'SELECT share_key
2109
            FROM ' . prefixTable('sharekeys_fields') . '
2110
            WHERE object_id = %i AND user_id = %i',
2111
            $record['id'],
2112
            $_SESSION['user_id']
2113
        );
2114
2115
        // Decrypt itemkey with admin key
2116
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2117
2118
        // Encrypt Item key
2119
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2120
2121
        // Save the key in DB
2122
        if ($post_self_change === false) {
2123
            DB::insert(
2124
                prefixTable('sharekeys_fields'),
2125
                array(
2126
                    'object_id' => (int) $record['id'],
2127
                    'user_id' => (int) $post_user_id,
2128
                    'share_key' => $share_key_for_item,
2129
                )
2130
            );
2131
        } else {
2132
            // Get itemIncrement from selected user
2133
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2134
                $currentUserKey = DB::queryFirstRow(
2135
                    'SELECT increment_id
2136
                    FROM ' . prefixTable('sharekeys_items') . '
2137
                    WHERE object_id = %i AND user_id = %i',
2138
                    $record['id'],
2139
                    $post_user_id
2140
                );
2141
            }
2142
2143
            // NOw update
2144
            DB::update(
2145
                prefixTable('sharekeys_fields'),
2146
                array(
2147
                    'share_key' => $share_key_for_item,
2148
                ),
2149
                'increment_id = %i',
2150
                $currentUserKey['increment_id']
2151
            );
2152
        }
2153
    }
2154
2155
    // SHould we change step?
2156
    DB::query(
2157
        'SELECT *
2158
        FROM ' . prefixTable('categories_items') . '
2159
        WHERE encryption_type = "teampass_aes"'
2160
    );
2161
2162
    $next_start = (int) $post_start + (int) $post_length;
2163
    return [
2164
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2165
        'post_action' => $next_start > DB::count() ? 'step4' : 'step3',
2166
    ];
2167
}
2168
2169
function continueReEncryptingUserSharekeysStep4(
2170
    int $post_user_id,
2171
    bool $post_self_change,
2172
    string $post_action,
2173
    int $post_start,
2174
    int $post_length,
2175
    string $user_public_key,
2176
    array $SETTINGS
2177
): array
2178
{
2179
    // Loop on suggestions
2180
    $rows = DB::query(
2181
        'SELECT id
2182
        FROM ' . prefixTable('suggestion') . '
2183
        LIMIT ' . $post_start . ', ' . $post_length
2184
    );
2185
    foreach ($rows as $record) {
2186
        // Get itemKey from current user
2187
        $currentUserKey = DB::queryFirstRow(
2188
            'SELECT share_key
2189
            FROM ' . prefixTable('sharekeys_suggestions') . '
2190
            WHERE object_id = %i AND user_id = %i',
2191
            $record['id'],
2192
            $_SESSION['user_id']
2193
        );
2194
2195
        // Decrypt itemkey with admin key
2196
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2197
2198
        // Encrypt Item key
2199
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2200
2201
        // Save the key in DB
2202
        if ($post_self_change === false) {
2203
            DB::insert(
2204
                prefixTable('sharekeys_suggestions'),
2205
                array(
2206
                    'object_id' => (int) $record['id'],
2207
                    'user_id' => (int) $post_user_id,
2208
                    'share_key' => $share_key_for_item,
2209
                )
2210
            );
2211
        } else {
2212
            // Get itemIncrement from selected user
2213
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2214
                $currentUserKey = DB::queryFirstRow(
2215
                    'SELECT increment_id
2216
                    FROM ' . prefixTable('sharekeys_items') . '
2217
                    WHERE object_id = %i AND user_id = %i',
2218
                    $record['id'],
2219
                    $post_user_id
2220
                );
2221
            }
2222
2223
            // NOw update
2224
            DB::update(
2225
                prefixTable('sharekeys_suggestions'),
2226
                array(
2227
                    'share_key' => $share_key_for_item,
2228
                ),
2229
                'increment_id = %i',
2230
                $currentUserKey['increment_id']
2231
            );
2232
        }
2233
    }
2234
2235
    // SHould we change step?
2236
    DB::query(
2237
        'SELECT *
2238
        FROM ' . prefixTable('suggestion')
2239
    );
2240
2241
    $next_start = (int) $post_start + (int) $post_length;
2242
    return [
2243
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2244
        'post_action' => $next_start > DB::count() ? 'step5' : 'step4',
2245
    ];
2246
}
2247
2248
function continueReEncryptingUserSharekeysStep5(
2249
    int $post_user_id,
2250
    bool $post_self_change,
2251
    string $post_action,
2252
    int $post_start,
2253
    int $post_length,
2254
    string $user_public_key,
2255
    array $SETTINGS
2256
): array
2257
{
2258
    // Loop on files
2259
    $rows = DB::query(
2260
        'SELECT id
2261
        FROM ' . prefixTable('files') . '
2262
        WHERE status = "' . TP_ENCRYPTION_NAME . '"
2263
        LIMIT ' . $post_start . ', ' . $post_length
2264
    ); //aes_encryption
2265
    foreach ($rows as $record) {
2266
        // Get itemKey from current user
2267
        $currentUserKey = DB::queryFirstRow(
2268
            'SELECT share_key
2269
            FROM ' . prefixTable('sharekeys_files') . '
2270
            WHERE object_id = %i AND user_id = %i',
2271
            $record['id'],
2272
            $_SESSION['user_id']
2273
        );
2274
2275
        // Decrypt itemkey with admin key
2276
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2277
2278
        // Encrypt Item key
2279
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2280
2281
        // Save the key in DB
2282
        if ($post_self_change === false) {
2283
            DB::insert(
2284
                prefixTable('sharekeys_files'),
2285
                array(
2286
                    'object_id' => (int) $record['id'],
2287
                    'user_id' => (int) $post_user_id,
2288
                    'share_key' => $share_key_for_item,
2289
                )
2290
            );
2291
        } else {
2292
            // Get itemIncrement from selected user
2293
            if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2294
                $currentUserKey = DB::queryFirstRow(
2295
                    'SELECT increment_id
2296
                    FROM ' . prefixTable('sharekeys_items') . '
2297
                    WHERE object_id = %i AND user_id = %i',
2298
                    $record['id'],
2299
                    $post_user_id
2300
                );
2301
            }
2302
2303
            // NOw update
2304
            DB::update(
2305
                prefixTable('sharekeys_files'),
2306
                array(
2307
                    'share_key' => $share_key_for_item,
2308
                ),
2309
                'increment_id = %i',
2310
                $currentUserKey['increment_id']
2311
            );
2312
        }
2313
    }
2314
2315
    // SHould we change step?
2316
    DB::query(
2317
        'SELECT *
2318
        FROM ' . prefixTable('files') . '
2319
        WHERE status = "' . TP_ENCRYPTION_NAME . '"'
2320
    );
2321
2322
    $next_start = (int) $post_start + (int) $post_length;
2323
    return [
2324
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2325
        'post_action' => $next_start > DB::count() ? 'step6' : 'step5',
2326
    ];
2327
}
2328
2329
function continueReEncryptingUserSharekeysStep6(
2330
    int $post_user_id,
2331
    bool $post_self_change,
2332
    string $post_action,
2333
    int $post_start,
2334
    int $post_length,
2335
    string $user_public_key,
2336
    array $SETTINGS
2337
): array
2338
{
2339
    // IF USER IS NOT THE SAME
2340
    if ((int) $post_user_id === (int) $_SESSION['user_id']) {
2341
        return [
2342
            'next_start' => 0,
2343
            'post_action' => 'finished',
2344
        ];
2345
    }
2346
    
2347
    // Loop on persoanl items
2348
    if (count($_SESSION['personal_folders']) > 0) {
2349
        $rows = DB::query(
2350
            'SELECT id, pw
2351
            FROM ' . prefixTable('items') . '
2352
            WHERE perso = 1 AND id_tree IN %ls
2353
            LIMIT ' . $post_start . ', ' . $post_length,
2354
            $_SESSION['personal_folders']
2355
        );
2356
        foreach ($rows as $record) {
2357
            // Get itemKey from current user
2358
            $currentUserKey = DB::queryFirstRow(
2359
                'SELECT share_key, increment_id
2360
                FROM ' . prefixTable('sharekeys_items') . '
2361
                WHERE object_id = %i AND user_id = %i',
2362
                $record['id'],
2363
                $_SESSION['user_id']
2364
            );
2365
2366
            // Decrypt itemkey with admin key
2367
            $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $_SESSION['user']['private_key']);
2368
2369
            // Encrypt Item key
2370
            $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
2371
2372
            // Save the key in DB
2373
            if ($post_self_change === false) {
2374
                DB::insert(
2375
                    prefixTable('sharekeys_items'),
2376
                    array(
2377
                        'object_id' => (int) $record['id'],
2378
                        'user_id' => (int) $post_user_id,
2379
                        'share_key' => $share_key_for_item,
2380
                    )
2381
                );
2382
            } else {
2383
                // Get itemIncrement from selected user
2384
                if ((int) $post_user_id !== (int) $_SESSION['user_id']) {
2385
                    $currentUserKey = DB::queryFirstRow(
2386
                        'SELECT increment_id
2387
                        FROM ' . prefixTable('sharekeys_items') . '
2388
                        WHERE object_id = %i AND user_id = %i',
2389
                        $record['id'],
2390
                        $post_user_id
2391
                    );
2392
                }
2393
2394
                // NOw update
2395
                DB::update(
2396
                    prefixTable('sharekeys_items'),
2397
                    array(
2398
                        'share_key' => $share_key_for_item,
2399
                    ),
2400
                    'increment_id = %i',
2401
                    $currentUserKey['increment_id']
2402
                );
2403
            }
2404
        }
2405
    }
2406
2407
    // SHould we change step?
2408
    DB::query(
2409
        'SELECT *
2410
        FROM ' . prefixTable('items') . '
2411
        WHERE perso = 0'
2412
    );
2413
2414
    // Is it done?
2415
    if ($next_start > DB::count()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $next_start seems to be never defined.
Loading history...
2416
        DB::update(
2417
            prefixTable('users'),
2418
            array(
2419
                'is_ready_for_usage' => 1,
2420
            ),
2421
            'id = %i',
2422
            $post_user_id
2423
        );
2424
    }
2425
2426
    $next_start = (int) $post_start + (int) $post_length;
2427
    return [
2428
        'next_start' => $next_start > DB::count() ? 0 : $next_start,
2429
        'post_action' => $next_start > DB::count() ? 'finished' : 'step6',
2430
    ];
2431
}
2432
2433
function migrateTo3_DoUserPersonalItemsEncryption(
2434
    int $post_user_id,
2435
    int $post_start,
2436
    int $post_length,
2437
    string $post_user_psk,
2438
    array $SETTINGS
2439
) {
2440
    $next_step = '';
2441
    
2442
    if (isUserIdValid($post_user_id) === true) {
2443
        // Check if user exists
2444
        $userInfo = DB::queryFirstRow(
2445
            'SELECT public_key, encrypted_psk
2446
            FROM ' . prefixTable('users') . '
2447
            WHERE id = %i',
2448
            $post_user_id
2449
        );
2450
        if (DB::count() > 0) {
2451
            // check if psk is correct.
2452
            if (empty($userInfo['encrypted_psk']) === false) {//echo $post_user_psk." ;; ".$userInfo['encrypted_psk']." ;; ";
2453
                $user_key_encoded = defuse_validate_personal_key(
2454
                    $post_user_psk,
2455
                    $userInfo['encrypted_psk']
2456
                );
2457
2458
                if (strpos($user_key_encoded, "Error ") !== false) {
2459
                    return prepareExchangedData(
2460
                        $SETTINGS['cpassman_dir'],
2461
                        array(
2462
                            'error' => true,
2463
                            'message' => langHdl('bad_psk'),
2464
                        ),
2465
                        'encode'
2466
                    );
2467
                }
2468
2469
                // Loop on persoanl items
2470
                $rows = DB::query(
2471
                    'SELECT id, pw
2472
                    FROM ' . prefixTable('items') . '
2473
                    WHERE perso = 1 AND id_tree IN %ls
2474
                    LIMIT ' . $post_start . ', ' . $post_length,
2475
                    $_SESSION['personal_folders']
2476
                );
2477
                $countUserPersonalItems = DB::count();
2478
                foreach ($rows as $record) {
2479
                    if ($record['encryption_type'] !== 'teampass_aes') {
2480
                        // Decrypt with Defuse
2481
                        $passwd = cryption(
2482
                            $record['pw'],
2483
                            $user_key_encoded,
2484
                            'decrypt',
2485
                            $SETTINGS
2486
                        );
2487
2488
                        // Encrypt with Object Key
2489
                        $cryptedStuff = doDataEncryption($passwd['string']);
2490
2491
                        // Store new password in DB
2492
                        DB::update(
2493
                            prefixTable('items'),
2494
                            array(
2495
                                'pw' => $cryptedStuff['encrypted'],
2496
                                'encryption_type' => 'teampass_aes',
2497
                            ),
2498
                            'id = %i',
2499
                            $record['id']
2500
                        );
2501
2502
                        // Insert in DB the new object key for this item by user
2503
                        DB::insert(
2504
                            prefixTable('sharekeys_items'),
2505
                            array(
2506
                                'object_id' => (int) $record['id'],
2507
                                'user_id' => (int) $post_user_id,
2508
                                'share_key' => encryptUserObjectKey($cryptedStuff['objectKey'], $userInfo['public_key']),
2509
                            )
2510
                        );
2511
2512
2513
                        // Does this item has Files?
2514
                        // Loop on files
2515
                        $rows = DB::query(
2516
                            'SELECT id, file
2517
                            FROM ' . prefixTable('files') . '
2518
                            WHERE status != %s
2519
                            AND id_item = %i',
2520
                            TP_ENCRYPTION_NAME,
2521
                            $record['id']
2522
                        );
2523
                        //aes_encryption
2524
                        foreach ($rows as $record2) {
2525
                            // Now decrypt the file
2526
                            prepareFileWithDefuse(
2527
                                'decrypt',
2528
                                $SETTINGS['path_to_upload_folder'] . '/' . $record2['file'],
2529
                                $SETTINGS['path_to_upload_folder'] . '/' . $record2['file'] . '.delete',
2530
                                $SETTINGS,
2531
                                $post_user_psk
2532
                            );
2533
2534
                            // Encrypt the file
2535
                            $encryptedFile = encryptFile($record2['file'] . '.delete', $SETTINGS['path_to_upload_folder']);
2536
2537
                            DB::update(
2538
                                prefixTable('files'),
2539
                                array(
2540
                                    'file' => $encryptedFile['fileHash'],
2541
                                    'status' => TP_ENCRYPTION_NAME,
2542
                                ),
2543
                                'id = %i',
2544
                                $record2['id']
2545
                            );
2546
2547
                            // Save key
2548
                            DB::insert(
2549
                                prefixTable('sharekeys_files'),
2550
                                array(
2551
                                    'object_id' => (int) $record2['id'],
2552
                                    'user_id' => (int) $_SESSION['user_id'],
2553
                                    'share_key' => encryptUserObjectKey($encryptedFile['objectKey'], $_SESSION['user']['public_key']),
2554
                                )
2555
                            );
2556
2557
                            // Unlink original file
2558
                            unlink($SETTINGS['path_to_upload_folder'] . '/' . $record2['file']);
2559
                        }
2560
                    }
2561
                }
2562
2563
                // SHould we change step?
2564
                $next_start = (int) $post_start + (int) $post_length;
2565
                if ($next_start > $countUserPersonalItems) {
2566
                    // Now update user
2567
                    DB::update(
2568
                        prefixTable('users'),
2569
                        array(
2570
                            'special' => 'none',
2571
                            'upgrade_needed' => 0,
2572
                            'encrypted_psk' => '',
2573
                        ),
2574
                        'id = %i',
2575
                        $post_user_id
2576
                    );
2577
2578
                    $next_step = 'finished';
2579
                    $next_start = 0;
2580
                }
2581
2582
                // Continu with next step
2583
                return prepareExchangedData(
2584
                    $SETTINGS['cpassman_dir'],
2585
                    array(
2586
                        'error' => false,
2587
                        'message' => '',
2588
                        'step' => $next_step,
2589
                        'start' => $next_start,
2590
                        'userId' => $post_user_id
2591
                    ),
2592
                    'encode'
2593
                );
2594
            }
2595
        }
2596
        
2597
        // Nothing to do
2598
        return prepareExchangedData(
2599
            $SETTINGS['cpassman_dir'],
2600
            array(
2601
                'error' => true,
2602
                'message' => langHdl('error_no_user'),
2603
            ),
2604
            'encode'
2605
        );
2606
    }
2607
    
2608
    // Nothing to do
2609
    return prepareExchangedData(
2610
        $SETTINGS['cpassman_dir'],
2611
        array(
2612
            'error' => true,
2613
            'message' => langHdl('error_no_user'),
2614
        ),
2615
        'encode'
2616
    );
2617
}
2618
2619
2620
function getUserInfo(
2621
    int $post_user_id,
2622
    string $post_fields,
2623
    array $SETTINGS
2624
)
2625
{
2626
    if (isUserIdValid($post_user_id) === true) {
2627
        // Get user info
2628
        $userData = DB::queryFirstRow(
2629
            'SELECT '.$post_fields.'
2630
            FROM ' . prefixTable('users') . '
2631
            WHERE id = %i',
2632
            $post_user_id
2633
        );
2634
        if (DB::count() > 0) {
2635
            return prepareExchangedData(
2636
                $SETTINGS['cpassman_dir'],
2637
                array(
2638
                    'error' => false,
2639
                    'message' => '',
2640
                    'queryResults' => $userData,
2641
                ),
2642
                'encode'
2643
            );
2644
        }
2645
    }
2646
    return prepareExchangedData(
2647
        $SETTINGS['cpassman_dir'],
2648
        array(
2649
            'error' => true,
2650
            'message' => langHdl('error_no_user'),
2651
        ),
2652
        'encode'
2653
    );
2654
}
2655
2656
/**
2657
 * Change user auth password
2658
 *
2659
 * @param integer $post_user_id
2660
 * @param string $post_current_pwd
2661
 * @param string $post_new_pwd
2662
 * @param array $SETTINGS
2663
 * @return string
2664
 */
2665
function changeUserAuthenticationPassword(
2666
    int $post_user_id,
2667
    string $post_current_pwd,
2668
    string $post_new_pwd,
2669
    array $SETTINGS
2670
)
2671
{
2672
    if (isUserIdValid($post_user_id) === true) {
2673
        // Get user info
2674
        $userData = DB::queryFirstRow(
2675
            'SELECT auth_type, login, private_key
2676
            FROM ' . prefixTable('users') . '
2677
            WHERE id = %i',
2678
            $post_user_id
2679
        );
2680
        if (DB::count() > 0 && empty($userData['private_key']) === false) {
2681
            // Now check if current password is correct
2682
            // For this, just check if it is possible to decrypt the privatekey
2683
            // And compare it to the one in session
2684
            try {
2685
                $privateKey = decryptPrivateKey($post_current_pwd, $userData['private_key']);
2686
            } catch (Exception $e) {
2687
                return prepareExchangedData(
2688
                    $SETTINGS['cpassman_dir'],
2689
                    array(
2690
                        'error' => true,
2691
                        'message' => langHdl('bad_password'),
2692
                    ),
2693
                    'encode'
2694
                );
2695
            }
2696
2697
            // Load superGlobals
2698
            include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2699
            $superGlobal = new protect\SuperGlobal\SuperGlobal();
2700
2701
            if ($superGlobal->get('private_key', 'SESSION', 'user') === $privateKey) {
2702
                // Encrypt it with new password
2703
                $hashedPrivateKey = encryptPrivateKey($post_new_pwd, $privateKey);
2704
2705
                // Generate new hash for auth password
2706
                // load passwordLib library
2707
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2708
                $pwdlib->register();
2709
                $pwdlib = new PasswordLib\PasswordLib();
2710
2711
                // Prepare variables
2712
                $newPw = $pwdlib->createPasswordHash($post_new_pwd);
2713
2714
                // Update user account
2715
                DB::update(
2716
                    prefixTable('users'),
2717
                    array(
2718
                        'private_key' => $hashedPrivateKey,
2719
                        'pw' => $newPw,
2720
                        'special' => 'none',
2721
                    ),
2722
                    'id = %i',
2723
                    $post_user_id
2724
                );
2725
2726
                $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2727
2728
                return prepareExchangedData(
2729
                    $SETTINGS['cpassman_dir'],
2730
                    array(
2731
                        'error' => false,
2732
                        'message' => langHdl('done'),'',
2733
                    ),
2734
                    'encode'
2735
                );
2736
            }
2737
            
2738
            // ERROR
2739
            return prepareExchangedData(
2740
                $SETTINGS['cpassman_dir'],
2741
                array(
2742
                    'error' => true,
2743
                    'message' => langHdl('bad_password'),
2744
                ),
2745
                'encode'
2746
            );
2747
        }
2748
    }
2749
        
2750
    return prepareExchangedData(
2751
        $SETTINGS['cpassman_dir'],
2752
        array(
2753
            'error' => true,
2754
            'message' => langHdl('error_no_user'),
2755
        ),
2756
        'encode'
2757
    );
2758
}
2759
2760
            
2761
function changeUserLDAPAuthenticationPassword(
2762
    int $post_user_id,
2763
    string $post_previous_pwd,
2764
    string $post_current_pwd,
2765
    array $SETTINGS
2766
)
2767
{
2768
    if (isUserIdValid($post_user_id) === true) {
2769
        // Get user info
2770
        $userData = DB::queryFirstRow(
2771
            'SELECT auth_type, login, private_key, special
2772
            FROM ' . prefixTable('users') . '
2773
            WHERE id = %i',
2774
            $post_user_id
2775
        );
2776
        
2777
        if (DB::count() > 0 && empty($userData['private_key']) === false) {
2778
            // Now check if current password is correct (only if not ldap)
2779
            if ($userData['auth_type'] === 'ldap' && $userData['special'] === 'auth-pwd-change') {
2780
                // As it is a change for an LDAP user
2781
                
2782
                // Now check if current password is correct
2783
                // For this, just check if it is possible to decrypt the privatekey
2784
                // And compare it to the one in session
2785
                $privateKey = decryptPrivateKey($post_previous_pwd, $userData['private_key']);
2786
2787
                // Encrypt it with new password
2788
                $hashedPrivateKey = encryptPrivateKey($post_current_pwd, $privateKey);
2789
2790
                // Update user account
2791
                DB::update(
2792
                    prefixTable('users'),
2793
                    array(
2794
                        'private_key' => $hashedPrivateKey,
2795
                        'special' => 'none',
2796
                    ),
2797
                    'id = %i',
2798
                    $post_user_id
2799
                );
2800
2801
                // Load superGlobals
2802
                include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2803
                $superGlobal = new protect\SuperGlobal\SuperGlobal();
2804
                $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2805
2806
                return prepareExchangedData(
2807
                    $SETTINGS['cpassman_dir'],
2808
                    array(
2809
                        'error' => false,
2810
                        'message' => langHdl('done'),'',
2811
                    ),
2812
                    'encode'
2813
                );
2814
            }
2815
2816
            // For this, just check if it is possible to decrypt the privatekey
2817
            // And try to decrypt one existing key
2818
            $privateKey = decryptPrivateKey($post_previous_pwd, $userData['private_key']);
2819
2820
            if (empty($privateKey) === true) {
2821
                return prepareExchangedData(
2822
                    $SETTINGS['cpassman_dir'],
2823
                    array(
2824
                        'error' => true,
2825
                        'message' => langHdl('password_is_not_correct'),
2826
                    ),
2827
                    'encode'
2828
                );
2829
            }
2830
2831
            // Test if possible to decvrypt one key
2832
            // Get one item
2833
            $record = DB::queryFirstRow(
2834
                'SELECT id, pw
2835
                FROM ' . prefixTable('items') . '
2836
                WHERE perso = 0'
2837
            );
2838
2839
            // Get itemKey from current user
2840
            $currentUserKey = DB::queryFirstRow(
2841
                'SELECT share_key, increment_id
2842
                FROM ' . prefixTable('sharekeys_items') . '
2843
                WHERE object_id = %i AND user_id = %i',
2844
                $record['id'],
2845
                $post_user_id
2846
            );
2847
2848
            if (count($currentUserKey) > 0) {
2849
                // Decrypt itemkey with user key
2850
                // use old password to decrypt private_key
2851
                $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $privateKey);
2852
                
2853
                if (empty(base64_decode($itemKey)) === false) {
2854
                    // GOOD password
2855
                    // Encrypt it with current password
2856
                    $hashedPrivateKey = encryptPrivateKey($post_current_pwd, $privateKey);
2857
                    
2858
                    // Update user account
2859
                    DB::update(
2860
                        prefixTable('users'),
2861
                        array(
2862
                            'private_key' => $hashedPrivateKey,
2863
                            'special' => 'none',
2864
                        ),
2865
                        'id = %i',
2866
                        $post_user_id
2867
                    );
2868
                    
2869
                    // Load superGlobals
2870
                    include_once $SETTINGS['cpassman_dir'] . '/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2871
                    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2872
                    $superGlobal->put('private_key', $privateKey, 'SESSION', 'user');
2873
2874
                    return prepareExchangedData(
2875
                        $SETTINGS['cpassman_dir'],
2876
                        array(
2877
                            'error' => false,
2878
                            'message' => langHdl('done'),
2879
                        ),
2880
                        'encode'
2881
                    );
2882
                }
2883
            }
2884
            
2885
            // ERROR
2886
            return prepareExchangedData(
2887
                $SETTINGS['cpassman_dir'],
2888
                array(
2889
                    'error' => true,
2890
                    'message' => langHdl('bad_password'),
2891
                ),
2892
                'encode'
2893
            );
2894
        }
2895
    }
2896
2897
    // ERROR
2898
    return prepareExchangedData(
2899
    $SETTINGS['cpassman_dir'],
2900
        array(
2901
            'error' => true,
2902
            'message' => langHdl('error_no_user'),
2903
        ),
2904
        'encode'
2905
    );
2906
}
2907
2908
2909
function increaseSessionDuration(
2910
    int $duration
2911
): string
2912
{
2913
    // check if session is not already expired.
2914
    if ($_SESSION['sessionDuration'] > time()) {
2915
        // Calculate end of session
2916
        $_SESSION['sessionDuration'] = (int) ($_SESSION['sessionDuration'] + $duration);
2917
        // Update table
2918
        DB::update(
2919
            prefixTable('users'),
2920
            array(
2921
                'session_end' => $_SESSION['sessionDuration'],
2922
            ),
2923
            'id = %i',
2924
            $_SESSION['user_id']
2925
        );
2926
        // Return data
2927
        return '[{"new_value":"' . $_SESSION['sessionDuration'] . '"}]';
2928
    }
2929
    
2930
    return '[{"new_value":"expired"}]';
2931
}