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

provideLog()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * Teampass - a collaborative passwords manager.
4
 * ---
5
 * This library is distributed in the hope that it will be useful,
6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8
 * ---
9
 *
10
 * @project   Teampass
11
 *
12
 * @file      processing_background_tasks.php
13
 * ---
14
 *
15
 * @author    Nils Laumaillé ([email protected])
16
 *
17
 * @copyright 2009-2022 Teampass.net
18
 *
19
 * @license   https://spdx.org/licenses/GPL-3.0-only.html#licenseText GPL-3.0
20
 * ---
21
 *
22
 * @see       https://www.teampass.net
23
 */
24
25
require_once __DIR__.'/../sources/SecureHandler.php';
26
session_name('teampass_session');
27
session_start();
28
29
// Load config
30
require_once __DIR__.'/../includes/config/tp.config.php';
31
32
// increase the maximum amount of time a script is allowed to run
33
set_time_limit($SETTINGS['task_maximum_run_time']);
34
35
// Do checks
36
require_once $SETTINGS['cpassman_dir'].'/includes/config/include.php';
37
require_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
38
header('Content-type: text/html; charset=utf-8');
39
header('Cache-Control: no-cache, must-revalidate');
40
require_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
41
// Connect to mysql server
42
require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
43
if (defined('DB_PASSWD_CLEAR') === false) {
44
    define('DB_PASSWD_CLEAR', defuseReturnDecrypted(DB_PASSWD, $SETTINGS));
45
}
46
DB::$host = DB_HOST;
47
DB::$user = DB_USER;
48
DB::$password = DB_PASSWD_CLEAR;
49
DB::$dbName = DB_NAME;
50
DB::$port = DB_PORT;
51
DB::$encoding = DB_ENCODING;
52
DB::$ssl = DB_SSL;
53
DB::$connect_options = DB_CONNECT_OPTIONS;
54
55
56
// Manage the tasks in queue.
57
// Task to treat selection is:
58
// 1- take first is_in_progress === 1
59
// 2- take first is_in_progress === 0 and finished_at === null
60
61
$process_to_perform = DB::queryfirstrow(
62
    'SELECT *
63
    FROM ' . prefixTable('processes') . '
64
    WHERE is_in_progress = %i
65
    ORDER BY increment_id ASC',
66
    1
67
);
68
69
if (DB::count() > 0) {
70
    // handle tasks inside this process
71
    //echo "Handle task<br>";
72
    handleTask(
73
        $process_to_perform['increment_id'],
74
        json_decode($process_to_perform['arguments'], true),
75
        $SETTINGS,
76
    );
77
} else {
78
    // search for next process to handle
79
    $process_to_perform = DB::queryfirstrow(
80
        'SELECT *
81
        FROM ' . prefixTable('processes') . '
82
        WHERE is_in_progress = %i AND finished_at IS NULL
83
        ORDER BY increment_id ASC',
84
        0
85
    );
86
    //print_r($process_to_perform);
87
    if (DB::count() > 0) {
88
        provideLog('[PROCESS][#'. $process_to_perform['increment_id'].'][START]', $SETTINGS);
89
        handleTask(
90
            $process_to_perform['increment_id'],
91
            json_decode($process_to_perform['arguments'], true),
92
            $SETTINGS,
93
        );
94
    } else {
95
96
    }
97
}
98
99
100
101
102
function handleTask(int $processId, array $ProcessArguments, array $SETTINGS)
103
{
104
    provideLog('[PROCESS][#'. $processId.'][START]', $SETTINGS);
105
    DB::debugmode(true);
106
    $task_to_perform = DB::queryfirstrow(
107
        'SELECT *
108
        FROM ' . prefixTable('processes_tasks') . '
109
        WHERE process_id = %i AND finished_at IS NULL
110
        ORDER BY increment_id ASC',
111
        $processId
112
    );
113
114
    
115
    if (DB::count() > 0) {
116
        // check if a linux process is not currently on going
117
        // if sub_task_in_progress === 1 then exit
118
        if ((int) $task_to_perform['sub_task_in_progress'] === 0) {
119
            provideLog('[TASK][#'. $task_to_perform['increment_id'].'][START]', $SETTINGS);
120
121
            // handle next task
122
            $args = json_decode($task_to_perform['task'], true);
123
            //print_r($args);
124
125
            // flag as in progress
126
            DB::update(
127
                prefixTable('processes'),
128
                array(
129
                    'updated_at' => time(),
130
                    'is_in_progress' => 1,
131
                ),
132
                'increment_id = %i',
133
                $processId
134
            );
135
136
            // flag task as on going
137
            if ((int) $args['index'] === 0) {
138
                DB::update(
139
                    prefixTable('processes_tasks'),
140
                    array(
141
                        'is_in_progress' => 1,
142
                    ),
143
                    'increment_id = %i',
144
                    $task_to_perform['increment_id']
145
                );
146
            }
147
148
            // flag sub task in progress as on going
149
            DB::update(
150
                prefixTable('processes_tasks'),
151
                array(
152
                    'sub_task_in_progress' => 1,
153
                ),
154
                'increment_id = %i',
155
                $task_to_perform['increment_id']
156
            );
157
158
            $taskStatus = performUserCreationKeys(
159
                (int) $ProcessArguments['new_user_id'],
160
                (bool) false,
161
                (string) $args['step'],
162
                (int) $args['index'],
163
                (int) $args['nb'],
164
                $SETTINGS,
165
                $ProcessArguments
166
            );
167
168
            // update the task status
169
            DB::update(
170
                prefixTable('processes_tasks'),
171
                array(
172
                    'sub_task_in_progress' => 0,    // flag sub task is no more in prgoress
173
                    'task' => $taskStatus['new_action'] !== $args['step'] ? 
174
                    json_encode(["status" => "Done"]) :
175
                    json_encode([
176
                        "step" => $taskStatus['new_action'],
177
                        "index" => $taskStatus['new_index'],
178
                        "nb" => $args['nb'],
179
                    ]),
180
                    'is_in_progress' => $taskStatus['new_action'] !== $args['step'] ? -1 : 1,
181
                    'finished_at' => $taskStatus['new_action'] !== $args['step'] ? time() : NULL,
182
                    'updated_at' => time(),
183
                ),
184
                'increment_id = %i',
185
                $task_to_perform['increment_id']
186
            );
187
188
            provideLog('[TASK]['.$args['step'].'] starting at '.$args['index'].' is done.', $SETTINGS);
189
190
            if ($args['step'] === 'step6') {
191
                // all done
192
                provideLog('[PROCESS]['.$processId.'][FINISHED]', $SETTINGS);
193
                DB::debugmode(false);
194
                DB::update(
195
                    prefixTable('processes'),
196
                    array(
197
                        'finished_at' => time(),
198
                        'is_in_progress' => -1,
199
                        'arguments' => json_encode([
200
                            'new_user_id' => $ProcessArguments['new_user_id'],
201
                        ])
202
                    ),
203
                    'increment_id = %i',
204
                    $processId
205
                );
206
            }
207
            return false;
208
209
        } else {
210
            // Task is currently being in progress by another server process
211
            provideLog('[TASK][#'. $task_to_perform['increment_id'].'][WARNING] Similar task already being processes', $SETTINGS);
212
            return false;
213
        }
214
    }
215
}
216
217
/**
218
 * Permits to encrypt user's keys
219
 *
220
 * @param integer $post_user_id
221
 * @param boolean $post_self_change
222
 * @param string $post_action
223
 * @param integer $post_start
224
 * @param integer $post_length
225
 * @param array $SETTINGS
226
 * @param array $extra_arguments
227
 * @return string
228
 */
229
function performUserCreationKeys(
230
    int     $post_user_id,
231
    bool    $post_self_change,
232
    string  $post_action,
233
    int     $post_start,
234
    int     $post_length,
235
    array   $SETTINGS,
236
    array   $extra_arguments
237
): array
238
{
239
    if (isUserIdValid($post_user_id) === true) {
240
        // Check if user exists
241
        $userInfo = DB::queryFirstRow(
242
            'SELECT public_key, private_key
243
            FROM ' . prefixTable('users') . '
244
            WHERE id = %i',
245
            $post_user_id
246
        );
247
        
248
        if (isset($userInfo['public_key']) === true) {
249
            $return = [];
250
251
            // WHAT STEP TO PERFORM?
252
            if ($post_action === 'step0') {
253
                //echo '<br>Start STEP0<br>';
254
                // CLear old sharekeys
255
                if ($post_self_change === false) {
256
                    deleteUserObjetsKeys($post_user_id, $SETTINGS);
257
                }
258
259
                $return['new_action'] = 'step1';
260
                $return['new_index'] = 0;
261
                provideLog('[STEP][0][FINISHED]', $SETTINGS);
262
            }
263
            
264
            // STEP 1 - ITEMS
265
            elseif ($post_action === 'step1') {
266
                provideLog('[STEP][1][START][INDEX]['.$post_start.']', $SETTINGS);
267
                $return = continueReEncryptingUserSharekeysStep1(
268
                    $post_user_id,
269
                    $post_self_change,
270
                    $post_action,
271
                    $post_start,
272
                    $post_length,
273
                    $userInfo['public_key'],
274
                    $SETTINGS,
275
                    $extra_arguments
0 ignored issues
show
Unused Code introduced by
The call to continueReEncryptingUserSharekeysStep1() has too many arguments starting with $extra_arguments. ( Ignorable by Annotation )

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

275
                $return = /** @scrutinizer ignore-call */ continueReEncryptingUserSharekeysStep1(

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...
276
                );
277
                provideLog('[STEP][1][FINISHED]', $SETTINGS);
278
            }
279
280
            // STEP 2 - LOGS
281
            elseif ($post_action === 'step2') {
282
                provideLog('[STEP][2][START][INDEX]['.$post_start.']', $SETTINGS);
283
                $return = continueReEncryptingUserSharekeysStep2(
284
                    $post_user_id,
285
                    $post_self_change,
286
                    $post_action,
287
                    $post_start,
288
                    $post_length,
289
                    $userInfo['public_key'],
290
                    $SETTINGS,
291
                    $extra_arguments
0 ignored issues
show
Unused Code introduced by
The call to continueReEncryptingUserSharekeysStep2() has too many arguments starting with $extra_arguments. ( Ignorable by Annotation )

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

291
                $return = /** @scrutinizer ignore-call */ continueReEncryptingUserSharekeysStep2(

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...
292
                );
293
                provideLog('[STEP][2][FINISHED]', $SETTINGS);
294
            }
295
296
            // STEP 3 - FIELDS
297
            elseif ($post_action === 'step3') {
298
                provideLog('[STEP][3][START][INDEX]['.$post_start.']', $SETTINGS);
299
                $return = continueReEncryptingUserSharekeysStep3(
300
                    $post_user_id,
301
                    $post_self_change,
302
                    $post_action,
303
                    $post_start,
304
                    $post_length,
305
                    $userInfo['public_key'],
306
                    $SETTINGS,
307
                    $extra_arguments
0 ignored issues
show
Unused Code introduced by
The call to continueReEncryptingUserSharekeysStep3() has too many arguments starting with $extra_arguments. ( Ignorable by Annotation )

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

307
                $return = /** @scrutinizer ignore-call */ continueReEncryptingUserSharekeysStep3(

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...
308
                );
309
                provideLog('[STEP][3][FINISHED]', $SETTINGS);
310
            }
311
            
312
            // STEP 4 - SUGGESTIONS
313
            elseif ($post_action === 'step4') {
314
                provideLog('[STEP][4][START][INDEX]['.$post_start.']', $SETTINGS);
315
                $return = continueReEncryptingUserSharekeysStep4(
316
                    $post_user_id,
317
                    $post_self_change,
318
                    $post_action,
319
                    $post_start,
320
                    $post_length,
321
                    $userInfo['public_key'],
322
                    $SETTINGS,
323
                    $extra_arguments
0 ignored issues
show
Unused Code introduced by
The call to continueReEncryptingUserSharekeysStep4() has too many arguments starting with $extra_arguments. ( Ignorable by Annotation )

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

323
                $return = /** @scrutinizer ignore-call */ continueReEncryptingUserSharekeysStep4(

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...
324
                );
325
                provideLog('[STEP][4][FINISHED]', $SETTINGS);
326
            }
327
            
328
            // STEP 5 - FILES
329
            elseif ($post_action === 'step5') {
330
                provideLog('[STEP][5][START][INDEX]['.$post_start.']', $SETTINGS);
331
                $return = continueReEncryptingUserSharekeysStep5(
332
                    $post_user_id,
333
                    $post_self_change,
334
                    $post_action,
335
                    $post_start,
336
                    $post_length,
337
                    $userInfo['public_key'],
338
                    $SETTINGS,
339
                    $extra_arguments
0 ignored issues
show
Unused Code introduced by
The call to continueReEncryptingUserSharekeysStep5() has too many arguments starting with $extra_arguments. ( Ignorable by Annotation )

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

339
                $return = /** @scrutinizer ignore-call */ continueReEncryptingUserSharekeysStep5(

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...
340
                );
341
                provideLog('[STEP][5][FINISHED]', $SETTINGS);
342
            }
343
            
344
            // STEP 6 - PERSONAL ITEMS
345
            elseif ($post_action === 'step6') {
346
                provideLog('[STEP][16][START][INDEX]['.$post_start.']', $SETTINGS);
347
                $return = continueReEncryptingUserSharekeysStep6(
348
                    $post_user_id,
349
                    $post_self_change,
350
                    $post_action,
351
                    $post_start,
352
                    $post_length,
353
                    $userInfo['public_key'],
354
                    $SETTINGS,
355
                    $extra_arguments
0 ignored issues
show
Unused Code introduced by
The call to continueReEncryptingUserSharekeysStep6() has too many arguments starting with $extra_arguments. ( Ignorable by Annotation )

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

355
                $return = /** @scrutinizer ignore-call */ continueReEncryptingUserSharekeysStep6(

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...
356
                );
357
                provideLog('[STEP][6][FINISHED]', $SETTINGS);
358
            }
359
            
360
            // Continu with next step
361
            return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return returns the type array|array<string,integer|string> which is incompatible with the documented return type string.
Loading history...
362
        }
363
        
364
        // Nothing to do
365
        provideLog('[USER][ERROR] No user public key', $SETTINGS);
366
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the type-hinted return array.
Loading history...
367
    }
368
    provideLog('[USER][ERROR] No user found', $SETTINGS);
369
    return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the type-hinted return array.
Loading history...
370
}
371
372
function getOwnerInfo(int $owner_id, string $owner_pwd, array $SETTINGS): array
373
{
374
    $userInfo = DB::queryFirstRow(
375
        'SELECT public_key, private_key
376
        FROM ' . prefixTable('users') . '
377
        WHERE id = %i',
378
        $owner_id
379
    );
380
echo "> ".$owner_pwd. " ;; ";
381
    // decrypt owner password
382
    $owner_pwd = cryption($owner_pwd, '','decrypt', $SETTINGS)['string'];
383
    provideLog('[USER][INFO]', $SETTINGS);
384
    // uncrypt private key and send back
385
    return [
386
        'private_key' => decryptPrivateKey($owner_pwd, $userInfo['private_key']),
387
    ];
388
}
389
390
391
function continueReEncryptingUserSharekeysStep1(
392
    int $post_user_id,
393
    bool $post_self_change,
394
    string $post_action,
395
    int $post_start,
396
    int $post_length,
397
    string $user_public_key,
398
    array $SETTINGS,
399
    array $extra_arguments
400
): array 
401
{
402
    // get user private key
403
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
404
405
    // Loop on items
406
    $rows = DB::query(
407
        'SELECT id, pw
408
        FROM ' . prefixTable('items') . '
409
        WHERE perso = 0
410
        LIMIT ' . $post_start . ', ' . $post_length
411
    );
412
    foreach ($rows as $record) {
413
        // Get itemKey from current user
414
        $currentUserKey = DB::queryFirstRow(
415
            'SELECT share_key, increment_id
416
            FROM ' . prefixTable('sharekeys_items') . '
417
            WHERE object_id = %i AND user_id = %i',
418
            $record['id'],
419
            $extra_arguments['owner_id']
420
        );
421
        if ($currentUserKey === null || count($currentUserKey) === 0) continue;
422
423
        // Decrypt itemkey with admin key
424
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
425
        
426
        // Encrypt Item key
427
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
428
        
429
        // Save the key in DB
430
        if ($post_self_change === false) {
431
            DB::insert(
432
                prefixTable('sharekeys_items'),
433
                array(
434
                    'object_id' => (int) $record['id'],
435
                    'user_id' => (int) $post_user_id,
436
                    'share_key' => $share_key_for_item,
437
                )
438
            );
439
        } else {
440
            // Get itemIncrement from selected user
441
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
442
                $currentUserKey = DB::queryFirstRow(
443
                    'SELECT increment_id
444
                    FROM ' . prefixTable('sharekeys_items') . '
445
                    WHERE object_id = %i AND user_id = %i',
446
                    $record['id'],
447
                    $post_user_id
448
                );
449
450
                if (DB::count() > 0) {
451
                    // NOw update
452
                    DB::update(
453
                        prefixTable('sharekeys_items'),
454
                        array(
455
                            'share_key' => $share_key_for_item,
456
                        ),
457
                        'increment_id = %i',
458
                        $currentUserKey['increment_id']
459
                    );
460
                } else {
461
                    DB::insert(
462
                        prefixTable('sharekeys_items'),
463
                        array(
464
                            'object_id' => (int) $record['id'],
465
                            'user_id' => (int) $post_user_id,
466
                            'share_key' => $share_key_for_item,
467
                        )
468
                    );
469
                }
470
            }
471
        }
472
    }
473
474
    // SHould we change step?
475
    DB::query(
476
        'SELECT *
477
        FROM ' . prefixTable('items') . '
478
        WHERE perso = 0'
479
    );
480
481
    $next_start = (int) $post_start + (int) $post_length;
482
    return [
483
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
484
        'new_action' => $next_start > DB::count() ? 'step2' : 'step1',
485
    ];
486
}
487
488
function continueReEncryptingUserSharekeysStep2(
489
    int $post_user_id,
490
    bool $post_self_change,
491
    string $post_action,
492
    int $post_start,
493
    int $post_length,
494
    string $user_public_key,
495
    array $SETTINGS,
496
    array $extra_arguments
497
): array
498
{
499
    // get user private key
500
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
501
502
    // Loop on logs
503
    $rows = DB::query(
504
        'SELECT increment_id
505
        FROM ' . prefixTable('log_items') . '
506
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"
507
        LIMIT ' . $post_start . ', ' . $post_length
508
    );
509
    foreach ($rows as $record) {
510
        // Get itemKey from current user
511
        $currentUserKey = DB::queryFirstRow(
512
            'SELECT share_key
513
            FROM ' . prefixTable('sharekeys_logs') . '
514
            WHERE object_id = %i AND user_id = %i',
515
            $record['increment_id'],
516
            $extra_arguments['owner_id']
517
        );
518
519
        // Decrypt itemkey with admin key
520
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
521
522
        // Encrypt Item key
523
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
524
525
        // Save the key in DB
526
        if ($post_self_change === false) {
527
            DB::insert(
528
                prefixTable('sharekeys_logs'),
529
                array(
530
                    'object_id' => (int) $record['increment_id'],
531
                    'user_id' => (int) $post_user_id,
532
                    'share_key' => $share_key_for_item,
533
                )
534
            );
535
        } else {
536
            // Get itemIncrement from selected user
537
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
538
                $currentUserKey = DB::queryFirstRow(
539
                    'SELECT increment_id
540
                    FROM ' . prefixTable('sharekeys_items') . '
541
                    WHERE object_id = %i AND user_id = %i',
542
                    $record['id'],
543
                    $post_user_id
544
                );
545
            }
546
547
            // NOw update
548
            DB::update(
549
                prefixTable('sharekeys_logs'),
550
                array(
551
                    'share_key' => $share_key_for_item,
552
                ),
553
                'increment_id = %i',
554
                $currentUserKey['increment_id']
555
            );
556
        }
557
    }
558
559
    // SHould we change step?
560
    DB::query(
561
        'SELECT increment_id
562
        FROM ' . prefixTable('log_items') . '
563
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"'
564
    );
565
566
    $next_start = (int) $post_start + (int) $post_length;
567
    return [
568
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
569
        'new_action' => $next_start > DB::count() ? 'step3' : 'step2',
570
    ];
571
}
572
573
function continueReEncryptingUserSharekeysStep3(
574
    int $post_user_id,
575
    bool $post_self_change,
576
    string $post_action,
577
    int $post_start,
578
    int $post_length,
579
    string $user_public_key,
580
    array $SETTINGS,
581
    array $extra_arguments
582
): array
583
{
584
    // get user private key
585
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
586
587
    // Loop on fields
588
    $rows = DB::query(
589
        'SELECT id
590
        FROM ' . prefixTable('categories_items') . '
591
        WHERE encryption_type = "teampass_aes"
592
        LIMIT ' . $post_start . ', ' . $post_length
593
    );
594
    foreach ($rows as $record) {
595
        // Get itemKey from current user
596
        $currentUserKey = DB::queryFirstRow(
597
            'SELECT share_key
598
            FROM ' . prefixTable('sharekeys_fields') . '
599
            WHERE object_id = %i AND user_id = %i',
600
            $record['id'],
601
            $extra_arguments['owner_id']
602
        );
603
604
        // Decrypt itemkey with admin key
605
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
606
607
        // Encrypt Item key
608
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
609
610
        // Save the key in DB
611
        if ($post_self_change === false) {
612
            DB::insert(
613
                prefixTable('sharekeys_fields'),
614
                array(
615
                    'object_id' => (int) $record['id'],
616
                    'user_id' => (int) $post_user_id,
617
                    'share_key' => $share_key_for_item,
618
                )
619
            );
620
        } else {
621
            // Get itemIncrement from selected user
622
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
623
                $currentUserKey = DB::queryFirstRow(
624
                    'SELECT increment_id
625
                    FROM ' . prefixTable('sharekeys_items') . '
626
                    WHERE object_id = %i AND user_id = %i',
627
                    $record['id'],
628
                    $post_user_id
629
                );
630
            }
631
632
            // NOw update
633
            DB::update(
634
                prefixTable('sharekeys_fields'),
635
                array(
636
                    'share_key' => $share_key_for_item,
637
                ),
638
                'increment_id = %i',
639
                $currentUserKey['increment_id']
640
            );
641
        }
642
    }
643
644
    // SHould we change step?
645
    DB::query(
646
        'SELECT *
647
        FROM ' . prefixTable('categories_items') . '
648
        WHERE encryption_type = "teampass_aes"'
649
    );
650
651
    $next_start = (int) $post_start + (int) $post_length;
652
    return [
653
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
654
        'new_action' => $next_start > DB::count() ? 'step4' : 'step3',
655
    ];
656
}
657
658
function continueReEncryptingUserSharekeysStep4(
659
    int $post_user_id,
660
    bool $post_self_change,
661
    string $post_action,
662
    int $post_start,
663
    int $post_length,
664
    string $user_public_key,
665
    array $SETTINGS,
666
    array $extra_arguments
667
): array
668
{
669
    // get user private key
670
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
671
672
    // Loop on suggestions
673
    $rows = DB::query(
674
        'SELECT id
675
        FROM ' . prefixTable('suggestion') . '
676
        LIMIT ' . $post_start . ', ' . $post_length
677
    );
678
    foreach ($rows as $record) {
679
        // Get itemKey from current user
680
        $currentUserKey = DB::queryFirstRow(
681
            'SELECT share_key
682
            FROM ' . prefixTable('sharekeys_suggestions') . '
683
            WHERE object_id = %i AND user_id = %i',
684
            $record['id'],
685
            $extra_arguments['owner_id']
686
        );
687
688
        // Decrypt itemkey with admin key
689
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
690
691
        // Encrypt Item key
692
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
693
694
        // Save the key in DB
695
        if ($post_self_change === false) {
696
            DB::insert(
697
                prefixTable('sharekeys_suggestions'),
698
                array(
699
                    'object_id' => (int) $record['id'],
700
                    'user_id' => (int) $post_user_id,
701
                    'share_key' => $share_key_for_item,
702
                )
703
            );
704
        } else {
705
            // Get itemIncrement from selected user
706
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
707
                $currentUserKey = DB::queryFirstRow(
708
                    'SELECT increment_id
709
                    FROM ' . prefixTable('sharekeys_items') . '
710
                    WHERE object_id = %i AND user_id = %i',
711
                    $record['id'],
712
                    $post_user_id
713
                );
714
            }
715
716
            // NOw update
717
            DB::update(
718
                prefixTable('sharekeys_suggestions'),
719
                array(
720
                    'share_key' => $share_key_for_item,
721
                ),
722
                'increment_id = %i',
723
                $currentUserKey['increment_id']
724
            );
725
        }
726
    }
727
728
    // SHould we change step?
729
    DB::query(
730
        'SELECT *
731
        FROM ' . prefixTable('suggestion')
732
    );
733
734
    $next_start = (int) $post_start + (int) $post_length;
735
    return [
736
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
737
        'new_action' => $next_start > DB::count() ? 'step5' : 'step4',
738
    ];
739
}
740
741
function continueReEncryptingUserSharekeysStep5(
742
    int $post_user_id,
743
    bool $post_self_change,
744
    string $post_action,
745
    int $post_start,
746
    int $post_length,
747
    string $user_public_key,
748
    array $SETTINGS,
749
    array $extra_arguments
750
): array
751
{
752
    // get user private key
753
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
754
755
    // Loop on files
756
    $rows = DB::query(
757
        'SELECT id
758
        FROM ' . prefixTable('files') . '
759
        WHERE status = "' . TP_ENCRYPTION_NAME . '"
760
        LIMIT ' . $post_start . ', ' . $post_length
761
    ); //aes_encryption
762
    foreach ($rows as $record) {
763
        // Get itemKey from current user
764
        $currentUserKey = DB::queryFirstRow(
765
            'SELECT share_key
766
            FROM ' . prefixTable('sharekeys_files') . '
767
            WHERE object_id = %i AND user_id = %i',
768
            $record['id'],
769
            $extra_arguments['owner_id']
770
        );
771
772
        // Decrypt itemkey with admin key
773
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
774
775
        // Encrypt Item key
776
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
777
778
        // Save the key in DB
779
        if ($post_self_change === false) {
780
            DB::insert(
781
                prefixTable('sharekeys_files'),
782
                array(
783
                    'object_id' => (int) $record['id'],
784
                    'user_id' => (int) $post_user_id,
785
                    'share_key' => $share_key_for_item,
786
                )
787
            );
788
        } else {
789
            // Get itemIncrement from selected user
790
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
791
                $currentUserKey = DB::queryFirstRow(
792
                    'SELECT increment_id
793
                    FROM ' . prefixTable('sharekeys_items') . '
794
                    WHERE object_id = %i AND user_id = %i',
795
                    $record['id'],
796
                    $post_user_id
797
                );
798
            }
799
800
            // NOw update
801
            DB::update(
802
                prefixTable('sharekeys_files'),
803
                array(
804
                    'share_key' => $share_key_for_item,
805
                ),
806
                'increment_id = %i',
807
                $currentUserKey['increment_id']
808
            );
809
        }
810
    }
811
812
    // SHould we change step?
813
    DB::query(
814
        'SELECT *
815
        FROM ' . prefixTable('files') . '
816
        WHERE status = "' . TP_ENCRYPTION_NAME . '"'
817
    );
818
819
    $next_start = (int) $post_start + (int) $post_length;
820
    return [
821
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
822
        'new_action' => $next_start > DB::count() ? 'step6' : 'step5',
823
    ];
824
}
825
826
function continueReEncryptingUserSharekeysStep6(
827
    int $post_user_id,
828
    bool $post_self_change,
829
    string $post_action,
830
    int $post_start,
831
    int $post_length,
832
    string $user_public_key,
833
    array $SETTINGS,
834
    array $extra_arguments
835
): array
836
{
837
    // get user private key
838
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
0 ignored issues
show
Unused Code introduced by
The assignment to $ownerInfo is dead and can be removed.
Loading history...
839
840
    // IF USER IS NOT THE SAME
841
    if ((int) $post_user_id === (int) $extra_arguments['owner_id']) {
842
        return [
843
            'new_index' => 0,
844
            'new_action' => 'finished',
845
        ];
846
    }
847
848
    // if done then send email to new user
849
    // get user info
850
    $userInfo = DB::queryFirstRow(
851
        'SELECT email, login 
852
        FROM ' . prefixTable('users') . '
853
        WHERE id = %i',
854
        $extra_arguments['new_user_id']
855
    );
856
857
    sendMailToUser(
858
        filter_var($userInfo['email'], FILTER_SANITIZE_STRING),
859
        langHdl('email_body_new_user'),
860
        'TEAMPASS - ' . langHdl('temporary_encryption_code'),
861
        (array) filter_var_array(
862
            [
863
                '#code#' => $extra_arguments['new_user_code'],
864
                '#login#' => $userInfo['login'],
865
                '#password#' => cryption($extra_arguments['new_user_pwd'], '','decrypt', $SETTINGS)['string'],
866
            ],
867
            FILTER_SANITIZE_STRING
868
        ),
869
        $SETTINGS
870
    );
871
872
    // Set user as ready for usage
873
    DB::update(
874
        prefixTable('users'),
875
        array(
876
            'is_ready_for_usage' => 1,
877
        ),
878
        'id = %i',
879
        $extra_arguments['new_user_id']
880
    );
881
882
    return [
883
        'new_index' => 0,
884
        'new_action' => 'finished',
885
    ];
886
}
887
888
889
890
function sendMailToUser(
891
    string $post_receipt,
892
    string $post_body,
893
    string $post_subject,
894
    array $post_replace,
895
    array $SETTINGS
896
): string
897
{
898
    if (count($post_replace) > 0 && is_null($post_replace) === false) {
899
        $post_body = str_replace(
900
            array_keys($post_replace),
901
            array_values($post_replace),
902
            $post_body
903
        );
904
    }
905
    
906
    $ret = sendEmail(
907
        $post_subject,
908
        $post_body,
909
        $post_receipt,
910
        $SETTINGS,
911
        '',
912
        false
913
    );
914
915
    $ret = json_decode($ret, true);
916
917
    return prepareExchangedData(
918
    $SETTINGS['cpassman_dir'],
919
        array(
920
            'error' => empty($ret['error']) === true ? false : true,
921
            'message' => $ret['message'],
922
        ),
923
        'encode'
924
    );
925
}
926
927
function provideLog(string $message, array $SETTINGS)
928
{
929
    echo '\n' . (string) date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], time()) . ' - '.$message . '\n';
930
}