Passed
Push — master ( cea058...bb409d )
by Nils
04:10
created

cronContinueReEncryptingUserSharekeysStep6()   B

Complexity

Conditions 9
Paths 3

Size

Total Lines 62
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 32
nc 3
nop 3
dl 0
loc 62
rs 8.0555
c 1
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/**
3
 * 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
 * @version   
12
 * @file      background_tasks___user_keys_creation.php
13
 * ---
14
 *
15
 * @author    Nils Laumaillé ([email protected])
16
 *
17
 * @copyright 2009-2023 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
require_once __DIR__.'/background_tasks___functions.php';
32
33
// increase the maximum amount of time a script is allowed to run
34
set_time_limit($SETTINGS['task_maximum_run_time']);
35
36
// Do checks
37
require_once $SETTINGS['cpassman_dir'].'/includes/config/include.php';
38
require_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
39
header('Content-type: text/html; charset=utf-8');
40
header('Cache-Control: no-cache, must-revalidate');
41
require_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
42
// Connect to mysql server
43
require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
44
if (defined('DB_PASSWD_CLEAR') === false) {
45
    define('DB_PASSWD_CLEAR', defuseReturnDecrypted(DB_PASSWD, $SETTINGS));
46
}
47
DB::$host = DB_HOST;
48
DB::$user = DB_USER;
49
DB::$password = DB_PASSWD_CLEAR;
50
DB::$dbName = DB_NAME;
51
DB::$port = DB_PORT;
52
DB::$encoding = DB_ENCODING;
53
DB::$ssl = DB_SSL;
54
DB::$connect_options = DB_CONNECT_OPTIONS;
55
56
// log start
57
$logID = doLog('start', 'user_keys', (isset($SETTINGS['enable_tasks_log']) === true ? (int) $SETTINGS['enable_tasks_log'] : 0));
58
59
60
// Manage the tasks in queue.
61
// Task to treat selection is:
62
// 1- take first is_in_progress === 1
63
// 2- take first is_in_progress === 0 and finished_at === null
64
DB::debugmode(false);
65
$process_to_perform = DB::queryfirstrow(
66
    'SELECT *
67
    FROM ' . prefixTable('processes') . '
68
    WHERE is_in_progress = %i AND process_type = %s
69
    ORDER BY increment_id ASC',
70
    1,
71
    'create_user_keys'
72
);
73
74
if (DB::count() > 0) {
75
    // handle tasks inside this process
76
    //echo "Handle task<br>";
77
    handleTask(
78
        $process_to_perform['increment_id'],
79
        json_decode($process_to_perform['arguments'], true),
80
        $SETTINGS,
81
    );
82
} else {
83
    // search for next process to handle
84
    $process_to_perform = DB::queryfirstrow(
85
        'SELECT *
86
        FROM ' . prefixTable('processes') . '
87
        WHERE is_in_progress = %i AND finished_at = "" AND process_type = %s
88
        ORDER BY increment_id ASC',
89
        0,
90
        'create_user_keys'
91
    );
92
    //print_r($process_to_perform);
93
    if (DB::count() > 0) {
94
        provideLog('[PROCESS][#'. $process_to_perform['increment_id'].'][START]', $SETTINGS);
95
        handleTask(
96
            $process_to_perform['increment_id'],
97
            json_decode($process_to_perform['arguments'], true),
98
            $SETTINGS,
99
        );
100
    } else {
101
102
    }
103
}
104
105
// log end
106
doLog('end', '', (isset($SETTINGS['enable_tasks_log']) === true ? (int) $SETTINGS['enable_tasks_log'] : 0), $logID);
107
108
109
110
111
function handleTask(int $processId, array $ProcessArguments, array $SETTINGS)
112
{
113
    provideLog('[PROCESS][#'. $processId.'][START]', $SETTINGS);
114
    //DB::debugmode(false);
115
    $task_to_perform = DB::queryfirstrow(
116
        'SELECT *
117
        FROM ' . prefixTable('processes_tasks') . '
118
        WHERE process_id = %i AND finished_at IS NULL
119
        ORDER BY increment_id ASC',
120
        $processId
121
    );
122
/*
123
    print_r($ProcessArguments);
124
    echo " ;; ".cryption($ProcessArguments['new_user_pwd'], '','decrypt', $SETTINGS)['string']." ;; ".cryption($ProcessArguments['new_user_code'], '','decrypt', $SETTINGS)['string']." ;; ";
125
    return false;
126
*/
127
    
128
    if (DB::count() > 0) {
129
        // check if a linux process is not currently on going
130
        // if sub_task_in_progress === 1 then exit
131
        if ((int) $task_to_perform['sub_task_in_progress'] === 0) {
132
            provideLog('[TASK][#'. $task_to_perform['increment_id'].'][START]', $SETTINGS);
133
134
            // handle next task
135
            $args = json_decode($task_to_perform['task'], true);
136
            //print_r($args);
137
138
            // flag as in progress
139
            DB::update(
140
                prefixTable('processes'),
141
                array(
142
                    'updated_at' => time(),
143
                    'is_in_progress' => 1,
144
                ),
145
                'increment_id = %i',
146
                $processId
147
            );
148
149
            // flag task as on going
150
            if ((int) $args['index'] === 0) {
151
                DB::update(
152
                    prefixTable('processes_tasks'),
153
                    array(
154
                        'is_in_progress' => 1,
155
                    ),
156
                    'increment_id = %i',
157
                    $task_to_perform['increment_id']
158
                );
159
            }
160
161
            // flag sub task in progress as on going
162
            DB::update(
163
                prefixTable('processes_tasks'),
164
                array(
165
                    'sub_task_in_progress' => 1,
166
                ),
167
                'increment_id = %i',
168
                $task_to_perform['increment_id']
169
            );
170
171
            $taskStatus = performUserCreationKeys(
172
                (int) $ProcessArguments['new_user_id'],
173
                (bool) false,
174
                (string) $args['step'],
175
                (int) $args['index'],
176
                (int) isset($SETTINGS['maximum_number_of_items_to_treat']) === true ? $SETTINGS['maximum_number_of_items_to_treat'] : $args['nb'],
0 ignored issues
show
introduced by
The condition (int)IssetNode === true is always false.
Loading history...
177
                $SETTINGS,
178
                $ProcessArguments
179
            );
180
181
            // update the task status
182
            DB::update(
183
                prefixTable('processes_tasks'),
184
                array(
185
                    'sub_task_in_progress' => 0,    // flag sub task is no more in prgoress
186
                    'task' => $taskStatus['new_action'] !== $args['step'] ? 
187
                    json_encode(["status" => "Done"]) :
188
                    json_encode([
189
                        "step" => $taskStatus['new_action'],
190
                        "index" => $taskStatus['new_index'],
191
                        "nb" => isset($SETTINGS['maximum_number_of_items_to_treat']) === true ? $SETTINGS['maximum_number_of_items_to_treat'] : $args['nb'],
192
                    ]),
193
                    'is_in_progress' => $taskStatus['new_action'] !== $args['step'] ? -1 : 1,
194
                    'finished_at' => $taskStatus['new_action'] !== $args['step'] ? time() : NULL,
195
                    'updated_at' => time(),
196
                ),
197
                'increment_id = %i',
198
                $task_to_perform['increment_id']
199
            );
200
201
            provideLog('[TASK]['.$args['step'].'] starting at '.$args['index'].' is done.', $SETTINGS);
202
203
            if ($args['step'] === 'step6') {
204
                // all done
205
                provideLog('[PROCESS]['.$processId.'][FINISHED]', $SETTINGS);
206
                DB::debugmode(false);
207
                DB::update(
208
                    prefixTable('processes'),
209
                    array(
210
                        'finished_at' => time(),
211
                        'is_in_progress' => -1,
212
                        'arguments' => json_encode([
213
                            'new_user_id' => $ProcessArguments['new_user_id'],
214
                        ])
215
                    ),
216
                    'increment_id = %i',
217
                    $processId
218
                );
219
            }
220
            return false;
221
222
        } else {
223
            // Task is currently being in progress by another server process
224
            provideLog('[TASK][#'. $task_to_perform['increment_id'].'][WARNING] Similar task already being processes', $SETTINGS);
225
            return false;
226
        }
227
    }
228
}
229
230
/**
231
 * Permits to encrypt user's keys
232
 *
233
 * @param integer $post_user_id
234
 * @param boolean $post_self_change
235
 * @param string $post_action
236
 * @param integer $post_start
237
 * @param integer $post_length
238
 * @param array $SETTINGS
239
 * @param array $extra_arguments
240
 * @return array
241
 */
242
function performUserCreationKeys(
243
    int     $post_user_id,
244
    bool    $post_self_change,
245
    string  $post_action,
246
    int     $post_start,
247
    int     $post_length,
248
    array   $SETTINGS,
249
    array   $extra_arguments
250
): array
251
{
252
    if (isUserIdValid($post_user_id) === true) {
253
        // Check if user exists
254
        $userInfo = DB::queryFirstRow(
255
            'SELECT public_key, private_key
256
            FROM ' . prefixTable('users') . '
257
            WHERE id = %i',
258
            $post_user_id
259
        );
260
        
261
        if (isset($userInfo['public_key']) === true) {
262
            $return = [];
263
264
            // WHAT STEP TO PERFORM?
265
            if ($post_action === 'step0') {
266
                //echo '<br>Start STEP0<br>';
267
                // CLear old sharekeys
268
                if ($post_self_change === false) {
269
                    deleteUserObjetsKeys($post_user_id, $SETTINGS);
270
                }
271
272
                $return['new_action'] = 'step1';
273
                $return['new_index'] = 0;
274
                provideLog('[STEP][0][FINISHED]', $SETTINGS);
275
            }
276
            
277
            // STEP 1 - ITEMS
278
            elseif ($post_action === 'step1') {
279
                provideLog('[STEP][1][START][INDEX]['.$post_start.']', $SETTINGS);
280
                $return = cronContinueReEncryptingUserSharekeysStep1(
281
                    $post_user_id,
282
                    $post_self_change,
283
                    $post_start,
284
                    $post_length,
285
                    $userInfo['public_key'],
286
                    $SETTINGS,
287
                    $extra_arguments
288
                );
289
                provideLog('[STEP][1][FINISHED]', $SETTINGS);
290
            }
291
292
            // STEP 2 - LOGS
293
            elseif ($post_action === 'step2') {
294
                provideLog('[STEP][2][START][INDEX]['.$post_start.']', $SETTINGS);
295
                $return = cronContinueReEncryptingUserSharekeysStep2(
296
                    $post_user_id,
297
                    $post_self_change,
298
                    $post_start,
299
                    $post_length,
300
                    $userInfo['public_key'],
301
                    $SETTINGS,
302
                    $extra_arguments
303
                );
304
                provideLog('[STEP][2][FINISHED]', $SETTINGS);
305
            }
306
307
            // STEP 3 - FIELDS
308
            elseif ($post_action === 'step3') {
309
                provideLog('[STEP][3][START][INDEX]['.$post_start.']', $SETTINGS);
310
                $return = cronContinueReEncryptingUserSharekeysStep3(
311
                    $post_user_id,
312
                    $post_self_change,
313
                    $post_start,
314
                    $post_length,
315
                    $userInfo['public_key'],
316
                    $SETTINGS,
317
                    $extra_arguments
318
                );
319
                provideLog('[STEP][3][FINISHED]', $SETTINGS);
320
            }
321
            
322
            // STEP 4 - SUGGESTIONS
323
            elseif ($post_action === 'step4') {
324
                provideLog('[STEP][4][START][INDEX]['.$post_start.']', $SETTINGS);
325
                $return = cronContinueReEncryptingUserSharekeysStep4(
326
                    $post_user_id,
327
                    $post_self_change,
328
                    $post_start,
329
                    $post_length,
330
                    $userInfo['public_key'],
331
                    $SETTINGS,
332
                    $extra_arguments
333
                );
334
                provideLog('[STEP][4][FINISHED]', $SETTINGS);
335
            }
336
            
337
            // STEP 5 - FILES
338
            elseif ($post_action === 'step5') {
339
                provideLog('[STEP][5][START][INDEX]['.$post_start.']', $SETTINGS);
340
                $return = cronContinueReEncryptingUserSharekeysStep5(
341
                    $post_user_id,
342
                    $post_self_change,
343
                    $post_start,
344
                    $post_length,
345
                    $userInfo['public_key'],
346
                    $SETTINGS,
347
                    $extra_arguments
348
                );
349
                provideLog('[STEP][5][FINISHED]', $SETTINGS);
350
            }
351
            
352
            // STEP 6 - PERSONAL ITEMS
353
            elseif ($post_action === 'step6') {
354
                provideLog('[STEP][16][START][INDEX]['.$post_start.']', $SETTINGS);
355
                $return = cronContinueReEncryptingUserSharekeysStep6(
356
                    $post_user_id,
357
                    $SETTINGS,
358
                    $extra_arguments
359
                );
360
                provideLog('[STEP][6][FINISHED]', $SETTINGS);
361
            }
362
            
363
            // Continu with next step
364
            return $return;
365
        }
366
        
367
        // Nothing to do
368
        provideLog('[USER][ERROR] No user public key', $SETTINGS);
369
        return [
370
            'error' => true,
371
            'new_action' => 'finished',
372
        ];
373
    }
374
    provideLog('[USER][ERROR] No user found', $SETTINGS);
375
    return [
376
        'error' => true,
377
        'new_action' => 'finished',
378
    ];
379
}
380
381
function getOwnerInfo(int $owner_id, string $owner_pwd, array $SETTINGS): array
382
{
383
    $userInfo = DB::queryFirstRow(
384
        'SELECT pw, public_key, private_key, login, name
385
        FROM ' . prefixTable('users') . '
386
        WHERE id = %i',
387
        $owner_id
388
    );
389
    
390
    // decrypt owner password
391
    $pwd = cryption($owner_pwd, '','decrypt', $SETTINGS)['string'];
392
    provideLog('[USER][INFO] ID:'.$owner_id, $SETTINGS);
393
    //provideLog('[DEBUG] '.$pwd." -- ", $SETTINGS);
394
    // decrypt private key and send back
395
    return [
396
        'private_key' => decryptPrivateKey($pwd, $userInfo['private_key']),
397
        'login' => $userInfo['login'],
398
        'name' => $userInfo['name'],
399
    ];
400
}
401
402
403
/**
404
 * Handle step 1
405
 *
406
 * @param integer $post_user_id
407
 * @param boolean $post_self_change
408
 * @param integer $post_start
409
 * @param integer $post_length
410
 * @param string $user_public_key
411
 * @param array $SETTINGS
412
 * @param array $extra_arguments
413
 * @return array
414
 */
415
function cronContinueReEncryptingUserSharekeysStep1(
416
    int $post_user_id,
417
    bool $post_self_change,
418
    int $post_start,
419
    int $post_length,
420
    string $user_public_key,
421
    array $SETTINGS,
422
    array $extra_arguments
423
): array 
424
{
425
    // get user private key
426
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
427
    
428
    // Loop on items
429
    $rows = DB::query(
430
        'SELECT id, pw
431
        FROM ' . prefixTable('items') . '
432
        WHERE perso = 0
433
        ORDER BY id ASC
434
        LIMIT ' . $post_start . ', ' . $post_length
435
    );
436
    foreach ($rows as $record) {
437
        // Get itemKey from current user
438
        $currentUserKey = DB::queryFirstRow(
439
            'SELECT share_key, increment_id
440
            FROM ' . prefixTable('sharekeys_items') . '
441
            WHERE object_id = %i AND user_id = %i',
442
            $record['id'],
443
            $extra_arguments['owner_id']
444
        );
445
446
        // do we have any input? (#3481)
447
        if ($currentUserKey === null || count($currentUserKey) === 0) {
448
            continue;
449
        }
450
451
        // Decrypt itemkey with admin key
452
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
453
        
454
        // Encrypt Item key
455
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
456
        
457
        // Save the key in DB
458
        if ($post_self_change === false) {
459
            DB::insert(
460
                prefixTable('sharekeys_items'),
461
                array(
462
                    'object_id' => (int) $record['id'],
463
                    'user_id' => (int) $post_user_id,
464
                    'share_key' => $share_key_for_item,
465
                )
466
            );
467
        } else {
468
            // Get itemIncrement from selected user
469
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
470
                $currentUserKey = DB::queryFirstRow(
471
                    'SELECT increment_id
472
                    FROM ' . prefixTable('sharekeys_items') . '
473
                    WHERE object_id = %i AND user_id = %i',
474
                    $record['id'],
475
                    $post_user_id
476
                );
477
478
                if (DB::count() > 0) {
479
                    // NOw update
480
                    DB::update(
481
                        prefixTable('sharekeys_items'),
482
                        array(
483
                            'share_key' => $share_key_for_item,
484
                        ),
485
                        'increment_id = %i',
486
                        $currentUserKey['increment_id']
487
                    );
488
                } else {
489
                    DB::insert(
490
                        prefixTable('sharekeys_items'),
491
                        array(
492
                            'object_id' => (int) $record['id'],
493
                            'user_id' => (int) $post_user_id,
494
                            'share_key' => $share_key_for_item,
495
                        )
496
                    );
497
                }
498
            }
499
        }
500
    }
501
502
    // SHould we change step?
503
    DB::query(
504
        'SELECT *
505
        FROM ' . prefixTable('items') . '
506
        WHERE perso = 0'
507
    );
508
509
    $next_start = (int) $post_start + (int) $post_length;
510
    return [
511
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
512
        'new_action' => $next_start > DB::count() ? 'step2' : 'step1',
513
    ];
514
}
515
516
517
/**
518
 * Handle step 2
519
 *
520
 * @param integer $post_user_id
521
 * @param boolean $post_self_change
522
 * @param integer $post_start
523
 * @param integer $post_length
524
 * @param string $user_public_key
525
 * @param array $SETTINGS
526
 * @param array $extra_arguments
527
 * @return array
528
 */
529
function cronContinueReEncryptingUserSharekeysStep2(
530
    int $post_user_id,
531
    bool $post_self_change,
532
    int $post_start,
533
    int $post_length,
534
    string $user_public_key,
535
    array $SETTINGS,
536
    array $extra_arguments
537
): array
538
{
539
    // get user private key
540
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
541
542
    // Loop on logs
543
    $rows = DB::query(
544
        'SELECT increment_id
545
        FROM ' . prefixTable('log_items') . '
546
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"
547
        LIMIT ' . $post_start . ', ' . $post_length
548
    );
549
    foreach ($rows as $record) {
550
        // Get itemKey from current user
551
        $currentUserKey = DB::queryFirstRow(
552
            'SELECT share_key
553
            FROM ' . prefixTable('sharekeys_logs') . '
554
            WHERE object_id = %i AND user_id = %i',
555
            $record['increment_id'],
556
            $extra_arguments['owner_id']
557
        );
558
559
        // do we have any input? (#3481)
560
        if ($currentUserKey === null || count($currentUserKey) === 0) {
561
            continue;
562
        }
563
564
        // Decrypt itemkey with admin key
565
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
566
567
        // Encrypt Item key
568
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
569
570
        // Save the key in DB
571
        if ($post_self_change === false) {
572
            DB::insert(
573
                prefixTable('sharekeys_logs'),
574
                array(
575
                    'object_id' => (int) $record['increment_id'],
576
                    'user_id' => (int) $post_user_id,
577
                    'share_key' => $share_key_for_item,
578
                )
579
            );
580
        } else {
581
            // Get itemIncrement from selected user
582
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
583
                $currentUserKey = DB::queryFirstRow(
584
                    'SELECT increment_id
585
                    FROM ' . prefixTable('sharekeys_items') . '
586
                    WHERE object_id = %i AND user_id = %i',
587
                    $record['id'],
588
                    $post_user_id
589
                );
590
            }
591
592
            // NOw update
593
            DB::update(
594
                prefixTable('sharekeys_logs'),
595
                array(
596
                    'share_key' => $share_key_for_item,
597
                ),
598
                'increment_id = %i',
599
                $currentUserKey['increment_id']
600
            );
601
        }
602
    }
603
604
    // SHould we change step?
605
    DB::query(
606
        'SELECT increment_id
607
        FROM ' . prefixTable('log_items') . '
608
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"'
609
    );
610
611
    $next_start = (int) $post_start + (int) $post_length;
612
    return [
613
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
614
        'new_action' => $next_start > DB::count() ? 'step3' : 'step2',
615
    ];
616
}
617
618
619
/**
620
 * Handle step 3 of re-encrypting user sharekeys
621
 *
622
 * @param integer $post_user_id
623
 * @param boolean $post_self_change
624
 * @param integer $post_start
625
 * @param integer $post_length
626
 * @param string $user_public_key
627
 * @param array $SETTINGS
628
 * @param array $extra_arguments
629
 * @return array
630
 */
631
function cronContinueReEncryptingUserSharekeysStep3(
632
    int $post_user_id,
633
    bool $post_self_change,
634
    int $post_start,
635
    int $post_length,
636
    string $user_public_key,
637
    array $SETTINGS,
638
    array $extra_arguments
639
): array
640
{
641
    // get user private key
642
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
643
644
    // Loop on fields
645
    $rows = DB::query(
646
        'SELECT id
647
        FROM ' . prefixTable('categories_items') . '
648
        WHERE encryption_type = "teampass_aes"
649
        LIMIT ' . $post_start . ', ' . $post_length
650
    );
651
    foreach ($rows as $record) {
652
        // Get itemKey from current user
653
        $currentUserKey = DB::queryFirstRow(
654
            'SELECT share_key
655
            FROM ' . prefixTable('sharekeys_fields') . '
656
            WHERE object_id = %i AND user_id = %i',
657
            $record['id'],
658
            $extra_arguments['owner_id']
659
        );
660
661
        if (isset($currentUserKey['share_key']) === true) {
662
            // Decrypt itemkey with admin key
663
            $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
664
665
            // Encrypt Item key
666
            $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
667
668
            // Save the key in DB
669
            if ($post_self_change === false) {
670
                DB::insert(
671
                    prefixTable('sharekeys_fields'),
672
                    array(
673
                        'object_id' => (int) $record['id'],
674
                        'user_id' => (int) $post_user_id,
675
                        'share_key' => $share_key_for_item,
676
                    )
677
                );
678
            } else {
679
                // Get itemIncrement from selected user
680
                if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
681
                    $currentUserKey = DB::queryFirstRow(
682
                        'SELECT increment_id
683
                        FROM ' . prefixTable('sharekeys_items') . '
684
                        WHERE object_id = %i AND user_id = %i',
685
                        $record['id'],
686
                        $post_user_id
687
                    );
688
                }
689
690
                // NOw update
691
                DB::update(
692
                    prefixTable('sharekeys_fields'),
693
                    array(
694
                        'share_key' => $share_key_for_item,
695
                    ),
696
                    'increment_id = %i',
697
                    $currentUserKey['increment_id']
698
                );
699
            }
700
        }
701
    }
702
703
    // SHould we change step?
704
    DB::query(
705
        'SELECT *
706
        FROM ' . prefixTable('categories_items') . '
707
        WHERE encryption_type = "teampass_aes"'
708
    );
709
710
    $next_start = (int) $post_start + (int) $post_length;
711
    return [
712
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
713
        'new_action' => $next_start > DB::count() ? 'step4' : 'step3',
714
    ];
715
}
716
717
718
/**
719
 * Handle step 4
720
 *
721
 * @param integer $post_user_id
722
 * @param boolean $post_self_change
723
 * @param integer $post_start
724
 * @param integer $post_length
725
 * @param string $user_public_key
726
 * @param array $SETTINGS
727
 * @param array $extra_arguments
728
 * @return array
729
 */
730
function cronContinueReEncryptingUserSharekeysStep4(
731
    int $post_user_id,
732
    bool $post_self_change,
733
    int $post_start,
734
    int $post_length,
735
    string $user_public_key,
736
    array $SETTINGS,
737
    array $extra_arguments
738
): array
739
{
740
    // get user private key
741
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
742
743
    // Loop on suggestions
744
    $rows = DB::query(
745
        'SELECT id
746
        FROM ' . prefixTable('suggestion') . '
747
        LIMIT ' . $post_start . ', ' . $post_length
748
    );
749
    foreach ($rows as $record) {
750
        // Get itemKey from current user
751
        $currentUserKey = DB::queryFirstRow(
752
            'SELECT share_key
753
            FROM ' . prefixTable('sharekeys_suggestions') . '
754
            WHERE object_id = %i AND user_id = %i',
755
            $record['id'],
756
            $extra_arguments['owner_id']
757
        );
758
759
        // do we have any input? (#3481)
760
        if ($currentUserKey === null || count($currentUserKey) === 0) {
761
            continue;
762
        }
763
764
        // Decrypt itemkey with admin key
765
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
766
767
        // Encrypt Item key
768
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
769
770
        // Save the key in DB
771
        if ($post_self_change === false) {
772
            DB::insert(
773
                prefixTable('sharekeys_suggestions'),
774
                array(
775
                    'object_id' => (int) $record['id'],
776
                    'user_id' => (int) $post_user_id,
777
                    'share_key' => $share_key_for_item,
778
                )
779
            );
780
        } else {
781
            // Get itemIncrement from selected user
782
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
783
                $currentUserKey = DB::queryFirstRow(
784
                    'SELECT increment_id
785
                    FROM ' . prefixTable('sharekeys_items') . '
786
                    WHERE object_id = %i AND user_id = %i',
787
                    $record['id'],
788
                    $post_user_id
789
                );
790
            }
791
792
            // NOw update
793
            DB::update(
794
                prefixTable('sharekeys_suggestions'),
795
                array(
796
                    'share_key' => $share_key_for_item,
797
                ),
798
                'increment_id = %i',
799
                $currentUserKey['increment_id']
800
            );
801
        }
802
    }
803
804
    // SHould we change step?
805
    DB::query(
806
        'SELECT *
807
        FROM ' . prefixTable('suggestion')
808
    );
809
810
    $next_start = (int) $post_start + (int) $post_length;
811
    return [
812
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
813
        'new_action' => $next_start > DB::count() ? 'step5' : 'step4',
814
    ];
815
}
816
817
818
/**
819
 * Handle step 5
820
 *
821
 * @param integer $post_user_id
822
 * @param boolean $post_self_change
823
 * @param integer $post_start
824
 * @param integer $post_length
825
 * @param string $user_public_key
826
 * @param array $SETTINGS
827
 * @param array $extra_arguments
828
 * @return array
829
 */
830
function cronContinueReEncryptingUserSharekeysStep5(
831
    int $post_user_id,
832
    bool $post_self_change,
833
    int $post_start,
834
    int $post_length,
835
    string $user_public_key,
836
    array $SETTINGS,
837
    array $extra_arguments
838
): array
839
{
840
    // get user private key
841
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
842
843
    // Loop on files
844
    $rows = DB::query(
845
        'SELECT id
846
        FROM ' . prefixTable('files') . '
847
        WHERE status = "' . TP_ENCRYPTION_NAME . '"
848
        LIMIT ' . $post_start . ', ' . $post_length
849
    ); //aes_encryption
850
    foreach ($rows as $record) {
851
        // Get itemKey from current user
852
        $currentUserKey = DB::queryFirstRow(
853
            'SELECT share_key
854
            FROM ' . prefixTable('sharekeys_files') . '
855
            WHERE object_id = %i AND user_id = %i',
856
            $record['id'],
857
            $extra_arguments['owner_id']
858
        );
859
860
        // do we have any input? (#3481)
861
        if ($currentUserKey === null || count($currentUserKey) === 0) {
862
            continue;
863
        }
864
865
        // Decrypt itemkey with admin key
866
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
867
868
        // Encrypt Item key
869
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
870
871
        // Save the key in DB
872
        if ($post_self_change === false) {
873
            DB::insert(
874
                prefixTable('sharekeys_files'),
875
                array(
876
                    'object_id' => (int) $record['id'],
877
                    'user_id' => (int) $post_user_id,
878
                    'share_key' => $share_key_for_item,
879
                )
880
            );
881
        } else {
882
            // Get itemIncrement from selected user
883
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
884
                $currentUserKey = DB::queryFirstRow(
885
                    'SELECT increment_id
886
                    FROM ' . prefixTable('sharekeys_items') . '
887
                    WHERE object_id = %i AND user_id = %i',
888
                    $record['id'],
889
                    $post_user_id
890
                );
891
            }
892
893
            // NOw update
894
            DB::update(
895
                prefixTable('sharekeys_files'),
896
                array(
897
                    'share_key' => $share_key_for_item,
898
                ),
899
                'increment_id = %i',
900
                $currentUserKey['increment_id']
901
            );
902
        }
903
    }
904
905
    // SHould we change step?
906
    DB::query(
907
        'SELECT *
908
        FROM ' . prefixTable('files') . '
909
        WHERE status = "' . TP_ENCRYPTION_NAME . '"'
910
    );
911
912
    $next_start = (int) $post_start + (int) $post_length;
913
    return [
914
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
915
        'new_action' => $next_start > DB::count() ? 'step6' : 'step5',
916
    ];
917
}
918
919
920
/**
921
 * Handle step 6
922
 *
923
 * @param integer $post_user_id
924
 * @param integer $post_start
925
 * @param integer $post_length
926
 * @param string $user_public_key
927
 * @param array $SETTINGS
928
 * @param array $extra_arguments
929
 * @return array
930
 */
931
function cronContinueReEncryptingUserSharekeysStep6(
932
    int $post_user_id,
933
    array $SETTINGS,
934
    array $extra_arguments
935
): array
936
{
937
    // IF USER IS NOT THE SAME
938
    if ((int) $post_user_id === (int) $extra_arguments['owner_id']) {
939
        return [
940
            'new_index' => 0,
941
            'new_action' => 'finished',
942
        ];
943
    }
944
945
    // if done then send email to new user
946
    // get user info
947
    $userInfo = DB::queryFirstRow(
948
        'SELECT email, login, auth_type, special, lastname, name
949
        FROM ' . prefixTable('users') . '
950
        WHERE id = %i',
951
        $extra_arguments['new_user_id']
952
    );
953
954
    // SEND EMAIL TO USER depending on context
955
    // Config 1: new user is a local user
956
    // Config 2: new user is an LDAP user
957
    // Config 3: send new password
958
    // COnfig 4: send new encryption code
959
    if (isset($extra_arguments['send_email']) === true && (int) $extra_arguments['send_email'] === 1) {
960
        sendMailToUser(
961
            filter_var($userInfo['email'], FILTER_SANITIZE_FULL_SPECIAL_CHARS),
962
            empty($extra_arguments['email_body']) === false ? $extra_arguments['email_body'] : langHdl('email_body_user_config_1'),
963
            'TEAMPASS - ' . langHdl('login_credentials'),
964
            (array) filter_var_array(
965
                [
966
                    '#code#' => cryption($extra_arguments['new_user_code'], '','decrypt', $SETTINGS)['string'],
967
                    '#lastname#' => isset($userInfo['name']) === true ? $userInfo['name'] : '',
968
                    '#login#' => isset($userInfo['login']) === true ? $userInfo['login'] : '',
969
                    '#password#' => cryption($extra_arguments['new_user_pwd'], '','decrypt', $SETTINGS)['string'],
970
                ],
971
                FILTER_SANITIZE_FULL_SPECIAL_CHARS
972
            ),
973
            $SETTINGS
974
        );
975
    }
976
        
977
    // Set user as ready for usage
978
    DB::update(
979
        prefixTable('users'),
980
        array(
981
            'is_ready_for_usage' => 1,
982
            'otp_provided' => isset($extra_arguments['otp_provided_new_value']) === true && (int) $extra_arguments['otp_provided_new_value'] === 1 ? $extra_arguments['otp_provided_new_value'] : 0,
983
            'ongoing_process_id' => NULL,
984
            'special' => 'none',
985
        ),
986
        'id = %i',
987
        $extra_arguments['new_user_id']
988
    );
989
990
    return [
991
        'new_index' => 0,
992
        'new_action' => 'finished',
993
    ];
994
}
995
996
997
/**
998
 * SEnd email to user
999
 *
1000
 * @param string $post_receipt
1001
 * @param string $post_body
1002
 * @param string $post_subject
1003
 * @param array $post_replace
1004
 * @param array $SETTINGS
1005
 * @return void
1006
 */
1007
function sendMailToUser(
1008
    string $post_receipt,
1009
    string $post_body,
1010
    string $post_subject,
1011
    array $post_replace,
1012
    array $SETTINGS
1013
): void
1014
{
1015
    if (count($post_replace) > 0 && is_null($post_replace) === false) {
1016
        $post_body = str_replace(
1017
            array_keys($post_replace),
1018
            array_values($post_replace),
1019
            $post_body
1020
        );
1021
    }
1022
1023
    prepareSendingEmail(
1024
        $post_subject,
1025
        $post_body,
1026
        $post_receipt,
1027
        "",
1028
        $SETTINGS
1029
    );
1030
}
1031
1032
function provideLog(string $message, array $SETTINGS)
1033
{
1034
    echo '\n' . (string) date($SETTINGS['date_format'] . ' ' . $SETTINGS['time_format'], time()) . ' - '.$message . '\n';
1035
}