Passed
Push — master ( b61ff7...0d33c7 )
by Nils
05:51
created

UserHandlerTrait   F

Complexity

Total Complexity 84

Size/Duplication

Total Lines 731
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 370
c 2
b 0
f 0
dl 0
loc 731
rs 2
wmc 84

11 Methods

Rating   Name   Duplication   Size   Complexity  
A handleUserBuildCacheTree() 0 2 1
A generateUserKeys() 0 25 6
A generateNewUserStep0() 0 4 2
B processGenerateUserKeysSubtask() 0 71 10
C generateNewUserStep99() 0 92 13
B generateNewUserStep50() 0 81 9
A getOwnerInfos() 0 27 3
B generateNewUserStep40() 0 79 8
C generateNewUserStep20() 0 83 12
B generateNewUserStep30() 0 80 9
B generateNewUserStep60() 0 87 11

How to fix   Complexity   

Complex Class

Complex classes like UserHandlerTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use UserHandlerTrait, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Teampass - a collaborative passwords manager.
4
 * ---
5
 * This file is part of the TeamPass project.
6
 * 
7
 * TeamPass is free software: you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, version 3 of the License.
10
 * 
11
 * TeamPass is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU General Public License for more details.
15
 * 
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18
 * 
19
 * Certain components of this file may be under different licenses. For
20
 * details, see the `licenses` directory or individual file headers.
21
 * ---
22
 * @file      UserHandlerTrait.php
23
 * @author    Nils Laumaillé ([email protected])
24
 * @copyright 2009-2025 Teampass.net
25
 * @license   GPL-3.0
26
 * @see       https://www.teampass.net
27
 */
28
29
use TeampassClasses\Language\Language;
30
31
trait UserHandlerTrait {
32
    abstract protected function completeTask();
33
34
    /**
35
     * Handle user build cache tree
36
     * @param array $arguments Useful arguments for the task
37
     * @return void
38
     */
39
    private function handleUserBuildCacheTree($arguments) {
40
        performVisibleFoldersHtmlUpdate($arguments['user_id']);
41
    }
42
43
44
    /**
45
     * Generate user keys
46
     * @param array $taskData Données de la tâche
47
     * @param array $arguments Arguments nécessaires pour la création des clés
48
     * @return void
49
     */
50
    private function generateUserKeys($arguments) {
51
        // Get all subtasks related to this task
52
        $subtasks = DB::query(
53
            'SELECT * FROM ' . prefixTable('background_subtasks') . ' WHERE task_id = %i AND is_in_progress = 0 ORDER BY `task` ASC',
54
            $this->taskId
55
        );
56
    
57
        if (empty($subtasks)) {
58
            if (LOG_TASKS=== true) $this->logger->log("No subtask was found for task {$this->taskId}");
59
            return;
60
        }
61
    
62
        // Process each subtask
63
        foreach ($subtasks as $subtask) {
64
            if (LOG_TASKS=== true) $this->logger->log("Processing subtask {$subtask['increment_id']} for task {$this->taskId}");
65
            $this->processGenerateUserKeysSubtask($subtask, $arguments);
66
        }
67
    
68
        // Are all subtasks completed?
69
        $remainingSubtasks = DB::queryFirstField(
70
            'SELECT COUNT(*) FROM ' . prefixTable('background_subtasks') . ' WHERE task_id = %i AND is_in_progress = 0',
71
            $this->taskId
72
        );    
73
        if ($remainingSubtasks == 0) {
74
            $this->completeTask();
75
        }
76
    }
77
    
78
79
    /**
80
     * Process a subtask for generating user keys.
81
     * @param array $subtask The subtask to process.
82
     * @param array $arguments Arguments for the task.
83
     * @return void
84
     */
85
    private function processGenerateUserKeysSubtask(array $subtask, array $arguments) {
86
        try {
87
            $taskData = json_decode($subtask['task'], true);
88
            
89
            // Mark the subtask as in progress
90
            DB::update(
91
                prefixTable('background_subtasks'),
92
                [
93
                    'is_in_progress' => 1,
94
                    'updated_at' => time(),
95
                    'status' => 'in progress'
96
                ],
97
                'increment_id = %i',
98
                $subtask['increment_id']
99
            );
100
            
101
            if (LOG_TASKS=== true) $this->logger->log("Subtask is in progress: ".$taskData['step'], 'INFO');
102
            switch ($taskData['step'] ?? '') {
103
                case 'step0':
104
                    $this->generateNewUserStep0($arguments);
105
                    break;
106
                case 'step20':
107
                    $this->generateNewUserStep20($taskData, $arguments);
108
                    break;
109
                case 'step30':
110
                    $this->generateNewUserStep30($taskData, $arguments);
111
                    break;
112
                case 'step40':
113
                    $this->generateNewUserStep40($taskData, $arguments);
114
                    break;
115
                case 'step50':
116
                    $this->generateNewUserStep50($taskData, $arguments);
117
                    break;
118
                case 'step60':
119
                    $this->generateNewUserStep60($taskData, $arguments);
120
                    break;
121
                case 'step99':
122
                    $this->generateNewUserStep99($arguments);
123
                break;
124
                default:
125
                    throw new Exception("Type of subtask unknown: {$this->processType}");
126
            }
127
    
128
            // Mark subtask as completed
129
            DB::update(
130
                prefixTable('background_subtasks'),
131
                [
132
                    'is_in_progress' => -1,
133
                    'finished_at' => time(),
134
                    'status' => 'completed',
135
                ],
136
                'increment_id = %i',
137
                $subtask['increment_id']
138
            );
139
    
140
        } catch (Exception $e) {
141
            // Failure handling
142
            DB::update(
143
                prefixTable('background_subtasks'),
144
                [
145
                    'is_in_progress' => -1,
146
                    'finished_at' => time(),
147
                    'updated_at' => time(),
148
                    'status' => 'failed',
149
                    'error_message' => $e->getMessage(),
150
                ],
151
                'increment_id = %i',
152
                $subtask['increment_id']
153
            );
154
            
155
            $this->logger->log("Subtask {$subtask['increment_id']} failure: " . $e->getMessage(), 'ERROR');
156
        }
157
    }
158
    
159
160
    /**
161
     * Generate new user keys - step 0
162
     * @param array $arguments Arguments for the task
163
     * @return void
164
     */
165
    private function generateNewUserStep0($arguments) {
166
        // CLear old sharekeys
167
        if ($arguments['user_self_change'] === 0) {
168
            deleteUserObjetsKeys($arguments['new_user_id'], $this->settings);
169
        }
170
    }
171
172
173
    /**
174
     * Generate new user keys
175
     * @param array $taskData Task data
176
     * @param array $arguments Arguments for the task
177
     */
178
    private function generateNewUserStep20($taskData, $arguments) {
179
        // get user private key
180
        $ownerInfo = isset($arguments['owner_id']) && isset($arguments['creator_pwd']) 
181
            ? $this->getOwnerInfos($arguments['owner_id'], $arguments['creator_pwd']) 
182
            : null;
183
        $userInfo = $this->getOwnerInfos(
184
            $arguments['new_user_id'],
185
            $arguments['new_user_pwd'],
186
            ($arguments['only_personal_items'] ?? 0) === 1 ? 1 : 0,
187
            $arguments['new_user_private_key'] ?? ''
188
        );
189
190
        // Start transaction for better performance
191
        DB::startTransaction();
192
193
        // Loop on items
194
        $rows = DB::query(
195
            'SELECT id, pw, perso
196
            FROM ' . prefixTable('items') . '
197
            WHERE perso =  %i
198
            ORDER BY id ASC
199
            LIMIT %i, %i',
200
            ($arguments['only_personal_items'] ?? 0) === 1 ? 1 : 0,
201
            $taskData['index'],
202
            $taskData['nb']
203
        );
204
        
205
        foreach ($rows as $record) {
206
            // Get itemKey from current user
207
            $currentUserKey = DB::queryFirstRow(
208
                'SELECT share_key, increment_id
209
                FROM ' . prefixTable('sharekeys_items') . '
210
                WHERE object_id = %i AND user_id = %i',
211
                $record['id'],
212
                (int) $record['perso'] === 0 ? $arguments['owner_id'] : $arguments['new_user_id']
213
            );
214
215
            // do we have any input? (#3481)
216
            if ($currentUserKey === null || count($currentUserKey) === 0) {
217
                continue;
218
            }
219
220
            // Decrypt itemkey with expected private key
221
            $itemKey = decryptUserObjectKey(
222
                $currentUserKey['share_key'],
223
                (int) $record['perso'] === 0 ? $ownerInfo['private_key'] : $userInfo['private_key']
224
            );
225
            
226
            // Prevent to change key if its key is empty
227
            if (empty($itemKey) === true) {
228
                $share_key_for_item = '';
229
            } else {
230
                // Encrypt Item key
231
                $share_key_for_item = encryptUserObjectKey($itemKey, $userInfo['public_key']);
232
            }
233
234
            // Save the new sharekey correctly encrypted in DB
235
            $affected = DB::update(
236
                prefixTable('sharekeys_items'),
237
                array(
238
                    'object_id' => (int) $record['id'],
239
                    'user_id' => (int) $arguments['new_user_id'],
240
                    'share_key' => $share_key_for_item,
241
                ),
242
                'increment_id = %i',
243
                $currentUserKey['increment_id']
244
            );
245
246
            // If now row was updated, it means the user has no key for this item, so we need to insert it
247
            if ($affected === 0) {
248
                DB::insert(
249
                    prefixTable('sharekeys_items'),
250
                    array(
251
                        'object_id' => (int) $record['id'],
252
                        'user_id' => (int) $arguments['new_user_id'],
253
                        'share_key' => $share_key_for_item,
254
                    )
255
                );
256
            }
257
        }
258
259
        // Commit transaction
260
        DB::commit();
261
    }
262
263
264
    /**
265
     * Generate new user keys - step 30
266
     * @param array $taskData Task data
267
     * @param array $arguments Arguments for the task
268
     * @return void
269
     */
270
    private function generateNewUserStep30($taskData, $arguments) {
271
        // get user private key
272
        $ownerInfo = isset($arguments['owner_id']) && isset($arguments['creator_pwd']) 
273
            ? $this->getOwnerInfos($arguments['owner_id'], $arguments['creator_pwd']) 
274
            : null;
275
        $userInfo = $this->getOwnerInfos(
276
            $arguments['new_user_id'],
277
            $arguments['new_user_pwd'],
278
            ($arguments['only_personal_items'] ?? 0) === 1 ? 1 : 0,
279
            $arguments['new_user_private_key'] ?? ''
280
        );
281
282
        // Start transaction for better performance
283
        DB::startTransaction();
284
285
        // Loop on logs
286
        $rows = DB::query(
287
            'SELECT increment_id
288
            FROM ' . prefixTable('log_items') . '
289
            WHERE raison LIKE "at_pw :%" AND encryption_type = "teampass_aes"
290
            ORDER BY increment_id ASC
291
            LIMIT ' . $taskData['index'] . ', ' . $taskData['nb']
292
        );
293
        foreach ($rows as $record) {
294
            // Get itemKey from current user
295
            $currentUserKey = DB::queryFirstRow(
296
                'SELECT share_key
297
                FROM ' . prefixTable('sharekeys_logs') . '
298
                WHERE object_id = %i AND user_id = %i',
299
                $record['increment_id'],
300
                $arguments['owner_id']
301
            );
302
303
            // do we have any input? (#3481)
304
            if ($currentUserKey === null || count($currentUserKey) === 0) {
305
                continue;
306
            }
307
308
            // Decrypt itemkey with admin key
309
            $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
310
311
            // Encrypt Item key
312
            $share_key_for_item = encryptUserObjectKey($itemKey, $userInfo['public_key']);
313
314
            // Save the key in DB
315
            if ($arguments['user_self_change'] === false) {
316
                DB::insert(
317
                    prefixTable('sharekeys_logs'),
318
                    array(
319
                        'object_id' => (int) $record['increment_id'],
320
                        'user_id' => (int) $arguments['new_user_id'],
321
                        'share_key' => $share_key_for_item,
322
                    )
323
                );
324
            } else {
325
                // Get itemIncrement from selected user
326
                if ((int) $arguments['new_user_id'] !== (int) $arguments['owner_id']) {
327
                    $currentUserKey = DB::queryFirstRow(
328
                        'SELECT increment_id
329
                        FROM ' . prefixTable('sharekeys_items') . '
330
                        WHERE object_id = %i AND user_id = %i',
331
                        $record['id'],
332
                        $arguments['new_user_id']
333
                    );
334
                }
335
336
                // NOw update
337
                DB::update(
338
                    prefixTable('sharekeys_logs'),
339
                    array(
340
                        'share_key' => $share_key_for_item,
341
                    ),
342
                    'increment_id = %i',
343
                    $currentUserKey['increment_id']
344
                );
345
            }
346
        }
347
348
        // Commit transaction
349
        DB::commit();
350
    }
351
352
353
    /**
354
     * Generate new user keys - step 40
355
     * @param array $taskData Task data
356
     * @param array $arguments Arguments for the task
357
     * @return void
358
     */
359
    private function generateNewUserStep40($taskData, $arguments) {
360
        // get user private key
361
        $ownerInfo = isset($arguments['owner_id']) && isset($arguments['creator_pwd']) 
362
            ? $this->getOwnerInfos($arguments['owner_id'], $arguments['creator_pwd']) 
363
            : null;
364
        $userInfo = $this->getOwnerInfos(
365
            $arguments['new_user_id'],
366
            $arguments['new_user_pwd'],
367
            ($arguments['only_personal_items'] ?? 0) === 1 ? 1 : 0,
368
            $arguments['new_user_private_key'] ?? ''
369
        );
370
371
        // Start transaction for better performance
372
        DB::startTransaction();
373
374
        // Loop on fields
375
        $rows = DB::query(
376
            'SELECT id
377
            FROM ' . prefixTable('categories_items') . '
378
            WHERE encryption_type = "teampass_aes"
379
            ORDER BY id ASC
380
            LIMIT %i, %i',
381
            $taskData['index'],
382
            $taskData['nb']
383
        );
384
        foreach ($rows as $record) {
385
            // Get itemKey from current user
386
            $currentUserKey = DB::queryFirstRow(
387
                'SELECT share_key
388
                FROM ' . prefixTable('sharekeys_fields') . '
389
                WHERE object_id = %i AND user_id = %i',
390
                $record['id'],
391
                $arguments['owner_id']
392
            );
393
394
            if (isset($currentUserKey['share_key']) === true) {
395
                // Decrypt itemkey with admin key
396
                $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
397
398
                // Encrypt Item key
399
                $share_key_for_item = encryptUserObjectKey($itemKey, $userInfo['public_key']);
400
401
                // Save the key in DB
402
                if ($arguments['user_self_change'] === false) {
403
                    DB::insert(
404
                        prefixTable('sharekeys_fields'),
405
                        array(
406
                            'object_id' => (int) $record['id'],
407
                            'user_id' => (int) $arguments['new_user_id'],
408
                            'share_key' => $share_key_for_item,
409
                        )
410
                    );
411
                } else {
412
                    // Get itemIncrement from selected user
413
                    if ((int) $arguments['new_user_id'] !== (int) $arguments['owner_id']) {
414
                        $currentUserKey = DB::queryFirstRow(
415
                            'SELECT increment_id
416
                            FROM ' . prefixTable('sharekeys_items') . '
417
                            WHERE object_id = %i AND user_id = %i',
418
                            $record['id'],
419
                            $arguments['new_user_id']
420
                        );
421
                    }
422
423
                    // NOw update
424
                    DB::update(
425
                        prefixTable('sharekeys_fields'),
426
                        array(
427
                            'share_key' => $share_key_for_item,
428
                        ),
429
                        'increment_id = %i',
430
                        $currentUserKey['increment_id']
431
                    );
432
                }
433
            }
434
        }
435
436
        // Commit transaction
437
        DB::commit();
438
    }
439
440
441
    /**
442
     * Generate new user keys - step 50
443
     * @param array $taskData Task data
444
     * @param array $arguments Arguments for the task
445
     * @return void
446
     */
447
    private function generateNewUserStep50($taskData, $arguments) {
448
        // get user private key
449
        $ownerInfo = isset($arguments['owner_id']) && isset($arguments['creator_pwd']) 
450
            ? $this->getOwnerInfos($arguments['owner_id'], $arguments['creator_pwd']) 
451
            : null;
452
        $userInfo = $this->getOwnerInfos(
453
            $arguments['new_user_id'],
454
            $arguments['new_user_pwd'],
455
            ($arguments['only_personal_items'] ?? 0) === 1 ? 1 : 0,
456
            $arguments['new_user_private_key'] ?? ''
457
        );
458
459
        // Start transaction for better performance
460
        DB::startTransaction();
461
462
        // Loop on suggestions
463
        $rows = DB::query(
464
            'SELECT id
465
            FROM ' . prefixTable('suggestion') . '
466
            ORDER BY id ASC
467
            LIMIT %i, %i',
468
            $taskData['index'],
469
            $taskData['nb']
470
        );
471
        foreach ($rows as $record) {
472
            // Get itemKey from current user
473
            $currentUserKey = DB::queryFirstRow(
474
                'SELECT share_key
475
                FROM ' . prefixTable('sharekeys_suggestions') . '
476
                WHERE object_id = %i AND user_id = %i',
477
                $record['id'],
478
                $arguments['owner_id']
479
            );
480
481
            // do we have any input? (#3481)
482
            if ($currentUserKey === null || count($currentUserKey) === 0) {
483
                continue;
484
            }
485
486
            // Decrypt itemkey with admin key
487
            $itemKey = decryptUserObjectKey($currentUserKey['share_key'], $ownerInfo['private_key']);
488
489
            // Encrypt Item key
490
            $share_key_for_item = encryptUserObjectKey($itemKey, $userInfo['public_key']);
491
492
            // Save the key in DB
493
            if ($arguments['user_self_change'] === false) {
494
                DB::insert(
495
                    prefixTable('sharekeys_suggestions'),
496
                    array(
497
                        'object_id' => (int) $record['id'],
498
                        'user_id' => (int) $arguments['new_user_id'],
499
                        'share_key' => $share_key_for_item,
500
                    )
501
                );
502
            } else {
503
                // Get itemIncrement from selected user
504
                if ((int) $arguments['new_user_id'] !== (int) $arguments['owner_id']) {
505
                    $currentUserKey = DB::queryFirstRow(
506
                        'SELECT increment_id
507
                        FROM ' . prefixTable('sharekeys_items') . '
508
                        WHERE object_id = %i AND user_id = %i',
509
                        $record['id'],
510
                        $arguments['new_user_id']
511
                    );
512
                }
513
514
                // NOw update
515
                DB::update(
516
                    prefixTable('sharekeys_suggestions'),
517
                    array(
518
                        'share_key' => $share_key_for_item,
519
                    ),
520
                    'increment_id = %i',
521
                    $currentUserKey['increment_id']
522
                );
523
            }
524
        }
525
526
        // Commit transaction
527
        DB::commit();
528
    }
529
530
531
    /**
532
     * Generate new user keys - step 60
533
     * @param array $taskData Task data
534
     * @param array $arguments Arguments for the task
535
     * @return void
536
     */
537
    private function generateNewUserStep60($taskData, $arguments) {
538
        // get user private key
539
        $ownerInfo = isset($arguments['owner_id']) && isset($arguments['creator_pwd']) 
540
            ? $this->getOwnerInfos($arguments['owner_id'], $arguments['creator_pwd']) 
541
            : null;
542
        $userInfo = $this->getOwnerInfos(
543
            $arguments['new_user_id'],
544
            $arguments['new_user_pwd'],
545
            ($arguments['only_personal_items'] ?? 0) === 1 ? 1 : 0,
546
            $arguments['new_user_private_key'] ?? ''
547
        );
548
549
        // Start transaction for better performance
550
        DB::startTransaction();
551
552
        // Loop on files
553
        $rows = DB::query(
554
            'SELECT f.id AS id, i.perso AS perso
555
            FROM ' . prefixTable('files') . ' AS f
556
            INNER JOIN ' . prefixTable('items') . ' AS i ON i.id = f.id_item
557
            WHERE f.status = "' . TP_ENCRYPTION_NAME . '"
558
            LIMIT %i, %i',
559
            $taskData['index'],
560
            $taskData['nb']
561
        ); //aes_encryption
562
        foreach ($rows as $record) {
563
            // Get itemKey from current user
564
            $currentUserKey = DB::queryFirstRow(
565
                'SELECT share_key, increment_id
566
                FROM ' . prefixTable('sharekeys_files') . '
567
                WHERE object_id = %i AND user_id = %i',
568
                $record['id'],
569
                (int) $record['perso'] === 0 ? $arguments['owner_id'] : $arguments['new_user_id']
570
            );
571
572
            // do we have any input? (#3481)
573
            if ($currentUserKey === null || count($currentUserKey) === 0) {
574
                continue;
575
            }
576
577
            // Decrypt itemkey with user key
578
            $itemKey = decryptUserObjectKey(
579
                $currentUserKey['share_key'],
580
                //$ownerInfo['private_key']
581
                (int) $record['perso'] === 0 ? $ownerInfo['private_key'] : $userInfo['private_key']
582
            );
583
            
584
            // Prevent to change key if its key is empty
585
            if (empty($itemKey) === true) {
586
                continue;
587
            }
588
589
            // Encrypt Item key
590
            $share_key_for_item = encryptUserObjectKey($itemKey, $userInfo['public_key']);
591
592
            $currentUserKey = DB::queryFirstRow(
593
                'SELECT increment_id
594
                FROM ' . prefixTable('sharekeys_files') . '
595
                WHERE object_id = %i AND user_id = %i',
596
                $record['id'],
597
                $arguments['new_user_id']
598
            );
599
            // Save the key in DB
600
            if (DB::count() > 0) {
601
                // NOw update
602
                DB::update(
603
                    prefixTable('sharekeys_files'),
604
                    array(
605
                        'share_key' => $share_key_for_item,
606
                    ),
607
                    'increment_id = %i',
608
                    $currentUserKey['increment_id']
609
                );
610
            } else {
611
                DB::insert(
612
                    prefixTable('sharekeys_files'),
613
                    array(
614
                        'object_id' => (int) $record['id'],
615
                        'user_id' => (int) $arguments['new_user_id'],
616
                        'share_key' => $share_key_for_item,
617
                    )
618
                );
619
            }
620
        }
621
622
        // Commit transaction
623
        DB::commit();
624
    }
625
626
627
    /**
628
     * Generate new user keys - step 99
629
     * @param array $arguments Arguments for the task
630
     */
631
    private function generateNewUserStep99($arguments) {
632
        $lang = new Language('english');
633
634
        // IF USER IS NOT THE SAME
635
        if (isset($arguments['owner_id']) && (int) $arguments['new_user_id'] === (int) $arguments['owner_id']) {
636
            return [
637
                'new_index' => 0,
638
                'new_action' => 'finished',
639
            ];
640
        }
641
        
642
        // update LOG
643
        logEvents(
644
            $this->settings,
645
            'user_mngt',
646
            'at_user_new_keys',
647
            TP_USER_ID,
648
            "",
649
            (string) $arguments['new_user_id']
650
        );
651
652
        // Personal items encryption only?
653
        if (($arguments['only_personal_items'] ?? 0) === 1) {
654
            // Set user as ready for usage
655
            DB::update(
656
                prefixTable('users'),
657
                array(
658
                    'ongoing_process_id' => NULL,
659
                    'special' => 'none',
660
                    'updated_at' => time(),
661
                ),
662
                'id = %i',
663
                $arguments['new_user_id']
664
            );
665
            return;
666
        }
667
668
        echo("User keys generation process is finished for user {$arguments['new_user_id']} - Personal items status: ".$arguments['only_personal_items']);
669
670
        // if done then send email to new user
671
        // get user info
672
        $userInfo = DB::queryFirstRow(
673
            'SELECT u.email, u.login, u.auth_type, u.special, u.lastname, u.name
674
            FROM ' . prefixTable('users') . ' AS u
675
            WHERE u.id = %i',
676
            $arguments['new_user_id']
677
        );
678
679
        // SEND EMAIL TO USER depending on context
680
        // Config 1: new user is a local user
681
        // Config 2: new user is an LDAP user
682
        // Config 3: send new password
683
        // COnfig 4: send new encryption code
684
        if (isset($arguments['send_email']) === true && (int) $arguments['send_email'] === 1 && !empty($userInfo['email'])) {
685
            sendMailToUser(
686
                filter_var($userInfo['email'], FILTER_SANITIZE_EMAIL),
687
                // @scrutinizer ignore-type
688
                empty($arguments['email_body']) === false ? $arguments['email_body'] : $lang->get('email_body_user_config_1'),
689
                'TEAMPASS - ' . $lang->get('login_credentials'),
690
                (array) filter_var_array(
691
                    [
692
                        '#code#' => cryption($arguments['new_user_code'], '','decrypt', $this->settings)['string'],
693
                        '#lastname#' => isset($userInfo['name']) === true ? $userInfo['name'] : '',
694
                        '#login#' => isset($userInfo['login']) === true ? $userInfo['login'] : '',
695
                    ],
696
                    FILTER_SANITIZE_FULL_SPECIAL_CHARS
697
                ),
698
                false,
699
                $arguments['new_user_pwd']
700
            );
701
        }
702
703
        // Does user has personal items?
704
        $personalItemsCount = DB::queryFirstField(
705
            'SELECT COUNT(*)
706
            FROM ' . prefixTable('items') . '
707
            WHERE perso = 1 AND id IN (SELECT object_id FROM ' . prefixTable('sharekeys_items') . ' WHERE user_id = %i)',
708
            $arguments['new_user_id']
709
        );
710
711
        // Set user as ready for usage
712
        DB::update(
713
            prefixTable('users'),
714
            array(
715
                'is_ready_for_usage' => 1,
716
                'otp_provided' => isset($arguments['otp_provided_new_value']) === true && (int) $arguments['otp_provided_new_value'] === 1 ? $arguments['otp_provided_new_value'] : 0,
717
                'ongoing_process_id' => NULL,
718
                'special' => $personalItemsCount > 0 ? 'encrypt_personal_items' : 'none',
719
                'updated_at' => time(),
720
            ),
721
            'id = %i',
722
            $arguments['new_user_id']
723
        );
724
    }
725
    
726
727
    /**
728
     * Get owner info
729
     * @param int $owner_id Owner ID
730
     * @param string $owner_pwd Owner password
731
     * @param int $only_personal_items 1 if only personal items, 0 else
732
     * @param string $owner_pwd Owner password
733
     * @return array Owner information
734
     */
735
    private function getOwnerInfos(int $owner_id, string $owner_pwd, int $only_personal_items = 0, string $owner_private_key = ''): array {
736
        $userInfo = DB::queryFirstRow(
737
            'SELECT pw, public_key, private_key, login, name
738
            FROM ' . prefixTable('users') . '
739
            WHERE id = %i',
740
            $owner_id
741
        );
742
743
        // decrypt owner password 
744
        $pwd = cryption($owner_pwd, '','decrypt', $this->settings)['string'];
745
746
        // decrypt private key and send back
747
        if ((int) $only_personal_items === 1 && empty($owner_private_key) === false) {
748
            // Explicitely case where we only want personal items and where user has provided his private key
749
            return [
750
                'private_key' => cryption($owner_private_key, '','decrypt')['string'],
751
                'public_key' => $userInfo['public_key'],
752
                'login' => $userInfo['login'],
753
                'name' => $userInfo['name'],
754
            ];
755
        }else {
756
            // Normal case
757
            return [
758
                'private_key' => decryptPrivateKey($pwd, $userInfo['private_key']),
759
                'public_key' => $userInfo['public_key'],
760
                'login' => $userInfo['login'],
761
                'name' => $userInfo['name'],
762
            ];
763
        }
764
    }
765
}