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

cronContinueReEncryptingUserSharekeysStep60()   C

Complexity

Conditions 11
Paths 40

Size

Total Lines 138
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 58
c 0
b 0
f 0
nc 40
nop 7
dl 0
loc 138
rs 6.7696

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/**
3
 * 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
use Symfony\Component\Process\Process;
26
27
require_once __DIR__.'/../sources/SecureHandler.php';
28
session_name('teampass_session');
29
session_start();
30
31
// Load config
32
require_once __DIR__.'/../includes/config/tp.config.php';
33
require_once __DIR__.'/background_tasks___functions.php';
34
35
// increase the maximum amount of time a script is allowed to run
36
set_time_limit($SETTINGS['task_maximum_run_time']);
37
38
// Do checks
39
require_once $SETTINGS['cpassman_dir'].'/includes/config/include.php';
40
require_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
41
header('Content-type: text/html; charset=utf-8');
42
header('Cache-Control: no-cache, must-revalidate');
43
require_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
44
// Connect to mysql server
45
require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
46
if (defined('DB_PASSWD_CLEAR') === false) {
47
    define('DB_PASSWD_CLEAR', defuseReturnDecrypted(DB_PASSWD, $SETTINGS));
48
}
49
DB::$host = DB_HOST;
50
DB::$user = DB_USER;
51
DB::$password = DB_PASSWD_CLEAR;
52
DB::$dbName = DB_NAME;
53
DB::$port = DB_PORT;
54
DB::$encoding = DB_ENCODING;
55
DB::$ssl = DB_SSL;
56
DB::$connect_options = DB_CONNECT_OPTIONS;
57
58
59
60
// Get PHP binary
61
$phpBinaryPath = getPHPBinary();
62
63
// log start
64
$logID = doLog('start', 'user_keys', (isset($SETTINGS['enable_tasks_log']) === true ? (int) $SETTINGS['enable_tasks_log'] : 0));
65
66
67
// Manage the tasks in queue.
68
// Task to treat selection is:
69
// 1- take first is_in_progress === 1
70
// 2- take first is_in_progress === 0 and finished_at === null
71
DB::debugmode(false);
72
$process_to_perform = DB::queryfirstrow(
73
    'SELECT *
74
    FROM ' . prefixTable('processes') . '
75
    WHERE is_in_progress = %i AND process_type = %s
76
    ORDER BY increment_id ASC',
77
    1,
78
    'create_user_keys'
79
);
80
81
if (DB::count() > 0) {
82
    // handle tasks inside this process
83
    //echo "Handle task<br>";
84
    handleTask(
85
        $process_to_perform['increment_id'],
86
        json_decode($process_to_perform['arguments'], true),
87
        $SETTINGS,
88
    );
89
90
} else {
91
    // search for next process to handle
92
    $process_to_perform = DB::queryfirstrow(
93
        'SELECT *
94
        FROM ' . prefixTable('processes') . '
95
        WHERE is_in_progress = %i AND finished_at = "" AND process_type = %s
96
        ORDER BY increment_id ASC',
97
        0,
98
        'create_user_keys'
99
    );
100
    //print_r($process_to_perform);
101
    if (DB::count() > 0) {
102
        // update DB - started_at
103
        DB::update(
104
            prefixTable('processes'),
105
            array(
106
                'started_at' => time(),
107
            ),
108
            'increment_id = %i',
109
            $process_to_perform['increment_id']
110
        );
111
112
        provideLog('[PROCESS][#'. $process_to_perform['increment_id'].'][START]', $SETTINGS);
113
        handleTask(
114
            $process_to_perform['increment_id'],
115
            json_decode($process_to_perform['arguments'], true),
116
            $SETTINGS,
117
        );
118
    }
119
}
120
121
// log end
122
doLog('end', '', (isset($SETTINGS['enable_tasks_log']) === true ? (int) $SETTINGS['enable_tasks_log'] : 0), $logID);
123
124
// launch a new iterative process
125
$process_to_perform = DB::queryfirstrow(
126
    'SELECT *
127
    FROM ' . prefixTable('processes') . '
128
    WHERE is_in_progress = %i AND process_type = %s
129
    ORDER BY increment_id ASC',
130
    1,
131
    'create_user_keys'
132
);
133
if (DB::count() > 0) {
134
    $process = new Symfony\Component\Process\Process([$phpBinaryPath, __FILE__]);
135
    $process->start();
136
    $process->wait();
137
}
138
139
140
141
/**
142
 * Undocumented function
143
 *
144
 * @param integer $processId
145
 * @param array $ProcessArguments
146
 * @param array $SETTINGS
147
 * @return bool
148
 */
149
function handleTask(int $processId, array $ProcessArguments, array $SETTINGS): bool
150
{
151
    provideLog('[PROCESS][#'. $processId.'][START]', $SETTINGS);
152
    //DB::debugmode(false);
153
    $task_to_perform = DB::queryfirstrow(
154
        'SELECT *
155
        FROM ' . prefixTable('processes_tasks') . '
156
        WHERE process_id = %i AND finished_at IS NULL
157
        ORDER BY increment_id ASC',
158
        $processId
159
    );
160
/*
161
    print_r($ProcessArguments);
162
    echo " ;; ".cryption($ProcessArguments['new_user_pwd'], '','decrypt', $SETTINGS)['string']." ;; ".cryption($ProcessArguments['new_user_code'], '','decrypt', $SETTINGS)['string']." ;; ";
163
    return false;
164
*/
165
    
166
    if (DB::count() > 0) {
167
        // check if a linux process is not currently on going
168
        // if sub_task_in_progress === 1 then exit
169
        if ((int) $task_to_perform['sub_task_in_progress'] === 0) {
170
            provideLog('[TASK][#'. $task_to_perform['increment_id'].'][START]', $SETTINGS);
171
172
            // handle next task
173
            $args = json_decode($task_to_perform['task'], true);
174
            //print_r($args);return false;
175
176
            // flag as in progress
177
            DB::update(
178
                prefixTable('processes'),
179
                array(
180
                    'updated_at' => time(),
181
                    'is_in_progress' => 1,
182
                ),
183
                'increment_id = %i',
184
                $processId
185
            );
186
187
            // flag task as on going
188
            if ((int) $args['index'] === 0) {
189
                DB::update(
190
                    prefixTable('processes_tasks'),
191
                    array(
192
                        'is_in_progress' => 1,
193
                    ),
194
                    'increment_id = %i',
195
                    $task_to_perform['increment_id']
196
                );
197
            }
198
199
            // flag sub task in progress as on going
200
            DB::update(
201
                prefixTable('processes_tasks'),
202
                array(
203
                    'sub_task_in_progress' => 1,
204
                ),
205
                'increment_id = %i',
206
                $task_to_perform['increment_id']
207
            );
208
209
            $taskStatus = performUserCreationKeys(
210
                (int) $ProcessArguments['new_user_id'],
211
                (bool) false,
212
                (string) $args['step'],
213
                (int) $args['index'],
214
                (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...
215
                $SETTINGS,
216
                $ProcessArguments
217
            );
218
219
            // update the task status
220
            DB::update(
221
                prefixTable('processes_tasks'),
222
                array(
223
                    'sub_task_in_progress' => 0,    // flag sub task is no more in prgoress
224
                    'task' => $taskStatus['new_action'] !== $args['step'] ? 
225
                    json_encode(["status" => "Done"]) :
226
                    json_encode([
227
                        "step" => $taskStatus['new_action'],
228
                        "index" => $taskStatus['new_index'],
229
                        "nb" => isset($SETTINGS['maximum_number_of_items_to_treat']) === true ? $SETTINGS['maximum_number_of_items_to_treat'] : $args['nb'],
230
                    ]),
231
                    'is_in_progress' => $taskStatus['new_action'] !== $args['step'] ? -1 : 1,
232
                    'finished_at' => $taskStatus['new_action'] !== $args['step'] ? time() : NULL,
233
                    'updated_at' => time(),
234
                ),
235
                'increment_id = %i',
236
                $task_to_perform['increment_id']
237
            );
238
239
            provideLog('[TASK]['.$args['step'].'] starting at '.$args['index'].' is done.', $SETTINGS);
240
241
            if ($args['step'] === 'step60') {
242
                // all done
243
                provideLog('[PROCESS]['.$processId.'][FINISHED]', $SETTINGS);
244
                DB::debugmode(false);
245
                DB::update(
246
                    prefixTable('processes'),
247
                    array(
248
                        'finished_at' => time(),
249
                        'is_in_progress' => -1,
250
                        'arguments' => json_encode([
251
                            'new_user_id' => $ProcessArguments['new_user_id'],
252
                        ])
253
                    ),
254
                    'increment_id = %i',
255
                    $processId
256
                );
257
            }
258
            return false;
259
260
        } else {
261
            // Task is currently being in progress by another server process
262
            provideLog('[TASK][#'. $task_to_perform['increment_id'].'][WARNING] Similar task already being processes', $SETTINGS);
263
            return false;
264
        }
265
    }
266
    return true;
267
}
268
269
/**
270
 * Permits to encrypt user's keys
271
 *
272
 * @param integer $post_user_id
273
 * @param boolean $post_self_change
274
 * @param string $post_action
275
 * @param integer $post_start
276
 * @param integer $post_length
277
 * @param array $SETTINGS
278
 * @param array $extra_arguments
279
 * @return array
280
 */
281
function performUserCreationKeys(
282
    int     $post_user_id,
283
    bool    $post_self_change,
284
    string  $post_action,
285
    int     $post_start,
286
    int     $post_length,
287
    array   $SETTINGS,
288
    array   $extra_arguments
289
): array
290
{
291
    if (isUserIdValid($post_user_id) === true) {
292
        // Check if user exists
293
        $userInfo = DB::queryFirstRow(
294
            'SELECT public_key, private_key
295
            FROM ' . prefixTable('users') . '
296
            WHERE id = %i',
297
            $post_user_id
298
        );
299
        
300
        if (isset($userInfo['public_key']) === true) {
301
            $return = [];
302
303
            // WHAT STEP TO PERFORM?
304
            if ($post_action === 'step0') {
305
                //echo '<br>Start STEP0<br>';
306
                // CLear old sharekeys
307
                if ($post_self_change === false) {
308
                    deleteUserObjetsKeys($post_user_id, $SETTINGS);
309
                }
310
311
                $return['new_action'] = 'step10';
312
                $return['new_index'] = 0;
313
                provideLog('[STEP][0][FINISHED]', $SETTINGS);
314
            }
315
            
316
            // STEP 10 - EMAIL
317
            elseif ($post_action === 'step10') {
318
                provideLog('[STEP][10][START][INDEX]['.$post_start.']', $SETTINGS);
319
                $return = cronContinueReEncryptingUserSharekeysStep10(
320
                    $post_user_id,
321
                    $SETTINGS,
322
                    $extra_arguments
323
                );
324
                provideLog('[STEP][10][FINISHED]', $SETTINGS);
325
            }
326
            
327
            // STEP 20 - ITEMS
328
            elseif ($post_action === 'step20') {
329
                provideLog('[STEP][20][START][INDEX]['.$post_start.']', $SETTINGS);
330
                $logID = doLog('start', 'user_keys-ITEMS', (isset($SETTINGS['enable_tasks_log']) === true ? (int) $SETTINGS['enable_tasks_log'] : 0));
331
                $return = cronContinueReEncryptingUserSharekeysStep20(
332
                    $post_user_id,
333
                    $post_self_change,
334
                    $post_start,
335
                    $post_length,
336
                    $userInfo['public_key'],
337
                    $SETTINGS,
338
                    $extra_arguments
339
                );
340
                $logID = doLog('end', '', (isset($SETTINGS['enable_tasks_log']) === true ? (int) $SETTINGS['enable_tasks_log'] : 0), $logID, $return['treated_items']);
0 ignored issues
show
Unused Code introduced by
The assignment to $logID is dead and can be removed.
Loading history...
341
                provideLog('[STEP][20][FINISHED]', $SETTINGS);
342
            }
343
344
            // STEP 30 - LOGS
345
            elseif ($post_action === 'step30') {
346
                provideLog('[STEP][30][START][INDEX]['.$post_start.']', $SETTINGS);
347
                $return = cronContinueReEncryptingUserSharekeysStep30(
348
                    $post_user_id,
349
                    $post_self_change,
350
                    $post_start,
351
                    $post_length,
352
                    $userInfo['public_key'],
353
                    $SETTINGS,
354
                    $extra_arguments
355
                );
356
                provideLog('[STEP][30][FINISHED]', $SETTINGS);
357
            }
358
359
            // STEP 40 - FIELDS
360
            elseif ($post_action === 'step40') {
361
                provideLog('[STEP][40][START][INDEX]['.$post_start.']', $SETTINGS);
362
                $return = cronContinueReEncryptingUserSharekeysStep40(
363
                    $post_user_id,
364
                    $post_self_change,
365
                    $post_start,
366
                    $post_length,
367
                    $userInfo['public_key'],
368
                    $SETTINGS,
369
                    $extra_arguments
370
                );
371
                provideLog('[STEP][40][FINISHED]', $SETTINGS);
372
            }
373
            
374
            // STEP 50 - SUGGESTIONS
375
            elseif ($post_action === 'step50') {
376
                provideLog('[STEP][50][START][INDEX]['.$post_start.']', $SETTINGS);
377
                $return = cronContinueReEncryptingUserSharekeysStep50(
378
                    $post_user_id,
379
                    $post_self_change,
380
                    $post_start,
381
                    $post_length,
382
                    $userInfo['public_key'],
383
                    $SETTINGS,
384
                    $extra_arguments
385
                );
386
                provideLog('[STEP][50][FINISHED]', $SETTINGS);
387
            }
388
            
389
            // STEP 60 - FILES
390
            elseif ($post_action === 'step60') {
391
                provideLog('[STEP][60][START][INDEX]['.$post_start.']', $SETTINGS);
392
                $return = cronContinueReEncryptingUserSharekeysStep60(
393
                    $post_user_id,
394
                    $post_self_change,
395
                    $post_start,
396
                    $post_length,
397
                    $userInfo['public_key'],
398
                    $SETTINGS,
399
                    $extra_arguments
400
                );
401
                provideLog('[STEP][60][FINISHED]', $SETTINGS);
402
            }
403
            
404
            // Continu with next step
405
            return $return;
406
        }
407
        
408
        // Nothing to do
409
        provideLog('[USER][ERROR] No user public key', $SETTINGS);
410
        return [
411
            'error' => true,
412
            'new_action' => 'finished',
413
        ];
414
    }
415
    provideLog('[USER][ERROR] No user found', $SETTINGS);
416
    return [
417
        'error' => true,
418
        'new_action' => 'finished',
419
    ];
420
}
421
422
function getOwnerInfo(int $owner_id, string $owner_pwd, array $SETTINGS): array
423
{
424
    $userInfo = DB::queryFirstRow(
425
        'SELECT pw, public_key, private_key, login, name
426
        FROM ' . prefixTable('users') . '
427
        WHERE id = %i',
428
        $owner_id
429
    );
430
    
431
    // decrypt owner password
432
    $pwd = cryption($owner_pwd, '','decrypt', $SETTINGS)['string'];
433
    provideLog('[USER][INFO] ID:'.$owner_id, $SETTINGS);
434
    //provideLog('[DEBUG] '.$pwd." -- ", $SETTINGS);
435
    // decrypt private key and send back
436
    return [
437
        'private_key' => decryptPrivateKey($pwd, $userInfo['private_key']),
438
        'login' => $userInfo['login'],
439
        'name' => $userInfo['name'],
440
    ];
441
}
442
443
444
/**
445
 * Handle step 1
446
 *
447
 * @param integer $post_user_id
448
 * @param boolean $post_self_change
449
 * @param integer $post_start
450
 * @param integer $post_length
451
 * @param string $user_public_key
452
 * @param array $SETTINGS
453
 * @param array $extra_arguments
454
 * @return array
455
 */
456
function cronContinueReEncryptingUserSharekeysStep20(
457
    int $post_user_id,
458
    bool $post_self_change,
0 ignored issues
show
Unused Code introduced by
The parameter $post_self_change is not used and could be removed. ( Ignorable by Annotation )

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

458
    /** @scrutinizer ignore-unused */ bool $post_self_change,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
459
    int $post_start,
460
    int $post_length,
461
    string $user_public_key,
462
    array $SETTINGS,
463
    array $extra_arguments
464
): array 
465
{    
466
    // get user private key
467
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
468
    $userInfo = getOwnerInfo($extra_arguments['new_user_id'], $extra_arguments['new_user_pwd'], $SETTINGS);
469
    
470
    // Loop on items
471
    $rows = DB::query(
472
        'SELECT id, pw, perso
473
        FROM ' . prefixTable('items') . '
474
        '.(isset($extra_arguments['only_personal_items']) === true && $extra_arguments['only_personal_items'] === 1 ? 'WHERE perso = 1' : '').'
475
        ORDER BY id ASC
476
        LIMIT ' . $post_start . ', ' . $post_length
477
    );
478
    //    WHERE perso = 0
479
    foreach ($rows as $record) {
480
        // Get itemKey from current user
481
        $currentUserKey = DB::queryFirstRow(
482
            'SELECT share_key, increment_id
483
            FROM ' . prefixTable('sharekeys_items') . '
484
            WHERE object_id = %i AND user_id = %i',
485
            $record['id'],
486
            //$extra_arguments['owner_id']
487
            (int) $record['perso'] === 0 ? $extra_arguments['owner_id'] : $extra_arguments['new_user_id']
488
        );
489
490
        // do we have any input? (#3481)
491
        if ($currentUserKey === null || count($currentUserKey) === 0) {
492
            continue;
493
        }
494
495
        // Decrypt itemkey with admin key
496
        $itemKey = decryptUserObjectKey(
497
            $currentUserKey['share_key'],
498
            //$ownerInfo['private_key']
499
            (int) $record['perso'] === 0 ? $ownerInfo['private_key'] : $userInfo['private_key']
500
        );
501
        
502
        // Prevent to change key if its key is empty
503
        if (empty($itemKey) === true) {
504
            continue;
505
        }
506
507
        // Encrypt Item key
508
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
509
        
510
        $currentUserKey = DB::queryFirstRow(
511
            'SELECT increment_id
512
            FROM ' . prefixTable('sharekeys_items') . '
513
            WHERE object_id = %i AND user_id = %i',
514
            $record['id'],
515
            $post_user_id
516
        );
517
518
        if (DB::count() > 0) {
519
            // NOw update
520
            DB::update(
521
                prefixTable('sharekeys_items'),
522
                array(
523
                    'share_key' => $share_key_for_item,
524
                ),
525
                'increment_id = %i',
526
                $currentUserKey['increment_id']
527
            );
528
        } else {
529
            DB::insert(
530
                prefixTable('sharekeys_items'),
531
                array(
532
                    'object_id' => (int) $record['id'],
533
                    'user_id' => (int) $post_user_id,
534
                    'share_key' => $share_key_for_item,
535
                )
536
            );
537
        }
538
    }
539
540
    // SHould we change step?
541
    DB::query(
542
        'SELECT *
543
        FROM ' . prefixTable('items')
544
    );
545
546
    $next_start = (int) $post_start + (int) $post_length;
547
    return [
548
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
549
        'new_action' => $next_start > DB::count() ? 'step30' : 'step20',
550
        'treated_items' => $next_start > DB::count() ? (DB::count() - (int) $post_start) : $post_length,
551
    ];
552
}
553
554
555
/**
556
 * Handle step 2
557
 *
558
 * @param integer $post_user_id
559
 * @param boolean $post_self_change
560
 * @param integer $post_start
561
 * @param integer $post_length
562
 * @param string $user_public_key
563
 * @param array $SETTINGS
564
 * @param array $extra_arguments
565
 * @return array
566
 */
567
function cronContinueReEncryptingUserSharekeysStep30(
568
    int $post_user_id,
569
    bool $post_self_change,
570
    int $post_start,
571
    int $post_length,
572
    string $user_public_key,
573
    array $SETTINGS,
574
    array $extra_arguments
575
): array
576
{
577
    // get user private key
578
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
579
580
    // Loop on logs
581
    $rows = DB::query(
582
        'SELECT increment_id
583
        FROM ' . prefixTable('log_items') . '
584
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"
585
        LIMIT ' . $post_start . ', ' . $post_length
586
    );
587
    foreach ($rows as $record) {
588
        // Get itemKey from current user
589
        $currentUserKey = DB::queryFirstRow(
590
            'SELECT share_key
591
            FROM ' . prefixTable('sharekeys_logs') . '
592
            WHERE object_id = %i AND user_id = %i',
593
            $record['increment_id'],
594
            $extra_arguments['owner_id']
595
        );
596
597
        // do we have any input? (#3481)
598
        if ($currentUserKey === null || count($currentUserKey) === 0) {
599
            continue;
600
        }
601
602
        // Decrypt itemkey with admin key
603
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
604
605
        // Encrypt Item key
606
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
607
608
        // Save the key in DB
609
        if ($post_self_change === false) {
610
            DB::insert(
611
                prefixTable('sharekeys_logs'),
612
                array(
613
                    'object_id' => (int) $record['increment_id'],
614
                    'user_id' => (int) $post_user_id,
615
                    'share_key' => $share_key_for_item,
616
                )
617
            );
618
        } else {
619
            // Get itemIncrement from selected user
620
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
621
                $currentUserKey = DB::queryFirstRow(
622
                    'SELECT increment_id
623
                    FROM ' . prefixTable('sharekeys_items') . '
624
                    WHERE object_id = %i AND user_id = %i',
625
                    $record['id'],
626
                    $post_user_id
627
                );
628
            }
629
630
            // NOw update
631
            DB::update(
632
                prefixTable('sharekeys_logs'),
633
                array(
634
                    'share_key' => $share_key_for_item,
635
                ),
636
                'increment_id = %i',
637
                $currentUserKey['increment_id']
638
            );
639
        }
640
    }
641
642
    // SHould we change step?
643
    DB::query(
644
        'SELECT increment_id
645
        FROM ' . prefixTable('log_items') . '
646
        WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"'
647
    );
648
649
    $next_start = (int) $post_start + (int) $post_length;
650
    return [
651
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
652
        'new_action' => $next_start > DB::count() ? 'step40' : 'step30',
653
    ];
654
}
655
656
657
/**
658
 * Handle step 3 of re-encrypting user sharekeys
659
 *
660
 * @param integer $post_user_id
661
 * @param boolean $post_self_change
662
 * @param integer $post_start
663
 * @param integer $post_length
664
 * @param string $user_public_key
665
 * @param array $SETTINGS
666
 * @param array $extra_arguments
667
 * @return array
668
 */
669
function cronContinueReEncryptingUserSharekeysStep40(
670
    int $post_user_id,
671
    bool $post_self_change,
672
    int $post_start,
673
    int $post_length,
674
    string $user_public_key,
675
    array $SETTINGS,
676
    array $extra_arguments
677
): array
678
{
679
    // get user private key
680
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
681
    $userInfo = getOwnerInfo($extra_arguments['new_user_id'], $extra_arguments['new_user_pwd'], $SETTINGS);
0 ignored issues
show
Unused Code introduced by
The assignment to $userInfo is dead and can be removed.
Loading history...
682
683
    // Loop on fields
684
    $rows = DB::query(
685
        'SELECT id
686
        FROM ' . prefixTable('categories_items') . '
687
        WHERE encryption_type = "teampass_aes"
688
        LIMIT ' . $post_start . ', ' . $post_length
689
    );
690
    foreach ($rows as $record) {
691
        // Get itemKey from current user
692
        $currentUserKey = DB::queryFirstRow(
693
            'SELECT share_key
694
            FROM ' . prefixTable('sharekeys_fields') . '
695
            WHERE object_id = %i AND user_id = %i',
696
            $record['id'],
697
            $extra_arguments['owner_id']
698
        );
699
700
        if (isset($currentUserKey['share_key']) === true) {
701
            // Decrypt itemkey with admin key
702
            $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
703
704
            // Encrypt Item key
705
            $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
706
707
            // Save the key in DB
708
            if ($post_self_change === false) {
709
                DB::insert(
710
                    prefixTable('sharekeys_fields'),
711
                    array(
712
                        'object_id' => (int) $record['id'],
713
                        'user_id' => (int) $post_user_id,
714
                        'share_key' => $share_key_for_item,
715
                    )
716
                );
717
            } else {
718
                // Get itemIncrement from selected user
719
                if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
720
                    $currentUserKey = DB::queryFirstRow(
721
                        'SELECT increment_id
722
                        FROM ' . prefixTable('sharekeys_items') . '
723
                        WHERE object_id = %i AND user_id = %i',
724
                        $record['id'],
725
                        $post_user_id
726
                    );
727
                }
728
729
                // NOw update
730
                DB::update(
731
                    prefixTable('sharekeys_fields'),
732
                    array(
733
                        'share_key' => $share_key_for_item,
734
                    ),
735
                    'increment_id = %i',
736
                    $currentUserKey['increment_id']
737
                );
738
            }
739
        }
740
    }
741
742
    // SHould we change step?
743
    DB::query(
744
        'SELECT *
745
        FROM ' . prefixTable('categories_items') . '
746
        WHERE encryption_type = "teampass_aes"'
747
    );
748
749
    $next_start = (int) $post_start + (int) $post_length;
750
    return [
751
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
752
        'new_action' => $next_start > DB::count() ? 'step50' : 'step40',
753
    ];
754
}
755
756
757
/**
758
 * Handle step 4
759
 *
760
 * @param integer $post_user_id
761
 * @param boolean $post_self_change
762
 * @param integer $post_start
763
 * @param integer $post_length
764
 * @param string $user_public_key
765
 * @param array $SETTINGS
766
 * @param array $extra_arguments
767
 * @return array
768
 */
769
function cronContinueReEncryptingUserSharekeysStep50(
770
    int $post_user_id,
771
    bool $post_self_change,
772
    int $post_start,
773
    int $post_length,
774
    string $user_public_key,
775
    array $SETTINGS,
776
    array $extra_arguments
777
): array
778
{
779
    // get user private key
780
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
781
782
    // Loop on suggestions
783
    $rows = DB::query(
784
        'SELECT id
785
        FROM ' . prefixTable('suggestion') . '
786
        LIMIT ' . $post_start . ', ' . $post_length
787
    );
788
    foreach ($rows as $record) {
789
        // Get itemKey from current user
790
        $currentUserKey = DB::queryFirstRow(
791
            'SELECT share_key
792
            FROM ' . prefixTable('sharekeys_suggestions') . '
793
            WHERE object_id = %i AND user_id = %i',
794
            $record['id'],
795
            $extra_arguments['owner_id']
796
        );
797
798
        // do we have any input? (#3481)
799
        if ($currentUserKey === null || count($currentUserKey) === 0) {
800
            continue;
801
        }
802
803
        // Decrypt itemkey with admin key
804
        $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
805
806
        // Encrypt Item key
807
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
808
809
        // Save the key in DB
810
        if ($post_self_change === false) {
811
            DB::insert(
812
                prefixTable('sharekeys_suggestions'),
813
                array(
814
                    'object_id' => (int) $record['id'],
815
                    'user_id' => (int) $post_user_id,
816
                    'share_key' => $share_key_for_item,
817
                )
818
            );
819
        } else {
820
            // Get itemIncrement from selected user
821
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
822
                $currentUserKey = DB::queryFirstRow(
823
                    'SELECT increment_id
824
                    FROM ' . prefixTable('sharekeys_items') . '
825
                    WHERE object_id = %i AND user_id = %i',
826
                    $record['id'],
827
                    $post_user_id
828
                );
829
            }
830
831
            // NOw update
832
            DB::update(
833
                prefixTable('sharekeys_suggestions'),
834
                array(
835
                    'share_key' => $share_key_for_item,
836
                ),
837
                'increment_id = %i',
838
                $currentUserKey['increment_id']
839
            );
840
        }
841
    }
842
843
    // SHould we change step?
844
    DB::query(
845
        'SELECT *
846
        FROM ' . prefixTable('suggestion')
847
    );
848
849
    $next_start = (int) $post_start + (int) $post_length;
850
    return [
851
        'new_index' => $next_start > DB::count() ? 0 : $next_start,
852
        'new_action' => $next_start > DB::count() ? 'step60' : 'step50',
853
    ];
854
}
855
856
857
/**
858
 * Handle step 5
859
 *
860
 * @param integer $post_user_id
861
 * @param boolean $post_self_change
862
 * @param integer $post_start
863
 * @param integer $post_length
864
 * @param string $user_public_key
865
 * @param array $SETTINGS
866
 * @param array $extra_arguments
867
 * @return array
868
 */
869
function cronContinueReEncryptingUserSharekeysStep60(
870
    int $post_user_id,
871
    bool $post_self_change,
0 ignored issues
show
Unused Code introduced by
The parameter $post_self_change is not used and could be removed. ( Ignorable by Annotation )

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

871
    /** @scrutinizer ignore-unused */ bool $post_self_change,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
872
    int $post_start,
873
    int $post_length,
874
    string $user_public_key,
875
    array $SETTINGS,
876
    array $extra_arguments
877
): array
878
{
879
    // get user private key
880
    $ownerInfo = getOwnerInfo($extra_arguments['owner_id'], $extra_arguments['creator_pwd'], $SETTINGS);
881
    $userInfo = getOwnerInfo($extra_arguments['new_user_id'], $extra_arguments['new_user_pwd'], $SETTINGS);
882
883
    // Loop on files
884
    $rows = DB::query(
885
        'SELECT f.id AS id, i.perso AS perso
886
        FROM ' . prefixTable('files') . ' AS f
887
        INNER JOIN ' . prefixTable('items') . ' AS i ON i.id = f.id_item
888
        WHERE f.status = "' . TP_ENCRYPTION_NAME . '"
889
        LIMIT ' . $post_start . ', ' . $post_length
890
    ); //aes_encryption
891
    foreach ($rows as $record) {
892
        // Get itemKey from current user
893
        $currentUserKey = DB::queryFirstRow(
894
            'SELECT share_key, increment_id
895
            FROM ' . prefixTable('sharekeys_files') . '
896
            WHERE object_id = %i AND user_id = %i',
897
            $record['id'],
898
            (int) $record['perso'] === 0 ? $extra_arguments['owner_id'] : $extra_arguments['new_user_id']
899
        );
900
901
        // do we have any input? (#3481)
902
        if ($currentUserKey === null || count($currentUserKey) === 0) {
903
            continue;
904
        }
905
906
        // Decrypt itemkey with user key
907
        $itemKey = decryptUserObjectKey(
908
            $currentUserKey['share_key'],
909
            //$ownerInfo['private_key']
910
            (int) $record['perso'] === 0 ? $ownerInfo['private_key'] : $userInfo['private_key']
911
        );
912
        
913
        // Prevent to change key if its key is empty
914
        if (empty($itemKey) === true) {
915
            continue;
916
        }
917
918
        // Encrypt Item key
919
        $share_key_for_item = encryptUserObjectKey($itemKey, $user_public_key);
920
921
        $currentUserKey = DB::queryFirstRow(
922
            'SELECT increment_id
923
            FROM ' . prefixTable('sharekeys_files') . '
924
            WHERE object_id = %i AND user_id = %i',
925
            $record['id'],
926
            $post_user_id
927
        );
928
        // Save the key in DB
929
        if (DB::count() > 0) {
930
            // NOw update
931
            DB::update(
932
                prefixTable('sharekeys_files'),
933
                array(
934
                    'share_key' => $share_key_for_item,
935
                ),
936
                'increment_id = %i',
937
                $currentUserKey['increment_id']
938
            );
939
        } else {
940
            DB::insert(
941
                prefixTable('sharekeys_files'),
942
                array(
943
                    'object_id' => (int) $record['id'],
944
                    'user_id' => (int) $post_user_id,
945
                    'share_key' => $share_key_for_item,
946
                )
947
            );
948
        }
949
        /*if ($post_self_change === false) {
950
            DB::insert(
951
                prefixTable('sharekeys_files'),
952
                array(
953
                    'object_id' => (int) $record['id'],
954
                    'user_id' => (int) $post_user_id,
955
                    'share_key' => $share_key_for_item,
956
                )
957
            );
958
        } else {
959
            // Get itemIncrement from selected user
960
            if ((int) $post_user_id !== (int) $extra_arguments['owner_id']) {
961
                $currentUserKey = DB::queryFirstRow(
962
                    'SELECT increment_id
963
                    FROM ' . prefixTable('sharekeys_files') . '
964
                    WHERE object_id = %i AND user_id = %i',
965
                    $record['id'],
966
                    $post_user_id
967
                );
968
            }
969
970
            // NOw update
971
            DB::update(
972
                prefixTable('sharekeys_files'),
973
                array(
974
                    'share_key' => $share_key_for_item,
975
                ),
976
                'increment_id = %i',
977
                $currentUserKey['increment_id']
978
            );
979
        }*/
980
    }
981
982
    // SHould we change step? Finished ?
983
    DB::query(
984
        'SELECT *
985
        FROM ' . prefixTable('files') . '
986
        WHERE status = "' . TP_ENCRYPTION_NAME . '"'
987
    );
988
    $counter = DB::count();
989
    $next_start = (int) $post_start + (int) $post_length;
990
991
    if ($next_start > $counter) {
992
        // Set user as ready for usage
993
        DB::update(
994
            prefixTable('users'),
995
            array(
996
                'ongoing_process_id' => NULL,
997
                'special' => 'none',
998
            ),
999
            'id = %i',
1000
            $extra_arguments['new_user_id']
1001
        );
1002
    }
1003
1004
    return [
1005
        'new_index' => $next_start > $counter ? 0 : $next_start,
1006
        'new_action' => $next_start > $counter ? 'finished' : 'step60',
1007
    ];
1008
}
1009
1010
1011
/**
1012
 * Handle step 6
1013
 *
1014
 * @param integer $post_user_id
1015
 * @param integer $post_start
1016
 * @param integer $post_length
1017
 * @param string $user_public_key
1018
 * @param array $SETTINGS
1019
 * @param array $extra_arguments
1020
 * @return array
1021
 */
1022
function cronContinueReEncryptingUserSharekeysStep10(
1023
    int $post_user_id,
1024
    array $SETTINGS,
1025
    array $extra_arguments
1026
): array
1027
{
1028
    // IF USER IS NOT THE SAME
1029
    if ((int) $post_user_id === (int) $extra_arguments['owner_id']) {
1030
        return [
1031
            'new_index' => 0,
1032
            'new_action' => 'finished',
1033
        ];
1034
    }
1035
    
1036
    // update LOG
1037
    logEvents(
1038
        $SETTINGS,
1039
        'user_mngt',
1040
        'at_user_new_keys',
1041
        TP_USER_ID,
1042
        "",
1043
        (string) $extra_arguments['new_user_id']
1044
    );
1045
1046
    // if done then send email to new user
1047
    // get user info
1048
    $userInfo = DB::queryFirstRow(
1049
        'SELECT email, login, auth_type, special, lastname, name
1050
        FROM ' . prefixTable('users') . '
1051
        WHERE id = %i',
1052
        $extra_arguments['new_user_id']
1053
    );
1054
1055
    // SEND EMAIL TO USER depending on context
1056
    // Config 1: new user is a local user
1057
    // Config 2: new user is an LDAP user
1058
    // Config 3: send new password
1059
    // COnfig 4: send new encryption code
1060
    if (isset($extra_arguments['send_email']) === true && (int) $extra_arguments['send_email'] === 1) {
1061
        sendMailToUser(
1062
            filter_var($userInfo['email'], FILTER_SANITIZE_FULL_SPECIAL_CHARS),
1063
            empty($extra_arguments['email_body']) === false ? $extra_arguments['email_body'] : langHdl('email_body_user_config_1'),
1064
            'TEAMPASS - ' . langHdl('login_credentials'),
1065
            (array) filter_var_array(
1066
                [
1067
                    '#code#' => cryption($extra_arguments['new_user_code'], '','decrypt', $SETTINGS)['string'],
1068
                    '#lastname#' => isset($userInfo['name']) === true ? $userInfo['name'] : '',
1069
                    '#login#' => isset($userInfo['login']) === true ? $userInfo['login'] : '',
1070
                    '#password#' => cryption($extra_arguments['new_user_pwd'], '','decrypt', $SETTINGS)['string'],
1071
                ],
1072
                FILTER_SANITIZE_FULL_SPECIAL_CHARS
1073
            ),
1074
            $SETTINGS
1075
        );
1076
    }
1077
        
1078
    // Set user as ready for usage
1079
    DB::update(
1080
        prefixTable('users'),
1081
        array(
1082
            'is_ready_for_usage' => 1,
1083
            '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
1084
        ),
1085
        'id = %i',
1086
        $extra_arguments['new_user_id']
1087
    );
1088
1089
    return [
1090
        'new_index' => 0,
1091
        'new_action' => 'step20',
1092
    ];
1093
}
1094
1095
1096
/**
1097
 * SEnd email to user
1098
 *
1099
 * @param string $post_receipt
1100
 * @param string $post_body
1101
 * @param string $post_subject
1102
 * @param array $post_replace
1103
 * @param array $SETTINGS
1104
 * @return void
1105
 */
1106
function sendMailToUser(
1107
    string $post_receipt,
1108
    string $post_body,
1109
    string $post_subject,
1110
    array $post_replace,
1111
    array $SETTINGS
1112
): void
1113
{
1114
    if (count($post_replace) > 0 && is_null($post_replace) === false) {
1115
        $post_body = str_replace(
1116
            array_keys($post_replace),
1117
            array_values($post_replace),
1118
            $post_body
1119
        );
1120
    }
1121
1122
    prepareSendingEmail(
1123
        $post_subject,
1124
        $post_body,
1125
        $post_receipt,
1126
        "",
1127
        $SETTINGS
1128
    );
1129
}