Passed
Push — development ( ee13b6...7c2d55 )
by Nils
04:34
created

api/functions.php (1 issue)

1
<?php
2
/**
3
 *
4
 * @file          (api)functions.php
5
 * @author        Nils Laumaillé
6
 * @version       2.1.0
7
 * @copyright     (c) 2009-2018 Nils Laumaillé
8
 * @licensing     GNU GPL-3.0
9
 * @link          http://www.teampass.net
10
 *
11
 * This library 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.
14
 */
15
16
$api_version = "2.0";
17
$_SESSION['CPM'] = 1;
18
require_once "../includes/config/include.php";
19
require_once "../sources/main.functions.php";
20
21
function get_ip()
22
{
23
    if (function_exists('apache_request_headers')) {
24
        $headers = apache_request_headers();
25
    } else {
26
        $headers = $_SERVER;
27
    }
28
    if (array_key_exists('X-Forwarded-For', $headers) && filter_var($headers['X-Forwarded-For'], FILTER_VALIDATE_IP)) {
29
        $the_ip = $headers['X-Forwarded-For'];
30
    } elseif (array_key_exists('HTTP_X_FORWARDED_FOR', $headers) && filter_var($headers['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP)) {
31
        $the_ip = $headers['HTTP_X_FORWARDED_FOR'];
32
    } else {
33
        $the_ip = filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP);
34
    }
35
    return $the_ip;
36
}
37
38
39
function teampass_api_enabled()
40
{
41
    teampass_connect();
42
    $response = DB::queryFirstRow(
43
        "SELECT `valeur` FROM ".prefix_table("misc")." WHERE type = %s AND intitule = %s",
44
        "admin",
45
        "api"
46
    );
47
    return $response['valeur'];
48
}
49
50
function teampass_whitelist()
51
{
52
    teampass_connect();
53
    $apiip_pool = teampass_get_ips();
54
    if (count($apiip_pool) > 0 && array_search(get_ip(), $apiip_pool) === false) {
55
        rest_error('IPWHITELIST');
56
    }
57
}
58
59
function teampass_connect()
60
{
61
    global $server, $user, $pass, $database, $link, $port, $encoding;
62
    require_once("../includes/config/settings.php");
63
    require_once('../includes/libraries/Database/Meekrodb/db.class.php');
64
    $pass = defuse_return_decrypted($pass);
65
    DB::$host = $server;
66
    DB::$user = $user;
67
    DB::$password = $pass;
68
    DB::$dbName = $database;
69
    DB::$port = $port;
70
    DB::$encoding = $encoding;
71
    DB::$error_handler = true;
72
    $link = mysqli_connect($server, $user, $pass, $database, $port);
73
    $link->set_charset($encoding);
74
}
75
76
function teampass_get_ips()
77
{
78
    $array_of_results = array();
79
    teampass_connect();
80
    $response = DB::query("select value from ".prefix_table("api")." WHERE type = %s", "ip");
81
    foreach ($response as $data) {
82
        array_push($array_of_results, $data['value']);
83
    }
84
85
    return $array_of_results;
86
}
87
88
function teampass_get_keys()
89
{
90
    teampass_connect();
91
    $response = array_unique(array_merge(
92
        DB::queryOneColumn("value", "select * from ".prefix_table("api")." WHERE type = %s", "key"),
93
        DB::queryOneColumn("user_api_key", "select * from ".prefix_table("users")."")
94
    ));
95
96
    // remove none value
97
    if (($key = array_search('none', $response)) !== false) {
98
        unset($response[$key]);
99
    }
100
101
    return $response;
102
}
103
104
function rest_head()
105
{
106
    header('HTTP/1.1 402 Payment Required');
107
}
108
109
function addToCacheTable($item_id)
110
{
111
    teampass_connect();
112
    // get data
113
    $data = DB::queryfirstrow(
114
        "SELECT i.label AS label, i.description AS description, i.id_tree AS id_tree, i.perso AS perso, i.restricted_to AS restricted_to, i.login AS login, i.id AS id
115
        FROM ".prefix_table("items")." AS i
116
        AND ".prefix_table("log_items")." AS l ON (l.id_item = i.id)
117
        WHERE i.id = %i
118
        AND l.action = %s",
119
        intval($item_id),
120
        at_creation
121
    );
122
123
    // Get all TAGS
124
    $tags = "";
125
    $data_tags = DB::query("SELECT tag FROM ".prefix_table("tags")." WHERE item_id=%i", $item_id);
126
    foreach ($data_tags as $itemTag) {
127
        if (!empty($itemTag['tag'])) {
128
            $tags .= $itemTag['tag']." ";
129
        }
130
    }
131
132
    // finaly update
133
    DB::insert(
134
        prefix_table("cache"),
135
        array(
136
            "id" => $data['id'],
137
            "label" => $data['label'],
138
            "description" => $data['description'],
139
            "tags" => $tags,
140
            "id_tree" => $data['id_tree'],
141
            "perso" => $data['perso'],
142
            "restricted_to" => $data['restricted_to'],
143
            "login" => $data['login'],
144
            "folder" => "",
145
            //"restricted_to" => "0",
146
            "author" => API_USER_ID,
147
            "renewal_period" => 0,
148
            "timestamp" => time(),
149
            "url" => 0
150
        )
151
    );
152
}
153
154
155
/**
156
 * @param string $setting
157
 */
158
function getSettingValue($setting)
159
{
160
    // get default language
161
    $set = DB::queryFirstRow(
162
        "SELECT `valeur` FROM ".prefix_table("misc")." WHERE type = %s AND intitule = %s",
163
        "admin",
164
        $setting
165
    );
166
167
    return $set['valeur'];
168
}
169
170
function rest_delete()
171
{
172
    if (!@count($GLOBALS['request']) == 0) {
173
        $request_uri = $GLOBALS['_SERVER']['REQUEST_URI'];
174
        preg_match('/\/api(\/index.php|)\/(.*)\?apikey=(.*)/', $request_uri, $matches);
175
        if (count($matches) == 0) {
176
            rest_error('REQUEST_SENT_NOT_UNDERSTANDABLE');
177
        }
178
        $GLOBALS['request'] = explode('/', $matches[2]);
179
    }
180
    if (apikey_checker($GLOBALS['apikey'])) {
181
        include "../sources/main.functions.php";
182
        teampass_connect();
183
        $category_query = "";
184
185
        if ($GLOBALS['request'][0] == "write") {
186
            if ($GLOBALS['request'][1] == "category") {
187
                $array_category = explode(';', $GLOBALS['request'][2]);
188
189
                foreach ($array_category as $category) {
190
                    if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $category, $result)) {
191
                        rest_error('CATEGORY_MALFORMED');
192
                    }
193
                }
194
195
                if (count($array_category) > 1 && count($array_category) < 5) {
196
                    for ($i = count($array_category); $i > 0; $i--) {
197
                        $slot = $i - 1;
198
                        if (!$slot) {
199
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[$slot], FILTER_SANITIZE_STRING)."' AND parent_id = 0";
200
                        } else {
201
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[$slot], FILTER_SANITIZE_STRING)."' AND parent_id = (";
202
                        }
203
                    }
204
                    for ($i = 1; $i < count($array_category); $i++) {
205
                        $category_query .= ")";
206
                    }
207
                } elseif (count($array_category) == 1) {
208
                    $category_query = "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[0], FILTER_SANITIZE_STRING)."' AND parent_id = 0";
209
                } else {
210
                    rest_error('NO_CATEGORY');
211
                }
212
213
                // Delete items which in category
214
                $response = DB::delete(prefix_table("items"), "id_tree = (".$category_query.")");
215
                // Delete sub-categories which in category
216
                $response = DB::delete(prefix_table("nested_tree"), "parent_id = (".$category_query.")");
217
                // Delete category
218
                $response = DB::delete(prefix_table("nested_tree"), "id = (".$category_query.")");
219
220
                $json['type'] = 'category';
221
                $json['category'] = $GLOBALS['request'][2];
222
                if ($response) {
223
                    $json['status'] = 'OK';
224
                } else {
225
                    $json['status'] = 'KO';
226
                }
227
            } elseif ($GLOBALS['request'][1] == "item") {
228
                $array_category = explode(';', $GLOBALS['request'][2]);
229
                $item = $GLOBALS['request'][3];
230
231
                foreach ($array_category as $category) {
232
                    if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $category, $result)) {
233
                        rest_error('CATEGORY_MALFORMED');
234
                    }
235
                }
236
237
                if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $item, $result)) {
238
                    rest_error('ITEM_MALFORMED');
239
                } elseif (empty($item) || count($array_category) == 0) {
240
                    rest_error('MALFORMED');
241
                }
242
243
                if (count($array_category) > 1 && count($array_category) < 5) {
244
                    for ($i = count($array_category); $i > 0; $i--) {
245
                        $slot = $i - 1;
246
                        if (!$slot) {
247
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[$slot], FILTER_SANITIZE_STRING)."' AND parent_id = 0";
248
                        } else {
249
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[$slot], FILTER_SANITIZE_STRING)."' AND parent_id = (";
250
                        }
251
                    }
252
                    for ($i = 1; $i < count($array_category); $i++) {
253
                        $category_query .= ")";
254
                    }
255
                } elseif (count($array_category) == 1) {
256
                    $category_query = "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[0], FILTER_SANITIZE_STRING)."' AND parent_id = 0";
257
                } else {
258
                    rest_error('NO_CATEGORY');
259
                }
260
261
                // Delete item
262
                $response = DB::delete(prefix_table("items"), "id_tree = (".$category_query.") and label LIKE '".filter_var($item, FILTER_SANITIZE_STRING)."'");
263
                $json['type'] = 'item';
264
                $json['item'] = $item;
265
                $json['category'] = $GLOBALS['request'][2];
266
                if ($response) {
267
                    $json['status'] = 'OK';
268
                } else {
269
                    $json['status'] = 'KO';
270
                }
271
            }
272
273
            if ($json) {
274
                echo json_encode($json);
275
            } else {
276
                rest_error('EMPTY');
277
            }
278
        } else {
279
            rest_error('METHOD');
280
        }
281
    }
282
}
283
284
function rest_get()
285
{
286
    global $api_version;
287
    global $SETTINGS;
288
289
    if (!@count($GLOBALS['request']) == 0) {
290
        $request_uri = $GLOBALS['_SERVER']['REQUEST_URI'];
291
        preg_match('/\/api(\/index.php|)\/(.*)\?apikey=(.*)/', $request_uri, $matches);
292
        if (count($matches) == 0) {
293
            rest_error('REQUEST_SENT_NOT_UNDERSTANDABLE');
294
        }
295
        $GLOBALS['request'] = explode('/', $matches[2]);
296
    }
297
298
    if (apikey_checker($GLOBALS['apikey'])) {
299
300
        teampass_connect();
301
302
        // define the API user through the LABEL of apikey
303
        $api_info = DB::queryFirstRow(
304
            "SELECT label
305
            FROM ".prefix_table("api")."
306
            WHERE value = %s",
307
            $GLOBALS['apikey']
308
        );
309
310
        // Load config
311
        if (file_exists('../includes/config/tp.config.php')) {
312
            require_once '../includes/config/tp.config.php';
313
        } else {
314
            throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
315
        }
316
317
        if ($GLOBALS['request'][0] == "read") {
318
            if ($GLOBALS['request'][1] == "folder") {
319
                /*
320
                * READ FOLDERS
321
                */
322
323
                // load library
324
                require_once '../sources/SplClassLoader.php';
325
                //Load Tree
326
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
327
                $tree->register();
328
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
329
330
                // get ids
331
                if (strpos($GLOBALS['request'][2], ";") > 0) {
332
                    $condition = "id_tree IN %ls";
333
                    $condition_value = explode(';', $GLOBALS['request'][2]);
334
                } else {
335
                    $condition = "id_tree = %s";
336
                    $condition_value = $GLOBALS['request'][2];
337
                }
338
339
                // get items in this folder
340
                $response = DB::query(
341
                    "SELECT id, label, login, pw, pw_iv, url, id_tree, description, email
342
                    FROM ".prefix_table("items")."
343
                    WHERE inactif='0' AND ".$condition,
344
                    $condition_value
345
                );
346
                $inc = 0;
347
                foreach ($response as $data) {
348
                    // build the path to the Item
349
                    $path = "";
350
                    $arbo = $tree->getPath($data['id_tree'], true);
351
                    foreach ($arbo as $elem) {
352
                        if (empty($path)) {
353
                            $path = stripslashes($elem->title);
354
                        } else {
355
                            $path .= " > ".stripslashes($elem->title);
356
                        }
357
                    }
358
359
                    // prepare output
360
                    $json[$inc]['id'] = $data['id'];
361
                    $json[$inc]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
362
                    $json[$inc]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
363
                    $json[$inc]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
364
                    $json[$inc]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
365
                    $json[$inc]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
366
                    $crypt_pw = cryption(
367
                        $data['pw'],
368
                        "",
369
                        "decrypt"
370
                    );
371
                    $json[$inc]['pw'] = $crypt_pw['string'];
372
                    $json[$inc]['folder_id'] = $data['id_tree'];
373
                    $json[$inc]['path'] = $path;
374
375
                    $inc++;
376
                }
377
            } elseif ($GLOBALS['request'][1] == "userpw") {
378
                /*
379
                * READ USER ITEMS
380
                */
381
382
                // load library
383
                require_once '../sources/SplClassLoader.php';
384
                //Load Tree
385
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
386
                $tree->register();
387
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
388
389
                // about the user
390
                $username = $GLOBALS['request'][2];
391
                if (strcmp($username, "admin") == 0) {
392
                    // forbid admin access
393
                }
394
                $response = DB::query(
395
                    "SELECT fonction_id
396
                    FROM ".prefix_table("users")."
397
                    WHERE login = %s'",
398
                    $username
399
                );
400
                if (count($response) === 0) {
401
                    rest_error('USER_NOT_EXISTS');
402
                }
403
                foreach ($response as $data) {
404
                    $role_str = $data['fonction_id'];
405
                }
406
                $folder_arr = array();
407
                $roles = explode(";", $role_str);
408
                foreach ($roles as $role) {
409
                    $response = DB::query(
410
                        "SELECT folder_id
411
                        FROM ".prefix_table("roles_values")."
412
                        WHERE role_id = %i",
413
                        $role
414
                    );
415
                    foreach ($response as $data) {
416
                        $folder_id = $data['folder_id'];
417
                        if (!array_key_exists($folder_id, $folder_arr)) {
418
                            array_push($folder_arr, $folder_id);
419
                        }
420
                    }
421
                }
422
                $folder_str = array_filter($folder_arr);
423
424
                // get ids
425
                if (is_array($folder_str)) {
426
                    $condition = "id_tree IN %ls";
427
                    $condition_value = $folder_str;
428
                } else {
429
                    $condition = "id_tree = %s";
430
                    $condition_value = $folder_str;
431
                }
432
433
                $data = "";
434
                // get items in this module
435
                $response = DB::query(
436
                    "SELECT id,label,url,login,pw, pw_iv, url, id_tree, description, email
437
                    FROM ".prefix_table("items")."
438
                    WHERE inactif='0' AND ".$condition,
439
                    $condition_value
440
                );
441
                $inc = 0;
442
                foreach ($response as $data) {
443
                    // build the path to the Item
444
                    $path = "";
445
                    $arbo = $tree->getPath($data['id_tree'], true);
446
                    foreach ($arbo as $elem) {
447
                        if (empty($path)) {
448
                            $path = stripslashes($elem->title);
449
                        } else {
450
                            $path .= " > ".stripslashes($elem->title);
451
                        }
452
                    }
453
454
                    // prepare output
455
                    $json[$data['id']]['id'] = $data['id'];
456
                    $json[$data['id']]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
457
                    $json[$data['id']]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
458
                    $json[$data['id']]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
459
                    $json[$data['id']]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
460
                    $json[$data['id']]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
461
                    $crypt_pw = cryption($data['pw'], "", "decrypt");
462
                    $json[$data['id']]['pw'] = $crypt_pw['string'];
463
                    $json[$data['id']]['folder_id'] = $data['id_tree'];
464
                    $json[$data['id']]['path'] = $path;
465
466
                    $inc++;
467
                }
468
            } elseif ($GLOBALS['request'][1] == "userfolders") {
469
                /*
470
                * READ USER FOLDERS
471
                * Sends back a list of folders
472
                */
473
                $json = "";
474
                $username = $GLOBALS['request'][2];
475
                if (strcmp($username, "admin") == 0) {
476
                    // forbid admin access
477
                }
478
                $response = DB::query(
479
                    "SELECT fonction_id
480
                    FROM ".prefix_table("users")."
481
                    WHERE login = %s",
482
                    $username
483
                );
484
                if (count($response) === 0) {
485
                    rest_error('USER_NOT_EXISTS');
486
                }
487
                foreach ($response as $data) {
488
                    $role_str = $data['fonction_id'];
489
                }
490
491
                $folder_arr = array();
492
                $roles = explode(";", $role_str);
493
                $inc = 0;
494
                foreach ($roles as $role) {
495
                    $response = DB::query(
496
                        "SELECT folder_id, type
497
                        FROM ".prefix_table("roles_values")."
498
                        WHERE role_id = %i",
499
                        $role
500
                    );
501
                    foreach ($response as $data) {
502
                        $folder_id = $data['folder_id'];
503
                        if (!array_key_exists($folder_id, $folder_arr)) {
504
                            array_push($folder_arr, $folder_id);
505
506
                            $response2 = DB::queryFirstRow(
507
                                "SELECT title, nlevel
508
                                FROM ".prefix_table("nested_tree")."
509
                                WHERE id = %i",
510
                                $folder_id
511
                            );
512
513
                            if (!empty($response2['title'])) {
514
                                $json[$folder_id]['id'] = $folder_id;
515
                                $json[$folder_id]['title'] = $response2['title'];
516
                                $json[$folder_id]['level'] = $response2['nlevel'];
517
                                $json[$folder_id]['access_type'] = $data['type'];
518
                                $inc++;
519
                            }
520
                        }
521
                    }
522
                }
523
            } elseif ($GLOBALS['request'][1] == "items") {
524
                /*
525
                * READ ITEMS asked
526
                */
527
528
                // load library
529
                require_once '../sources/SplClassLoader.php';
530
                //Load Tree
531
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
532
                $tree->register();
533
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
534
535
                // get parameters
536
                $array_items = explode(';', $GLOBALS['request'][2]);
537
538
                // check if not empty
539
                if (count($array_items) == 0) {
540
                    rest_error('NO_ITEM');
541
                }
542
543
                // only accepts numeric
544
                foreach ($array_items as $item) {
545
                    if (!is_numeric($item)) {
546
                        rest_error('ITEM_MALFORMED');
547
                    }
548
                }
549
550
                $response = DB::query(
551
                    "SELECT id,label,login,pw, pw_iv, url, id_tree, description, email
552
                    FROM ".prefix_table("items")."
553
                    WHERE inactif = %i AND id IN %ls",
554
                    "0",
555
                    $array_items
556
                );
557
                $inc = 0;
558
                foreach ($response as $data) {
559
                    // build the path to the Item
560
                    $path = "";
561
                    $arbo = $tree->getPath($data['id_tree'], true);
562
                    foreach ($arbo as $elem) {
563
                        if (empty($path)) {
564
                            $path = stripslashes($elem->title);
565
                        } else {
566
                            $path .= " > ".stripslashes($elem->title);
567
                        }
568
                    }
569
570
                    // prepare output
571
                    $json[$inc]['id'] = $data['id'];
572
                    $json[$inc]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
573
                    $json[$inc]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
574
                    $json[$inc]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
575
                    $json[$inc]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
576
                    $json[$inc]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
577
                    $crypt_pw = cryption($data['pw'], "", "decrypt");
578
                    $json[$inc]['pw'] = $crypt_pw['string'];
579
                    $json[$inc]['folder_id'] = $data['id_tree'];
580
                    $json[$inc]['path'] = $path;
581
582
                    $inc++;
583
                }
584
            } elseif ($GLOBALS['request'][1] == "folder_descendants") {
585
                /*
586
                * PRovide full list of folders
587
                * <url to teampass>/api/index.php/read/folder_descendants/<id OR title>/<folder_id or folder_title>?apikey=<valid api key>
588
                */
589
590
                // get parameters
591
                if (isset($GLOBALS['request'][2]) === true && isset($GLOBALS['request'][3]) === true) {
592
                    // load library
593
                    require_once '../sources/SplClassLoader.php';
594
                    //Load Tree
595
                    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
596
                    $tree->register();
597
                    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
598
599
                    // get parameters
600
                    $parameter_by = $GLOBALS['request'][2];
601
                    $parameter_criteria = $GLOBALS['request'][3];
602
603
                    // Check data consistency
604
                    if (preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $parameter_by, $result) === false) {
605
                        rest_error('MALFORMED');
606
                    }
607
608
                    if (preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $parameter_criteria, $result) === false) {
609
                        rest_error('MALFORMED');
610
                    }
611
612
                    // Is BY criteria correct
613
                    if ($parameter_by !== "id" && $parameter_by !== "title") {
614
                        rest_error('EXPECTED_PARAMETER_NOT_PROVIDED');
615
                    }
616
617
                    // If criteria is by Title
618
                    // Then search its id first
619
                    if ($parameter_by === "title") {
620
                        $response = DB::queryFirstRow(
621
                            "SELECT id
622
                            FROM ".prefix_table("nested_tree")."
623
                            WHERE
624
                            title LIKE %s",
625
                            $parameter_criteria
626
                        );
627
                        $parameter_criteria = $response['id'];
628
                    }
629
630
                    // List folder descendants
631
                    $folders = $tree->getDescendants(intval($parameter_criteria), true, false, false);
632
                    if (count($folders) > 0) {
633
                        $inc = 0;
634
                        foreach ($folders as $folder) {
635
                            // Prepare answer
636
                            $json[$inc]['id'] = mb_convert_encoding($folder->id, mb_detect_encoding($folder->id), 'UTF-8');
637
                            $json[$inc]['parent_id'] = mb_convert_encoding($folder->parent_id, mb_detect_encoding($folder->parent_id), 'UTF-8');
638
                            $json[$inc]['title'] = mb_convert_encoding(htmlspecialchars_decode($folder->title, ENT_QUOTES), mb_detect_encoding($folder->title), 'UTF-8');
639
                            $json[$inc]['nleft'] = mb_convert_encoding($folder->nleft, mb_detect_encoding($folder->nleft), 'UTF-8');
640
                            $json[$inc]['nright'] = mb_convert_encoding($folder->nright, mb_detect_encoding($folder->nright), 'UTF-8');
641
                            $json[$inc]['nlevel'] = mb_convert_encoding($folder->nlevel, mb_detect_encoding($folder->nlevel), 'UTF-8');
642
                            $json[$inc]['personal'] = mb_convert_encoding($folder->personal_folder, mb_detect_encoding($folder->personal_folder), 'UTF-8');
643
644
                            $inc ++;
645
                        }
646
                    }
647
                }
648
            }
649
650
            if (isset($json) && $json) {
651
                echo json_encode($json);
652
            } else {
653
                rest_error('EMPTY');
654
            }
655
        } elseif ($GLOBALS['request'][0] == "find") {
656
            if ($GLOBALS['request'][1] == "item") {
657
                /*
658
                * FIND ITEMS in FOLDERS
659
                */
660
661
                // load library
662
                require_once '../sources/SplClassLoader.php';
663
                //Load Tree
664
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
665
                $tree->register();
666
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
667
668
                // get parameters
669
                $array_category = explode(';', $GLOBALS['request'][2]);
670
                $item = $GLOBALS['request'][3];
671
                foreach ($array_category as $category) {
672
                    if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $category, $result)) {
673
                        rest_error('CATEGORY_MALFORMED');
674
                    }
675
                }
676
677
                if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $item, $result)) {
678
                    rest_error('ITEM_MALFORMED');
679
                } elseif (empty($item) || count($array_category) == 0) {
680
                    rest_error('MALFORMED');
681
                }
682
683
                if (count($array_category) === 0) {
684
                    rest_error('NO_CATEGORY');
685
                }
686
687
                DB::debugMode(false);
688
                $response = DB::query(
689
                    "SELECT id, label, login, pw, pw_iv, url, id_tree, description, email
690
                    FROM ".prefix_table("items")."
691
                    WHERE
692
                    inactif = %i
693
                    AND id_tree IN %ls
694
                    AND label LIKE %ss",
695
                    "0",
696
                    $array_category,
697
                    $item
698
                );
699
                $inc = 0;
700
                foreach ($response as $data) {
701
                    // build the path to the Item
702
                    $path = "";
703
                    $arbo = $tree->getPath($data['id_tree'], true);
704
                    foreach ($arbo as $elem) {
705
                        if (empty($path)) {
706
                            $path = stripslashes($elem->title);
707
                        } else {
708
                            $path .= " > ".stripslashes($elem->title);
709
                        }
710
                    }
711
712
                    // prepare output
713
                    $json[$inc]['id'] = mb_convert_encoding($data['id'], mb_detect_encoding($data['id']), 'UTF-8');
714
                    $json[$inc]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
715
                    $json[$inc]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
716
                    $json[$inc]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
717
                    $json[$inc]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
718
                    $json[$inc]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
719
                    $crypt_pw = cryption($data['pw'], "", "decrypt");
720
                    $json[$inc]['pw'] = $crypt_pw['string'];
721
                    $json[$inc]['folder_id'] = $data['id_tree'];
722
                    $json[$inc]['path'] = $path;
723
                    $json[$inc]['status'] = utf8_encode("OK");
724
725
                    $inc++;
726
                }
727
                if (isset($json) && $json) {
728
                    echo json_encode($json);
729
                } else {
730
                    rest_error('EMPTY');
731
                }
732
            }
733
        } elseif ($GLOBALS['request'][0] == "add") {
734
            if ($GLOBALS['request'][1] == "item") {
735
                // get sent parameters
736
                $params = explode(';', base64_decode($GLOBALS['request'][2]));
737
                if (count($params) != 9) {
738
                    rest_error('ITEMBADDEFINITION');
739
                }
740
741
                $item_label = $params[0];
742
                $item_pwd = $params[1];
743
                $item_desc = $params[2];
744
                $item_folder_id = $params[3];
745
                $item_login = $params[4];
746
                $item_email = $params[5];
747
                $item_url = $params[6];
748
                $item_tags = $params[7];
749
                $item_anyonecanmodify = $params[8];
750
751
                // do some checks
752
                if (!empty($item_label) && !empty($item_pwd) && !empty($item_folder_id)) {
753
                    // Check length
754
                    if (strlen($item_pwd) > 50) {
755
                        rest_error('PASSWORDTOOLONG');
756
                    }
757
758
                    // Check Folder ID
759
                    DB::query("SELECT * FROM ".prefix_table("nested_tree")." WHERE id = %i", $item_folder_id);
760
                    $counter = DB::count();
761
                    if ($counter == 0) {
762
                        rest_error('NOSUCHFOLDER');
763
                    }
764
765
                    // check if element doesn't already exist
766
                    $item_duplicate_allowed = getSettingValue("duplicate_item");
767
                    if ($item_duplicate_allowed !== "1") {
768
                        DB::query(
769
                            "SELECT *
770
                            FROM ".prefix_table("items")."
771
                            WHERE label = %s AND inactif = %i",
772
                            addslashes($item_label),
773
                            "0"
774
                        );
775
                        $counter = DB::count();
776
                        if ($counter != 0) {
777
                            $itemExists = 1;
778
                            // prevent the error if the label already exists
779
                            // so lets just add the time() as a random factor
780
                            $item_label .= " (".time().")";
781
                        } else {
782
                            $itemExists = 0;
783
                        }
784
                    } else {
785
                        $itemExists = 0;
786
                    }
787
                    if ($itemExists === 0) {
788
                        $encrypt = cryption(
789
                            $item_pwd,
790
                            "",
791
                            "encrypt"
792
                        );
793
                        if (empty($encrypt['string'])) {
794
                            rest_error('PASSWORDEMPTY');
795
                        }
796
797
                        // ADD item
798
                        try {
799
                            DB::insert(
800
                                prefix_table("items"),
801
                                array(
802
                                    "label" => $item_label,
803
                                    "description" => $item_desc,
804
                                    'pw' => $encrypt['string'],
805
                                    'pw_iv' => '',
806
                                    "email" => $item_email,
807
                                    "url" => $item_url,
808
                                    "id_tree" => intval($item_folder_id),
809
                                    "login" => $item_login,
810
                                    "inactif" => 0,
811
                                    "restricted_to" => "",
812
                                    "perso" => 0,
813
                                    "anyone_can_modify" => intval($item_anyonecanmodify)
814
                                )
815
                            );
816
                            $newID = DB::InsertId();
817
818
                            // log
819
                            DB::insert(
820
                                prefix_table("log_items"),
821
                                array(
822
                                    "id_item" => $newID,
823
                                    "date" => time(),
824
                                    "id_user" => API_USER_ID,
825
                                    "action" => "at_creation",
826
                                    "raison" => $api_info['label']
827
                                )
828
                            );
829
830
                            // Add tags
831
                            $tags = explode(' ', $item_tags);
832
                            foreach ((array) $tags as $tag) {
833
                                if (!empty($tag)) {
834
                                    DB::insert(
835
                                        prefix_table("tags"),
836
                                        array(
837
                                            "item_id" => $newID,
838
                                            "tag" => strtolower($tag)
839
                                        )
840
                                    );
841
                                }
842
                            }
843
844
                            // Update CACHE table
845
                            DB::insert(
846
                                prefix_table("cache"),
847
                                array(
848
                                    "id" => $newID,
849
                                    "label" => $item_label,
850
                                    "description" => $item_desc,
851
                                    "tags" => $item_tags,
852
                                    "id_tree" => $item_folder_id,
853
                                    "perso" => "0",
854
                                    "restricted_to" => "",
855
                                    "login" => $item_login,
856
                                    "folder" => "",
857
                                    "author" => API_USER_ID,
858
                                    "renewal_period" => "0",
859
                                    "timestamp" => time(),
860
                                    "url" => "0"
861
                                )
862
                            );
863
864
                            echo '{"status":"item added" , "new_item_id" : "'.$newID.'"}';
865
                        } catch (PDOException $ex) {
866
                            echo '<br />'.$ex->getMessage();
867
                        }
868
                    } else {
869
                        rest_error('ITEMEXISTS');
870
                    }
871
                } else {
872
                    rest_error('ITEMMISSINGDATA');
873
                }
874
            } elseif ($GLOBALS['request'][1] == "user") {
875
            /*
876
             * Case where a new user has to be added
877
             *
878
             * Expected call format: .../api/index.php/add/user/<LOGIN>;<NAME>;<LASTNAME>;<PASSWORD>;<EMAIL>;<ADMINISTRATEDBY>;<READ_ONLY>;<ROLE1,ROLE2,...>;<IS_ADMIN>;<ISMANAGER>;<PERSONAL_FOLDER>?apikey=<VALID API KEY>
879
             * with:
880
             * for READ_ONLY, IS_ADMIN, IS_MANAGER, PERSONAL_FOLDER, accepted value is 1 for TRUE and 0 for FALSE
881
             * for ADMINISTRATEDBY and ROLE1, accepted value is the real label (not the IDs)
882
             *
883
             * Example: /api/index.php/add/user/U4;Nils;Laumaille;test;[email protected];Users;0;Managers,Users;0;1;1?apikey=sae6iekahxiseL3viShoo0chahc1ievei8aequi
884
             *
885
             */
886
887
                // get user definition
888
                $array_user = explode(';', base64_decode($GLOBALS['request'][2]));
889
                if (count($array_user) != 11) {
890
                    rest_error('USERBADDEFINITION');
891
                }
892
893
                $login = $array_user[0];
894
                $name = $array_user[1];
895
                $lastname = $array_user[2];
896
                $password = $array_user[3];
897
                $email = $array_user[4];
898
                $adminby = urldecode($array_user[5]);
899
                $isreadonly = urldecode($array_user[6]);
900
                $roles = urldecode($array_user[7]);
901
                $isadmin = $array_user[8];
902
                $ismanager = $array_user[9];
903
                $haspf = $array_user[10];
904
905
                // Empty user
906
                if (mysqli_escape_string($link, htmlspecialchars_decode($login)) == "") {
907
                    rest_error('USERLOGINEMPTY');
908
                }
909
                // Check if user already exists
910
                $data = DB::query(
911
                    "SELECT id, fonction_id, groupes_interdits, groupes_visibles
912
                    FROM ".prefix_table("users")."
913
                    WHERE login LIKE %ss",
914
                    mysqli_escape_string($link, stripslashes($login))
915
                );
916
917
                if (DB::count() == 0) {
918
                    try {
919
                        // find AdminRole code in DB
920
                        $resRole = DB::queryFirstRow(
921
                            "SELECT id
922
                            FROM ".prefix_table("roles_title")."
923
                            WHERE title LIKE %ss",
924
                            mysqli_escape_string($link, stripslashes($adminby))
925
                        );
926
927
                        // get default language
928
                        $lang = DB::queryFirstRow(
929
                            "SELECT `valeur`
930
                            FROM ".prefix_table("misc")."
931
                            WHERE type = %s AND intitule = %s",
932
                            "admin",
933
                            "default_language"
934
                        );
935
936
                        // prepare roles list
937
                        $rolesList = "";
938
                        foreach (explode(',', $roles) as $role) {
939
                            $tmp = DB::queryFirstRow(
940
                                "SELECT `id`
941
                                FROM ".prefix_table("roles_title")."
942
                                WHERE title = %s",
943
                                $role
944
                            );
945
                            if (empty($rolesList)) {
946
                                $rolesList = $tmp['id'];
947
                            } else {
948
                                $rolesList .= ";".$tmp['id'];
949
                            }
950
                        }
951
952
                        // Add user in DB
953
                        DB::insert(
954
                            prefix_table("users"),
955
                            array(
956
                                'login' => $login,
957
                                'name' => $name,
958
                                'lastname' => $lastname,
959
                                'pw' => bCrypt(stringUtf8Decode($password), COST),
960
                                'email' => $email,
961
                                'admin' => intval($isadmin),
962
                                'gestionnaire' => intval($ismanager),
963
                                'read_only' => intval($isreadonly),
964
                                'personal_folder' => intval($haspf),
965
                                'user_language' => $lang['valeur'],
966
                                'fonction_id' => $rolesList,
967
                                'groupes_interdits' => '0',
968
                                'groupes_visibles' => '0',
969
                                'isAdministratedByRole' => empty($resRole) ? '0' : $resRole['id']
970
                            )
971
                        );
972
                        $new_user_id = DB::insertId();
973
                        // Create personnal folder
974
                        if (intval($haspf) === 1) {
975
                            DB::insert(
976
                                prefix_table("nested_tree"),
977
                                array(
978
                                    'parent_id' => '0',
979
                                    'title' => $new_user_id,
980
                                    'bloquer_creation' => '0',
981
                                    'bloquer_modification' => '0',
982
                                    'personal_folder' => '1'
983
                                )
984
                            );
985
                        }
986
987
                        // load settings
988
                        loadSettings();
989
990
                        // Send email to new user
991
                        @sendEmail(
992
                            $LANG['email_subject_new_user'],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $LANG seems to be never defined.
Loading history...
993
                            str_replace(
994
                                array('#tp_login#', '#tp_pw#', '#tp_link#'),
995
                                array(" ".addslashes($login), addslashes($password), $SETTINGS['email_server_url']),
996
                                $LANG['email_new_user_mail']
997
                            ),
998
                            $email,
999
                            $LANG,
1000
                            $SETTINGS
1001
                        );
1002
1003
                        // update LOG
1004
                        logEvents('user_mngt', 'at_user_added', 'api - '.$GLOBALS['apikey'], $new_user_id, "");
1005
1006
                        echo '{"status":"user added"}';
1007
                    } catch (PDOException $ex) {
1008
                        echo '<br />'.$ex->getMessage();
1009
                    }
1010
                } else {
1011
                    rest_error('USERALREADYEXISTS');
1012
                }
1013
            } elseif ($GLOBALS['request'][1] == "folder") {
1014
            /*
1015
            * ADDING A FOLDER
1016
            * <url to teampass>/api/index.php/add/folder/<title>;<complexity_level>;<parent_id>;<renewal_period>;<personal>?apikey=<valid api key>
1017
            * http://localhost/teampass/api/index.php/add/folder/Import from API;0;38;0;0?apikey=piesae7ahghae1iiP9ohPhaefaideeThohgh1te
1018
            */
1019
                if (!empty($GLOBALS['request'][2])) {
1020
                    // get sent parameters
1021
                    $params = explode(';', base64_decode($GLOBALS['request'][2]));
1022
1023
                    if (empty($params[0]) === false && (intval($params[1]) >= 0 && intval($params[1]) <= 1000)) {
1024
                        if (empty($params[3])) {
1025
                            $params[3] = 0;
1026
                        }
1027
                        if (empty($params[4])) {
1028
                            $params[4] = 0;
1029
                        }
1030
                        if (empty($params[2])) {
1031
                            rest_error('NO_DESTINATION_FOLDER');
1032
                        }
1033
                        if ($params[2] < 0) {
1034
                            rest_error('NO_DATA_EXIST');
1035
                        }
1036
1037
                        //Check if title doesn't contains html codes
1038
                        if (preg_match_all("|<[^>]+>(.*)</[^>]+>|U", $params[0], $out)) {
1039
                            rest_error('HTML_CODES_NOT_ALLOWED');
1040
                        }
1041
1042
                        // check if title is numeric
1043
                        if (is_numeric($params[0]) === true) {
1044
                            rest_error('TITLE_ONLY_WITH_NUMBERS');
1045
                        }
1046
1047
                        //Check if duplicate folders name are allowed
1048
                        $data = DB::queryfirstrow(
1049
                            "SELECT valeur
1050
                            FROM ".prefix_table("misc")."
1051
                            WHERE type = %s AND intitule = %s",
1052
                            "admin",
1053
                            "duplicate_folder"
1054
                        );
1055
                        // if valeur = 0 then duplicate folders not allowed
1056
                        if ($data['valeur'] === '0') {
1057
                            DB::query(
1058
                                "SELECT *
1059
                                FROM ".prefix_table("nested_tree")."
1060
                                WHERE title = %s",
1061
                                $params[0]
1062
                            );
1063
                            $counter = DB::count();
1064
                            if ($counter != 0) {
1065
                                rest_error('ALREADY_EXISTS');
1066
                            }
1067
                        }
1068
1069
                        //check if parent folder is personal
1070
                        $data = DB::queryfirstrow(
1071
                            "SELECT personal_folder
1072
                            FROM ".prefix_table("nested_tree")."
1073
                            WHERE id = %i",
1074
                            $params[2]
1075
                        );
1076
                        if ($data['personal_folder'] === "1") {
1077
                            $isPersonal = 1;
1078
                        } else {
1079
                            if ($params[4] === 1) {
1080
                                $isPersonal = 1;
1081
                            } else {
1082
                                $isPersonal = 0;
1083
                            }
1084
1085
                            // get complexity level for this folder
1086
                            $data = DB::queryfirstrow(
1087
                                "SELECT valeur
1088
                                FROM ".prefix_table("misc")."
1089
                                WHERE intitule = %i AND type = %s",
1090
                                $params[2],
1091
                                "complex"
1092
                            );
1093
                            if (intval($params[1]) < intval($data['valeur'])) {
1094
                                rest_error('COMPLEXICITY_LEVEL_NOT_REACHED');
1095
                            }
1096
                        }
1097
1098
                        try {
1099
                            //create folder
1100
                            DB::insert(
1101
                                prefix_table("nested_tree"),
1102
                                array(
1103
                                    'parent_id' => $params[2],
1104
                                    'title' => $params[0],
1105
                                    'personal_folder' => $isPersonal,
1106
                                    'renewal_period' => $params[3],
1107
                                    'bloquer_creation' => '0',
1108
                                    'bloquer_modification' => '0'
1109
                                )
1110
                            );
1111
                            $newId = DB::insertId();
1112
1113
                            //Add complexity
1114
                            DB::insert(
1115
                                prefix_table("misc"),
1116
                                array(
1117
                                    'type' => 'complex',
1118
                                    'intitule' => $newId,
1119
                                    'valeur' => $params[1]
1120
                                )
1121
                            );
1122
1123
                            // Run nested tree update
1124
                            require_once '../sources/SplClassLoader.php';
1125
                            $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1126
                            $tree->register();
1127
                            $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
1128
                            $tree->rebuild();
1129
1130
                            // We need to allocate the same access rights as the parent
1131
                            // We will considere that if created as root then its rights must be set through the GUI
1132
                            $ret = DB::query(
1133
                                "SELECT role_id, type
1134
                                FROM ".prefix_table("roles_values")."
1135
                                WHERE folder_id = %i",
1136
                                $params[2]
1137
                            );
1138
                            foreach ($ret as $entry) {
1139
                                DB::insert(
1140
                                    prefix_table("roles_values"),
1141
                                    array(
1142
                                        'role_id' => $entry['role_id'],
1143
                                        'folder_id' => $newId,
1144
                                        'type' => $entry['type']
1145
                                    )
1146
                                );
1147
                            }
1148
1149
                            echo '{"status":"folder created" , "new_folder_id":"'.$newId.'"}';
1150
                        } catch (PDOException $ex) {
1151
                            echo '<br />'.$ex->getMessage();
1152
                        }
1153
                    } else {
1154
                        rest_error('NO_DATA_EXIST');
1155
                    }
1156
                } else {
1157
                    rest_error('SET_NO_DATA');
1158
                }
1159
            }
1160
        } elseif ($GLOBALS['request'][0] == "update") {
1161
            /*
1162
            * Section dedicated for UPDATING
1163
            */
1164
            if ($GLOBALS['request'][1] == "item") {
1165
                /*
1166
                * Expected call format: .../api/index.php/update/item/<item_id>/<label>;<password>;<description>;<folder_id>;<login>;<email>;<url>;<tags>;<any one can modify>?apikey=<VALID API KEY>
1167
                */
1168
                if ($GLOBALS['request'][2] !== "" && is_numeric($GLOBALS['request'][2])) {
1169
                    // get sent parameters
1170
                    $params = explode(';', base64_decode($GLOBALS['request'][3]));
1171
1172
                    if (!empty($params[0]) && !empty($params[1]) && !empty($params[3])) {
1173
                        // Check length
1174
                        if (strlen($params[1]) > 50) {
1175
                            rest_error('PASSWORDTOOLONG');
1176
                        }
1177
1178
                        // Check Folder ID
1179
                        DB::query(
1180
                            "SELECT *
1181
                            FROM ".prefix_table("nested_tree")."
1182
                            WHERE id = %i",
1183
                            $params[3]
1184
                        );
1185
                        $counter = DB::count();
1186
                        if ($counter == 0) {
1187
                            rest_error('NOSUCHFOLDER');
1188
                        }
1189
1190
                        // check if item exists
1191
                        DB::query(
1192
                            "SELECT *
1193
                            FROM ".prefix_table("items")."
1194
                            WHERE id = %i",
1195
                            $GLOBALS['request'][2]
1196
                        );
1197
                        $counter = DB::count();
1198
                        if ($counter > 0) {
1199
                            // encrypt pwd
1200
                            $encrypt = cryption(
1201
                                $params[1],
1202
                                "",
1203
                                "encrypt"
1204
                            );
1205
                            if (empty($encrypt['string'])) {
1206
                                rest_error('PASSWORDEMPTY');
1207
                            }
1208
1209
                            // ADD item
1210
                            try {
1211
                                DB::update(
1212
                                    prefix_table("items"),
1213
                                    array(
1214
                                        "label" => $params[0],
1215
                                        "description" => $params[2],
1216
                                        'pw' => $encrypt['string'],
1217
                                        'pw_iv' => '',
1218
                                        "email" => $params[5],
1219
                                        "url" => $params[6],
1220
                                        "id_tree" => intval($params[3]),
1221
                                        "login" => $params[4],
1222
                                        "anyone_can_modify" => intval($params[8])
1223
                                    ),
1224
                                    "id = %i",
1225
                                    $GLOBALS['request'][2]
1226
                                );
1227
1228
                                // log
1229
                                DB::insert(
1230
                                    prefix_table("log_items"),
1231
                                    array(
1232
                                        "id_item" => $GLOBALS['request'][2],
1233
                                        "date" => time(),
1234
                                        "id_user" => API_USER_ID,
1235
                                        "action" => "at_modification"
1236
                                    )
1237
                                );
1238
1239
                                // Add tags
1240
                                $tags = explode(' ', $params[7]);
1241
                                foreach ((array) $tags as $tag) {
1242
                                    if (!empty($tag)) {
1243
                                        // check if already exists
1244
                                        DB::query(
1245
                                            "SELECT *
1246
                                            FROM ".prefix_table("tags")."
1247
                                            WHERE tag = %s AND item_id = %i",
1248
                                            strtolower($tag),
1249
                                            $GLOBALS['request'][2]
1250
                                        );
1251
                                        $counter = DB::count();
1252
                                        if ($counter === 0) {
1253
                                            DB::insert(
1254
                                                prefix_table("tags"),
1255
                                                array(
1256
                                                    "item_id" => $GLOBALS['request'][2],
1257
                                                    "tag" => strtolower($tag)
1258
                                                )
1259
                                            );
1260
                                        }
1261
                                    }
1262
                                }
1263
1264
                                // Update CACHE table
1265
                                DB::update(
1266
                                    prefix_table("cache"),
1267
                                    array(
1268
                                        "label" => $params[0],
1269
                                        "description" => $params[2],
1270
                                        "tags" => $params[7],
1271
                                        "id_tree" => intval($params[3]),
1272
                                        "perso" => "0",
1273
                                        "restricted_to" => "",
1274
                                        "login" => $params[4],
1275
                                        "folder" => "",
1276
                                        "author" => API_USER_ID,
1277
                                        "renewal_period" => "0",
1278
                                        "timestamp" => time(),
1279
                                        "url" => $params[6],
1280
                                    ),
1281
                                    "id = %i",
1282
                                    $GLOBALS['request'][2]
1283
                                );
1284
1285
                                echo '{"status":"item updated"}';
1286
                            } catch (PDOException $ex) {
1287
                                echo '<br />'.$ex->getMessage();
1288
                            }
1289
                        } else {
1290
                            rest_error('NO_DATA_EXIST');
1291
                        }
1292
                    } else {
1293
                        rest_error('ITEMMISSINGDATA');
1294
                    }
1295
                } else {
1296
                    rest_error('NO_ITEM');
1297
                }
1298
            } elseif ($GLOBALS['request'][1] == "folder") {
1299
            /*
1300
            * UPDATING A FOLDER
1301
            * <url to teampass>/api/index.php/update/folder/<folder_id>/<title>;<complexity_level>;<renewal_period>?apikey=<valid api key>
1302
            */
1303
                if ($GLOBALS['request'][2] !== "" && is_numeric($GLOBALS['request'][2])) {
1304
                    // get sent parameters
1305
                    $params = explode(';', base64_decode($GLOBALS['request'][3]));
1306
1307
                    if (!empty($params[0])) {
1308
                        if ($params[1] < 0) {
1309
                            rest_error('NO_DATA_EXIST');
1310
                        }
1311
                        if (empty($params[2])) {
1312
                            $params[2] = 0;
1313
                        }
1314
1315
                        // check if folder exists and get folder data
1316
                        $data_folder = DB::queryfirstrow(
1317
                            "SELECT *
1318
                            FROM ".prefix_table("nested_tree")."
1319
                            WHERE id = %s",
1320
                            $GLOBALS['request'][2]
1321
                        );
1322
                        $counter = DB::count();
1323
                        if ($counter === 0) {
1324
                            rest_error('NO_DATA_EXIST');
1325
                        }
1326
1327
                        //Check if title doesn't contains html codes
1328
                        if (preg_match_all("|<[^>]+>(.*)</[^>]+>|U", $params[0], $out)) {
1329
                            rest_error('HTML_CODES_NOT_ALLOWED');
1330
                        }
1331
1332
                        // check if title is numeric
1333
                        if (is_numeric($params[0]) === true) {
1334
                            rest_error('TITLE_ONLY_WITH_NUMBERS');
1335
                        }
1336
1337
                        // get complexity level for this folder
1338
                        $data = DB::queryfirstrow(
1339
                            "SELECT valeur
1340
                            FROM ".prefix_table("misc")."
1341
                            WHERE intitule = %i AND type = %s",
1342
                            $data_folder['parent_id'],
1343
                            "complex"
1344
                        );
1345
                        if (intval($params[1]) < intval($data['valeur'])) {
1346
                            rest_error('COMPLEXICITY_LEVEL_NOT_REACHED');
1347
                        }
1348
1349
                        try {
1350
                            DB::update(
1351
                                prefix_table("nested_tree"),
1352
                                array(
1353
                                    'parent_id' => $data_folder['parent_id'],
1354
                                    'title' => $params[0],
1355
                                    'personal_folder' => 0,
1356
                                    'renewal_period' => $params[2],
1357
                                    'bloquer_creation' => '0',
1358
                                    'bloquer_modification' => '0'
1359
                                ),
1360
                                "id = %i",
1361
                                $GLOBALS['request'][2]
1362
                            );
1363
1364
                            //Add complexity
1365
                            DB::update(
1366
                                prefix_table("misc"),
1367
                                array(
1368
                                    'valeur' => $params[1]
1369
                                ),
1370
                                "intitule = %s AND type = %s",
1371
                                $GLOBALS['request'][2],
1372
                                "complex"
1373
                            );
1374
1375
                            // Run nested tree update
1376
                            require_once '../sources/SplClassLoader.php';
1377
                            $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1378
                            $tree->register();
1379
                            $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
1380
                            $tree->rebuild();
1381
1382
                            echo '{"status":"folder updated"}';
1383
                        } catch (PDOException $ex) {
1384
                            echo '<br />'.$ex->getMessage();
1385
                        }
1386
                    } else {
1387
                        rest_error('ITEMMISSINGDATA');
1388
                    }
1389
                } else {
1390
                    rest_error('NO_ITEM');
1391
                }
1392
            } elseif ($GLOBALS['request'][1] == "user") {
1393
            /*
1394
             * Case where a user has to be updated
1395
             *
1396
             * Expected call format: .../api/index.php/updated/user/<LOGIN>;<NAME>;<LASTNAME>;<PASSWORD>;<EMAIL>;<ADMINISTRATEDBY>;<READ_ONLY>;<ROLE1,ROLE2,...>;<IS_ADMIN>;<ISMANAGER>;<PERSONAL_FOLDER>?apikey=<VALID API KEY>
1397
             * with:
1398
             * for READ_ONLY, IS_ADMIN, IS_MANAGER, PERSONAL_FOLDER, accepted value is 1 for TRUE and 0 for FALSE
1399
             * for ADMINISTRATEDBY and ROLE1, accepted value is the real label (not the IDs)
1400
             *
1401
             * Example: /api/index.php/update/user/U4;Nils;Laumaille;test;[email protected];Users;0;Managers,Users;0;1;1?apikey=sae6iekahxiseL3viShoo0chahc1ievei8aequi
1402
             *
1403
             */
1404
1405
                // get user definition
1406
                $array_user = explode(';', base64_decode($GLOBALS['request'][2]));
1407
                if (count($array_user) != 11) {
1408
                    rest_error('USERBADDEFINITION');
1409
                }
1410
1411
                $login = $array_user[0];
1412
                $name = $array_user[1];
1413
                $lastname = $array_user[2];
1414
                $password = $array_user[3];
1415
                $email = $array_user[4];
1416
                $adminby = urldecode($array_user[5]);
1417
                $isreadonly = urldecode($array_user[6]);
1418
                $roles = urldecode($array_user[7]);
1419
                $isadmin = $array_user[8];
1420
                $ismanager = $array_user[9];
1421
                $haspf = $array_user[10];
1422
1423
                // Empty user
1424
                if (mysqli_escape_string($link, htmlspecialchars_decode($login)) == "") {
1425
                    rest_error('USERLOGINEMPTY');
1426
                }
1427
                // Check if user already exists
1428
                $data = DB::query(
1429
                    "SELECT id, fonction_id, groupes_interdits, groupes_visibles, personal_folder
1430
                    FROM ".prefix_table("users")."
1431
                    WHERE login LIKE %ss",
1432
                    mysqli_escape_string($link, stripslashes($login))
1433
                );
1434
1435
                if (DB::count() === 1) {
1436
                    try {
1437
                        // find AdminRole code in DB
1438
                        $resRole = DB::queryFirstRow(
1439
                            "SELECT id
1440
                            FROM ".prefix_table("roles_title")."
1441
                            WHERE title LIKE %ss",
1442
                            mysqli_escape_string($link, stripslashes($adminby))
1443
                        );
1444
1445
1446
                        // get default language
1447
                        $lang = DB::queryFirstRow(
1448
                            "SELECT `valeur`
1449
                            FROM ".prefix_table("misc")."
1450
                            WHERE type = %s AND intitule = %s",
1451
                            "admin",
1452
                            "default_language"
1453
                        );
1454
1455
                        // prepare roles list
1456
                        $rolesList = "";
1457
                        foreach (explode(',', $roles) as $role) {
1458
                            $tmp = DB::queryFirstRow(
1459
                                "SELECT `id`
1460
                                FROM ".prefix_table("roles_title")."
1461
                                WHERE title = %s",
1462
                                $role
1463
                            );
1464
                            if (empty($rolesList)) {
1465
                                $rolesList = $tmp['id'];
1466
                            } else {
1467
                                $rolesList .= ";".$tmp['id'];
1468
                            }
1469
                        }
1470
1471
                        // Update user in DB
1472
                        DB::update(
1473
                            prefix_table("users"),
1474
                            array(
1475
                                'login' => $login,
1476
                                'name' => $name,
1477
                                'lastname' => $lastname,
1478
                                'pw' => bCrypt(stringUtf8Decode($password), COST),
1479
                                'email' => $email,
1480
                                'admin' => intval($isadmin),
1481
                                'gestionnaire' => intval($ismanager),
1482
                                'read_only' => intval($isreadonly),
1483
                                'personal_folder' => intval($haspf),
1484
                                'user_language' => $lang['valeur'],
1485
                                'fonction_id' => $rolesList,
1486
                                'groupes_interdits' => '0',
1487
                                'groupes_visibles' => '0',
1488
                                'isAdministratedByRole' => empty($resRole) ? '0' : $resRole['id']
1489
                            ),
1490
                            "id = %i",
1491
                            $data['id']
1492
                        );
1493
1494
                        // Create personnal folder
1495
                        if (intval($haspf) === 1) {
1496
                            DB::query(
1497
                                "SELECT id
1498
                                FROM ".prefix_table("nested_tree")."
1499
                                WHERE title = %s",
1500
                                $data['id']
1501
                            );
1502
                            if (DB::count() === 0) {
1503
                                DB::insert(
1504
                                    prefix_table("nested_tree"),
1505
                                    array(
1506
                                        'parent_id' => '0',
1507
                                        'title' => $data['id'],
1508
                                        'bloquer_creation' => '0',
1509
                                        'bloquer_modification' => '0',
1510
                                        'personal_folder' => '1'
1511
                                    )
1512
                                );
1513
                            }
1514
                        }
1515
1516
                        // load settings
1517
                        loadSettings();
1518
1519
                        // update LOG
1520
                        logEvents('user_mngt', 'at_user_updated', 'api - '.$GLOBALS['apikey'], $data['id'], "");
1521
1522
                        echo '{"status":"user added"}';
1523
                    } catch (PDOException $ex) {
1524
                        echo '<br />'.$ex->getMessage();
1525
                    }
1526
                } else {
1527
                    rest_error('USER_NOT_EXISTS');
1528
                }
1529
            }
1530
        } elseif ($GLOBALS['request'][0] == "auth") {
1531
            /*
1532
            ** FOR SECURITY PURPOSE, it is mandatory to use SSL to connect your teampass instance. The user password is not encrypted!
1533
            **
1534
            **
1535
            ** Expected call format: .../api/index.php/auth/<PROTOCOL>/<URL>/<login>/<password>?apikey=<VALID API KEY>
1536
            ** Example: https://127.0.0.1/teampass/api/index.php/auth/http/www.zadig-tge.adp.com/U1/test/76?apikey=chahthait5Aidood6johh6Avufieb6ohpaixain
1537
            ** RESTRICTIONS:
1538
            **              - <PROTOCOL>        ==> http|https|ftp|...
1539
            **              - <URL>             ==> encode URL without protocol (example: http://www.teampass.net becomes www.teampass.net)
1540
            **              - <login>           ==> user's login
1541
            **              - <password>        ==> currently clear password
1542
            **
1543
            ** RETURNED ANSWER:
1544
            **              - format sent back is JSON
1545
            **              - Example: {"<item_id>":{"label":"<pass#1>","login":"<login#1>","pw":"<pwd#1>"},"<item_id>":{"label":"<pass#2>","login":"<login#2>","pw":"<pwd#2>"}}
1546
            **
1547
            */
1548
            // get user credentials
1549
            if (isset($GLOBALS['request'][3]) && isset($GLOBALS['request'][4])) {
1550
                // get url
1551
                if (isset($GLOBALS['request'][1]) && isset($GLOBALS['request'][2])) {
1552
                    // is user granted?
1553
                    $userData = DB::queryFirstRow(
1554
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`
1555
                        FROM ".prefix_table("users")."
1556
                        WHERE login = %s",
1557
                        $GLOBALS['request'][3]
1558
                    );
1559
1560
                    // load passwordLib library
1561
                    require_once '../sources/SplClassLoader.php';
1562
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1563
                    $pwdlib->register();
1564
                    $pwdlib = new PasswordLib\PasswordLib();
1565
1566
                    if ($pwdlib->verifyPasswordHash($GLOBALS['request'][4], $userData['pw']) === true) {
1567
                        // define the restriction of "id_tree" of this user
1568
                        //db::debugMode(true);
1569
                        $userDef = DB::queryOneColumn(
1570
                            'folder_id',
1571
                            "SELECT DISTINCT folder_id
1572
                            FROM ".prefix_table("roles_values")."
1573
                            WHERE type IN ('R', 'W', 'ND', 'NE', 'NDNE', 'NEND') ",
1574
                            empty($userData['groupes_interdits']) ? "" : "
1575
                            AND folder_id NOT IN (".str_replace(";", ",", $userData['groupes_interdits']).")",
1576
                            "AND role_id IN %ls
1577
                            GROUP BY folder_id",
1578
                            explode(";", $userData['groupes_interdits'])
1579
                        );
1580
                        // complete with "groupes_visibles"
1581
                        foreach (explode(";", $userData['groupes_visibles']) as $v) {
1582
                            array_push($userDef, $v);
1583
                        }
1584
1585
                        // find the item associated to the url
1586
                        $response = DB::query(
1587
                            "SELECT id, label, login, pw, pw_iv, id_tree, restricted_to
1588
                            FROM ".prefix_table("items")."
1589
                            WHERE url LIKE %s
1590
                            AND id_tree IN (".implode(",", $userDef).")
1591
                            ORDER BY id DESC",
1592
                            $GLOBALS['request'][1]."://".urldecode($GLOBALS['request'][2].'%')
1593
                        );
1594
                        $counter = DB::count();
1595
1596
                        if ($counter > 0) {
1597
                            $json = "";
1598
                            foreach ($response as $data) {
1599
                                // check if item visible
1600
                                if (empty($data['restricted_to']) ||
1601
                                    ($data['restricted_to'] != "" && in_array($userData['id'], explode(";", $data['restricted_to'])))
1602
                                ) {
1603
                                    // prepare export
1604
                                    $json[$data['id']]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
1605
                                    $json[$data['id']]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
1606
                                    $crypt_pw = cryption(
1607
                                        $data['pw'],
1608
                                        "",
1609
                                        "decrypt"
1610
                                    );
1611
                                    $json[$data['id']]['pw'] = $crypt_pw['string'];
1612
                                }
1613
                            }
1614
                            // prepare answer. If no access then inform
1615
                            if (empty($json)) {
1616
                                rest_error('AUTH_NO_DATA');
1617
                            } else {
1618
                                echo json_encode($json);
1619
                            }
1620
                        } else {
1621
                            rest_error('NO_DATA_EXIST');
1622
                        }
1623
                    } else {
1624
                        rest_error('AUTH_NOT_GRANTED');
1625
                    }
1626
                } else {
1627
                    rest_error('AUTH_NO_URL');
1628
                }
1629
            } else {
1630
                rest_error('AUTH_NO_IDENTIFIER');
1631
            }
1632
        } elseif ($GLOBALS['request'][0] === "auth_tpc") {
1633
            /*
1634
            ** TO BE USED ONLY BY TEAMPASS-CONNECT
1635
            **
1636
            */
1637
            // get user credentials
1638
            if (isset($GLOBALS['request'][1])) {
1639
                // Get passed variables
1640
                $passedData = explode(';', base64_decode($GLOBALS['request'][1]));
1641
                if (count($passedData) === 4) {
1642
                    $tpc_url = $passedData[0];
1643
                    $user_login = $passedData[1];
1644
                    $user_pwd = $passedData[2];
1645
                    $user_saltkey = $passedData[3];
1646
1647
                    // get url
1648
                    if (isset($tpc_url)) {
1649
                        // is user granted?
1650
                        $userData = DB::queryFirstRow(
1651
                            "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`, `encrypted_psk`
1652
                            FROM ".prefix_table("users")."
1653
                            WHERE login = %s",
1654
                            $user_login
1655
                        );
1656
1657
                        // Check if user exists
1658
                        if (empty($userData['id']) === true) {
1659
                            rest_error('AUTH_NOT_GRANTED');
1660
                        }
1661
1662
                        // check if psk is correct.
1663
                        if (empty($user_saltkey) === false) {
1664
                            $user_saltkey = defuse_validate_personal_key(
1665
                                $user_saltkey,
1666
                                $userData['encrypted_psk']
1667
                            );
1668
                            if (strpos($user_saltkey, "Error ") !== false) {
1669
                                // error
1670
                                rest_error('AUTH_PSK_ERROR');
1671
                            }
1672
                        }
1673
1674
                        // load passwordLib library
1675
                        require_once '../sources/SplClassLoader.php';
1676
                        $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1677
                        $pwdlib->register();
1678
                        $pwdlib = new PasswordLib\PasswordLib();
1679
1680
                        if ($pwdlib->verifyPasswordHash($user_pwd, $userData['pw']) === true) {
1681
                            // Manage the case TPC asks for user identification
1682
                            if ($tpc_url === 'identify_user') {
1683
                                echo json_encode(array('err' => '', 'status' => 'USER_GRANTED'));
1684
                                return false;
1685
                            }
1686
1687
                            // define the restriction of "id_tree" of this user
1688
                            //db::debugMode(true);
1689
                            $userDef = DB::queryOneColumn(
1690
                                'folder_id',
1691
                                "SELECT DISTINCT folder_id
1692
                                FROM ".prefix_table("roles_values")."
1693
                                WHERE type IN ('R', 'W', 'ND', 'NE', 'NDNE', 'NEND') ",
1694
                                empty($userData['groupes_interdits']) ? "" : "AND folder_id NOT IN (".str_replace(";", ",", $userData['groupes_interdits']).")",
1695
                                "AND role_id IN %ls
1696
                                GROUP BY folder_id",
1697
                                explode(";", $userData['groupes_interdits'])
1698
                            );
1699
                            // complete with "groupes_visibles"
1700
                            foreach (explode(";", $userData['groupes_visibles']) as $v) {
1701
                                array_push($userDef, $v);
1702
                            }
1703
1704
                            // add PF
1705
                            $userpf = DB::queryFirstRow(
1706
                                "SELECT `id` FROM ".prefix_table("nested_tree")." WHERE title = %s",
1707
                                $userData['id']
1708
                            );
1709
                            array_push($userDef, $userpf['id']);
1710
1711
                            // Parse provided URL
1712
                            $url_scheme = parse_url($tpc_url, PHP_URL_SCHEME);
1713
                            $url_post = parse_url($tpc_url, PHP_URL_HOST);
1714
1715
                            // find the item associated to the url
1716
                            //db::debugmode(true);
1717
                            $response = DB::query(
1718
                                "SELECT id, label, login, pw, pw_iv, id_tree, restricted_to, perso
1719
                                FROM ".prefix_table("items")."
1720
                                WHERE url LIKE %s
1721
                                AND id_tree IN (".implode(",", array_filter($userDef)).")
1722
                                AND inactif = %i
1723
                                ORDER BY id DESC",
1724
                                $url_scheme.'://'.$url_post.'%',
1725
                                0
1726
                            );
1727
                            $counter = DB::count();
1728
1729
                            if ($counter > 0) {
1730
                                $json = [];
1731
                                foreach ($response as $data) {
1732
                                    // check if item visible
1733
                                    if (empty($data['restricted_to']) ||
1734
                                        ($data['restricted_to'] != "" && in_array($userData['id'], explode(";", $data['restricted_to'])))
1735
                                    ) {
1736
                                        // prepare export
1737
                                        $json[$data['id']]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
1738
                                        $json[$data['id']]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
1739
                                        if ($data['perso'] === "0") {
1740
                                            $crypt_pw = cryption(
1741
                                                $data['pw'],
1742
                                                "",
1743
                                                "decrypt"
1744
                                            );
1745
                                        } elseif (empty($user_saltkey)) {
1746
                                            $crypt_pw['string'] = "no_psk";
1747
                                        } else {
1748
                                            $crypt_pw = cryption(
1749
                                                $data['pw'],
1750
                                                $user_saltkey,
1751
                                                "decrypt"
1752
                                            );
1753
                                        }
1754
                                        $json[$data['id']]['pw'] = mb_detect_encoding($crypt_pw['string'], 'UTF-8', true) ? $crypt_pw['string'] : "not_utf8";
1755
                                        $json[$data['id']]['perso'] = $data['perso'];
1756
                                        $json[$data['id']]['domain'] = $url_scheme.'://'.$url_post;
1757
                                        $json[$data['id']]['id'] = $data['id'];
1758
                                    }
1759
                                }
1760
                                // prepare answer. If no access then inform
1761
                                if (empty($json)) {
1762
                                    rest_error('AUTH_NO_DATA');
1763
                                } else {
1764
                                    echo json_encode($json);
1765
                                }
1766
                            } else {
1767
                                rest_error('NO_DATA_EXIST');
1768
                            }
1769
                        } else {
1770
                            rest_error('AUTH_NOT_GRANTED');
1771
                        }
1772
                    } else {
1773
                        rest_error('AUTH_NO_URL');
1774
                    }
1775
                } else {
1776
                  rest_error('AUTH_NO_IDENTIFIER');
1777
                }
1778
            } else {
1779
                rest_error('AUTH_NO_IDENTIFIER');
1780
            }
1781
        } else if ($GLOBALS['request'][0] === "tpc_find") {
1782
            // get user credentials
1783
            if (isset($GLOBALS['request'][1])) {
1784
                // Get passed variables
1785
                $passedData = explode(';', base64_decode($GLOBALS['request'][1]));
1786
                $tpc_phrase = $passedData[0];
1787
                $user_login = $passedData[1];
1788
                $user_pwd = $passedData[2];
1789
                $user_saltkey = $passedData[3];
1790
1791
                // get url
1792
                if (isset($tpc_phrase)) {
1793
                    // is user granted?
1794
                    //db::debugMode(true);
1795
                    $userData = DB::queryFirstRow(
1796
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`, `encrypted_psk`
1797
                        FROM ".prefix_table("users")."
1798
                        WHERE login = %s",
1799
                        $user_login
1800
                    );
1801
1802
                    // check if psk is correct.
1803
                    if (empty($user_saltkey) === false) {
1804
                        $user_saltkey = defuse_validate_personal_key(
1805
                            $user_saltkey,
1806
                            $userData['encrypted_psk']
1807
                        );
1808
                        if (strpos($user_saltkey, "Error ") !== false) {
1809
                            // error
1810
                            rest_error('AUTH_PSK_ERROR');
1811
                        }
1812
                    }
1813
1814
                    // load passwordLib library
1815
                    require_once '../sources/SplClassLoader.php';
1816
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1817
                    $pwdlib->register();
1818
                    $pwdlib = new PasswordLib\PasswordLib();
1819
1820
                    if ($pwdlib->verifyPasswordHash($user_pwd, $userData['pw']) === true) {
1821
                        // define the restriction of "id_tree" of this user
1822
                        //db::debugMode(true);
1823
                        $userDef = DB::queryOneColumn(
1824
                            'folder_id',
1825
                            "SELECT DISTINCT folder_id
1826
                            FROM ".prefix_table("roles_values")."
1827
                            WHERE type IN ('R', 'W', 'ND', 'NE', 'NDNE', 'NEND') ",
1828
                            empty($userData['groupes_interdits']) ? "" : "AND folder_id NOT IN (".str_replace(";", ",", $userData['groupes_interdits']).")",
1829
                            "AND role_id IN %ls
1830
                            GROUP BY folder_id",
1831
                            explode(";", $userData['groupes_interdits'])
1832
                        );
1833
                        // complete with "groupes_visibles"
1834
                        foreach (explode(";", $userData['groupes_visibles']) as $v) {
1835
                            array_push($userDef, $v);
1836
                        }
1837
1838
                        // add PF
1839
                        $userpf = DB::queryFirstRow(
1840
                            "SELECT `id` FROM ".prefix_table("nested_tree")." WHERE title = %s",
1841
                            $userData['id']
1842
                        );
1843
                        array_push($userDef, $userpf['id']);
1844
1845
                        // Clean phrase
1846
                        if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $tpc_phrase, $result)) {
1847
                            rest_error('ITEM_MALFORMED');
1848
                        } elseif (empty($tpc_phrase)) {
1849
                            rest_error('MALFORMED');
1850
                        }
1851
1852
                        // find the item associated to the url
1853
                        //db::debugmode(true);
1854
                        $response = DB::query(
1855
                            "SELECT id, label, login, pw, pw_iv, id_tree, restricted_to, perso, url
1856
                            FROM ".prefix_table("items")."
1857
                            WHERE (url LIKE %s OR label LIKE %s)
1858
                            AND id_tree IN (".implode(",", array_filter($userDef)).")
1859
                            AND inactif = %i
1860
                            ORDER BY id DESC",
1861
                            $tpc_phrase.'%',
1862
                            $tpc_phrase.'%',
1863
                            0
1864
                        );
1865
                        $counter = DB::count();
1866
1867
                        if ($counter > 0) {
1868
                            $json = [];
1869
                            $i = 0;
1870
                            foreach ($response as $data) {
1871
                                // check if item visible
1872
                                if (empty($data['restricted_to']) ||
1873
                                    ($data['restricted_to'] != "" && in_array($userData['id'], explode(";", $data['restricted_to'])))
1874
                                ) {
1875
                                    // prepare export
1876
                                    $json[$i]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
1877
                                    $json[$i]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
1878
                                    if ($data['perso'] === "0") {
1879
                                        $crypt_pw = cryption(
1880
                                            $data['pw'],
1881
                                            "",
1882
                                            "decrypt"
1883
                                        );
1884
                                    } elseif (empty($user_saltkey)) {
1885
                                        $crypt_pw['string'] = "no_psk";
1886
                                    } else {
1887
                                        $crypt_pw = cryption(
1888
                                            $data['pw'],
1889
                                            $user_saltkey,
1890
                                            "decrypt"
1891
                                        );
1892
                                    }
1893
                                    $json[$i]['pw'] = mb_detect_encoding($crypt_pw['string'], 'UTF-8', true) ? $crypt_pw['string'] : "not_utf8";
1894
                                    $json[$i]['perso'] = $data['perso'];
1895
                                    $json[$i]['domain'] = $data['url'];
1896
                                    $json[$i]['id'] = $data['id'];
1897
1898
                                    $i++;
1899
                                }
1900
                            }
1901
                            // prepare answer. If no access then inform
1902
                            if (empty($json)) {
1903
                                rest_error('AUTH_NO_DATA');
1904
                            } else {
1905
                                echo json_encode($json);
1906
                            }
1907
                        } else {
1908
                            rest_error('NO_DATA_EXIST');
1909
                        }
1910
                    } else {
1911
                        rest_error('AUTH_NOT_GRANTED');
1912
                    }
1913
                } else {
1914
                    rest_error('AUTH_NO_URL');
1915
                }
1916
            } else {
1917
                rest_error('AUTH_NO_IDENTIFIER');
1918
            }
1919
        } elseif ($GLOBALS['request'][0] == "tpc_userfolders") {
1920
            /*
1921
            * READ USER FOLDERS
1922
            * Sends back a list of folders
1923
            */
1924
            // get user credentials
1925
            if (isset($GLOBALS['request'][1])) {
1926
                // Get passed variables
1927
                $passedData = explode(';', base64_decode($GLOBALS['request'][1]));
1928
                $user_login = $passedData[0];
1929
                $user_pwd = $passedData[1];
1930
                $user_saltkey = $passedData[2];
1931
1932
                $json = [];
1933
                $inc = 0;
1934
                if (strcmp($user_login, "admin") == 0) {
1935
                    // forbid admin access
1936
                }
1937
                $response = DB::query(
1938
                    "SELECT id AS user_id, fonction_id
1939
                    FROM ".prefix_table("users")."
1940
                    WHERE login = %s",
1941
                    $user_login
1942
                );
1943
                if (count($response) === 0) {
1944
                    rest_error('USER_NOT_EXISTS ');
1945
                }
1946
                foreach ($response as $data) {
1947
                    $role_str = $data['fonction_id'];
1948
                    $user_id = $data['user_id'];
1949
                }
1950
1951
                // Build tree
1952
                require_once '../sources/SplClassLoader.php';
1953
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1954
                $tree->register();
1955
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
1956
                $tree->rebuild();
1957
1958
                // If personal exists then get list of PF
1959
                $persoFld = DB::queryfirstrow(
1960
                    "SELECT id, title, nlevel
1961
                    FROM ".prefix_table("nested_tree")."
1962
                    WHERE title = %s",
1963
                    $user_id
1964
                );
1965
                if (empty($persoFld['id']) === false) {
1966
                    // Store main PF
1967
                    $json[$inc]['id'] = $persoFld['id'];
1968
                    $json[$inc]['title'] = $user_login;
1969
                    $json[$inc]['level'] = $persoFld['nlevel'];
1970
                    $json[$inc]['access_type'] = "W";
1971
                    $inc++;
1972
1973
                    // get all descendants
1974
                    $ids = $tree->getDescendants($persoFld['id'], false, false);
1975
                    foreach ($ids as $ident) {
1976
                        // Do query to get folder info
1977
                        $fldInfo = DB::queryfirstrow(
1978
                            "SELECT title, nlevel
1979
                            FROM ".prefix_table("nested_tree")."
1980
                            WHERE id = %i",
1981
                            $ident->id
1982
                        );
1983
1984
                        // Store info
1985
                        $json[$inc]['id'] = $ident->id;
1986
                        $json[$inc]['title'] = $fldInfo['title'];
1987
                        $json[$inc]['level'] = $fldInfo['nlevel'];
1988
                        $json[$inc]['personal'] = "1";
1989
                        $json[$inc]['access_type'] = "W";
1990
                        $inc++;
1991
                    }
1992
                }
1993
1994
                $folder_arr = array();
1995
                $roles = explode(";", $role_str);
1996
                foreach ($roles as $role) {
1997
                    $response = DB::query(
1998
                        "SELECT folder_id, type
1999
                        FROM ".prefix_table("roles_values")."
2000
                        WHERE role_id = %i",
2001
                        $role
2002
                    );
2003
                    foreach ($response as $data) {
2004
                        $folder_id = $data['folder_id'];
2005
                        if (array_key_exists($folder_id, $folder_arr) === false) {
2006
                            array_push($folder_arr, $folder_id);
2007
2008
                            $response2 = DB::queryFirstRow(
2009
                                "SELECT title, nlevel
2010
                                FROM ".prefix_table("nested_tree")."
2011
                                WHERE id = %i",
2012
                                $folder_id
2013
                            );
2014
2015
                            if (empty($response2['title']) === false) {
2016
                                // get all descendants
2017
                                $ids = $tree->getDescendants($folder_id, true, false);
2018
                                foreach ($ids as $ident) {
2019
                                    if (array_key_exists($ident->id, $folder_arr) === false) {
2020
                                        array_push($folder_arr, $ident->id);
2021
                                        // Do query to get folder info
2022
                                        $fldInfo = DB::queryfirstrow(
2023
                                            "SELECT title, nlevel
2024
                                            FROM ".prefix_table("nested_tree")."
2025
                                            WHERE id = %i",
2026
                                            $ident->id
2027
                                        );
2028
2029
                                        // Store info
2030
                                        $json[$inc]['id'] = $ident->id;
2031
                                        $json[$inc]['title'] = $fldInfo['title'];
2032
                                        $json[$inc]['level'] = $fldInfo['nlevel'];
2033
                                        $json[$inc]['personal'] = "0";
2034
                                        $json[$inc]['access_type'] = "W";
2035
                                        $inc++;
2036
                                    }
2037
                                }
2038
                                /*$json[$inc]['id'] = $folder_id;
2039
                                $json[$inc]['title'] = $response2['title'];
2040
                                $json[$inc]['level'] = $response2['nlevel'];
2041
                                $json[$inc]['access_type'] = $data['type'];
2042
                                $json[$inc]['personal'] = "0";
2043
                                $inc++;*/
2044
                            }
2045
                        }
2046
                    }
2047
                }
2048
                // prepare answer. If no access then inform
2049
                if (empty($json)) {
2050
                    rest_error('AUTH_NO_DATA');
2051
                } else {
2052
                    echo json_encode($json);
2053
                }
2054
            }
2055
        } elseif ($GLOBALS['request'][0] == "set") {
2056
            /*
2057
             * Expected call format: .../api/index.php/set/<login_to_save>/<password_to_save>/<url>/<user_login>/<user_password>/<label>/<protocol>?apikey=<VALID API KEY>
2058
             * Example: https://127.0.0.1/teampass/api/index.php/set/newLogin/newPassword/newUrl/myLogin/myPassword?apikey=gu6Eexaewaishooph6iethoh5woh0yoit6ohquo
2059
             *
2060
             * NEW ITEM WILL BE STORED IN SPECIFIC FOLDER
2061
             */
2062
            // get user credentials
2063
            if (isset($GLOBALS['request'][4]) && isset($GLOBALS['request'][5])) {
2064
                // get url
2065
                if (isset($GLOBALS['request'][1]) && isset($GLOBALS['request'][2]) && isset($GLOBALS['request'][3])) {
2066
                    // is user granted?
2067
                    $userData = DB::queryFirstRow(
2068
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`
2069
                        FROM ".prefix_table("users")."
2070
                        WHERE login = %s",
2071
                        $GLOBALS['request'][4]
2072
                    );
2073
                    if (DB::count() == 0) {
2074
                        rest_error('AUTH_NO_IDENTIFIER');
2075
                    }
2076
2077
                    // load passwordLib library
2078
                    require_once '../sources/SplClassLoader.php';
2079
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2080
                    $pwdlib->register();
2081
                    $pwdlib = new PasswordLib\PasswordLib();
2082
2083
                    // is user identified?
2084
                    if ($pwdlib->verifyPasswordHash($GLOBALS['request'][5], $userData['pw']) === true) {
2085
                        // does the personal folder of this user exists?
2086
                        DB::queryFirstRow(
2087
                            "SELECT `id`
2088
                            FROM ".prefix_table("nested_tree")."
2089
                            WHERE title = %s AND personal_folder = 1",
2090
                            $userData['id']
2091
                        );
2092
                        if (DB::count() > 0) {
2093
                            // check if "teampass-connect" folder exists
2094
                            // if not create it
2095
                            $folder = DB::queryFirstRow(
2096
                                "SELECT `id`
2097
                                FROM " . $pre."nested_tree
2098
                                WHERE title = %s",
2099
                                "teampass-connect"
2100
                            );
2101
                            if (DB::count() == 0) {
2102
                                DB::insert(
2103
                                    prefix_table("nested_tree"),
2104
                                    array(
2105
                                        'parent_id' => '0',
2106
                                        'title' => "teampass-connect"
2107
                                    )
2108
                                );
2109
                                $tpc_folder_id = DB::insertId();
2110
2111
                                //Add complexity
2112
                                DB::insert(
2113
                                    prefix_table("misc"),
2114
                                    array(
2115
                                        'type' => 'complex',
2116
                                        'intitule' => $tpc_folder_id,
2117
                                        'valeur' => '0'
2118
                                    )
2119
                                );
2120
2121
                                // rebuild tree
2122
                                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
2123
                                $tree->register();
2124
                                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
2125
                                $tree->rebuild();
2126
                            } else {
2127
                                $tpc_folder_id = $folder['id'];
2128
                            }
2129
2130
                            // encrypt password
2131
                            $encrypt = cryption(
2132
                                $GLOBALS['request'][2],
2133
                                "",
2134
                                "encrypt"
2135
                            );
2136
2137
                            // is there a protocol?
2138
                            if (isset($GLOBALS['request'][7]) || empty($GLOBALS['request'][7])) {
2139
                                $protocol = "http://";
2140
                            } else {
2141
                                $protocol = urldecode($GLOBALS['request'][7])."://";
2142
                            }
2143
2144
                            // add new item
2145
                            DB::insert(
2146
                                prefix_table("items"),
2147
                                array(
2148
                                    'label' => "Credentials for ".urldecode($GLOBALS['request'][3]),
2149
                                    'description' => "Imported with Teampass-Connect",
2150
                                    'pw' => $encrypt['string'],
2151
                                    'pw_iv' => "",
2152
                                    'email' => "",
2153
                                    'url' => urldecode($GLOBALS['request'][3]),
2154
                                    'id_tree' => $tpc_folder_id,
2155
                                    'login' => $GLOBALS['request'][1],
2156
                                    'inactif' => '0',
2157
                                    'restricted_to' => $userData['id'],
2158
                                    'perso' => '0',
2159
                                    'anyone_can_modify' => '0',
2160
                                    'complexity_level' => '0'
2161
                                )
2162
                            );
2163
                            $newID = DB::insertId();
2164
2165
                            // log
2166
                            logItems(
2167
                                $newID,
2168
                                "Credentials for ".urldecode($GLOBALS['request'][3].'%'),
2169
                                $userData['id'],
2170
                                'at_creation',
2171
                                $GLOBALS['request'][1]
2172
                            );
2173
2174
                            $json['status'] = "ok";
2175
                            // prepare answer. If no access then inform
2176
                            if (empty($json)) {
2177
                                rest_error('AUTH_NO_DATA');
2178
                            } else {
2179
                                echo json_encode($json);
2180
                            }
2181
                        } else {
2182
                            rest_error('NO_PF_EXIST_FOR_USER');
2183
                        }
2184
                    } else {
2185
                        rest_error('AUTH_NOT_GRANTED');
2186
                    }
2187
                } else {
2188
                    rest_error('SET_NO_DATA');
2189
                }
2190
            } else {
2191
                rest_error('AUTH_NO_IDENTIFIER');
2192
            }
2193
        } elseif ($GLOBALS['request'][0] == "set_tpc") {
2194
            /*
2195
             * TO BE USED ONLY BY TEAMPASS-CONNECT
2196
             */
2197
            // get user credentials
2198
            if (isset($GLOBALS['request'][1]) === true && isset($GLOBALS['request'][2]) === true && isset($GLOBALS['request'][3]) === true) {
2199
                // Get passed variables
2200
                $item_definition = json_decode(base64_decode($GLOBALS['request'][2]), true);
2201
                $passedData = explode(';', base64_decode($GLOBALS['request'][3]));
2202
                $user_login = $passedData[0];
2203
                $user_pwd = $passedData[1];
2204
                $user_saltkey = $passedData[2];
2205
2206
                // is user granted?
2207
                $userData = DB::queryFirstRow(
2208
                    "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`
2209
                    FROM ".prefix_table("users")."
2210
                    WHERE login = %s",
2211
                    $user_login
2212
                );
2213
                if (DB::count() === 0) {
2214
                    rest_error('AUTH_NO_IDENTIFIER');
2215
                }
2216
2217
                // load passwordLib library
2218
                require_once '../sources/SplClassLoader.php';
2219
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2220
                $pwdlib->register();
2221
                $pwdlib = new PasswordLib\PasswordLib();
2222
2223
                // is user identified?
2224
                if ($pwdlib->verifyPasswordHash($user_pwd, $userData['pw']) === true) {
2225
                    // It is a new ITEM
2226
                    if ($GLOBALS['request'][1] === "add") {
2227
                        // encrypt PW
2228
                        if ($item_definition['personal'] === '1') {
2229
                            $passwd = cryption(
2230
                                $item_definition['pwd'],
2231
                                $user_saltkey,
2232
                                "encrypt"
2233
                            );
2234
                        } else {
2235
                            $passwd = cryption(
2236
                                $item_definition['pwd'],
2237
                                "",
2238
                                "encrypt"
2239
                            );
2240
                        }
2241
2242
                        // add new item
2243
                        DB::insert(
2244
                            prefix_table("items"),
2245
                            array(
2246
                                'label' => $item_definition['label'],
2247
                                'description' => $item_definition['description'],
2248
                                'pw' => $passwd['string'],
2249
                                'pw_iv' => "",
2250
                                'email' => "",
2251
                                'url' => $item_definition['url'],
2252
                                'id_tree' => $item_definition['destination_folder'],
2253
                                'login' => $item_definition['login'],
2254
                                'inactif' => '0',
2255
                                'restricted_to' => $userData['id'],
2256
                                'perso' => '0',
2257
                                'anyone_can_modify' => '0',
2258
                                'complexity_level' => '0'
2259
                            )
2260
                        );
2261
                        $newID = DB::insertId();
2262
2263
                        // log
2264
                        logItems(
2265
                            $newID,
2266
                            $item_definition['label'],
2267
                            $userData['id'],
2268
                            'at_creation',
2269
                            $GLOBALS['request'][1]
2270
                        );
2271
2272
                        // rebuild tree
2273
                        $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
2274
                        $tree->register();
2275
                        $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
2276
                        $tree->rebuild();
2277
2278
                        echo json_encode(array('new_id' => $newID , 'err' => ''));
2279
                    } elseif ($GLOBALS['request'][1] === "edit") {
2280
                        // Is this folder a personal one?
2281
                        $fldData = DB::queryFirstRow(
2282
                            "SELECT `personal_folder`
2283
                            FROM ".prefix_table("nested_tree")."
2284
                            WHERE id = %i",
2285
                            $item_definition['item_id']
2286
                        );
2287
2288
                        // encrypt PW
2289
                        if ($fldData['personal_folder'] === '1') {
2290
                            $passwd = cryption(
2291
                                $item_definition['pwd'],
2292
                                $user_saltkey,
2293
                                "encrypt"
2294
                            );
2295
                        } else {
2296
                            $passwd = cryption(
2297
                                $item_definition['pwd'],
2298
                                "",
2299
                                "encrypt"
2300
                            );
2301
                        }
2302
2303
                        // UPDATE item
2304
                        DB::update(
2305
                            prefix_table("items"),
2306
                            array(
2307
                                'pw' => $passwd['string'],
2308
                                'pw_iv' => '',
2309
                                "url" => $item_definition['url'],
2310
                                "login" => $item_definition['login']
2311
                            ),
2312
                            "id = %i",
2313
                            $item_definition['item_id']
2314
                        );
2315
2316
                        // log
2317
                        DB::insert(
2318
                            prefix_table("log_items"),
2319
                            array(
2320
                                "id_item" => $item_definition['item_id'],
2321
                                "date" => time(),
2322
                                "id_user" => $userData['id'],
2323
                                "action" => "at_modification"
2324
                            )
2325
                        );
2326
2327
                        // Update CACHE table
2328
                        DB::update(
2329
                            prefix_table("cache"),
2330
                            array(
2331
                                "login" => $item_definition['login'],
2332
                                "author" => $userData['id'],
2333
                                "timestamp" => time(),
2334
                                "url" => $item_definition['url'],
2335
                            ),
2336
                            "id = %i",
2337
                            $item_definition['item_id']
2338
                        );
2339
2340
                        echo json_encode(array('new_id' => '' , 'err' => ''));
2341
                    }
2342
                } else {
2343
                    rest_error('AUTH_NOT_GRANTED');
2344
                }
2345
            } else {
2346
                rest_error('AUTH_NO_IDENTIFIER');
2347
            }
2348
        } elseif ($GLOBALS['request'][0] == "tpc_delete") {
2349
            /*
2350
             * TO BE USED ONLY BY TEAMPASS-CONNECT
2351
             */
2352
            // get user credentials
2353
            if (isset($GLOBALS['request'][1]) === true) {
2354
                // Get passed variables
2355
                $passedData = explode(';', base64_decode($GLOBALS['request'][1]));
2356
                $item_id = $passedData[0];
2357
                $user_login = $passedData[1];
2358
                $user_pwd = $passedData[2];
2359
                $user_saltkey = $passedData[3];
2360
2361
                // is user granted?
2362
                $userData = DB::queryFirstRow(
2363
                    "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`
2364
                    FROM ".prefix_table("users")."
2365
                    WHERE login = %s",
2366
                    $user_login
2367
                );
2368
                if (DB::count() == 0) {
2369
                    rest_error('AUTH_NO_IDENTIFIER');
2370
                }
2371
2372
                // load passwordLib library
2373
                require_once '../sources/SplClassLoader.php';
2374
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2375
                $pwdlib->register();
2376
                $pwdlib = new PasswordLib\PasswordLib();
2377
2378
                // is user identified?
2379
                if ($pwdlib->verifyPasswordHash($user_pwd, $userData['pw']) === true) {
2380
                    DB::update(
2381
                        prefix_table("items"),
2382
                        array(
2383
                            'inactif' => '1',
2384
                        ),
2385
                        "id = %i",
2386
                        $item_id
2387
                    );
2388
                    //log
2389
                    DB::insert(
2390
                        prefix_table("log_items"),
2391
                        array(
2392
                            'id_item' => $item_id,
2393
                            'date' => time(),
2394
                            'id_user' => $userData['id'],
2395
                            'action' => 'at_delete'
2396
                        )
2397
                    );
2398
2399
                    //Update CACHE table
2400
                    updateCacheTable("delete_value", $item_id);
2401
2402
                    echo json_encode(array('code' => 'done'));
2403
                } else {
2404
                    rest_error('AUTH_NOT_GRANTED');
2405
                }
2406
            } else {
2407
                rest_error('AUTH_NO_IDENTIFIER');
2408
            }
2409
        } elseif ($GLOBALS['request'][0] === "delete") {
2410
        /*
2411
        * DELETE
2412
        *
2413
        * Expected call format: .../api/index.php/delete/folder/<folder_id1;folder_id2;folder_id3>?apikey=<VALID API KEY>
2414
        * Expected call format: .../api/index.php/delete/item>/<item_id1;item_id2;item_id3>?apikey=<VALID API KEY>
2415
        */
2416
            if ($GLOBALS['request'][1] === "folder") {
2417
                $array_category = explode(';', $GLOBALS['request'][2]);
2418
2419
                // get user info
2420
                if (isset($GLOBALS['request'][3]) && !empty($GLOBALS['request'][3])) {
2421
                    $userData = DB::queryFirstRow(
2422
                        "SELECT `id` FROM ".$pre."users WHERE login = %s",
2423
                        $GLOBALS['request'][3]
2424
                    );
2425
                    if (DB::count() == 0) {
2426
                        $user_id = API_USER_ID;
2427
                    } else {
2428
                        $user_id = $userData['id'];
2429
                    }
2430
                } else {
2431
                    $user_id = API_USER_ID;
2432
                }
2433
2434
                if (count($array_category) > 0 && count($array_category) < 5) {
2435
                    // load passwordLib library
2436
                    require_once '../sources/SplClassLoader.php';
2437
2438
                    // prepare tree
2439
                    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
2440
                    $tree->register();
2441
                    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title', 'personal_folder');
2442
2443
                    // this will delete all sub folders and items associated
2444
                    for ($i = 0; $i < count($array_category); $i++) {
2445
                        // Does this folder exist?
2446
                        DB::queryFirstRow(
2447
                            "SELECT id
2448
                            FROM ".prefix_table("nested_tree")."
2449
                            WHERE id = %i",
2450
                            $array_category[$i]
2451
                        );
2452
                        if (DB::count() > 0) {
2453
                            // Get through each subfolder
2454
                            $folders = $tree->getDescendants($array_category[$i], true);
2455
                            if (count($folders) > 0) {
2456
                                foreach ($folders as $folder) {
2457
                                    if (($folder->parent_id > 0 || $folder->parent_id == 0) && $folder->personal_folder != 1) {
2458
                                        //Store the deleted folder (recycled bin)
2459
                                        DB::insert(
2460
                                            prefix_table("misc"),
2461
                                            array(
2462
                                                'type' => 'folder_deleted',
2463
                                                'intitule' => "f".$array_category[$i],
2464
                                                'valeur' => $folder->id.', '.$folder->parent_id.', '.
2465
                                                    $folder->title.', '.$folder->nleft.', '.$folder->nright.', '.$folder->nlevel.', 0, 0, 0, 0'
2466
                                            )
2467
                                        );
2468
                                        //delete folder
2469
                                        DB::delete(prefix_table("nested_tree"), "id = %i", $folder->id);
2470
2471
                                        //delete items & logs
2472
                                        $items = DB::query(
2473
                                            "SELECT id
2474
                                            FROM ".prefix_table("items")."
2475
                                            WHERE id_tree=%i",
2476
                                            $folder->id
2477
                                        );
2478
                                        foreach ($items as $item) {
2479
                                            DB::update(
2480
                                                prefix_table("items"),
2481
                                                array(
2482
                                                    'inactif' => '1',
2483
                                                ),
2484
                                                "id = %i",
2485
                                                $item['id']
2486
                                            );
2487
                                            //log
2488
                                            DB::insert(
2489
                                                prefix_table("log_items"),
2490
                                                array(
2491
                                                    'id_item' => $item['id'],
2492
                                                    'date' => time(),
2493
                                                    'id_user' => $user_id,
2494
                                                    'action' => 'at_delete'
2495
                                                )
2496
                                            );
2497
                                        }
2498
                                        //Update CACHE table
2499
                                        updateCacheTable("delete_value", $array_category[$i]);
2500
                                    }
2501
                                }
2502
                            }
2503
                        } else {
2504
                            // Folder doesn't exist
2505
                        }
2506
                    }
2507
                } else {
2508
                    rest_error('NO_CATEGORY');
2509
                }
2510
2511
                $json['status'] = 'OK';
2512
            } elseif ($GLOBALS['request'][1] == "item") {
2513
                $array_items = explode(';', $GLOBALS['request'][2]);
2514
2515
                // get user info
2516
                if (isset($GLOBALS['request'][3]) && !empty($GLOBALS['request'][3])) {
2517
                    $userData = DB::queryFirstRow(
2518
                        "SELECT `id` FROM ".$pre."users WHERE login = %s",
2519
                        $GLOBALS['request'][3]
2520
                    );
2521
                    if (DB::count() == 0) {
2522
                        $user_id = API_USER_ID;
2523
                    } else {
2524
                        $user_id = $userData['id'];
2525
                    }
2526
                }
2527
2528
                for ($i = 0, $c = count($array_items); $i < $c; $i++) {
2529
                    DB::update(
2530
                        prefix_table("items"),
2531
                        array(
2532
                            'inactif' => '1',
2533
                        ),
2534
                        "id = %i",
2535
                        $array_items[$i]
2536
                    );
2537
                    //log
2538
                    DB::insert(
2539
                        prefix_table("log_items"),
2540
                        array(
2541
                            'id_item' => $array_items[$i],
2542
                            'date' => time(),
2543
                            'id_user' => $user_id,
2544
                            'action' => 'at_delete'
2545
                        )
2546
                    );
2547
2548
                    //Update CACHE table
2549
                    updateCacheTable("delete_value", $array_items[$i]);
2550
                }
2551
2552
                $json['status'] = 'OK';
2553
            }
2554
2555
            if ($json) {
2556
                echo json_encode($json);
2557
            } else {
2558
                rest_error('EMPTY');
2559
            }
2560
        } elseif ($GLOBALS['request'][0] == "new_password") {
2561
            if (!empty($GLOBALS['request'][1])) {
2562
                $params = explode(";", $GLOBALS['request'][1]);
2563
2564
                if (empty($params[0])) {
2565
                    $params[0] = 8;
2566
                }
2567
                if (empty($params[1])) {
2568
                    $params[1] = 0;
2569
                }
2570
                if (empty($params[2])) {
2571
                    $params[2] = 0;
2572
                }
2573
                if (empty($params[3])) {
2574
                    $params[3] = 0;
2575
                }
2576
                if (empty($params[4])) {
2577
                    $params[4] = 0;
2578
                }
2579
                if (empty($params[5])) {
2580
                    $params[5] = 0;
2581
                }
2582
                if (empty($params[6])) {
2583
                    $params[6] = 0;
2584
                }
2585
2586
                // Generate key
2587
                $pwd = GenerateCryptKey(
2588
                    $params[0],
2589
                    $params[1] === "1" ? true : false,
2590
                    $params[2] === "1" ? true : false,
2591
                    $params[3] === "1" ? true : false,
2592
                    $params[5] === "1" && $params[6] === "1" ? true : false
2593
                );
2594
2595
                // generate and send back (generate in base64 if symbols are asked)
2596
                if ($params[6] === "1") {
2597
                    echo '{"password" : "'.base64_encode($pwd).'"}';
2598
                } else {
2599
                    echo '{"password" : "'.$pwd.'"}';
2600
                }
2601
            } else {
2602
                rest_error('NO_PARAMETERS');
2603
            }
2604
        } elseif ($GLOBALS['request'][0] === "info") {
2605
            if ($GLOBALS['request'][1] === "complexicity_levels_list") {
2606
                require_once '../includes/language/english.php';
2607
                $json = array(
2608
                    0=> $LANG['complex_level0'],
2609
                    25=> $LANG['complex_level1'],
2610
                    50=> $LANG['complex_level2'],
2611
                    60=> $LANG['complex_level3'],
2612
                    70=> $LANG['complex_level4'],
2613
                    80=> $LANG['complex_level5'],
2614
                    90=> $LANG['complex_level6']
2615
                );
2616
2617
                echo json_encode($json);
2618
            } elseif ($GLOBALS['request'][1] === "folder") {
2619
                if (!empty($GLOBALS['request'][2]) && is_numeric($GLOBALS['request'][2])) {
2620
                    $data = DB::queryFirstRow(
2621
                        "SELECT * FROM ".$pre."nested_tree WHERE id = %i",
2622
                        $GLOBALS['request'][2]
2623
                    );
2624
                    if (DB::count() == 0) {
2625
                        rest_error('NOSUCHFOLDER');
2626
                    }
2627
2628
                    // form id_tree to full foldername
2629
                    require_once '../sources/SplClassLoader.php';
2630
                    //Load Tree
2631
                    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
2632
                    $tree->register();
2633
                    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
2634
2635
                    $folder = "";
2636
                    $arbo = $tree->getPath($GLOBALS['request'][2], true);
2637
                    foreach ($arbo as $elem) {
2638
                        if (empty($folder)) {
2639
                            $folder = stripslashes($elem->title);
2640
                        } else {
2641
                            $folder .= " > ".stripslashes($elem->title);
2642
                        }
2643
                    }
2644
2645
                    // prepare info
2646
                    $json = array(
2647
                        "title" => $data['title'],
2648
                        "personal_folder" => $data['personal_folder'],
2649
                        "renewal_period" => $data['renewal_period'],
2650
                        "parent_id" => $data['parent_id'],
2651
                        "path" => $folder,
2652
                    );
2653
2654
                    echo json_encode($json);
2655
                } else {
2656
                    rest_error('NO_PARAMETERS');
2657
                }
2658
            } elseif ($GLOBALS['request'][1] === "version") {
2659
                echo '{"api-version":"'.$api_version.'"}';
2660
            } else {
2661
                rest_error('NO_PARAMETERS');
2662
            }
2663
        } else {
2664
            rest_error('METHOD');
2665
        }
2666
    }
2667
}
2668
2669
function rest_put()
2670
{
2671
    if (!@count($GLOBALS['request']) == 0) {
2672
        $request_uri = $GLOBALS['_SERVER']['REQUEST_URI'];
2673
        preg_match('/\/api(\/index.php|)\/(.*)\?apikey=(.*)/', $request_uri, $matches);
2674
        if (count($matches) == 0) {
2675
            rest_error('REQUEST_SENT_NOT_UNDERSTANDABLE');
2676
        }
2677
        $GLOBALS['request'] = explode('/', $matches[2]);
2678
    }
2679
    if (apikey_checker($GLOBALS['apikey'])) {
2680
        teampass_connect();
2681
    }
2682
}
2683
2684
/**
2685
 * @param string $type
2686
 */
2687
function rest_error($type, $detail = 'N/A')
2688
{
2689
    switch ($type) {
2690
        case 'APIKEY':
2691
            $message = array('err' => 'This api_key '.$GLOBALS['apikey'].' doesn\'t exist', 'code' => 'API_KEY_NOT_FOUND');
2692
            header('HTTP/1.1 405 Method Not Allowed');
2693
            break;
2694
        case 'NO_CATEGORY':
2695
            $message = array('err' => 'No folder specified');
2696
            break;
2697
        case 'NO_ITEM':
2698
            $message = array('err' => 'No item specified');
2699
            break;
2700
        case 'EMPTY':
2701
            $message = array('err' => 'No results');
2702
            break;
2703
        case 'IPWHITELIST':
2704
            $message = array('err' => 'Ip address not allowed.');
2705
            header('HTTP/1.1 405 Method Not Allowed');
2706
            break;
2707
        case 'MYSQLERR':
2708
            $message = array('err' => $detail);
2709
            header('HTTP/1.1 500 Internal Server Error');
2710
            break;
2711
        case 'METHOD':
2712
            $message = array('err' => 'Method not authorized', 'code' => 'METHOD_NOT_AUTHORIZED');
2713
            header('HTTP/1.1 405 Method Not Allowed');
2714
            break;
2715
        case 'ITEMBADDEFINITION':
2716
            $message = array('err' => 'Item definition not complete');
2717
            header('HTTP/1.1 405 Method Not Allowed');
2718
            break;
2719
        case 'ITEM_MALFORMED':
2720
            $message = array('err' => 'Item definition not numeric');
2721
            header('HTTP/1.1 405 Method Not Allowed');
2722
            break;
2723
        case 'USERBADDEFINITION':
2724
            $message = array('err' => 'User definition not complete');
2725
            header('HTTP/1.1 405 Method Not Allowed');
2726
            break;
2727
        case 'USERLOGINEMPTY':
2728
            $message = array('err' => 'Empty Login given');
2729
            header('HTTP/1.1 405 Method Not Allowed');
2730
            break;
2731
        case 'USERALREADYEXISTS':
2732
            $message = array('err' => 'User already exists');
2733
            header('HTTP/1.1 405 Method Not Allowed');
2734
            break;
2735
        case 'REQUEST_SENT_NOT_UNDERSTANDABLE':
2736
            $message = array('err' => 'URL format is not following requirements');
2737
            break;
2738
        case 'AUTH_NOT_GRANTED':
2739
            $message = array('err' => 'Bad credentials for user', 'code' => 'AUTH_NOT_GRANTED');
2740
            header('HTTP/1.1 404 Error');
2741
            break;
2742
        case 'AUTH_NO_URL':
2743
            $message = array('err' => 'URL needed to grant access');
2744
            break;
2745
        case 'AUTH_NO_IDENTIFIER':
2746
            $message = array('err' => 'Credentials needed to grant access', 'code' => 'AUTH_NO_IDENTIFIER');
2747
            break;
2748
        case 'AUTH_NO_DATA':
2749
            $message = array('err' => 'Data not allowed for the user', 'code' => 'AUTH_NO_DATA');
2750
            break;
2751
        case 'AUTH_PSK_ERROR':
2752
            $message = array('err' => 'Personal Saltkey is wrong', 'code' => 'AUTH_PSK_ERROR');
2753
            header('HTTP/1.1 404 Error');
2754
            break;
2755
        case 'NO_DATA_EXIST':
2756
            $message = array('err' => 'No data exists', 'code' => 'NO_DATA_EXIST');
2757
            break;
2758
        case 'NO_DESTINATION_FOLDER':
2759
            $message = array('err' => 'No destination folder provided');
2760
            break;
2761
        case 'PASSWORDTOOLONG':
2762
            $message = array('err' => 'Password is too long');
2763
            break;
2764
        case 'NOSUCHFOLDER':
2765
            $message = array('err' => 'Folder ID does not exist');
2766
            break;
2767
        case 'PASSWORDEMPTY':
2768
            $message = array('err' => 'Password is empty');
2769
            break;
2770
        case 'ITEMEXISTS':
2771
            $message = array('err' => 'Label already exists');
2772
            break;
2773
        case 'ITEMMISSINGDATA':
2774
            $message = array('err' => 'Label or Password or Folder ID is missing');
2775
            break;
2776
        case 'SET_NO_DATA':
2777
            $message = array('err' => 'No data to be stored');
2778
            break;
2779
        case 'NO_PF_EXIST_FOR_USER':
2780
            $message = array('err' => 'No Personal Folder exists for this user');
2781
            break;
2782
        case 'HTML_CODES_NOT_ALLOWED':
2783
            $message = array('err' => 'HTML tags not allowed');
2784
            break;
2785
        case 'TITLE_ONLY_WITH_NUMBERS':
2786
            $message = array('err' => 'Title only with numbers not allowed');
2787
            break;
2788
        case 'ALREADY_EXISTS':
2789
            $message = array('err' => 'Data already exists');
2790
            break;
2791
        case 'COMPLEXICITY_LEVEL_NOT_REACHED':
2792
            $message = array('err' => 'complexity level was not reached');
2793
            break;
2794
        case 'NO_PARAMETERS':
2795
            $message = array('err' => 'No parameters given');
2796
            break;
2797
        case 'USER_NOT_EXISTS':
2798
            $message = array('err' => 'User does not exist');
2799
            break;
2800
        case 'NO_PSALTK_PROVIDED':
2801
            $message = array('err' => 'No Personal saltkey provided');
2802
            break;
2803
        case 'EXPECTED_PARAMETER_NOT_PROVIDED':
2804
            $message = array('err' => 'Provided parameters are not correct');
2805
            break;
2806
        default:
2807
            $message = array('err' => 'Something happen ... but what ?');
2808
            header('HTTP/1.1 500 Internal Server Error');
2809
            break;
2810
    }
2811
2812
    echo json_encode($message);
2813
    exit(0);
2814
}
2815
2816
function apikey_checker($apikey_used)
2817
{
2818
    teampass_connect();
2819
    $apikey_pool = teampass_get_keys();
2820
2821
    // if needed extract key from credentials
2822
    if (strlen($apikey_used) > 40) {
2823
        $userCredentials = base64_decode(substr($apikey_used, 40));
2824
        $apikey_used = substr($apikey_used, 0, 39);
2825
    }
2826
2827
    if (in_array($apikey_used, $apikey_pool)) {
2828
        return(1);
2829
    } else {
2830
        rest_error('APIKEY', $apikey_used);
2831
    }
2832
}
2833
2834
function teampass_pbkdf2_hash($var_p, $var_s, $var_c, $var_kl, $var_st = 0, $var_a = 'sha256')
2835
{
2836
    $var_kb = $var_st + $var_kl;
2837
    $var_dk = '';
2838
2839
    for ($block = 1; $block <= $var_kb; $block++) {
2840
        $var_ib = $var_h = hash_hmac($var_a, $var_s.pack('N', $block), $var_p, true);
2841
        for ($var_i = 1; $var_i < $var_c; $var_i++) {
2842
            $var_ib ^= ($var_h = hash_hmac($var_a, $var_h, $var_p, true));
2843
        }
2844
        $var_dk .= $var_ib;
2845
    }
2846
2847
    return substr($var_dk, $var_st, $var_kl);
2848
}
2849