Passed
Branch teampass_3.0 (9035f8)
by Nils
02:55
created

initTempArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 10
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 13
rs 9.9332
1
<?php
2
/**
3
 * @author        Nils Laumaillé <[email protected]>
4
 *
5
 * @version       2.1.27
6
 *
7
 * @copyright     2009-2018 Nils Laumaillé
8
 * @license       GNU GPL-3.0
9
 *
10
 * @see          https://www.teampass.net
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
 */
16
use Goodby\CSV\Import\Standard\Lexer;
17
use Goodby\CSV\Import\Standard\Interpreter;
18
use Goodby\CSV\Import\Standard\LexerConfig;
19
20
require_once 'SecureHandler.php';
21
session_start();
22
if (!isset($_SESSION['CPM']) || $_SESSION['CPM'] === false || !isset($_SESSION['key']) || empty($_SESSION['key'])) {
23
    die('Hacking attempt...');
24
}
25
26
// Load config
27
if (file_exists('../includes/config/tp.config.php')) {
28
    include_once '../includes/config/tp.config.php';
29
} elseif (file_exists('./includes/config/tp.config.php')) {
30
    include_once './includes/config/tp.config.php';
31
} else {
32
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
33
}
34
35
// Do checks
36
require_once $SETTINGS['cpassman_dir'].'/includes/config/include.php';
37
require_once $SETTINGS['cpassman_dir'].'/sources/checks.php';
38
if (checkUser($_SESSION['user_id'], $_SESSION['key'], 'items', $SETTINGS) === false) {
39
    // Not allowed page
40
    $_SESSION['error']['code'] = ERR_NOT_ALLOWED;
41
    include $SETTINGS['cpassman_dir'].'/error.php';
42
    exit();
43
}
44
45
/*
46
 * Define Timezone
47
**/
48
if (isset($SETTINGS['timezone']) === true) {
49
    date_default_timezone_set($SETTINGS['timezone']);
50
} else {
51
    date_default_timezone_set('UTC');
52
}
53
54
require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$_SESSION['user_language'].'.php';
55
require_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
56
header('Content-type: text/html; charset=utf-8');
57
header('Cache-Control: no-cache, must-revalidate');
58
require_once 'main.functions.php';
59
60
// No time limit
61
set_time_limit(0);
62
63
// Set some constants for program readability
64
define('KP_PATH', 0);
65
define('KP_GROUP', 1);
66
define('KP_TITLE', 2);
67
define('KP_PASSWORD', 3);
68
define('KP_USERNAME', 4);
69
define('KP_URL', 5);
70
define('KP_UUID', 6);
71
define('KP_NOTES', 7);
72
73
// Connect to mysql server
74
require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
75
$link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
76
$link->set_charset(DB_ENCODING);
77
78
// Class loader
79
require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
80
81
//Load Tree
82
$tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
83
$tree->register();
84
$tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
85
86
//Load AES
87
$aes = new SplClassLoader('Encryption\Crypt', '../includes/libraries');
88
$aes->register();
89
90
//User's language loading
91
require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$_SESSION['user_language'].'.php';
92
93
// POST Varaibles
94
$post_key = filter_input(INPUT_POST, 'key', FILTER_SANITIZE_STRING);
95
$post_data = filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
96
97
// Build query
98
switch (filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING)) {
99
    //Check if import CSV file format is what expected
100
    case 'import_file_format_csv':
101
        // Check KEY and rights
102
        if ($post_key !== $_SESSION['key']) {
103
            echo prepareExchangedData(
104
                array(
105
                    'error' => true,
106
                    'message' => langHdl('key_is_not_correct'),
107
                ),
108
                'encode'
109
            );
110
            break;
111
        }
112
113
        //load full tree
114
        $tree->rebuild();
115
        $tree = $tree->getDescendants();
116
117
        // Init post variable
118
        $post_operation_id = filter_input(INPUT_POST, 'file', FILTER_SANITIZE_NUMBER_INT);
119
120
        // Get filename from database
121
        $data = DB::queryFirstRow(
122
            'SELECT valeur
123
            FROM '.prefixTable('misc').'
124
            WHERE increment_id = %i AND type = "temp_file"',
125
            $post_operation_id
126
        );
127
128
        // Delete operation id
129
        DB::delete(
130
            prefixTable('misc'),
131
            "increment_id = %i AND type = 'temp_file'",
132
            $post_operation_id
133
        );
134
135
        // do some initializations
136
        $file = $SETTINGS['path_to_files_folder'].'/'.$data['valeur'];
137
        $size = 4096;
138
        $separator = ',';
139
        $enclosure = '"';
140
        $fields_expected = array('Label', 'Login', 'Password', 'URL', 'Comments'); //requiered fields from CSV
141
        $importation_possible = true;
142
        $itemsArray = array();
143
        $line_number = 0;
144
        $account = $text = '';
145
        $continue_on_next_line = false;
146
147
        // Open file
148
        if ($fp = fopen($file, 'r')) {
149
            // data from CSV
150
            $valuesToImport = array();
151
            // load libraries
152
            include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Goodby/CSV/Import/Standard/Lexer.php';
153
            include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Goodby/CSV/Import/Standard/Interpreter.php';
154
            include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Goodby/CSV/Import/Standard/LexerConfig.php';
155
156
            // Lexer configuration
157
            $config = new LexerConfig();
158
            $lexer = new Lexer($config);
159
            $config->setIgnoreHeaderLine('true');
160
            // extract data from CSV file
161
            $interpreter = new Interpreter();
162
            $interpreter->addObserver(function (array $row) use (&$valuesToImport) {
163
                $valuesToImport[] = array(
164
                    'Label' => $row[0],
165
                    'Login' => $row[1],
166
                    'Password' => $row[2],
167
                    'url' => $row[3],
168
                    'Comments' => $row[4],
169
                );
170
            });
171
            $lexer->parse($file, $interpreter);
172
173
            // extract one line
174
            foreach ($valuesToImport as $key => $row) {
175
                //increment number of lines found
176
                ++$line_number;
177
178
                //Check number of fields. MUST be 5. if not stop importation
179
                if (count($row) != 5) {
180
                    $importation_possible = false;
181
                    //Stop if file has not expected structure
182
                    if ($importation_possible === false) {
183
                        echo '[{"error":"bad_structure"}]';
184
                        break;
185
                    }
186
                }
187
188
                //If any comment is on several lines, then replace 'lf' character
189
                $row['Comments'] = str_replace(array("\r\n", "\n", "\r"), '<br>', $row['Comments']);
190
191
                // Check if current line contains a "<br>" character in order to identify an ITEM on several CSV lines
192
                if (substr_count('<br>', $row['Comments']) > 0 || substr_count('<br>', $row['Label']) > 0) {
193
                    $continue_on_next_line = true;
194
                    $comment .= addslashes($row['Label']);
195
                } else {
196
                    // Store in variable values from previous line
197
                    if (empty($account) === false) {
198
                        if ($continue_on_next_line === false) {
199
                            // Prepare listing that will be shown to user
200
                            array_push(
201
                                $itemsArray,
202
                                array(
203
                                    'label' => $account,
204
                                    'login' => $login,
205
                                    'pwd' => $pwd,
206
                                    'url' => $url,
207
                                    'comment' => $comment,
208
                                    'label' => $account,
209
                                    'label' => $account,
210
                                )
211
                            );
212
213
                            // Initialize this variable in order to restart from scratch
214
                            $account = '';
215
                        }
216
                    }
217
                }
218
219
                // Get values of current line
220
                if ($account == '' && $continue_on_next_line === false) {
221
                    $account = trim(htmlspecialchars($row['Label'], ENT_QUOTES, 'UTF-8'));
222
                    $login = trim(htmlspecialchars($row['Login'], ENT_QUOTES, 'UTF-8'));
223
                    $pwd = trim(str_replace('"', '&quot;', $row['Password']));
224
                    $url = trim($row['url']);
225
                    $to_find = array('"', "'");
226
                    $to_ins = array('&quot', '&#39;');
227
                    $comment = htmlentities(
228
                        addslashes(str_replace($to_find, $to_ins, $row['Comments'])),
229
                        ENT_QUOTES,
230
                        'UTF-8'
231
                    );
232
233
                    $continue_on_next_line = false;
234
                }
235
            }
236
            // close file
237
            fclose($fp);
238
        } else {
239
            echo prepareExchangedData(
240
                array(
241
                    'error' => true,
242
                    'message' => langHdl('cannot_open_file'),
243
                ),
244
                'encode'
245
            );
246
247
            //delete file
248
            unlink($file);
249
            break;
250
        }
251
252
        if ($line_number > 0) {
253
            array_push(
254
                $itemsArray,
255
                array(
256
                    'label' => $account,
257
                    'login' => $login,
258
                    'pwd' => $pwd,
259
                    'url' => $url,
260
                    'comment' => $comment,
261
                    'label' => $account,
262
                    'label' => $account,
263
                )
264
            );
265
266
            // Show results to user.
267
            echo prepareExchangedData(
268
                array(
269
                    'error' => false,
270
                    'message' => '',
271
                    'output' => $itemsArray,
272
                    'number' => $line_number++,
273
                ),
274
                'encode'
275
            );
276
        }
277
278
        //delete file
279
        unlink($file);
280
281
        break;
282
283
    //Insert into DB the items the user has selected
284
    case 'import_items':
285
        // Check KEY and rights
286
        if ($post_key !== $_SESSION['key']) {
287
            echo prepareExchangedData(
288
                array(
289
                    'error' => true,
290
                    'message' => langHdl('key_is_not_correct'),
291
                ),
292
                'encode'
293
            );
294
            break;
295
        }
296
297
        // Init
298
        $list = [];
299
300
        // Decrypt and retreive data in JSON format
301
        $post_items = prepareExchangedData($post_data, 'decode');
302
303
        // Init post variable
304
        $post_folder = filter_input(INPUT_POST, 'folder', FILTER_SANITIZE_NUMBER_INT);
305
306
        // Get title for this folder
307
        $data_fld = DB::queryFirstRow(
308
            'SELECT title
309
            FROM '.prefixTable('nested_tree').'
310
            WHERE id = %i',
311
            $post_folder
312
        );
313
314
        //Get some info about personal folder
315
        if (in_array($post_folder, $_SESSION['personal_folders']) === true) {
316
            $personalFolder = 1;
317
        } else {
318
            $personalFolder = 0;
319
        }
320
321
        //Prepare variables
322
        //$listItems = json_decode($post_items, true);
323
324
        // Clean each array entry
325
        array_walk_recursive($post_items, 'cleanOutput');
0 ignored issues
show
Bug introduced by
$post_items of type string is incompatible with the type array expected by parameter $input of array_walk_recursive(). ( Ignorable by Annotation )

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

325
        array_walk_recursive(/** @scrutinizer ignore-type */ $post_items, 'cleanOutput');
Loading history...
326
327
        // Loop on array
328
        foreach ($post_items as $item) {
329
            //For each item, insert into DB
330
331
            //Encryption key
332
            if ($personalFolder == 1) {
333
                $encrypt = cryption(
334
                    $item['pwd'],
335
                    $_SESSION['user_settings']['session_psk'],
336
                    'encrypt',
337
                    $SETTINGS
338
                );
339
            } else {
340
                $encrypt = cryption(
341
                    $item['pwd'],
342
                    '',
343
                    'encrypt',
344
                    $SETTINGS
345
                );
346
            }
347
348
            // Insert new item in table ITEMS
349
            DB::insert(
350
                prefixTable('items'),
351
                array(
352
                    'label' => substr($item['label'], 0, 500),
353
                    'description' => empty($item['description']) === true ? '' : $item['description'],
354
                    'pw' => $encrypt['string'],
355
                    'pw_iv' => '',
356
                    'url' => empty($item['url']) === true ? '' : substr($item['url'], 0, 500),
357
                    'id_tree' => filter_input(INPUT_POST, 'folder', FILTER_SANITIZE_NUMBER_INT),
358
                    'login' => empty($item['login']) === true ? '' : substr($item['login'], 0, 200),
359
                    'anyone_can_modify' => filter_input(INPUT_POST, 'import_csv_anyone_can_modify', FILTER_SANITIZE_STRING) === 'true' ? 1 : 0,
360
                )
361
            );
362
            $newId = DB::insertId();
363
364
            //if asked, anyone in role can modify
365
            if (null !== filter_input(INPUT_POST, 'import_csv_anyone_can_modify_in_role', FILTER_SANITIZE_STRING)
366
                && filter_input(INPUT_POST, 'import_csv_anyone_can_modify_in_role', FILTER_SANITIZE_STRING) === 'true'
367
            ) {
368
                foreach ($_SESSION['arr_roles'] as $role) {
369
                    DB::insert(
370
                        prefixTable('restriction_to_roles'),
371
                        array(
372
                            'role_id' => $role['id'],
373
                            'item_id' => $newId,
374
                        )
375
                    );
376
                }
377
            }
378
379
            // Insert new item in table LOGS_ITEMS
380
            DB::insert(
381
                prefixTable('log_items'),
382
                array(
383
                    'id_item' => $newId,
384
                    'date' => time(),
385
                    'id_user' => $_SESSION['user_id'],
386
                    'action' => 'at_creation',
387
                )
388
            );
389
390
            array_push($list, $item['row']);
391
392
            //Add entry to cache table
393
            DB::insert(
394
                prefixTable('cache'),
395
                array(
396
                    'id' => $newId,
397
                    'label' => substr($item['label'], 0, 500),
398
                    'description' => empty($item['description']) ? '' : $item['description'],
399
                    'id_tree' => filter_input(INPUT_POST, 'folder', FILTER_SANITIZE_NUMBER_INT),
400
                    'url' => '0',
401
                    'perso' => $personalFolder == 0 ? 0 : 1,
402
                    'login' => empty($item['login']) ? '' : substr($item['login'], 0, 500),
403
                    'folder' => $data_fld['title'],
404
                    'author' => $_SESSION['user_id'],
405
                    'timestamp' => time(),
406
                    'tags' => '',
407
                    'restricted_to' => '0',
408
                    'renewal_period' => '0',
409
                    'timestamp' => time(),
410
                )
411
            );
412
        }
413
414
        echo prepareExchangedData(
415
            array(
416
                'error' => false,
417
                'message' => '',
418
                'items' => $list,
419
            ),
420
            'encode'
421
        );
422
        break;
423
424
    //Check if import KEEPASS file format is what expected
425
    case 'import_file_format_keepass':
426
        // Check KEY and rights
427
        if ($post_key !== $_SESSION['key']) {
428
            echo prepareExchangedData(
429
                array(
430
                    'error' => true,
431
                    'message' => langHdl('key_is_not_correct'),
432
                ),
433
                'encode'
434
            );
435
            break;
436
        }
437
438
        // Decrypt and retreive data in JSON format
439
        $receivedParameters = prepareExchangedData($post_data, 'decode');
440
441
        $post_folder_id = filter_var($receivedParameters['folder-id'], FILTER_SANITIZE_NUMBER_INT);
442
        $post_operation_id = filter_var($receivedParameters['file'], FILTER_SANITIZE_STRING);
443
        $post_edit_all = filter_var($receivedParameters['edit-all'], FILTER_SANITIZE_NUMBER_INT);
444
        $post_edit_role = filter_var($receivedParameters['edit-role'], FILTER_SANITIZE_NUMBER_INT);
445
446
        //Initialization
447
        $root = $meta = $group = $entry = $key = $title = $notes = $pwd = $username = $url = $notKeepassFile = $newItem = $history = $generatorFound = false;
448
        $name = $levelInProgress = $previousLevel = $fullPath = $historyLevel = $path = $display = $keepassVersion = '';
449
        $numGroups = $numItems = 0;
450
        $arrFolders = array();
451
        $temparray = array();
452
        $levelMin = 2;
453
        $foldersSeparator = '@&##&@';
454
        $itemsSeparator = '<=|#|=>';
455
        $lineEndSeparator = '@*1|#9*|@';
456
457
        //prepare CACHE files
458
        $cacheFileName = $SETTINGS['path_to_files_folder'].'/cpassman_cache_'.md5(time().mt_rand());
459
        $cacheFileNameFolder = $cacheFileName.'_folders';
460
        $cacheFile = fopen($cacheFileName, 'w');
461
        $cacheFileF = fopen($cacheFileNameFolder, 'w');
462
        $logFileName = '/keepassImport_'.date('YmdHis').'.log';
463
        $cacheLogFile = fopen($SETTINGS['path_to_files_folder'].$logFileName, 'w');
464
465
        // Get filename from database
466
        $data = DB::queryFirstRow(
467
            'SELECT valeur
468
            FROM '.prefixTable('misc').'
469
            WHERE increment_id = %i AND type = "temp_file"',
470
            $post_operation_id
471
        );
472
473
        // Delete operation id
474
        DB::delete(
475
            prefixTable('misc'),
476
            'increment_id = %i AND type = "temp_file"',
477
            $post_operation_id
478
        );
479
480
        // do some initializations
481
        $file = $data['valeur'];
482
483
        //read xml file
484
        if (file_exists($SETTINGS['path_to_files_folder'].'/'.$file)) {
485
            $xml = simplexml_load_file(
486
                $SETTINGS['path_to_files_folder'].'/'.$file
487
            );
488
        }
489
490
        /**
491
         ** Recursive function that will permit to read each level of XML nodes.
492
         */
493
        function recursiveKeepassXML($xmlRoot, $xmlLevel = 0)
494
        {
495
            global $meta, $root, $group, $name, $entry, $levelMin, $title, $notes, $pwd, $username, $url,
496
                $newItem, $history, $levelInProgress, $historyLevel, $temparray,
497
                $path, $previousLevel, $generatorFound, $cacheFile, $cacheFileF, $numGroups,
498
                $numItems, $foldersSeparator, $itemsSeparator, $keepassVersion, $arrFolders;
499
500
            $groupsArray = array();
501
            if (count($temparray) === 0) {
502
                $temparray = initTempArray();
503
            }
504
505
            // For each node, get the name and SimpleXML balise
506
            foreach ($xmlRoot as $nom => $elem) {
507
                /*
508
                * check if file is generated by keepass 1
509
                * key "pwentry" is only used in KP1.xx XML files
510
                */
511
                if ($nom == 'pwentry') {
512
                    if (empty($keepassVersion)) {
513
                        $keepassVersion = 1;
514
                        $generatorFound = true;
515
                        $entry = true;
516
                    } else {
517
                        $entry = true;
518
                    }
519
520
                    //get children
521
                    $xmlChildren = $elem->children();
522
523
                    //recursive call
524
                    recursiveKeepassXML($xmlChildren, $xmlLevel + 1);
525
                }
526
                //IMPORTING KEEPASS 1 XML FILE
527
                if ($keepassVersion == 1) {
528
                    if ($entry === true && $nom == 'expiretime') {
529
                        //save previous keepass entry
530
                        $tree = preg_replace('/\\\\/', $foldersSeparator, $temparray['tree']);
531
                        fputs(
532
                            $cacheFile,
533
                            $tree.$itemsSeparator.$temparray[KP_GROUP].$itemsSeparator.$temparray[KP_TITLE].
534
                            $itemsSeparator.$temparray[KP_PASSWORD].$itemsSeparator.$temparray[KP_USERNAME].
535
                            $itemsSeparator.$temparray[KP_URL].$itemsSeparator.$temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n"
536
                        );
537
538
                        if (!in_array($temparray['tree'], $arrFolders)) {
539
                            fwrite($cacheFileF, $tree."\n");
540
                            array_push($arrFolders, $temparray['tree']);
541
                        }
542
543
                        $temparray = initTempArray();
544
                        ++$newItem;
545
                    }
546
547
                    if ($entry === true && $nom == 'group') {
548
                        $temparray[KP_GROUP] = addslashes(preg_replace('#[\r\n]#', '', $elem));
549
                        foreach ($elem->attributes() as $attributeskey0 => $attributesvalue1) {
550
                            if ($attributeskey0 == 'tree') {
551
                                $path = explode('\\', $attributesvalue1);
552
                                if (count($path) > 1) {
553
                                    unset($path[0]);
554
                                    $temparray['tree'] = implode('\\', $path).'\\'.$temparray[KP_GROUP];
555
                                } else {
556
                                    $temparray['tree'] = $temparray[KP_GROUP];
557
                                }
558
                            }
559
                        }
560
                        ++$numGroups;
561
                    } elseif ($entry === true && $nom == 'title') {
562
                        $temparray[KP_TITLE] = sanitiseString($elem, '');
563
                    } elseif ($entry === true && $nom == 'username') {
564
                        $temparray[KP_USERNAME] = sanitiseString($elem, '');
565
                    } elseif ($entry === true && $nom == 'url') {
566
                        $temparray[KP_URL] = sanitiseString($elem, '');
567
                    } elseif ($entry === true && $nom == 'uuid') {
568
                        $temparray[KP_UUID] = addslashes(preg_replace('#[\r\n]#', '', $elem));
569
                    } elseif ($entry === true && $nom == 'password') {
570
                        $temparray[KP_PASSWORD] = sanitiseString($elem, '');
571
                    } elseif ($entry === true && $nom == 'notes') {
572
                        $temparray[KP_NOTES] = sanitiseString($elem, '');
573
                    }
574
                }
575
576
                /*
577
                   * check if file is generated by keepass 2
578
                */
579
                if (trim($elem) == '' && $keepassVersion != 1) {
580
                    //check if file is generated by keepass 2
581
                    if ($nom == 'Meta') {
582
                        $meta = true;
583
                    }
584
                    if ($nom == 'Root') {
585
                        $root = true;
586
                    }
587
588
                    if ($nom == 'Group') {
589
                        $group = true;
590
                        $entry = false;
591
                        $name = '';
592
593
                        // recap previous info
594
                        if (!empty($temparray[KP_TITLE])) {
595
                            //store data
596
                            fputs(
597
                                $cacheFile,
598
                                $temparray[KP_PATH].$itemsSeparator.$temparray[KP_GROUP].$itemsSeparator
599
                                .$temparray[KP_TITLE].$itemsSeparator.$temparray[KP_PASSWORD].$itemsSeparator
600
                                .$temparray[KP_USERNAME].$itemsSeparator.$temparray[KP_URL].$itemsSeparator.
601
                                $temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n"
602
                            );
603
604
                            //Clean temp array
605
                            $temparray = initTempArray();
606
607
                            //increment number
608
                            ++$numItems;
609
                        }
610
                        $historyLevel = 0;
611
                    }
612
613
                    //History node needs to be managed in order to not polluate final list
614
                    if ($nom == 'History') {
615
                        $history = true;
616
                        $entry = false;
617
                        $historyLevel = $xmlLevel;
618
                    }
619
620
                    if ($nom == 'Entry' && ($xmlLevel < $historyLevel || empty($historyLevel))) {
621
                        $entry = true;
622
                        $group = false;
623
                        $history = false;
624
625
                        // recap previous info
626
                        if (!empty($temparray[KP_TITLE])) {
627
                            //store data
628
                            fputs(
629
                                $cacheFile,
630
                                $temparray[KP_PATH].$itemsSeparator.$temparray[KP_GROUP].$itemsSeparator
631
                                .$temparray[KP_TITLE].$itemsSeparator.$temparray[KP_PASSWORD].$itemsSeparator
632
                                .$temparray[KP_USERNAME].$itemsSeparator.$temparray[KP_URL].$itemsSeparator
633
                                .$temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n"
634
                            );
635
636
                            //Clean temp array
637
                            $temparray = initTempArray();
638
639
                            //increment number
640
                            ++$numItems;
641
                        }
642
                        $historyLevel = 0;
643
                    }
644
645
                    //get children
646
                    $xmlChildren = $elem->children();
647
648
                    //recursive call
649
                    if ($history !== true) {
650
                        recursiveKeepassXML($xmlChildren, $xmlLevel + 1);
651
                    }
652
653
                    // Force History to false
654
                    $history = false;
655
656
                //IMPORTING KEEPASS 2 XML FILE
657
                } elseif ($keepassVersion != 1) {
658
                    // exit if XML file not generated by KeePass
659
                    if ($meta === true && $nom == 'Generator' && $elem == 'KeePass') {
660
                        $generatorFound = true;
661
                        $keepassVersion = 2;
662
                        break;
663
                    } elseif ($root === true && $xmlLevel > $levelMin) {
664
                        //echo $elem.' - '.$nom.' - ';
665
                        //Check each node name and get data from some of them
666
                        if ($entry === true && $nom == 'Key' && $elem == 'Title') {
667
                            $title = true;
668
                            $notes = $pwd = $url = $username = false;
669
                        } elseif ($entry === true && $nom == 'Key' && $elem == 'Notes') {
670
                            $notes = true;
671
                            $title = $pwd = $url = $username = false;
672
                        } elseif ($entry === true && $nom == 'UUID') {
673
                            $temparray[KP_UUID] = $elem;
674
                        } elseif ($entry === true && $nom == 'Key' && $elem == 'Password') {
675
                            $pwd = true;
676
                            $notes = $title = $url = $username = false;
677
                        } elseif ($entry === true && $nom == 'Key' && $elem == 'URL') {
678
                            $url = true;
679
                            $notes = $pwd = $title = $username = false;
680
                        } elseif ($entry === true && $nom == 'Key' && $elem == 'UserName') {
681
                            $username = true;
682
                            $notes = $pwd = $url = $title = false;
683
                        } elseif ($group === true && $nom == 'Name') {
684
                            $temparray[KP_GROUP] = addslashes(preg_replace('#[\r\n]#', '', $elem));
685
                            $temparray['level'] = $xmlLevel;
686
                            //build current path
687
                            if ($xmlLevel > $levelInProgress) {
688
                                if (!empty($temparray[KP_PATH])) {
689
                                    $temparray[KP_PATH] .= $foldersSeparator.$temparray[KP_GROUP];
690
                                } else {
691
                                    $temparray[KP_PATH] = $temparray[KP_GROUP];
692
                                }
693
                            } elseif ($xmlLevel == $levelInProgress) {
694
                                if ($levelInProgress == 3) {
695
                                    $temparray[KP_PATH] = $temparray[KP_GROUP];
696
                                } else {
697
                                    $temparray[KP_PATH] = substr($temparray[KP_PATH], 0, strrpos($temparray[KP_PATH], $foldersSeparator) + strlen($foldersSeparator)).$temparray[KP_GROUP];
698
                                }
699
                            } else {
700
                                $diff = abs($xmlLevel - $levelInProgress) + 1;
701
                                $tmp = explode($foldersSeparator, $temparray[KP_PATH]);
702
                                $temparray[KP_PATH] = '';
703
                                for ($x = 0; $x < (count($tmp) - $diff); ++$x) {
704
                                    if (!empty($temparray[KP_PATH])) {
705
                                        $temparray[KP_PATH] = $temparray[KP_PATH].$foldersSeparator.$tmp[$x];
706
                                    } else {
707
                                        $temparray[KP_PATH] = $tmp[$x];
708
                                    }
709
                                }
710
                                if (!empty($temparray[KP_PATH])) {
711
                                    $temparray[KP_PATH] .= $foldersSeparator.$temparray[KP_GROUP];
712
                                } else {
713
                                    $temparray[KP_PATH] = $temparray[KP_GROUP];
714
                                }
715
                            }
716
717
                            //store folders
718
                            if (!in_array($temparray[KP_PATH], $groupsArray)) {
719
                                fwrite($cacheFileF, $temparray[KP_PATH]."\n");
720
                                array_push($groupsArray, $temparray[KP_PATH]);
721
                                //increment number
722
                                ++$numGroups;
723
                            }
724
725
                            //Store actual level
726
                            $levelInProgress = $xmlLevel;
727
                            $previousLevel = $temparray[KP_GROUP];
728
                        } elseif ($title === true && $nom == 'Value') {
729
                            $title = false;
730
                            $temparray[KP_TITLE] = sanitiseString($elem, '');
731
                        } elseif ($notes === true && $nom == 'Value') {
732
                            $notes = false;
733
                            $temparray[KP_NOTES] = sanitiseString($elem, '');
734
                        } elseif ($pwd === true && $nom == 'Value') {
735
                            $pwd = false;
736
                            $temparray[KP_PASSWORD] = sanitiseString($elem, '');
737
                        } elseif ($url === true && $nom == 'Value') {
738
                            $url = false;
739
                            $temparray[KP_URL] = sanitiseString($elem, '');
740
                        } elseif ($username === true && $nom == 'Value') {
741
                            $username = false;
742
                            $temparray[KP_USERNAME] = sanitiseString($elem, '');
743
                        }
744
                    }
745
                }
746
            }
747
        }
748
749
        function initTempArray()
750
        {
751
            $temparray = array();
752
            $temparray[KP_PATH] = '';
753
            $temparray[KP_GROUP] = '';
754
            $temparray[KP_TITLE] = '';
755
            $temparray[KP_PASSWORD] = '';
756
            $temparray[KP_USERNAME] = '';
757
            $temparray[KP_URL] = '';
758
            $temparray[KP_UUID] = '';
759
            $temparray[KP_NOTES] = '';
760
761
            return $temparray;
762
        }
763
764
        fputs($cacheLogFile, date('H:i:s ').'Writing XML File '.filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING)."\n");
0 ignored issues
show
Bug introduced by
It seems like $cacheLogFile can also be of type false; however, parameter $handle of fputs() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

764
        fputs(/** @scrutinizer ignore-type */ $cacheLogFile, date('H:i:s ').'Writing XML File '.filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING)."\n");
Loading history...
765
766
        // Go through each node of XML file
767
        recursiveKeepassXML($xml);
768
769
        //Stop if not a keepass file
770
        if ($generatorFound === false) {
1 ignored issue
show
introduced by
The condition $generatorFound === false is always true.
Loading history...
771
            //Close file & delete it
772
            fclose($cacheFileF);
0 ignored issues
show
Bug introduced by
It seems like $cacheFileF can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

772
            fclose(/** @scrutinizer ignore-type */ $cacheFileF);
Loading history...
773
            fclose($cacheFile);
774
            unlink($cacheFileName);
775
            unlink($cacheFileNameFolder);
776
            unlink($SETTINGS['url_to_files_folder'].'/'.filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING));
777
778
            fputs($cacheLogFile, date('H:i').langHdl('import_error_no_read_possible_kp')."\n");
779
780
            echo prepareExchangedData(
781
                array(
782
                    'error' => true,
783
                    'message' => langHdl('import_error_no_read_possible_kp'),
784
                ),
785
                'encode'
786
            );
787
            break;
788
        }
789
790
        //save last item
791
        if (!empty($temparray[KP_TITLE])) {
792
            //store data
793
            fputs(
794
                $cacheFile,
795
                $temparray[KP_PATH].$itemsSeparator.$temparray[KP_GROUP].$itemsSeparator.
796
                $temparray[KP_TITLE].$itemsSeparator.$temparray[KP_PASSWORD].$itemsSeparator
797
                .$temparray[KP_USERNAME].$itemsSeparator.$temparray[KP_URL].$itemsSeparator
798
                .$temparray[KP_UUID].$itemsSeparator.$temparray[KP_NOTES]."\n"
799
            );
800
801
            //increment number
802
            ++$numItems;
803
        }
804
805
        //#################
806
        //# STARTING IMPORTING IF NO ERRORS OR NOT EMPTY
807
        //#################
808
        if ($numItems > 0 || $numGroups > 0) {
809
            // Write in file
810
            fputs($cacheLogFile, date('H:i:s ').langHdl('nb_folders').' '.$numGroups."\n");
811
            fputs($cacheLogFile, date('H:i:s ').langHdl('nb_items').' '.$numItems."\n");
812
813
            $import_perso = false;
814
            $itemsArray = array();
815
            $text = '<span class="fas fa-folder-open"></span>&nbsp;'.langHdl('nb_folders').': '.
816
                $numGroups.'<br><span class="fas fa-tag"></span>>&nbsp;'.langHdl('nb_items').': '.
817
                $numItems.'<br><br>';
818
819
            // If destination is not ROOT then get the complexity level
820
            if (in_array($post_folder_id, $_SESSION['personal_folders']) === true) {
821
                $levelPwComplexity = 50;
822
                $startPathLevel = 1;
823
                $import_perso = true;
824
            } elseif ($post_folder_id > 0) {
825
                $data = DB::queryFirstRow(
826
                    'SELECT m.valeur as value, t.nlevel as nlevel
827
                    FROM '.prefixTable('misc').' as m
828
                    INNER JOIN '.prefixTable('nested_tree').' as t ON (m.intitule = t.id)
829
                    WHERE m.type = %s AND m.intitule = %s',
830
                    'complex',
831
                    $post_folder_id
832
                );
833
                $levelPwComplexity = $data['value'];
834
                $startPathLevel = $data['nlevel'];
835
            } else {
836
                $levelPwComplexity = 50;
837
                $startPathLevel = 0;
838
            }
839
840
            //Get all folders from file
841
            fclose($cacheFileF);
842
            $cacheFileF = fopen($cacheFileNameFolder, 'r');
843
844
            //Create folders
845
            $i = 1;
846
            $level = 0;
847
            $foldersArray = array();
848
            $nbFoldersImported = 0;
849
850
            fputs($cacheLogFile, date('H:i:s ')."Creating Folders\n");
851
            $results = "Folders\n\n";
852
853
            while (!feof($cacheFileF)) {
854
                $folder = fgets($cacheFileF, 4096);
855
                if (!empty($folder)) {
856
                    $folder = str_replace(array("\r\n", "\n", "\r"), '', $folder);
857
                    //get number of levels in path
858
                    $path = explode($foldersSeparator, $folder);
859
                    $folderLevel = count($path);
860
861
                    //get folder name
862
                    if (strrpos($folder, $foldersSeparator) > 0) {
863
                        $fold = substr($folder, strrpos($folder, $foldersSeparator) + strlen($foldersSeparator));
864
                        $parent = implode($foldersSeparator, array_slice($path, 0, -1));
865
                        $parent_id = $foldersArray[$parent]['id'];
866
                    } else {
867
                        $fold = $folder;
868
                        $parent_id = $post_folder_id; //permits to select the folder destination
869
                    }
870
871
                    $fold = stripslashes($fold);
872
                    //create folder - if not exists at the same level
873
                    DB::query(
874
                        'SELECT * FROM '.prefixTable('nested_tree').'
875
                        WHERE nlevel = %i AND title = %s AND parent_id = %i LIMIT 1',
876
                        intval($folderLevel + $startPathLevel),
877
                        $fold,
878
                        $parent_id
879
                    );
880
                    $results .= str_replace($foldersSeparator, '\\', $folder);
881
                    $counter = DB::count();
882
                    if ($counter == 0) {
883
                        $results .= " - Inserting\n";
884
                        //do query
885
                        DB::insert(
886
                            prefixTable('nested_tree'),
887
                            array(
888
                                'parent_id' => $parent_id,
889
                                'title' => stripslashes($fold),
890
                                'nlevel' => $folderLevel,
891
                            )
892
                        );
893
                        $id = DB::insertId();
894
                        //Add complexity level => level is set to "medium" by default.
895
                        DB::insert(
896
                            prefixTable('misc'),
897
                            array(
898
                                'type' => 'complex',
899
                                'intitule' => $id,
900
                                'valeur' => $levelPwComplexity,
901
                            )
902
                        );
903
904
                        //For each role to which the user depends on, add the folder just created.
905
                        foreach ($_SESSION['arr_roles'] as $role) {
906
                            DB::insert(
907
                                prefixTable('roles_values'),
908
                                array(
909
                                    'role_id' => $role['id'],
910
                                    'folder_id' => $id,
911
                                    'type' => 'W',
912
                                )
913
                            );
914
                        }
915
916
                        //Add this new folder to the list of visible folders for the user.
917
                        array_push($_SESSION['groupes_visibles'], $id);
918
919
                        //increment number of imported folders
920
                        ++$nbFoldersImported;
921
                    } else {
922
                        $results .= " - Skipped\n";
923
                        //get folder actual ID
924
                        $data = DB::queryFirstRow(
925
                            'SELECT id FROM '.prefixTable('nested_tree').'
926
                            WHERE nlevel = %i AND title = %s AND parent_id = %i',
927
                            intval($folderLevel + $startPathLevel),
928
                            $fold,
929
                            $parent_id
930
                        );
931
                        $id = $data['id'];
932
                    }
933
934
                    //store in array
935
                    $foldersArray[$folder] = array(
936
                        'folder' => $fold,
937
                        'nlevel' => $folderLevel,
938
                        'id' => $id,
939
                    );
940
941
                    ++$_SESSION['nb_folders'];
942
                    ++$i;
943
                }
944
            }
945
946
            $results .= "\n\nItems\n\n";
947
            //if no new folders them inform
948
            if ($nbFoldersImported > 0) {
949
                fputs($cacheLogFile, date('H:i:s ')."Setting User Rights\n");
950
                //Refresh the rights of actual user
951
                identifyUserRights(
952
                    implode(';', $_SESSION['groupes_visibles']).';'.$id,
953
                    $_SESSION['groupes_interdits'],
954
                    $_SESSION['is_admin'],
955
                    $_SESSION['fonction_id'],
956
                    $SETTINGS
957
                );
958
959
                fputs($cacheLogFile, date('H:i:s ')."Rebuilding Tree\n");
960
                //rebuild full tree
961
                $tree->rebuild();
962
            }
963
964
            fputs($cacheLogFile, date('H:i:s ')."Importing Items\n");
965
966
            // Now import ITEMS
967
            $nbItemsImported = 0;
968
            $count = 0;
969
970
            //Get some info about personal folder
971
            if (in_array($post_folder_id, $_SESSION['personal_folders']) === true) {
972
                $personalFolder = 1;
973
            } else {
974
                $personalFolder = 0;
975
            }
976
977
            //prepare file to be read
978
            fclose($cacheFile);
979
            $cacheFile = fopen($cacheFileName, 'r');
980
981
            while (!feof($cacheFile)) {
982
                //prepare an array with item to import
983
                $full_item = fgets($cacheFile, 8192);
984
                $full_item = str_replace(array("\r\n", "\n", "\r"), '', $full_item);
985
                $item = explode($itemsSeparator, $full_item);
986
987
                ++$count;
988
                if (!($count % 10)) {
989
                    fputs($cacheLogFile, date('H:i:s ')."  Imported $count items (".number_format(($count / $numItems) * 100, 1).")\n");
990
                }
991
992
                if (!empty($item[KP_TITLE])) {
993
                    //$count++;
994
                    //check if not exists
995
                    $results .= str_replace($foldersSeparator, '\\', $item[KP_PATH]).'\\'.$item[KP_TITLE];
996
997
                    $pwd = $item[KP_PASSWORD];
998
999
                    //Get folder label
1000
                    if (count($foldersArray) == 0 || empty($item[KP_PATH])) {
1001
                        $folderId = $post_folder_id;
1002
                    } else {
1003
                        $folderId = $foldersArray[$item[KP_PATH]]['id'];
1004
                    }
1005
                    $data = DB::queryFirstRow(
1006
                        'SELECT title FROM '.prefixTable('nested_tree').' WHERE id = %i',
1007
                        intval($folderId)
1008
                    );
1009
1010
                    // escape if folderId is empty
1011
                    if (!empty($folderId)) {
1012
                        $results .= " - Inserting\n";
1013
1014
                        // prepare PW
1015
                        if ($import_perso === true) {
1016
                            $encrypt = cryption(
1017
                                $pwd,
1018
                                $_SESSION['user_settings']['session_psk'],
1019
                                'encrypt',
1020
                                $SETTINGS
1021
                            );
1022
                        } else {
1023
                            $encrypt = cryption(
1024
                                $pwd,
1025
                                '',
1026
                                'encrypt',
1027
                                $SETTINGS
1028
                            );
1029
                        }
1030
1031
                        //ADD item
1032
                        DB::insert(
1033
                            prefixTable('items'),
1034
                            array(
1035
                                'label' => substr(stripslashes($item[KP_TITLE]), 0, 500),
1036
                                'description' => stripslashes(str_replace($lineEndSeparator, '<br>', $item[KP_NOTES])),
1037
                                'pw' => $encrypt['string'],
1038
                                'pw_iv' => '',
1039
                                'url' => substr(stripslashes($item[KP_URL]), 0, 500),
1040
                                'id_tree' => $folderId,
1041
                                'login' => substr(stripslashes($item[KP_USERNAME]), 0, 500),
1042
                                'anyone_can_modify' => $post_edit_all,
1043
                            )
1044
                        );
1045
                        $newId = DB::insertId();
1046
1047
                        //if asked, anyone in role can modify
1048
                        if ($post_edit_role === 1) {
1049
                            foreach ($_SESSION['arr_roles'] as $role) {
1050
                                DB::insert(
1051
                                    prefixTable('restriction_to_roles'),
1052
                                    array(
1053
                                        'role_id' => $role['id'],
1054
                                        'item_id' => $newId,
1055
                                    )
1056
                                );
1057
                            }
1058
                        }
1059
1060
                        //Add log
1061
                        DB::insert(
1062
                            prefixTable('log_items'),
1063
                            array(
1064
                                'id_item' => $newId,
1065
                                'date' => time(),
1066
                                'id_user' => $_SESSION['user_id'],
1067
                                'action' => 'at_creation',
1068
                                'raison' => 'at_import',
1069
                            )
1070
                        );
1071
1072
                        //Add entry to cache table
1073
                        DB::insert(
1074
                            prefixTable('cache'),
1075
                            array(
1076
                                'id' => $newId,
1077
                                'label' => substr(stripslashes($item[KP_TITLE]), 0, 500),
1078
                                'description' => stripslashes(str_replace($lineEndSeparator, '<br>', $item[KP_NOTES])),
1079
                                'url' => substr(stripslashes($item[KP_URL]), 0, 500),
1080
                                'tags' => '',
1081
                                'id_tree' => $folderId,
1082
                                'perso' => $personalFolder == 0 ? 0 : 1,
1083
                                'login' => substr(stripslashes($item[KP_USERNAME]), 0, 500),
1084
                                'restricted_to' => '0',
1085
                                'folder' => $data['title'],
1086
                                'author' => $_SESSION['user_id'],
1087
                                'renewal_period' => '0',
1088
                                'timestamp' => time(),
1089
                            )
1090
                        );
1091
1092
                        //increment number of imported items
1093
                        ++$nbItemsImported;
1094
                    } else {
1095
                        $results .= ' - '.$item[KP_TITLE]." was not imported\n";
1096
                    }
1097
                    fputs($cacheLogFile, date('H:i:s ').' '.$results."\n");
1098
                }
1099
            }
1100
1101
            //SHow finished
1102
            $text = '<div class="row ml-3">'.
1103
                '<div class="col-12"><i class="far fa-hand-point-right fa-sm mr-2"></i>'.langHdl('number_of_folders_imported').': <b>'.$nbFoldersImported.'</b></div>'.
1104
                '<div class="col-12"><i class="far fa-hand-point-right fa-sm mr-2"></i>'.langHdl('number_of_items_imported').': <b>'.$nbItemsImported.'</b></div>'.
1105
                '</div>'.
1106
                '<div class="row col-12 ml-3 mt-3 font-weight-bold"><i class="fas fa-check fa-lg mr-2"></i>'.langHdl('import_kp_finished').'</div>';
1107
1108
            //Delete cache file
1109
            fclose($cacheFileF);
1110
            fclose($cacheFile);
1111
            fclose($cacheLogFile);
1112
            unlink($cacheFileName);
1113
            unlink($cacheFileNameFolder);
1114
            unlink($SETTINGS['path_to_files_folder'].'/'.$file);
1115
            unlink($SETTINGS['path_to_files_folder'].$logFileName);
1116
1117
            //Display all messages to user
1118
            echo prepareExchangedData(
1119
                array(
1120
                    'error' => false,
1121
                    'message' => '',
1122
                    'info' => $text,
1123
                ),
1124
                'encode'
1125
            );
1126
        } else {
1127
            echo prepareExchangedData(
1128
                array(
1129
                    'error' => true,
1130
                    'message' => langHdl('no_item_found'),
1131
                ),
1132
                'encode'
1133
            );
1134
        }
1135
        break;
1136
}
1137
1138
spl_autoload_register(function ($class) {
1139
    $prefix = 'League\\Csv\\';
1140
    $base_dir = __DIR__.'/src/';
1141
    $len = strlen($prefix);
1142
    if (strncmp($prefix, $class, $len) !== 0) {
1143
        // no, move to the next registered autoloader
1144
        return;
1145
    }
1146
    $relative_class = substr($class, $len);
1147
    $file = $base_dir.str_replace('\\', '/', $relative_class).'.php';
1148
    if (file_exists($file)) {
1149
        require $file;
1150
    }
1151
});
1152
1153
/**
1154
 * Used to format the string ready for insertion in to the database.
1155
 *
1156
 * @param string $str             String to clean
1157
 * @param string $crLFReplacement Replacement
1158
 *
1159
 * @return string
1160
 */
1161
function sanitiseString($str, $crLFReplacement)
1162
{
1163
    $str = preg_replace('#[\r\n]#', $crLFReplacement, $str);
1164
    $str = str_replace('\\', '&#92;', $str);
1165
    $str = str_replace('"', '&quot;', $str);
1166
    if (!empty($str)) {
1167
        addslashes($str);
1168
    }
1169
1170
    return $str;
1171
}
1172
1173
/**
1174
 * Clean array values.
1175
 *
1176
 * @param string $value String to clean
1177
 *
1178
 * @return string
1179
 */
1180
function cleanOutput(&$value)
1181
{
1182
    return htmlspecialchars_decode($value);
1183
}
1184