Passed
Push — development ( 81a4db...5845ec )
by Nils
07:52
created

restError()   D

Complexity

Conditions 36
Paths 36

Size

Total Lines 127
Code Lines 123

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 36
eloc 123
nc 36
nop 2
dl 0
loc 127
rs 4.273
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 26 and the first side effect is on line 16.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 *
4
 * @package       (api)functions.php
5
 * @author        Nils Laumaillé <[email protected]>
6
 * @version       2.1.1
7
 * @copyright     2009-2018 Nils Laumaillé
8
 * @license       GNU GPL-3.0
9
 * @link          https://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.1.1";
17
$_SESSION['CPM'] = 1;
18
require_once "../includes/config/include.php";
19
require_once "../sources/main.functions.php";
20
21
/**
22
 * Get IP used
23
 *
24
 * @return void
25
 */
26
function getIp()
27
{
28
    if (function_exists('apache_request_headers')) {
29
        $headers = apache_request_headers();
30
    } else {
31
        $headers = $_SERVER;
32
    }
33
    if (array_key_exists('X-Forwarded-For', $headers) && filter_var($headers['X-Forwarded-For'], FILTER_VALIDATE_IP)) {
34
        $the_ip = $headers['X-Forwarded-For'];
35
    } elseif (array_key_exists('HTTP_X_FORWARDED_FOR', $headers) && filter_var($headers['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP)) {
36
        $the_ip = $headers['HTTP_X_FORWARDED_FOR'];
37
    } else {
38
        $the_ip = filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP);
39
    }
40
    return $the_ip;
41
}
42
43
/**
44
 * Is API enabled by admin
45
 *
46
 * @return void
47
 */
48
function teampassApiEnabled()
49
{
50
    teampassConnect();
51
    $response = DB::queryFirstRow(
0 ignored issues
show
Bug introduced by
The type DB was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
52
        "SELECT `valeur` FROM ".prefix_table("misc")." WHERE type = %s AND intitule = %s",
53
        "admin",
54
        "api"
55
    );
56
    return $response['valeur'];
57
}
58
59
/**
60
 * Get list of allowed IPs
61
 *
62
 * @return void
63
 */
64
function teampassWhitelist()
65
{
66
    teampassConnect();
67
    $apiip_pool = teampassGetIps();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $apiip_pool is correct as teampassGetIps() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
68
    if (count($apiip_pool) > 0 && array_search(getIp(), $apiip_pool) === false) {
0 ignored issues
show
Bug introduced by
$apiip_pool of type void is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

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

68
    if (count(/** @scrutinizer ignore-type */ $apiip_pool) > 0 && array_search(getIp(), $apiip_pool) === false) {
Loading history...
Bug introduced by
$apiip_pool of type void is incompatible with the type array expected by parameter $haystack of array_search(). ( Ignorable by Annotation )

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

68
    if (count($apiip_pool) > 0 && array_search(getIp(), /** @scrutinizer ignore-type */ $apiip_pool) === false) {
Loading history...
Bug introduced by
Are you sure the usage of getIp() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
69
        restError('IPWHITELIST');
70
    }
71
}
72
73
/**
74
 * Connect to teampass database
75
 *
76
 * @return void
77
 */
78
function teampassConnect()
79
{
80
    global $server, $user, $pass, $database, $link, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
81
    require_once("../includes/config/settings.php");
82
    require_once('../includes/libraries/Database/Meekrodb/db.class.php');
83
    $pass = defuse_return_decrypted($pass);
84
    DB::$host = $server;
85
    DB::$user = $user;
86
    DB::$password = $pass;
87
    DB::$dbName = $database;
88
    DB::$port = $port;
89
    DB::$encoding = $encoding;
90
    DB::$error_handler = true;
91
    $link = mysqli_connect($server, $user, $pass, $database, $port);
92
    $link->set_charset($encoding);
93
}
94
95
/**
96
 * Get list of ips
97
 *
98
 * @return void
99
 */
100
function teampassGetIps()
101
{
102
    $array_of_results = array();
103
    teampassConnect();
104
    $response = DB::query("select value from ".prefix_table("api")." WHERE type = %s", "ip");
105
    foreach ($response as $data) {
106
        array_push($array_of_results, $data['value']);
107
    }
108
109
    return $array_of_results;
110
}
111
112
/**
113
 * Get list of api keys
114
 *
115
 * @return void
116
 */
117
function teampassGetKeys()
118
{
119
    teampassConnect();
120
    $response = array_unique(array_merge(
121
        DB::queryOneColumn("value", "select * from ".prefix_table("api")." WHERE type = %s", "key"),
122
        DB::queryOneColumn("user_api_key", "select * from ".prefix_table("users")."")
123
    ));
124
125
    // remove none value
126
    if (($key = array_search('none', $response)) !== false) {
127
        unset($response[$key]);
128
    }
129
130
    return $response;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $response returns the type array which is incompatible with the documented return type void.
Loading history...
131
}
132
133
/**
134
 * Set header
135
 *
136
 * @return void
137
 */
138
function restHead()
139
{
140
    header('HTTP/1.1 402 Payment Required');
141
}
142
143
/**
144
 * Add new entry to cache table
145
 *
146
 * @param  integer $item_id
147
 * @return void
148
 */
149
function addToCacheTable($item_id)
150
{
151
    teampassConnect();
152
    // get data
153
    $data = DB::queryfirstrow(
154
        "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
155
        FROM ".prefix_table("items")." AS i
156
        AND ".prefix_table("log_items")." AS l ON (l.id_item = i.id)
157
        WHERE i.id = %i
158
        AND l.action = %s",
159
        intval($item_id),
160
        'at_creation'
161
    );
162
163
    // Get all TAGS
164
    $tags = "";
165
    $data_tags = DB::query("SELECT tag FROM ".prefix_table("tags")." WHERE item_id=%i", $item_id);
166
    foreach ($data_tags as $itemTag) {
167
        if (!empty($itemTag['tag'])) {
168
            $tags .= $itemTag['tag']." ";
169
        }
170
    }
171
172
    // finaly update
173
    DB::insert(
174
        prefix_table("cache"),
175
        array(
176
            "id" => $data['id'],
177
            "label" => $data['label'],
178
            "description" => $data['description'],
179
            "tags" => $tags,
180
            "id_tree" => $data['id_tree'],
181
            "perso" => $data['perso'],
182
            "restricted_to" => $data['restricted_to'],
183
            "login" => $data['login'],
184
            "folder" => "",
185
            //"restricted_to" => "0",
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
186
            "author" => API_USER_ID,
187
            "renewal_period" => 0,
188
            "timestamp" => time(),
189
            "url" => 0
190
        )
191
    );
192
}
193
194
195
/**
196
 * Get the setting value
197
 *
198
 * @param  string] $setting
199
 * @return void
200
 */
201
function getSettingValue($setting)
202
{
203
    // get default language
204
    $set = DB::queryFirstRow(
205
        "SELECT `valeur` FROM ".prefix_table("misc")." WHERE type = %s AND intitule = %s",
206
        "admin",
207
        $setting
208
    );
209
210
    return $set['valeur'];
211
}
212
213
/**
214
 * Permits to get rid of special characters that can break the url
215
 *
216
 * @param  string $string adapted base64 encoded string
217
 * @return string
218
 */
219
function urlSafeB64Decode($string)
220
{
221
    $data = str_replace(
222
        array('-', '_'),
223
        array('+', '/'),
224
        $string
225
    );
226
    $mod4 = strlen($data) % 4;
227
    if ($mod4) {
228
        $data .= substr('====', $mod4);
229
    }
230
    return base64_decode($data);
231
}
232
233
/**
234
 * Delete an item
235
 *
236
 * @return void
237
 */
238
function restDelete()
239
{
240
    if (!@count($GLOBALS['request']) == 0) {
241
        $request_uri = $GLOBALS['_SERVER']['REQUEST_URI'];
242
        preg_match('/\/api(\/index.php|)\/(.*)\?apikey=(.*)/', $request_uri, $matches);
243
        if (count($matches) == 0) {
244
            restError('REQUEST_SENT_NOT_UNDERSTANDABLE');
245
        }
246
        $GLOBALS['request'] = explode('/', $matches[2]);
247
    }
248
    if (apikeyChecker($GLOBALS['apikey'])) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of apikeyChecker($GLOBALS['apikey']) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
249
        include "../sources/main.functions.php";
250
        teampassConnect();
251
        $category_query = "";
252
253
        if ($GLOBALS['request'][0] == "write") {
254
            if ($GLOBALS['request'][1] == "category") {
255
                $array_category = explode(';', $GLOBALS['request'][2]);
256
257
                foreach ($array_category as $category) {
258
                    if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $category, $result)) {
259
                        restError('CATEGORY_MALFORMED');
260
                    }
261
                }
262
263
                if (count($array_category) > 1 && count($array_category) < 5) {
264
                    for ($i = count($array_category); $i > 0; $i--) {
265
                        $slot = $i - 1;
266
                        if (!$slot) {
267
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[$slot], FILTER_SANITIZE_STRING)."' AND parent_id = 0";
268
                        } else {
269
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[$slot], FILTER_SANITIZE_STRING)."' AND parent_id = (";
270
                        }
271
                    }
272
                    for ($i = 1; $i < count($array_category); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
273
                        $category_query .= ")";
274
                    }
275
                } elseif (count($array_category) == 1) {
276
                    $category_query = "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[0], FILTER_SANITIZE_STRING)."' AND parent_id = 0";
277
                } else {
278
                    restError('NO_CATEGORY');
279
                }
280
281
                // Delete items which in category
282
                $response = DB::delete(prefix_table("items"), "id_tree = (".$category_query.")");
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
283
                // Delete sub-categories which in category
284
                $response = DB::delete(prefix_table("nested_tree"), "parent_id = (".$category_query.")");
285
                // Delete category
286
                $response = DB::delete(prefix_table("nested_tree"), "id = (".$category_query.")");
287
288
                $json['type'] = 'category';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$json was never initialized. Although not strictly required by PHP, it is generally a good practice to add $json = array(); before regardless.
Loading history...
289
                $json['category'] = $GLOBALS['request'][2];
290
                if ($response) {
291
                    $json['status'] = 'OK';
292
                } else {
293
                    $json['status'] = 'KO';
294
                }
295
            } elseif ($GLOBALS['request'][1] == "item") {
296
                $array_category = explode(';', $GLOBALS['request'][2]);
297
                $item = $GLOBALS['request'][3];
298
299
                foreach ($array_category as $category) {
300
                    if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $category, $result)) {
301
                        restError('CATEGORY_MALFORMED');
302
                    }
303
                }
304
305
                if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $item, $result)) {
306
                    restError('ITEM_MALFORMED');
307
                } elseif (empty($item) || count($array_category) == 0) {
308
                    restError('MALFORMED');
309
                }
310
311
                if (count($array_category) > 1 && count($array_category) < 5) {
312
                    for ($i = count($array_category); $i > 0; $i--) {
313
                        $slot = $i - 1;
314
                        if (!$slot) {
315
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[$slot], FILTER_SANITIZE_STRING)."' AND parent_id = 0";
316
                        } else {
317
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[$slot], FILTER_SANITIZE_STRING)."' AND parent_id = (";
318
                        }
319
                    }
320
                    for ($i = 1; $i < count($array_category); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
321
                        $category_query .= ")";
322
                    }
323
                } elseif (count($array_category) == 1) {
324
                    $category_query = "select id from ".prefix_table("nested_tree")." where title LIKE '".filter_var($array_category[0], FILTER_SANITIZE_STRING)."' AND parent_id = 0";
325
                } else {
326
                    restError('NO_CATEGORY');
327
                }
328
329
                // Delete item
330
                $response = DB::delete(prefix_table("items"), "id_tree = (".$category_query.") and label LIKE '".filter_var($item, FILTER_SANITIZE_STRING)."'");
331
                $json['type'] = 'item';
332
                $json['item'] = $item;
333
                $json['category'] = $GLOBALS['request'][2];
334
                if ($response) {
335
                    $json['status'] = 'OK';
336
                } else {
337
                    $json['status'] = 'KO';
338
                }
339
            }
340
341
            if ($json) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $json does not seem to be defined for all execution paths leading up to this point.
Loading history...
342
                echo json_encode($json);
343
            } else {
344
                restError('EMPTY');
345
            }
346
        } else {
347
            restError('METHOD');
348
        }
349
    }
350
}
351
352
/**
353
 * Send back data to user
354
 *
355
 * @return void
356
 */
357
function restGet()
358
{
359
    global $api_version;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
360
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
361
    global $link;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
362
363
    if (!@count($GLOBALS['request']) == 0) {
364
        $request_uri = $GLOBALS['_SERVER']['REQUEST_URI'];
365
        preg_match('/\/api(\/index.php|)\/(.*)\?apikey=(.*)/', $request_uri, $matches);
366
        if (count($matches) == 0) {
367
            restError('REQUEST_SENT_NOT_UNDERSTANDABLE');
368
        }
369
        $GLOBALS['request'] = explode('/', $matches[2]);
370
    }
371
372
    if (apikeyChecker($GLOBALS['apikey'])) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of apikeyChecker($GLOBALS['apikey']) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
373
374
        teampassConnect();
375
376
        // define the API user through the LABEL of apikey
377
        $api_info = DB::queryFirstRow(
378
            "SELECT label
379
            FROM ".prefix_table("api")."
380
            WHERE value = %s",
381
            $GLOBALS['apikey']
382
        );
383
384
        // Load config
385
        if (file_exists('../includes/config/tp.config.php')) {
386
            include_once '../includes/config/tp.config.php';
387
        } else {
388
            throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
389
        }
390
391
        if ($GLOBALS['request'][0] == "read") {
392
            if ($GLOBALS['request'][1] == "folder") {
393
                /*
394
                * READ FOLDERS
395
                */
396
397
                // load library
398
                require_once '../sources/SplClassLoader.php';
399
                //Load Tree
400
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
401
                $tree->register();
402
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
0 ignored issues
show
Bug introduced by
The type Tree\NestedTree\NestedTree was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
403
404
                // get ids
405
                if (strpos($GLOBALS['request'][2], ";") > 0) {
406
                    $condition = "id_tree IN %ls";
407
                    $condition_value = explode(';', $GLOBALS['request'][2]);
408
                } else {
409
                    $condition = "id_tree = %s";
410
                    $condition_value = $GLOBALS['request'][2];
411
                }
412
413
                // get items in this folder
414
                $response = DB::query(
415
                    "SELECT id, label, login, pw, pw_iv, url, id_tree, description, email
416
                    FROM ".prefix_table("items")."
417
                    WHERE inactif='0' AND ".$condition,
418
                    $condition_value
419
                );
420
                $inc = 0;
421
                foreach ($response as $data) {
422
                    // build the path to the Item
423
                    $path = "";
424
                    $arbo = $tree->getPath($data['id_tree'], true);
425
                    foreach ($arbo as $elem) {
426
                        if (empty($path)) {
427
                            $path = stripslashes($elem->title);
428
                        } else {
429
                            $path .= " > ".stripslashes($elem->title);
430
                        }
431
                    }
432
433
                    // prepare output
434
                    $json[$inc]['id'] = $data['id'];
435
                    $json[$inc]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
436
                    $json[$inc]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
437
                    $json[$inc]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
438
                    $json[$inc]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
439
                    $json[$inc]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
440
                    $crypt_pw = cryption(
441
                        $data['pw'],
442
                        "",
443
                        "decrypt"
444
                    );
445
                    $json[$inc]['pw'] = $crypt_pw['string'];
446
                    $json[$inc]['folder_id'] = $data['id_tree'];
447
                    $json[$inc]['path'] = $path;
448
449
                    $inc++;
450
                }
451
            } elseif ($GLOBALS['request'][1] == "userpw") {
452
                /*
453
                * READ USER ITEMS
454
                */
455
456
                // load library
457
                require_once '../sources/SplClassLoader.php';
458
                //Load Tree
459
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
460
                $tree->register();
461
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
462
463
                // about the user
464
                $username = $GLOBALS['request'][2];
465
                if (strcmp($username, "admin") == 0) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
466
                    // forbid admin access
467
                }
468
                $response = DB::query(
469
                    "SELECT fonction_id
470
                    FROM ".prefix_table("users")."
471
                    WHERE login = %s'",
472
                    $username
473
                );
474
                if (count($response) === 0) {
475
                    restError('USER_NOT_EXISTS');
476
                }
477
                foreach ($response as $data) {
478
                    $role_str = $data['fonction_id'];
479
                }
480
                $folder_arr = array();
481
                $roles = explode(";", $role_str);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $role_str seems to be defined by a foreach iteration on line 477. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
482
                foreach ($roles as $role) {
483
                    $response = DB::query(
484
                        "SELECT folder_id
485
                        FROM ".prefix_table("roles_values")."
486
                        WHERE role_id = %i",
487
                        $role
488
                    );
489
                    foreach ($response as $data) {
490
                        $folder_id = $data['folder_id'];
491
                        if (!array_key_exists($folder_id, $folder_arr)) {
492
                            array_push($folder_arr, $folder_id);
493
                        }
494
                    }
495
                }
496
                $folder_str = array_filter($folder_arr);
497
498
                // get ids
499
                if (is_array($folder_str)) {
0 ignored issues
show
introduced by
The condition is_array($folder_str) is always true.
Loading history...
500
                    $condition = "id_tree IN %ls";
501
                    $condition_value = $folder_str;
502
                } else {
503
                    $condition = "id_tree = %s";
504
                    $condition_value = $folder_str;
505
                }
506
507
                $data = "";
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
508
                // get items in this module
509
                $response = DB::query(
510
                    "SELECT id,label,url,login,pw, pw_iv, url, id_tree, description, email
511
                    FROM ".prefix_table("items")."
512
                    WHERE inactif='0' AND ".$condition,
513
                    $condition_value
514
                );
515
                $inc = 0;
516
                foreach ($response as $data) {
517
                    // build the path to the Item
518
                    $path = "";
519
                    $arbo = $tree->getPath($data['id_tree'], true);
520
                    foreach ($arbo as $elem) {
521
                        if (empty($path)) {
522
                            $path = stripslashes($elem->title);
523
                        } else {
524
                            $path .= " > ".stripslashes($elem->title);
525
                        }
526
                    }
527
528
                    // prepare output
529
                    $json[$data['id']]['id'] = $data['id'];
530
                    $json[$data['id']]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
531
                    $json[$data['id']]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
532
                    $json[$data['id']]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
533
                    $json[$data['id']]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
534
                    $json[$data['id']]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
535
                    $crypt_pw = cryption($data['pw'], "", "decrypt");
536
                    $json[$data['id']]['pw'] = $crypt_pw['string'];
537
                    $json[$data['id']]['folder_id'] = $data['id_tree'];
538
                    $json[$data['id']]['path'] = $path;
539
540
                    $inc++;
541
                }
542
            } elseif ($GLOBALS['request'][1] == "userfolders") {
543
                /*
544
                * READ USER FOLDERS
545
                * Sends back a list of folders
546
                */
547
                $json = "";
548
                $username = $GLOBALS['request'][2];
549
                if (strcmp($username, "admin") == 0) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
550
                    // forbid admin access
551
                }
552
                $response = DB::query(
553
                    "SELECT fonction_id
554
                    FROM ".prefix_table("users")."
555
                    WHERE login = %s",
556
                    $username
557
                );
558
                if (count($response) === 0) {
559
                    restError('USER_NOT_EXISTS');
560
                }
561
                foreach ($response as $data) {
562
                    $role_str = $data['fonction_id'];
563
                }
564
565
                $folder_arr = array();
566
                $roles = explode(";", $role_str);
567
                $inc = 0;
568
                foreach ($roles as $role) {
569
                    $response = DB::query(
570
                        "SELECT folder_id, type
571
                        FROM ".prefix_table("roles_values")."
572
                        WHERE role_id = %i",
573
                        $role
574
                    );
575
                    foreach ($response as $data) {
576
                        $folder_id = $data['folder_id'];
577
                        if (!array_key_exists($folder_id, $folder_arr)) {
578
                            array_push($folder_arr, $folder_id);
579
580
                            $response2 = DB::queryFirstRow(
581
                                "SELECT title, nlevel
582
                                FROM ".prefix_table("nested_tree")."
583
                                WHERE id = %i",
584
                                $folder_id
585
                            );
586
587
                            if (!empty($response2['title'])) {
588
                                $json[$folder_id]['id'] = $folder_id;
589
                                $json[$folder_id]['title'] = $response2['title'];
590
                                $json[$folder_id]['level'] = $response2['nlevel'];
591
                                $json[$folder_id]['access_type'] = $data['type'];
592
                                $inc++;
593
                            }
594
                        }
595
                    }
596
                }
597
            } elseif ($GLOBALS['request'][1] == "items") {
598
                /*
599
                * READ ITEMS asked
600
                */
601
602
                // load library
603
                require_once '../sources/SplClassLoader.php';
604
                //Load Tree
605
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
606
                $tree->register();
607
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
608
609
                // get parameters
610
                $array_items = explode(';', $GLOBALS['request'][2]);
611
612
                // check if not empty
613
                if (count($array_items) == 0) {
614
                    restError('NO_ITEM');
615
                }
616
617
                // only accepts numeric
618
                foreach ($array_items as $item) {
619
                    if (!is_numeric($item)) {
620
                        restError('ITEM_MALFORMED');
621
                    }
622
                }
623
624
                $response = DB::query(
625
                    "SELECT id,label,login,pw, pw_iv, url, id_tree, description, email
626
                    FROM ".prefix_table("items")."
627
                    WHERE inactif = %i AND id IN %ls",
628
                    "0",
629
                    $array_items
630
                );
631
                $inc = 0;
632
                foreach ($response as $data) {
633
                    // build the path to the Item
634
                    $path = "";
635
                    $arbo = $tree->getPath($data['id_tree'], true);
636
                    foreach ($arbo as $elem) {
637
                        if (empty($path)) {
638
                            $path = stripslashes($elem->title);
639
                        } else {
640
                            $path .= " > ".stripslashes($elem->title);
641
                        }
642
                    }
643
644
                    // prepare output
645
                    $json[$inc]['id'] = $data['id'];
646
                    $json[$inc]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
647
                    $json[$inc]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
648
                    $json[$inc]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
649
                    $json[$inc]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
650
                    $json[$inc]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
651
                    $crypt_pw = cryption($data['pw'], "", "decrypt");
652
                    $json[$inc]['pw'] = $crypt_pw['string'];
653
                    $json[$inc]['folder_id'] = $data['id_tree'];
654
                    $json[$inc]['path'] = $path;
655
656
                    $inc++;
657
                }
658
            } elseif ($GLOBALS['request'][1] == "folder_descendants") {
659
                /*
660
                * PRovide full list of folders
661
                * <url to teampass>/api/index.php/read/folder_descendants/<id OR title>/<folder_id or folder_title>?apikey=<valid api key>
662
                */
663
664
                // get parameters
665
                if (isset($GLOBALS['request'][2]) === true && isset($GLOBALS['request'][3]) === true) {
666
                    // load library
667
                    require_once '../sources/SplClassLoader.php';
668
                    //Load Tree
669
                    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
670
                    $tree->register();
671
                    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
672
673
                    // get parameters
674
                    $parameter_by = $GLOBALS['request'][2];
675
                    $parameter_criteria = $GLOBALS['request'][3];
676
677
                    // Check data consistency
678
                    if (preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $parameter_by, $result) === false) {
679
                        restError('MALFORMED');
680
                    }
681
682
                    if (preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $parameter_criteria, $result) === false) {
683
                        restError('MALFORMED');
684
                    }
685
686
                    // Is BY criteria correct
687
                    if ($parameter_by !== "id" && $parameter_by !== "title") {
688
                        restError('EXPECTED_PARAMETER_NOT_PROVIDED');
689
                    }
690
691
                    // If criteria is by Title
692
                    // Then search its id first
693
                    if ($parameter_by === "title") {
694
                        $response = DB::queryFirstRow(
695
                            "SELECT id
696
                            FROM ".prefix_table("nested_tree")."
697
                            WHERE
698
                            title LIKE %s",
699
                            $parameter_criteria
700
                        );
701
                        $parameter_criteria = $response['id'];
702
                    }
703
704
                    // List folder descendants
705
                    $folders = $tree->getDescendants(intval($parameter_criteria), true, false, false);
706
                    if (count($folders) > 0) {
707
                        $inc = 0;
708
                        foreach ($folders as $folder) {
709
                            // Prepare answer
710
                            $json[$inc]['id'] = mb_convert_encoding($folder->id, mb_detect_encoding($folder->id), 'UTF-8');
711
                            $json[$inc]['parent_id'] = mb_convert_encoding($folder->parent_id, mb_detect_encoding($folder->parent_id), 'UTF-8');
712
                            $json[$inc]['title'] = mb_convert_encoding(htmlspecialchars_decode($folder->title, ENT_QUOTES), mb_detect_encoding($folder->title), 'UTF-8');
713
                            $json[$inc]['nleft'] = mb_convert_encoding($folder->nleft, mb_detect_encoding($folder->nleft), 'UTF-8');
714
                            $json[$inc]['nright'] = mb_convert_encoding($folder->nright, mb_detect_encoding($folder->nright), 'UTF-8');
715
                            $json[$inc]['nlevel'] = mb_convert_encoding($folder->nlevel, mb_detect_encoding($folder->nlevel), 'UTF-8');
716
                            $json[$inc]['personal'] = mb_convert_encoding($folder->personal_folder, mb_detect_encoding($folder->personal_folder), 'UTF-8');
717
718
                            $inc++;
719
                        }
720
                    }
721
                }
722
            }
723
724
            if (isset($json) && $json) {
725
                echo json_encode($json);
726
            } else {
727
                restError('EMPTY');
728
            }
729
        } elseif ($GLOBALS['request'][0] == "find") {
730
            if ($GLOBALS['request'][1] == "item") {
731
                /*
732
                * FIND ITEMS in FOLDERS
733
                */
734
735
                // load library
736
                require_once '../sources/SplClassLoader.php';
737
                //Load Tree
738
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
739
                $tree->register();
740
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
741
742
                // get parameters
743
                $array_category = explode(';', $GLOBALS['request'][2]);
744
                $item = $GLOBALS['request'][3];
745
                foreach ($array_category as $category) {
746
                    if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $category, $result)) {
747
                        restError('CATEGORY_MALFORMED');
748
                    }
749
                }
750
751
                if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $item, $result)) {
752
                    restError('ITEM_MALFORMED');
753
                } elseif (empty($item) || count($array_category) == 0) {
754
                    restError('MALFORMED');
755
                }
756
757
                if (count($array_category) === 0) {
758
                    restError('NO_CATEGORY');
759
                }
760
761
                DB::debugMode(false);
762
                $response = DB::query(
763
                    "SELECT id, label, login, pw, pw_iv, url, id_tree, description, email
764
                    FROM ".prefix_table("items")."
765
                    WHERE
766
                    inactif = %i
767
                    AND id_tree IN %ls
768
                    AND label LIKE %ss",
769
                    "0",
770
                    $array_category,
771
                    $item
772
                );
773
                $inc = 0;
774
                foreach ($response as $data) {
775
                    // build the path to the Item
776
                    $path = "";
777
                    $arbo = $tree->getPath($data['id_tree'], true);
778
                    foreach ($arbo as $elem) {
779
                        if (empty($path)) {
780
                            $path = stripslashes($elem->title);
781
                        } else {
782
                            $path .= " > ".stripslashes($elem->title);
783
                        }
784
                    }
785
786
                    // prepare output
787
                    $json[$inc]['id'] = mb_convert_encoding($data['id'], mb_detect_encoding($data['id']), 'UTF-8');
788
                    $json[$inc]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
789
                    $json[$inc]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
790
                    $json[$inc]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
791
                    $json[$inc]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
792
                    $json[$inc]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
793
                    $crypt_pw = cryption($data['pw'], "", "decrypt");
794
                    $json[$inc]['pw'] = $crypt_pw['string'];
795
                    $json[$inc]['folder_id'] = $data['id_tree'];
796
                    $json[$inc]['path'] = $path;
797
                    $json[$inc]['status'] = utf8_encode("OK");
798
799
                    $inc++;
800
                }
801
                if (isset($json) && $json) {
802
                    echo json_encode($json);
803
                } else {
804
                    restError('EMPTY');
805
                }
806
            }
807
        } elseif ($GLOBALS['request'][0] == "add") {
808
            if ($GLOBALS['request'][1] == "item") {
809
                // get sent parameters
810
                $params = explode(';', urlSafeB64Decode($GLOBALS['request'][2]));
811
                if (count($params) != 9) {
812
                    restError('ITEMBADDEFINITION');
813
                }
814
815
                $item_label = $params[0];
816
                $item_pwd = $params[1];
817
                $item_desc = $params[2];
818
                $item_folder_id = $params[3];
819
                $item_login = $params[4];
820
                $item_email = $params[5];
821
                $item_url = $params[6];
822
                $item_tags = $params[7];
823
                $item_anyonecanmodify = $params[8];
824
825
                // do some checks
826
                if (!empty($item_label) && !empty($item_pwd) && !empty($item_folder_id)) {
827
                    // Check length
828
                    if (strlen($item_pwd) > 50) {
829
                        restError('PASSWORDTOOLONG');
830
                    }
831
832
                    // Check Folder ID
833
                    DB::query("SELECT * FROM ".prefix_table("nested_tree")." WHERE id = %i", $item_folder_id);
834
                    $counter = DB::count();
835
                    if ($counter == 0) {
836
                        restError('NOSUCHFOLDER');
837
                    }
838
839
                    // check if element doesn't already exist
840
                    $item_duplicate_allowed = getSettingValue("duplicate_item");
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $item_duplicate_allowed is correct as getSettingValue('duplicate_item') seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
841
                    if ($item_duplicate_allowed !== "1") {
0 ignored issues
show
introduced by
The condition $item_duplicate_allowed !== '1' is always true.
Loading history...
842
                        DB::query(
843
                            "SELECT *
844
                            FROM ".prefix_table("items")."
845
                            WHERE label = %s AND inactif = %i",
846
                            addslashes($item_label),
847
                            "0"
848
                        );
849
                        $counter = DB::count();
850
                        if ($counter != 0) {
851
                            $itemExists = 1;
852
                            // prevent the error if the label already exists
853
                            // so lets just add the time() as a random factor
854
                            $item_label .= " (".time().")";
855
                        } else {
856
                            $itemExists = 0;
857
                        }
858
                    } else {
859
                        $itemExists = 0;
860
                    }
861
                    if ($itemExists === 0) {
862
                        $encrypt = cryption(
863
                            $item_pwd,
864
                            "",
865
                            "encrypt"
866
                        );
867
                        if (empty($encrypt['string'])) {
868
                            restError('PASSWORDEMPTY');
869
                        }
870
871
                        // ADD item
872
                        try {
873
                            DB::insert(
874
                                prefix_table("items"),
875
                                array(
876
                                    "label" => $item_label,
877
                                    "description" => $item_desc,
878
                                    'pw' => $encrypt['string'],
879
                                    'pw_iv' => '',
880
                                    "email" => $item_email,
881
                                    "url" => $item_url,
882
                                    "id_tree" => intval($item_folder_id),
883
                                    "login" => $item_login,
884
                                    "inactif" => 0,
885
                                    "restricted_to" => "",
886
                                    "perso" => 0,
887
                                    "anyone_can_modify" => intval($item_anyonecanmodify)
888
                                )
889
                            );
890
                            $newID = DB::InsertId();
891
892
                            // log
893
                            DB::insert(
894
                                prefix_table("log_items"),
895
                                array(
896
                                    "id_item" => $newID,
897
                                    "date" => time(),
898
                                    "id_user" => API_USER_ID,
899
                                    "action" => "at_creation",
900
                                    "raison" => $api_info['label']
901
                                )
902
                            );
903
904
                            // Add tags
905
                            $tags = explode(' ', $item_tags);
906
                            foreach ((array) $tags as $tag) {
907
                                if (!empty($tag)) {
908
                                    DB::insert(
909
                                        prefix_table("tags"),
910
                                        array(
911
                                            "item_id" => $newID,
912
                                            "tag" => strtolower($tag)
913
                                        )
914
                                    );
915
                                }
916
                            }
917
918
                            // Update CACHE table
919
                            DB::insert(
920
                                prefix_table("cache"),
921
                                array(
922
                                    "id" => $newID,
923
                                    "label" => $item_label,
924
                                    "description" => $item_desc,
925
                                    "tags" => $item_tags,
926
                                    "id_tree" => $item_folder_id,
927
                                    "perso" => "0",
928
                                    "restricted_to" => "",
929
                                    "login" => $item_login,
930
                                    "folder" => "",
931
                                    "author" => API_USER_ID,
932
                                    "renewal_period" => "0",
933
                                    "timestamp" => time(),
934
                                    "url" => "0"
935
                                )
936
                            );
937
938
                            echo '{"status":"item added" , "new_item_id" : "'.$newID.'"}';
939
                        } catch (PDOException $ex) {
940
                            echo '<br />'.$ex->getMessage();
941
                        }
942
                    } else {
943
                        restError('ITEMEXISTS');
944
                    }
945
                } else {
946
                    restError('ITEMMISSINGDATA');
947
                }
948
            } elseif ($GLOBALS['request'][1] == "user") {
949
            /*
950
             * Case where a new user has to be added
951
             *
952
             * 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>
953
             * with:
954
             * for READ_ONLY, IS_ADMIN, IS_MANAGER, PERSONAL_FOLDER, accepted value is 1 for TRUE and 0 for FALSE
955
             * for ADMINISTRATEDBY and ROLE1, accepted value is the real label (not the IDs)
956
             *
957
             * Example: /api/index.php/add/user/U4;Nils;Laumaille;test;[email protected];Users;0;Managers,Users;0;1;1?apikey=sae6iekahxiseL3viShoo0chahc1ievei8aequi
958
             *
959
             */
960
961
                // get user definition
962
                $array_user = explode(';', urlSafeB64Decode($GLOBALS['request'][2]));
963
                if (count($array_user) != 11) {
964
                    restError('USERBADDEFINITION');
965
                }
966
967
                $login = $array_user[0];
968
                $name = $array_user[1];
969
                $lastname = $array_user[2];
970
                $password = $array_user[3];
971
                $email = $array_user[4];
972
                $adminby = urldecode($array_user[5]);
973
                $isreadonly = urldecode($array_user[6]);
974
                $roles = urldecode($array_user[7]);
975
                $isadmin = $array_user[8];
976
                $ismanager = $array_user[9];
977
                $haspf = $array_user[10];
978
979
                // Empty user
980
                if (mysqli_escape_string($link, htmlspecialchars_decode($login)) == "") {
981
                    restError('USERLOGINEMPTY');
982
                }
983
                // Check if user already exists
984
                $data = DB::query(
985
                    "SELECT id, fonction_id, groupes_interdits, groupes_visibles
986
                    FROM ".prefix_table("users")."
987
                    WHERE login LIKE %ss",
988
                    mysqli_escape_string($link, stripslashes($login))
989
                );
990
991
                if (DB::count() == 0) {
992
                    try {
993
                        // find AdminRole code in DB
994
                        $resRole = DB::queryFirstRow(
995
                            "SELECT id
996
                            FROM ".prefix_table("roles_title")."
997
                            WHERE title LIKE %ss",
998
                            mysqli_escape_string($link, stripslashes($adminby))
999
                        );
1000
1001
                        // get default language
1002
                        $lang = DB::queryFirstRow(
1003
                            "SELECT `valeur`
1004
                            FROM ".prefix_table("misc")."
1005
                            WHERE type = %s AND intitule = %s",
1006
                            "admin",
1007
                            "default_language"
1008
                        );
1009
1010
                        // prepare roles list
1011
                        $rolesList = "";
1012
                        foreach (explode(',', $roles) as $role) {
1013
                            $tmp = DB::queryFirstRow(
1014
                                "SELECT `id`
1015
                                FROM ".prefix_table("roles_title")."
1016
                                WHERE title = %s",
1017
                                $role
1018
                            );
1019
                            if (empty($rolesList)) {
1020
                                $rolesList = $tmp['id'];
1021
                            } else {
1022
                                $rolesList .= ";".$tmp['id'];
1023
                            }
1024
                        }
1025
1026
                        // Add user in DB
1027
                        DB::insert(
1028
                            prefix_table("users"),
1029
                            array(
1030
                                'login' => $login,
1031
                                'name' => $name,
1032
                                'lastname' => $lastname,
1033
                                'pw' => bCrypt(stringUtf8Decode($password), COST),
1034
                                'email' => $email,
1035
                                'admin' => intval($isadmin),
1036
                                'gestionnaire' => intval($ismanager),
1037
                                'read_only' => intval($isreadonly),
1038
                                'personal_folder' => intval($haspf),
1039
                                'user_language' => $lang['valeur'],
1040
                                'fonction_id' => $rolesList,
1041
                                'groupes_interdits' => '0',
1042
                                'groupes_visibles' => '0',
1043
                                'isAdministratedByRole' => empty($resRole) ? '0' : $resRole['id']
1044
                            )
1045
                        );
1046
                        $new_user_id = DB::insertId();
1047
                        // Create personnal folder
1048
                        if (intval($haspf) === 1) {
1049
                            DB::insert(
1050
                                prefix_table("nested_tree"),
1051
                                array(
1052
                                    'parent_id' => '0',
1053
                                    'title' => $new_user_id,
1054
                                    'bloquer_creation' => '0',
1055
                                    'bloquer_modification' => '0',
1056
                                    'personal_folder' => '1'
1057
                                )
1058
                            );
1059
                        }
1060
1061
                        // load settings
1062
                        loadSettings();
1063
1064
                        // Send email to new user
1065
                        @sendEmail(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for sendEmail(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

1065
                        /** @scrutinizer ignore-unhandled */ @sendEmail(

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1066
                            $LANG['email_subject_new_user'],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $LANG seems to be never defined.
Loading history...
1067
                            str_replace(
1068
                                array('#tp_login#', '#tp_pw#', '#tp_link#'),
1069
                                array(" ".addslashes($login), addslashes($password), $SETTINGS['email_server_url']),
1070
                                $LANG['email_new_user_mail']
1071
                            ),
1072
                            $email,
1073
                            $LANG,
1074
                            $SETTINGS
1075
                        );
1076
1077
                        // update LOG
1078
                        logEvents(
1079
                            'user_mngt',
1080
                            'at_user_added',
1081
                            'api - '.$GLOBALS['apikey'],
1082
                            $new_user_id,
1083
                            ""
1084
                        );
1085
1086
                        echo '{"status":"user added"}';
1087
                    } catch (PDOException $ex) {
1088
                        echo '<br />'.$ex->getMessage();
1089
                    }
1090
                } else {
1091
                    restError('USERALREADYEXISTS');
1092
                }
1093
            } elseif ($GLOBALS['request'][1] == "folder") {
1094
            /*
1095
            * ADDING A FOLDER
1096
            * <url to teampass>/api/index.php/add/folder/<title>;<complexity_level>;<parent_id>;<renewal_period>;<personal>?apikey=<valid api key>
1097
            * http://localhost/teampass/api/index.php/add/folder/Import from API;0;38;0;0?apikey=piesae7ahghae1iiP9ohPhaefaideeThohgh1te
1098
            */
1099
                if (!empty($GLOBALS['request'][2])) {
1100
                    // get sent parameters
1101
                    $params = explode(';', urlSafeB64Decode($GLOBALS['request'][2]));
1102
1103
                    if (empty($params[0]) === false && (intval($params[1]) >= 0 && intval($params[1]) <= 1000)) {
1104
                        if (empty($params[3])) {
1105
                            $params[3] = 0;
1106
                        }
1107
                        if (empty($params[4])) {
1108
                            $params[4] = 0;
1109
                        }
1110
                        if (empty($params[2])) {
1111
                            restError('NO_DESTINATION_FOLDER');
1112
                        }
1113
                        if ($params[2] < 0) {
1114
                            restError('NO_DATA_EXIST');
1115
                        }
1116
1117
                        //Check if title doesn't contains html codes
1118
                        if (preg_match_all("|<[^>]+>(.*)</[^>]+>|U", $params[0], $out)) {
1119
                            restError('HTML_CODES_NOT_ALLOWED');
1120
                        }
1121
1122
                        // check if title is numeric
1123
                        if (is_numeric($params[0]) === true) {
1124
                            restError('TITLE_ONLY_WITH_NUMBERS');
1125
                        }
1126
1127
                        //Check if duplicate folders name are allowed
1128
                        $data = DB::queryfirstrow(
1129
                            "SELECT valeur
1130
                            FROM ".prefix_table("misc")."
1131
                            WHERE type = %s AND intitule = %s",
1132
                            "admin",
1133
                            "duplicate_folder"
1134
                        );
1135
                        // if valeur = 0 then duplicate folders not allowed
1136
                        if ($data['valeur'] === '0') {
1137
                            DB::query(
1138
                                "SELECT *
1139
                                FROM ".prefix_table("nested_tree")."
1140
                                WHERE title = %s",
1141
                                $params[0]
1142
                            );
1143
                            $counter = DB::count();
1144
                            if ($counter != 0) {
1145
                                restError('ALREADY_EXISTS');
1146
                            }
1147
                        }
1148
1149
                        //check if parent folder is personal
1150
                        $data = DB::queryfirstrow(
1151
                            "SELECT personal_folder
1152
                            FROM ".prefix_table("nested_tree")."
1153
                            WHERE id = %i",
1154
                            $params[2]
1155
                        );
1156
                        if ($data['personal_folder'] === "1") {
1157
                            $isPersonal = 1;
1158
                        } else {
1159
                            if ($params[4] === 1) {
0 ignored issues
show
introduced by
The condition $params[4] === 1 is always false.
Loading history...
1160
                                $isPersonal = 1;
1161
                            } else {
1162
                                $isPersonal = 0;
1163
                            }
1164
1165
                            // get complexity level for this folder
1166
                            $data = DB::queryfirstrow(
1167
                                "SELECT valeur
1168
                                FROM ".prefix_table("misc")."
1169
                                WHERE intitule = %i AND type = %s",
1170
                                $params[2],
1171
                                "complex"
1172
                            );
1173
                            if (intval($params[1]) < intval($data['valeur'])) {
1174
                                restError('COMPLEXICITY_LEVEL_NOT_REACHED');
1175
                            }
1176
                        }
1177
1178
                        try {
1179
                            //create folder
1180
                            DB::insert(
1181
                                prefix_table("nested_tree"),
1182
                                array(
1183
                                    'parent_id' => $params[2],
1184
                                    'title' => $params[0],
1185
                                    'personal_folder' => $isPersonal,
1186
                                    'renewal_period' => $params[3],
1187
                                    'bloquer_creation' => '0',
1188
                                    'bloquer_modification' => '0'
1189
                                )
1190
                            );
1191
                            $newId = DB::insertId();
1192
1193
                            //Add complexity
1194
                            DB::insert(
1195
                                prefix_table("misc"),
1196
                                array(
1197
                                    'type' => 'complex',
1198
                                    'intitule' => $newId,
1199
                                    'valeur' => $params[1]
1200
                                )
1201
                            );
1202
1203
                            // Run nested tree update
1204
                            require_once '../sources/SplClassLoader.php';
1205
                            $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1206
                            $tree->register();
1207
                            $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
1208
                            $tree->rebuild();
1209
1210
                            // We need to allocate the same access rights as the parent
1211
                            // We will considere that if created as root then its rights must be set through the GUI
1212
                            $ret = DB::query(
1213
                                "SELECT role_id, type
1214
                                FROM ".prefix_table("roles_values")."
1215
                                WHERE folder_id = %i",
1216
                                $params[2]
1217
                            );
1218
                            foreach ($ret as $entry) {
1219
                                DB::insert(
1220
                                    prefix_table("roles_values"),
1221
                                    array(
1222
                                        'role_id' => $entry['role_id'],
1223
                                        'folder_id' => $newId,
1224
                                        'type' => $entry['type']
1225
                                    )
1226
                                );
1227
                            }
1228
1229
                            echo '{"status":"folder created" , "new_folder_id":"'.$newId.'"}';
1230
                        } catch (PDOException $ex) {
1231
                            echo '<br />'.$ex->getMessage();
1232
                        }
1233
                    } else {
1234
                        restError('NO_DATA_EXIST');
1235
                    }
1236
                } else {
1237
                    restError('SET_NO_DATA');
1238
                }
1239
            }
1240
        } elseif ($GLOBALS['request'][0] == "update") {
1241
            /*
1242
            * Section dedicated for UPDATING
1243
            */
1244
            if ($GLOBALS['request'][1] == "item") {
1245
                /*
1246
                * 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>
1247
                */
1248
                if ($GLOBALS['request'][2] !== "" && is_numeric($GLOBALS['request'][2])) {
1249
                    // get sent parameters
1250
                    $params = explode(';', urlSafeB64Decode($GLOBALS['request'][3]));
1251
1252
                    if (!empty($params[0]) && !empty($params[1]) && !empty($params[3])) {
1253
                        // Check length
1254
                        if (strlen($params[1]) > 50) {
1255
                            restError('PASSWORDTOOLONG');
1256
                        }
1257
1258
                        // Check Folder ID
1259
                        DB::query(
1260
                            "SELECT *
1261
                            FROM ".prefix_table("nested_tree")."
1262
                            WHERE id = %i",
1263
                            $params[3]
1264
                        );
1265
                        $counter = DB::count();
1266
                        if ($counter == 0) {
1267
                            restError('NOSUCHFOLDER');
1268
                        }
1269
1270
                        // check if item exists
1271
                        DB::query(
1272
                            "SELECT *
1273
                            FROM ".prefix_table("items")."
1274
                            WHERE id = %i",
1275
                            $GLOBALS['request'][2]
1276
                        );
1277
                        $counter = DB::count();
1278
                        if ($counter > 0) {
1279
                            // encrypt pwd
1280
                            $encrypt = cryption(
1281
                                $params[1],
1282
                                "",
1283
                                "encrypt"
1284
                            );
1285
                            if (empty($encrypt['string'])) {
1286
                                restError('PASSWORDEMPTY');
1287
                            }
1288
1289
                            // ADD item
1290
                            try {
1291
                                DB::update(
1292
                                    prefix_table("items"),
1293
                                    array(
1294
                                        "label" => $params[0],
1295
                                        "description" => $params[2],
1296
                                        'pw' => $encrypt['string'],
1297
                                        'pw_iv' => '',
1298
                                        "email" => $params[5],
1299
                                        "url" => $params[6],
1300
                                        "id_tree" => intval($params[3]),
1301
                                        "login" => $params[4],
1302
                                        "anyone_can_modify" => intval($params[8])
1303
                                    ),
1304
                                    "id = %i",
1305
                                    $GLOBALS['request'][2]
1306
                                );
1307
1308
                                // log
1309
                                DB::insert(
1310
                                    prefix_table("log_items"),
1311
                                    array(
1312
                                        "id_item" => $GLOBALS['request'][2],
1313
                                        "date" => time(),
1314
                                        "id_user" => API_USER_ID,
1315
                                        "action" => "at_modification"
1316
                                    )
1317
                                );
1318
1319
                                // Add tags
1320
                                $tags = explode(' ', $params[7]);
1321
                                foreach ((array) $tags as $tag) {
1322
                                    if (!empty($tag)) {
1323
                                        // check if already exists
1324
                                        DB::query(
1325
                                            "SELECT *
1326
                                            FROM ".prefix_table("tags")."
1327
                                            WHERE tag = %s AND item_id = %i",
1328
                                            strtolower($tag),
1329
                                            $GLOBALS['request'][2]
1330
                                        );
1331
                                        $counter = DB::count();
1332
                                        if ($counter === 0) {
1333
                                            DB::insert(
1334
                                                prefix_table("tags"),
1335
                                                array(
1336
                                                    "item_id" => $GLOBALS['request'][2],
1337
                                                    "tag" => strtolower($tag)
1338
                                                )
1339
                                            );
1340
                                        }
1341
                                    }
1342
                                }
1343
1344
                                // Update CACHE table
1345
                                DB::update(
1346
                                    prefix_table("cache"),
1347
                                    array(
1348
                                        "label" => $params[0],
1349
                                        "description" => $params[2],
1350
                                        "tags" => $params[7],
1351
                                        "id_tree" => intval($params[3]),
1352
                                        "perso" => "0",
1353
                                        "restricted_to" => "",
1354
                                        "login" => $params[4],
1355
                                        "folder" => "",
1356
                                        "author" => API_USER_ID,
1357
                                        "renewal_period" => "0",
1358
                                        "timestamp" => time(),
1359
                                        "url" => $params[6],
1360
                                    ),
1361
                                    "id = %i",
1362
                                    $GLOBALS['request'][2]
1363
                                );
1364
1365
                                echo '{"status":"item updated"}';
1366
                            } catch (PDOException $ex) {
1367
                                echo '<br />'.$ex->getMessage();
1368
                            }
1369
                        } else {
1370
                            restError('NO_DATA_EXIST');
1371
                        }
1372
                    } else {
1373
                        restError('ITEMMISSINGDATA');
1374
                    }
1375
                } else {
1376
                    restError('NO_ITEM');
1377
                }
1378
            } elseif ($GLOBALS['request'][1] == "folder") {
1379
            /*
1380
            * UPDATING A FOLDER
1381
            * <url to teampass>/api/index.php/update/folder/<folder_id>/<title>;<complexity_level>;<renewal_period>?apikey=<valid api key>
1382
            */
1383
                if ($GLOBALS['request'][2] !== "" && is_numeric($GLOBALS['request'][2])) {
1384
                    // get sent parameters
1385
                    $params = explode(';', urlSafeB64Decode($GLOBALS['request'][3]));
1386
1387
                    if (!empty($params[0])) {
1388
                        if ($params[1] < 0) {
1389
                            restError('NO_DATA_EXIST');
1390
                        }
1391
                        if (empty($params[2])) {
1392
                            $params[2] = 0;
1393
                        }
1394
1395
                        // check if folder exists and get folder data
1396
                        $data_folder = DB::queryfirstrow(
1397
                            "SELECT *
1398
                            FROM ".prefix_table("nested_tree")."
1399
                            WHERE id = %s",
1400
                            $GLOBALS['request'][2]
1401
                        );
1402
                        $counter = DB::count();
1403
                        if ($counter === 0) {
1404
                            restError('NO_DATA_EXIST');
1405
                        }
1406
1407
                        //Check if title doesn't contains html codes
1408
                        if (preg_match_all("|<[^>]+>(.*)</[^>]+>|U", $params[0], $out)) {
1409
                            restError('HTML_CODES_NOT_ALLOWED');
1410
                        }
1411
1412
                        // check if title is numeric
1413
                        if (is_numeric($params[0]) === true) {
1414
                            restError('TITLE_ONLY_WITH_NUMBERS');
1415
                        }
1416
1417
                        // get complexity level for this folder
1418
                        $data = DB::queryfirstrow(
1419
                            "SELECT valeur
1420
                            FROM ".prefix_table("misc")."
1421
                            WHERE intitule = %i AND type = %s",
1422
                            $data_folder['parent_id'],
1423
                            "complex"
1424
                        );
1425
                        if (intval($params[1]) < intval($data['valeur'])) {
1426
                            restError('COMPLEXICITY_LEVEL_NOT_REACHED');
1427
                        }
1428
1429
                        try {
1430
                            DB::update(
1431
                                prefix_table("nested_tree"),
1432
                                array(
1433
                                    'parent_id' => $data_folder['parent_id'],
1434
                                    'title' => $params[0],
1435
                                    'personal_folder' => 0,
1436
                                    'renewal_period' => $params[2],
1437
                                    'bloquer_creation' => '0',
1438
                                    'bloquer_modification' => '0'
1439
                                ),
1440
                                "id = %i",
1441
                                $GLOBALS['request'][2]
1442
                            );
1443
1444
                            //Add complexity
1445
                            DB::update(
1446
                                prefix_table("misc"),
1447
                                array(
1448
                                    'valeur' => $params[1]
1449
                                ),
1450
                                "intitule = %s AND type = %s",
1451
                                $GLOBALS['request'][2],
1452
                                "complex"
1453
                            );
1454
1455
                            // Run nested tree update
1456
                            require_once '../sources/SplClassLoader.php';
1457
                            $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1458
                            $tree->register();
1459
                            $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
1460
                            $tree->rebuild();
1461
1462
                            echo '{"status":"folder updated"}';
1463
                        } catch (PDOException $ex) {
1464
                            echo '<br />'.$ex->getMessage();
1465
                        }
1466
                    } else {
1467
                        restError('ITEMMISSINGDATA');
1468
                    }
1469
                } else {
1470
                    restError('NO_ITEM');
1471
                }
1472
            } elseif ($GLOBALS['request'][1] == "user") {
1473
            /*
1474
             * Case where a user has to be updated
1475
             *
1476
             * 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>
1477
             * with:
1478
             * for READ_ONLY, IS_ADMIN, IS_MANAGER, PERSONAL_FOLDER, accepted value is 1 for TRUE and 0 for FALSE
1479
             * for ADMINISTRATEDBY and ROLE1, accepted value is the real label (not the IDs)
1480
             *
1481
             * Example: /api/index.php/update/user/U4;Nils;Laumaille;test;[email protected];Users;0;Managers,Users;0;1;1?apikey=sae6iekahxiseL3viShoo0chahc1ievei8aequi
1482
             *
1483
             */
1484
1485
                // get user definition
1486
                $array_user = explode(';', urlSafeB64Decode($GLOBALS['request'][2]));
1487
                if (count($array_user) != 11) {
1488
                    restError('USERBADDEFINITION');
1489
                }
1490
1491
                $login = $array_user[0];
1492
                $name = $array_user[1];
1493
                $lastname = $array_user[2];
1494
                $password = $array_user[3];
1495
                $email = $array_user[4];
1496
                $adminby = urldecode($array_user[5]);
1497
                $isreadonly = urldecode($array_user[6]);
1498
                $roles = urldecode($array_user[7]);
1499
                $isadmin = $array_user[8];
1500
                $ismanager = $array_user[9];
1501
                $haspf = $array_user[10];
1502
1503
                // Empty user
1504
                if (mysqli_escape_string($link, htmlspecialchars_decode($login)) == "") {
1505
                    restError('USERLOGINEMPTY');
1506
                }
1507
                // Check if user already exists
1508
                $data = DB::query(
1509
                    "SELECT id, fonction_id, groupes_interdits, groupes_visibles, personal_folder
1510
                    FROM ".prefix_table("users")."
1511
                    WHERE login LIKE %ss",
1512
                    mysqli_escape_string($link, stripslashes($login))
1513
                );
1514
1515
                if (DB::count() === 1) {
1516
                    try {
1517
                        // find AdminRole code in DB
1518
                        $resRole = DB::queryFirstRow(
1519
                            "SELECT id
1520
                            FROM ".prefix_table("roles_title")."
1521
                            WHERE title LIKE %ss",
1522
                            mysqli_escape_string($link, stripslashes($adminby))
1523
                        );
1524
1525
1526
                        // get default language
1527
                        $lang = DB::queryFirstRow(
1528
                            "SELECT `valeur`
1529
                            FROM ".prefix_table("misc")."
1530
                            WHERE type = %s AND intitule = %s",
1531
                            "admin",
1532
                            "default_language"
1533
                        );
1534
1535
                        // prepare roles list
1536
                        $rolesList = "";
1537
                        foreach (explode(',', $roles) as $role) {
1538
                            $tmp = DB::queryFirstRow(
1539
                                "SELECT `id`
1540
                                FROM ".prefix_table("roles_title")."
1541
                                WHERE title = %s",
1542
                                $role
1543
                            );
1544
                            if (empty($rolesList)) {
1545
                                $rolesList = $tmp['id'];
1546
                            } else {
1547
                                $rolesList .= ";".$tmp['id'];
1548
                            }
1549
                        }
1550
1551
                        // Update user in DB
1552
                        DB::update(
1553
                            prefix_table("users"),
1554
                            array(
1555
                                'login' => $login,
1556
                                'name' => $name,
1557
                                'lastname' => $lastname,
1558
                                'pw' => bCrypt(stringUtf8Decode($password), COST),
1559
                                'email' => $email,
1560
                                'admin' => intval($isadmin),
1561
                                'gestionnaire' => intval($ismanager),
1562
                                'read_only' => intval($isreadonly),
1563
                                'personal_folder' => intval($haspf),
1564
                                'user_language' => $lang['valeur'],
1565
                                'fonction_id' => $rolesList,
1566
                                'groupes_interdits' => '0',
1567
                                'groupes_visibles' => '0',
1568
                                'isAdministratedByRole' => empty($resRole) ? '0' : $resRole['id']
1569
                            ),
1570
                            "id = %i",
1571
                            $data['id']
1572
                        );
1573
1574
                        // Create personnal folder
1575
                        if (intval($haspf) === 1) {
1576
                            DB::query(
1577
                                "SELECT id
1578
                                FROM ".prefix_table("nested_tree")."
1579
                                WHERE title = %s",
1580
                                $data['id']
1581
                            );
1582
                            if (DB::count() === 0) {
1583
                                DB::insert(
1584
                                    prefix_table("nested_tree"),
1585
                                    array(
1586
                                        'parent_id' => '0',
1587
                                        'title' => $data['id'],
1588
                                        'bloquer_creation' => '0',
1589
                                        'bloquer_modification' => '0',
1590
                                        'personal_folder' => '1'
1591
                                    )
1592
                                );
1593
                            }
1594
                        }
1595
1596
                        // load settings
1597
                        loadSettings();
1598
1599
                        // update LOG
1600
                        logEvents(
1601
                            'user_mngt',
1602
                            'at_user_updated',
1603
                            'api - '.$GLOBALS['apikey'],
1604
                            $data['id'],
1605
                            ""
1606
                        );
1607
1608
                        echo '{"status":"user added"}';
1609
                    } catch (PDOException $ex) {
1610
                        echo '<br />'.$ex->getMessage();
1611
                    }
1612
                } else {
1613
                    restError('USER_NOT_EXISTS');
1614
                }
1615
            }
1616
        } elseif ($GLOBALS['request'][0] == "auth") {
1617
            /*
1618
            ** FOR SECURITY PURPOSE, it is mandatory to use SSL to connect your teampass instance. The user password is not encrypted!
1619
            **
1620
            **
1621
            ** Expected call format: .../api/index.php/auth/<PROTOCOL>/<URL>/<login>/<password>?apikey=<VALID API KEY>
1622
            ** Example: https://127.0.0.1/teampass/api/index.php/auth/http/www.zadig-tge.adp.com/U1/test/76?apikey=chahthait5Aidood6johh6Avufieb6ohpaixain
1623
            ** RESTRICTIONS:
1624
            **              - <PROTOCOL>        ==> http|https|ftp|...
1625
            **              - <URL>             ==> encode URL without protocol (example:  * @package        becomes www.teampass.net)
1626
            **              - <login>           ==> user's login
1627
            **              - <password>        ==> currently clear password
1628
            **
1629
            ** RETURNED ANSWER:
1630
            **              - format sent back is JSON
1631
            **              - Example: {"<item_id>":{"label":"<pass#1>","login":"<login#1>","pw":"<pwd#1>"},"<item_id>":{"label":"<pass#2>","login":"<login#2>","pw":"<pwd#2>"}}
1632
            **
1633
            */
1634
            // get user credentials
1635
            if (isset($GLOBALS['request'][3]) && isset($GLOBALS['request'][4])) {
1636
                // get url
1637
                if (isset($GLOBALS['request'][1]) && isset($GLOBALS['request'][2])) {
1638
                    // is user granted?
1639
                    $userData = DB::queryFirstRow(
1640
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`
1641
                        FROM ".prefix_table("users")."
1642
                        WHERE login = %s",
1643
                        $GLOBALS['request'][3]
1644
                    );
1645
1646
                    // load passwordLib library
1647
                    require_once '../sources/SplClassLoader.php';
1648
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1649
                    $pwdlib->register();
1650
                    $pwdlib = new PasswordLib\PasswordLib();
0 ignored issues
show
Bug introduced by
The type PasswordLib\PasswordLib was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1651
1652
                    if ($pwdlib->verifyPasswordHash($GLOBALS['request'][4], $userData['pw']) === true) {
1653
                        // define the restriction of "id_tree" of this user
1654
                        //db::debugMode(true);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1655
                        $userDef = DB::queryOneColumn(
1656
                            'folder_id',
1657
                            "SELECT DISTINCT folder_id
1658
                            FROM ".prefix_table("roles_values")."
1659
                            WHERE type IN ('R', 'W', 'ND', 'NE', 'NDNE', 'NEND') ",
1660
                            empty($userData['groupes_interdits']) ? "" : "
1661
                            AND folder_id NOT IN (".str_replace(";", ",", $userData['groupes_interdits']).")",
1662
                            "AND role_id IN %ls
1663
                            GROUP BY folder_id",
1664
                            explode(";", $userData['groupes_interdits'])
1665
                        );
1666
                        // complete with "groupes_visibles"
1667
                        foreach (explode(";", $userData['groupes_visibles']) as $v) {
1668
                            array_push($userDef, $v);
1669
                        }
1670
1671
                        // find the item associated to the url
1672
                        $response = DB::query(
1673
                            "SELECT id, label, login, pw, pw_iv, id_tree, restricted_to
1674
                            FROM ".prefix_table("items")."
1675
                            WHERE url LIKE %s
1676
                            AND id_tree IN (".implode(",", $userDef).")
1677
                            ORDER BY id DESC",
1678
                            $GLOBALS['request'][1]."://".urldecode($GLOBALS['request'][2].'%')
1679
                        );
1680
                        $counter = DB::count();
1681
1682
                        if ($counter > 0) {
1683
                            $json = "";
1684
                            foreach ($response as $data) {
1685
                                // check if item visible
1686
                                if (empty($data['restricted_to']) ||
1687
                                    ($data['restricted_to'] != "" && in_array($userData['id'], explode(";", $data['restricted_to'])))
1688
                                ) {
1689
                                    // prepare export
1690
                                    $json[$data['id']]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
1691
                                    $json[$data['id']]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
1692
                                    $crypt_pw = cryption(
1693
                                        $data['pw'],
1694
                                        "",
1695
                                        "decrypt"
1696
                                    );
1697
                                    $json[$data['id']]['pw'] = $crypt_pw['string'];
1698
                                }
1699
                            }
1700
                            // prepare answer. If no access then inform
1701
                            if (empty($json)) {
0 ignored issues
show
introduced by
The condition empty($json) is always true.
Loading history...
1702
                                restError('AUTH_NO_DATA');
1703
                            } else {
1704
                                echo json_encode($json);
1705
                            }
1706
                        } else {
1707
                            restError('NO_DATA_EXIST');
1708
                        }
1709
                    } else {
1710
                        restError('AUTH_NOT_GRANTED');
1711
                    }
1712
                } else {
1713
                    restError('AUTH_NO_URL');
1714
                }
1715
            } else {
1716
                restError('AUTH_NO_IDENTIFIER');
1717
            }
1718
        } elseif ($GLOBALS['request'][0] === "auth_tpc") {
1719
            /*
1720
            ** TO BE USED ONLY BY TEAMPASS-CONNECT
1721
            **
1722
            */
1723
            // get user credentials
1724
            if (isset($GLOBALS['request'][1]) === true
1725
                && isset($GLOBALS['request'][2]) === true
1726
                && isset($GLOBALS['request'][3]) === true
1727
                && isset($GLOBALS['request'][4]) === true
1728
            ) {
1729
                // Get passed variables
1730
                $tpc_url = urlSafeB64Decode($GLOBALS['request'][1]);
1731
                $user_login = urlSafeB64Decode($GLOBALS['request'][2]);
1732
                $user_pwd = urlSafeB64Decode($GLOBALS['request'][3]);
1733
                $user_saltkey = urlSafeB64Decode($GLOBALS['request'][4]);
1734
1735
                // get url
1736
                if (isset($tpc_url) === true) {
1737
                    // is user granted?
1738
                    $userData = DB::queryFirstRow(
1739
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`, `encrypted_psk`
1740
                        FROM ".prefix_table("users")."
1741
                        WHERE login = %s",
1742
                        $user_login
1743
                    );
1744
1745
                    // Check if user exists
1746
                    if (empty($userData['id']) === true) {
1747
                        restError('AUTH_NOT_GRANTED');
1748
                    }
1749
1750
                    // check if psk is correct.
1751
                    if (empty($user_saltkey) === false) {
1752
                        $user_saltkey = defuse_validate_personal_key(
1753
                            $user_saltkey,
1754
                            $userData['encrypted_psk']
1755
                        );
1756
                        if (strpos($user_saltkey, "Error ") !== false) {
1757
                            // error
1758
                            restError('AUTH_PSK_ERROR');
1759
                        }
1760
                    }
1761
1762
                    // load passwordLib library
1763
                    include_once '../sources/SplClassLoader.php';
1764
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1765
                    $pwdlib->register();
1766
                    $pwdlib = new PasswordLib\PasswordLib();
1767
1768
                    if ($pwdlib->verifyPasswordHash($user_pwd, $userData['pw']) === true) {
1769
                        // Manage the case TPC asks for user identification
1770
                        if ($tpc_url === 'identify_user') {
1771
                            echo json_encode(array('err' => '', 'status' => 'USER_GRANTED'));
1772
                            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type void.
Loading history...
1773
                        }
1774
1775
                        // define the restriction of "id_tree" of this user
1776
                        //db::debugMode(true);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1777
                        $userDef = DB::queryOneColumn(
1778
                            'folder_id',
1779
                            "SELECT DISTINCT folder_id
1780
                            FROM ".prefix_table("roles_values")."
1781
                            WHERE type IN ('R', 'W', 'ND', 'NE', 'NDNE', 'NEND') ",
1782
                            empty($userData['groupes_interdits']) ? "" : "AND folder_id NOT IN (".str_replace(";", ",", $userData['groupes_interdits']).")",
1783
                            "AND role_id IN %ls
1784
                            GROUP BY folder_id",
1785
                            explode(";", $userData['groupes_interdits'])
1786
                        );
1787
                        // complete with "groupes_visibles"
1788
                        foreach (explode(";", $userData['groupes_visibles']) as $v) {
1789
                            array_push($userDef, $v);
1790
                        }
1791
1792
                        // add PF
1793
                        $userpf = DB::queryFirstRow(
1794
                            "SELECT `id` FROM ".prefix_table("nested_tree")." WHERE title = %s",
1795
                            $userData['id']
1796
                        );
1797
                        array_push($userDef, $userpf['id']);
1798
1799
                        // Parse provided URL
1800
                        $url_scheme = parse_url($tpc_url, PHP_URL_SCHEME);
1801
                        $url_post = parse_url($tpc_url, PHP_URL_HOST);
1802
1803
                        // find the item associated to the url
1804
                        //db::debugmode(true);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1805
                        $response = DB::query(
1806
                            "SELECT id, label, login, pw, pw_iv, id_tree, restricted_to, perso
1807
                            FROM ".prefix_table("items")."
1808
                            WHERE url LIKE %s
1809
                            AND id_tree IN (".implode(",", array_filter($userDef)).")
1810
                            AND inactif = %i
1811
                            ORDER BY id DESC",
1812
                            $url_scheme.'://'.$url_post.'%',
1813
                            0
1814
                        );
1815
                        $counter = DB::count();
1816
1817
                        if ($counter > 0) {
1818
                            $json = [];
1819
                            foreach ($response as $data) {
1820
                                // check if item visible
1821
                                if (empty($data['restricted_to']) ||
1822
                                    ($data['restricted_to'] != "" && in_array($userData['id'], explode(";", $data['restricted_to'])))
1823
                                ) {
1824
                                    // prepare export
1825
                                    $json[$data['id']]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
1826
                                    $json[$data['id']]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
1827
                                    if ($data['perso'] === "0") {
1828
                                        $crypt_pw = cryption(
1829
                                            $data['pw'],
1830
                                            "",
1831
                                            "decrypt"
1832
                                        );
1833
                                    } elseif (empty($user_saltkey)) {
1834
                                        $crypt_pw['string'] = "no_psk";
1835
                                    } else {
1836
                                        $crypt_pw = cryption(
1837
                                            $data['pw'],
1838
                                            $user_saltkey,
1839
                                            "decrypt"
1840
                                        );
1841
                                    }
1842
                                    $json[$data['id']]['pw'] = mb_detect_encoding($crypt_pw['string'], 'UTF-8', true) ? $crypt_pw['string'] : "not_utf8";
1843
                                    $json[$data['id']]['perso'] = $data['perso'];
1844
                                    $json[$data['id']]['domain'] = $url_scheme.'://'.$url_post;
1845
                                    $json[$data['id']]['id'] = $data['id'];
1846
                                }
1847
                            }
1848
                            // prepare answer. If no access then inform
1849
                            if (empty($json)) {
1850
                                restError('AUTH_NO_DATA');
1851
                            } else {
1852
                                echo json_encode($json);
1853
                            }
1854
                        } else {
1855
                            restError('NO_DATA_EXIST');
1856
                        }
1857
                    } else {
1858
                        restError('AUTH_NOT_GRANTED');
1859
                    }
1860
                } else {
1861
                    restError('AUTH_NO_URL');
1862
                }
1863
            } else {
1864
                restError('AUTH_NO_IDENTIFIER');
1865
            }
1866
        } else if ($GLOBALS['request'][0] === "tpc_find") {
1867
            // get user credentials
1868
            if (isset($GLOBALS['request'][1])) {
1869
                // Get passed variables
1870
                $tpc_phrase = urlSafeB64Decode($GLOBALS['request'][1]);
1871
                $user_login = urlSafeB64Decode($GLOBALS['request'][2]);
1872
                $user_pwd = urlSafeB64Decode($GLOBALS['request'][3]);
1873
                $user_saltkey = urlSafeB64Decode($GLOBALS['request'][4]);
1874
1875
                // get url
1876
                if (isset($tpc_phrase) === true) {
1877
                    // is user granted?
1878
                    $userData = DB::queryFirstRow(
1879
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`, `encrypted_psk`
1880
                        FROM ".prefix_table("users")."
1881
                        WHERE login = %s",
1882
                        $user_login
1883
                    );
1884
1885
                    // check if psk is correct.
1886
                    if (empty($user_saltkey) === false) {
1887
                        $user_saltkey = defuse_validate_personal_key(
1888
                            $user_saltkey,
1889
                            $userData['encrypted_psk']
1890
                        );
1891
                        if (strpos($user_saltkey, "Error ") !== false) {
1892
                            // error
1893
                            restError('AUTH_PSK_ERROR');
1894
                        }
1895
                    }
1896
1897
                    // load passwordLib library
1898
                    include_once '../sources/SplClassLoader.php';
1899
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1900
                    $pwdlib->register();
1901
                    $pwdlib = new PasswordLib\PasswordLib();
1902
1903
                    if ($pwdlib->verifyPasswordHash($user_pwd, $userData['pw']) === true) {
1904
                        // define the restriction of "id_tree" of this user
1905
                        //db::debugMode(true);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1906
                        $userDef = DB::queryOneColumn(
1907
                            'folder_id',
1908
                            "SELECT DISTINCT folder_id
1909
                            FROM ".prefix_table("roles_values")."
1910
                            WHERE type IN ('R', 'W', 'ND', 'NE', 'NDNE', 'NEND') ",
1911
                            empty($userData['groupes_interdits']) ? "" : "AND folder_id NOT IN (".str_replace(";", ",", $userData['groupes_interdits']).")",
1912
                            "AND role_id IN %ls
1913
                            GROUP BY folder_id",
1914
                            explode(";", $userData['groupes_interdits'])
1915
                        );
1916
                        // complete with "groupes_visibles"
1917
                        foreach (explode(";", $userData['groupes_visibles']) as $v) {
1918
                            array_push($userDef, $v);
1919
                        }
1920
1921
                        // add PF
1922
                        $userpf = DB::queryFirstRow(
1923
                            "SELECT `id` FROM ".prefix_table("nested_tree")." WHERE title = %s",
1924
                            $userData['id']
1925
                        );
1926
                        array_push($userDef, $userpf['id']);
1927
1928
                        // Clean phrase
1929
                        if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $tpc_phrase, $result)) {
1930
                            restError('ITEM_MALFORMED');
1931
                        } elseif (empty($tpc_phrase)) {
1932
                            restError('MALFORMED');
1933
                        }
1934
1935
                        // find the item associated to the url
1936
                        //db::debugmode(true);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1937
                        $response = DB::query(
1938
                            "SELECT id, label, login, pw, pw_iv, id_tree, restricted_to, perso, url
1939
                            FROM ".prefix_table("items")."
1940
                            WHERE (url LIKE %s OR label LIKE %s)
1941
                            AND id_tree IN (".implode(",", array_filter($userDef)).")
1942
                            AND inactif = %i
1943
                            ORDER BY id DESC",
1944
                            $tpc_phrase.'%',
1945
                            $tpc_phrase.'%',
1946
                            0
1947
                        );
1948
                        $counter = DB::count();
1949
1950
                        if ($counter > 0) {
1951
                            $json = [];
1952
                            $i = 0;
1953
                            foreach ($response as $data) {
1954
                                // check if item visible
1955
                                if (empty($data['restricted_to']) ||
1956
                                    ($data['restricted_to'] != "" && in_array($userData['id'], explode(";", $data['restricted_to'])))
1957
                                ) {
1958
                                    // prepare export
1959
                                    $json[$i]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
1960
                                    $json[$i]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
1961
                                    if ($data['perso'] === "0") {
1962
                                        $crypt_pw = cryption(
1963
                                            $data['pw'],
1964
                                            "",
1965
                                            "decrypt"
1966
                                        );
1967
                                    } elseif (empty($user_saltkey)) {
1968
                                        $crypt_pw['string'] = "no_psk";
1969
                                    } else {
1970
                                        $crypt_pw = cryption(
1971
                                            $data['pw'],
1972
                                            $user_saltkey,
1973
                                            "decrypt"
1974
                                        );
1975
                                    }
1976
                                    $json[$i]['pw'] = mb_detect_encoding($crypt_pw['string'], 'UTF-8', true) ? $crypt_pw['string'] : "not_utf8";
1977
                                    $json[$i]['perso'] = $data['perso'];
1978
                                    $json[$i]['domain'] = $data['url'];
1979
                                    $json[$i]['id'] = $data['id'];
1980
1981
                                    $i++;
1982
                                }
1983
                            }
1984
                            // prepare answer. If no access then inform
1985
                            if (empty($json)) {
1986
                                restError('AUTH_NO_DATA');
1987
                            } else {
1988
                                echo json_encode($json);
1989
                            }
1990
                        } else {
1991
                            restError('NO_DATA_EXIST');
1992
                        }
1993
                    } else {
1994
                        restError('AUTH_NOT_GRANTED');
1995
                    }
1996
                } else {
1997
                    restError('AUTH_NO_URL');
1998
                }
1999
            } else {
2000
                restError('AUTH_NO_IDENTIFIER');
2001
            }
2002
        } elseif ($GLOBALS['request'][0] == "tpc_userfolders") {
2003
            /*
2004
            * READ USER FOLDERS
2005
            * Sends back a list of folders
2006
            */
2007
            // get user credentials
2008
            if (isset($GLOBALS['request'][1])) {
2009
                // Get passed variables
2010
                $user_login = urlSafeB64Decode($GLOBALS['request'][1]);
2011
                $user_pwd = urlSafeB64Decode($GLOBALS['request'][2]);
0 ignored issues
show
Unused Code introduced by
The assignment to $user_pwd is dead and can be removed.
Loading history...
2012
                $user_saltkey = urlSafeB64Decode($GLOBALS['request'][3]);
0 ignored issues
show
Unused Code introduced by
The assignment to $user_saltkey is dead and can be removed.
Loading history...
2013
2014
                $json = [];
2015
                $inc = 0;
2016
                if (strcmp($user_login, "admin") == 0) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
2017
                    // forbid admin access
2018
                }
2019
                $response = DB::query(
2020
                    "SELECT id AS user_id, fonction_id
2021
                    FROM ".prefix_table("users")."
2022
                    WHERE login = %s",
2023
                    $user_login
2024
                );
2025
                if (count($response) === 0) {
2026
                    restError('USER_NOT_EXISTS ');
2027
                }
2028
                foreach ($response as $data) {
2029
                    $role_str = $data['fonction_id'];
2030
                    $user_id = $data['user_id'];
2031
                }
2032
2033
                // Build tree
2034
                include_once '../sources/SplClassLoader.php';
2035
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
2036
                $tree->register();
2037
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
2038
                $tree->rebuild();
2039
2040
                // If personal exists then get list of PF
2041
                $persoFld = DB::queryfirstrow(
2042
                    "SELECT id, title, nlevel
2043
                    FROM ".prefix_table("nested_tree")."
2044
                    WHERE title = %s",
2045
                    $user_id
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $user_id seems to be defined by a foreach iteration on line 2028. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
2046
                );
2047
                if (empty($persoFld['id']) === false) {
2048
                    // Store main PF
2049
                    $json[$inc]['id'] = $persoFld['id'];
2050
                    $json[$inc]['title'] = $user_login;
2051
                    $json[$inc]['level'] = $persoFld['nlevel'];
2052
                    $json[$inc]['access_type'] = "W";
2053
                    $inc++;
2054
2055
                    // get all descendants
2056
                    $ids = $tree->getDescendants($persoFld['id'], false, false);
2057
                    foreach ($ids as $ident) {
2058
                        // Do query to get folder info
2059
                        $fldInfo = DB::queryfirstrow(
2060
                            "SELECT title, nlevel
2061
                            FROM ".prefix_table("nested_tree")."
2062
                            WHERE id = %i",
2063
                            $ident->id
2064
                        );
2065
2066
                        // Store info
2067
                        $json[$inc]['id'] = $ident->id;
2068
                        $json[$inc]['title'] = $fldInfo['title'];
2069
                        $json[$inc]['level'] = $fldInfo['nlevel'];
2070
                        $json[$inc]['personal'] = "1";
2071
                        $json[$inc]['access_type'] = "W";
2072
                        $inc++;
2073
                    }
2074
                }
2075
2076
                $folder_arr = array();
2077
                $roles = explode(";", $role_str);
2078
                foreach ($roles as $role) {
2079
                    $response = DB::query(
2080
                        "SELECT folder_id, type
2081
                        FROM ".prefix_table("roles_values")."
2082
                        WHERE role_id = %i",
2083
                        $role
2084
                    );
2085
                    foreach ($response as $data) {
2086
                        $folder_id = $data['folder_id'];
2087
                        if (array_key_exists($folder_id, $folder_arr) === false) {
2088
                            array_push($folder_arr, $folder_id);
2089
2090
                            $response2 = DB::queryFirstRow(
2091
                                "SELECT title, nlevel
2092
                                FROM ".prefix_table("nested_tree")."
2093
                                WHERE id = %i",
2094
                                $folder_id
2095
                            );
2096
2097
                            if (empty($response2['title']) === false) {
2098
                                $json[$inc]['id'] = $folder_id;
2099
                                $json[$inc]['title'] = $response2['title'];
2100
                                $json[$inc]['level'] = $response2['nlevel'];
2101
                                $json[$inc]['access_type'] = $data['type'];
2102
                                $json[$inc]['personal'] = "0";
2103
                                $inc++;
2104
                            }
2105
                        }
2106
                    }
2107
                }
2108
                // prepare answer. If no access then inform
2109
                if (empty($json)) {
2110
                    restError('AUTH_NO_DATA');
2111
                } else {
2112
                    echo json_encode($json);
2113
                }
2114
            }
2115
        } elseif ($GLOBALS['request'][0] == "set") {
2116
            /*
2117
             * Expected call format: .../api/index.php/set/<login_to_save>/<password_to_save>/<url>/<user_login>/<user_password>/<label>/<protocol>?apikey=<VALID API KEY>
2118
             * Example: https://127.0.0.1/teampass/api/index.php/set/newLogin/newPassword/newUrl/myLogin/myPassword?apikey=gu6Eexaewaishooph6iethoh5woh0yoit6ohquo
2119
             *
2120
             * NEW ITEM WILL BE STORED IN SPECIFIC FOLDER
2121
             */
2122
            // get user credentials
2123
            if (isset($GLOBALS['request'][4]) && isset($GLOBALS['request'][5])) {
2124
                // get url
2125
                if (isset($GLOBALS['request'][1]) && isset($GLOBALS['request'][2]) && isset($GLOBALS['request'][3])) {
2126
                    // is user granted?
2127
                    $userData = DB::queryFirstRow(
2128
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`
2129
                        FROM ".prefix_table("users")."
2130
                        WHERE login = %s",
2131
                        $GLOBALS['request'][4]
2132
                    );
2133
                    if (DB::count() == 0) {
2134
                        restError('AUTH_NO_IDENTIFIER');
2135
                    }
2136
2137
                    // load passwordLib library
2138
                    include_once '../sources/SplClassLoader.php';
2139
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2140
                    $pwdlib->register();
2141
                    $pwdlib = new PasswordLib\PasswordLib();
2142
2143
                    // is user identified?
2144
                    if ($pwdlib->verifyPasswordHash($GLOBALS['request'][5], $userData['pw']) === true) {
2145
                        // does the personal folder of this user exists?
2146
                        DB::queryFirstRow(
2147
                            "SELECT `id`
2148
                            FROM ".prefix_table("nested_tree")."
2149
                            WHERE title = %s AND personal_folder = 1",
2150
                            $userData['id']
2151
                        );
2152
                        if (DB::count() > 0) {
2153
                            // check if "teampass-connect" folder exists
2154
                            // if not create it
2155
                            $folder = DB::queryFirstRow(
2156
                                "SELECT `id`
2157
                                FROM " . $pre."nested_tree
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pre seems to be never defined.
Loading history...
2158
                                WHERE title = %s",
2159
                                "teampass-connect"
2160
                            );
2161
                            if (DB::count() == 0) {
2162
                                DB::insert(
2163
                                    prefix_table("nested_tree"),
2164
                                    array(
2165
                                        'parent_id' => '0',
2166
                                        'title' => "teampass-connect"
2167
                                    )
2168
                                );
2169
                                $tpc_folder_id = DB::insertId();
2170
2171
                                //Add complexity
2172
                                DB::insert(
2173
                                    prefix_table("misc"),
2174
                                    array(
2175
                                        'type' => 'complex',
2176
                                        'intitule' => $tpc_folder_id,
2177
                                        'valeur' => '0'
2178
                                    )
2179
                                );
2180
2181
                                // rebuild tree
2182
                                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
2183
                                $tree->register();
2184
                                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
2185
                                $tree->rebuild();
2186
                            } else {
2187
                                $tpc_folder_id = $folder['id'];
2188
                            }
2189
2190
                            // encrypt password
2191
                            $encrypt = cryption(
2192
                                $GLOBALS['request'][2],
2193
                                "",
2194
                                "encrypt"
2195
                            );
2196
2197
                            // is there a protocol?
2198
                            if (isset($GLOBALS['request'][7]) || empty($GLOBALS['request'][7])) {
2199
                                $protocol = "http://";
0 ignored issues
show
Unused Code introduced by
The assignment to $protocol is dead and can be removed.
Loading history...
2200
                            } else {
2201
                                $protocol = urldecode($GLOBALS['request'][7])."://";
2202
                            }
2203
2204
                            // add new item
2205
                            DB::insert(
2206
                                prefix_table("items"),
2207
                                array(
2208
                                    'label' => "Credentials for ".urldecode($GLOBALS['request'][3]),
2209
                                    'description' => "Imported with Teampass-Connect",
2210
                                    'pw' => $encrypt['string'],
2211
                                    'pw_iv' => "",
2212
                                    'email' => "",
2213
                                    'url' => urldecode($GLOBALS['request'][3]),
2214
                                    'id_tree' => $tpc_folder_id,
2215
                                    'login' => $GLOBALS['request'][1],
2216
                                    'inactif' => '0',
2217
                                    'restricted_to' => $userData['id'],
2218
                                    'perso' => '0',
2219
                                    'anyone_can_modify' => '0',
2220
                                    'complexity_level' => '0'
2221
                                )
2222
                            );
2223
                            $newID = DB::insertId();
2224
2225
                            // log
2226
                            logItems(
2227
                                $newID,
2228
                                "Credentials for ".urldecode($GLOBALS['request'][3].'%'),
2229
                                $userData['id'],
2230
                                'at_creation',
2231
                                $GLOBALS['request'][4]
2232
                            );
2233
2234
                            $json['status'] = "ok";
0 ignored issues
show
Comprehensibility Best Practice introduced by
$json was never initialized. Although not strictly required by PHP, it is generally a good practice to add $json = array(); before regardless.
Loading history...
2235
                            // prepare answer. If no access then inform
2236
                            if (empty($json)) {
2237
                                restError('AUTH_NO_DATA');
2238
                            } else {
2239
                                echo json_encode($json);
2240
                            }
2241
                        } else {
2242
                            restError('NO_PF_EXIST_FOR_USER');
2243
                        }
2244
                    } else {
2245
                        restError('AUTH_NOT_GRANTED');
2246
                    }
2247
                } else {
2248
                    restError('SET_NO_DATA');
2249
                }
2250
            } else {
2251
                restError('AUTH_NO_IDENTIFIER');
2252
            }
2253
        } elseif ($GLOBALS['request'][0] == "set_tpc") {
2254
            /*
2255
             * TO BE USED ONLY BY TEAMPASS-CONNECT
2256
             */
2257
            // get user credentials
2258
            if (isset($GLOBALS['request'][1]) === true
2259
                && isset($GLOBALS['request'][2]) === true
2260
                && isset($GLOBALS['request'][3]) === true
2261
                && isset($GLOBALS['request'][4]) === true
2262
                && isset($GLOBALS['request'][5]) === true
2263
            ) {
2264
                // Get passed variables
2265
                $item_definition = json_decode(urlSafeB64Decode($GLOBALS['request'][2]), true);
2266
                $user_login = urlSafeB64Decode($GLOBALS['request'][3]);
2267
                $user_pwd = urlSafeB64Decode($GLOBALS['request'][4]);
2268
                $user_saltkey = urlSafeB64Decode($GLOBALS['request'][5]);
2269
2270
                // is user granted?
2271
                $userData = DB::queryFirstRow(
2272
                    "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`
2273
                    FROM ".prefix_table("users")."
2274
                    WHERE login = %s",
2275
                    $user_login
2276
                );
2277
                if (DB::count() === 0) {
2278
                    restError('AUTH_NO_IDENTIFIER');
2279
                }
2280
2281
                // load passwordLib library
2282
                include_once '../sources/SplClassLoader.php';
2283
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2284
                $pwdlib->register();
2285
                $pwdlib = new PasswordLib\PasswordLib();
2286
2287
                // is user identified?
2288
                if ($pwdlib->verifyPasswordHash($user_pwd, $userData['pw']) === true) {
2289
                    // It is a new ITEM
2290
                    if ($GLOBALS['request'][1] === "add") {
2291
                        // encrypt PW
2292
                        if ($item_definition['personal'] === '1') {
2293
                            $passwd = cryption(
2294
                                $item_definition['pwd'],
2295
                                $user_saltkey,
2296
                                "encrypt"
2297
                            );
2298
                        } else {
2299
                            $passwd = cryption(
2300
                                $item_definition['pwd'],
2301
                                "",
2302
                                "encrypt"
2303
                            );
2304
                        }
2305
2306
                        // add new item
2307
                        DB::insert(
2308
                            prefix_table("items"),
2309
                            array(
2310
                                'label' => $item_definition['label'],
2311
                                'description' => $item_definition['description'],
2312
                                'pw' => $passwd['string'],
2313
                                'pw_iv' => "",
2314
                                'email' => "",
2315
                                'url' => $item_definition['url'],
2316
                                'id_tree' => $item_definition['destination_folder'],
2317
                                'login' => $item_definition['login'],
2318
                                'inactif' => '0',
2319
                                'restricted_to' => $userData['id'],
2320
                                'perso' => '0',
2321
                                'anyone_can_modify' => '0',
2322
                                'complexity_level' => '0'
2323
                            )
2324
                        );
2325
                        $newID = DB::insertId();
2326
2327
                        // log
2328
                        logItems(
2329
                            $newID,
2330
                            $item_definition['label'],
2331
                            $userData['id'],
2332
                            'at_creation',
2333
                            $user_login
2334
                        );
2335
2336
                        // rebuild tree
2337
                        $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
2338
                        $tree->register();
2339
                        $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
2340
                        $tree->rebuild();
2341
2342
                        echo json_encode(array('new_id' => $newID, 'err' => ''));
2343
                    } elseif ($GLOBALS['request'][1] === "edit") {
2344
                        // Is this folder a personal one?
2345
                        $fldData = DB::queryFirstRow(
2346
                            "SELECT `personal_folder`
2347
                            FROM ".prefix_table("nested_tree")."
2348
                            WHERE id = %i",
2349
                            $item_definition['item_id']
2350
                        );
2351
2352
                        // encrypt PW
2353
                        if ($fldData['personal_folder'] === '1') {
2354
                            $passwd = cryption(
2355
                                $item_definition['pwd'],
2356
                                $user_saltkey,
2357
                                "encrypt"
2358
                            );
2359
                        } else {
2360
                            $passwd = cryption(
2361
                                $item_definition['pwd'],
2362
                                "",
2363
                                "encrypt"
2364
                            );
2365
                        }
2366
2367
                        // UPDATE item
2368
                        DB::update(
2369
                            prefix_table("items"),
2370
                            array(
2371
                                'pw' => $passwd['string'],
2372
                                'pw_iv' => '',
2373
                                "url" => $item_definition['url'],
2374
                                "login" => $item_definition['login']
2375
                            ),
2376
                            "id = %i",
2377
                            $item_definition['item_id']
2378
                        );
2379
2380
                        // log
2381
                        DB::insert(
2382
                            prefix_table("log_items"),
2383
                            array(
2384
                                "id_item" => $item_definition['item_id'],
2385
                                "date" => time(),
2386
                                "id_user" => $userData['id'],
2387
                                "action" => "at_modification"
2388
                            )
2389
                        );
2390
2391
                        // Update CACHE table
2392
                        DB::update(
2393
                            prefix_table("cache"),
2394
                            array(
2395
                                "login" => $item_definition['login'],
2396
                                "author" => $userData['id'],
2397
                                "timestamp" => time(),
2398
                                "url" => $item_definition['url'],
2399
                            ),
2400
                            "id = %i",
2401
                            $item_definition['item_id']
2402
                        );
2403
2404
                        echo json_encode(array('new_id' => '', 'err' => ''));
2405
                    }
2406
                } else {
2407
                    restError('AUTH_NOT_GRANTED');
2408
                }
2409
            } else {
2410
                restError('AUTH_NO_IDENTIFIER');
2411
            }
2412
        } elseif ($GLOBALS['request'][0] == "tpc_delete") {
2413
            /*
2414
             * TO BE USED ONLY BY TEAMPASS-CONNECT
2415
             */
2416
            // get user credentials
2417
            if (isset($GLOBALS['request'][1]) === true
2418
                && isset($GLOBALS['request'][2]) === true
2419
                && isset($GLOBALS['request'][3]) === true
2420
                && isset($GLOBALS['request'][4]) === true
2421
            ) {
2422
                // Get passed variables
2423
                $item_id = urlSafeB64Decode($GLOBALS['request'][1]);
2424
                $user_login = urlSafeB64Decode($GLOBALS['request'][2]);
2425
                $user_pwd = urlSafeB64Decode($GLOBALS['request'][3]);
2426
                $user_saltkey = urlSafeB64Decode($GLOBALS['request'][4]);
2427
                
2428
2429
                // is user granted?
2430
                $userData = DB::queryFirstRow(
2431
                    "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`
2432
                    FROM ".prefix_table("users")."
2433
                    WHERE login = %s",
2434
                    $user_login
2435
                );
2436
                if (DB::count() == 0) {
2437
                    restError('AUTH_NO_IDENTIFIER');
2438
                }
2439
2440
                // load passwordLib library
2441
                include_once '../sources/SplClassLoader.php';
2442
                $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
2443
                $pwdlib->register();
2444
                $pwdlib = new PasswordLib\PasswordLib();
2445
2446
                // is user identified?
2447
                if ($pwdlib->verifyPasswordHash($user_pwd, $userData['pw']) === true) {
2448
                    DB::update(
2449
                        prefix_table("items"),
2450
                        array(
2451
                            'inactif' => '1',
2452
                        ),
2453
                        "id = %i",
2454
                        $item_id
2455
                    );
2456
                    //log
2457
                    DB::insert(
2458
                        prefix_table("log_items"),
2459
                        array(
2460
                            'id_item' => $item_id,
2461
                            'date' => time(),
2462
                            'id_user' => $userData['id'],
2463
                            'action' => 'at_delete'
2464
                        )
2465
                    );
2466
2467
                    //Update CACHE table
2468
                    updateCacheTable("delete_value", $item_id);
2469
2470
                    echo json_encode(array('code' => 'done'));
2471
                } else {
2472
                    restError('AUTH_NOT_GRANTED');
2473
                }
2474
            } else {
2475
                restError('AUTH_NO_IDENTIFIER');
2476
            }
2477
        } elseif ($GLOBALS['request'][0] === "delete") {
2478
        /*
2479
        * DELETE
2480
        *
2481
        * Expected call format: .../api/index.php/delete/folder/<folder_id1;folder_id2;folder_id3>?apikey=<VALID API KEY>
2482
        * Expected call format: .../api/index.php/delete/item>/<item_id1;item_id2;item_id3>?apikey=<VALID API KEY>
2483
        */
2484
            if ($GLOBALS['request'][1] === "folder") {
2485
                $array_category = explode(';', $GLOBALS['request'][2]);
2486
2487
                // get user info
2488
                if (isset($GLOBALS['request'][3]) && !empty($GLOBALS['request'][3])) {
2489
                    $userData = DB::queryFirstRow(
2490
                        "SELECT `id` FROM ".$pre."users WHERE login = %s",
2491
                        $GLOBALS['request'][3]
2492
                    );
2493
                    if (DB::count() == 0) {
2494
                        $user_id = API_USER_ID;
2495
                    } else {
2496
                        $user_id = $userData['id'];
2497
                    }
2498
                } else {
2499
                    $user_id = API_USER_ID;
2500
                }
2501
2502
                if (count($array_category) > 0 && count($array_category) < 5) {
2503
                    // load passwordLib library
2504
                    require_once '../sources/SplClassLoader.php';
2505
2506
                    // prepare tree
2507
                    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
2508
                    $tree->register();
2509
                    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title', 'personal_folder');
2510
2511
                    // this will delete all sub folders and items associated
2512
                    for ($i = 0; $i < count($array_category); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2513
                        // Does this folder exist?
2514
                        DB::queryFirstRow(
2515
                            "SELECT id
2516
                            FROM ".prefix_table("nested_tree")."
2517
                            WHERE id = %i",
2518
                            $array_category[$i]
2519
                        );
2520
                        if (DB::count() > 0) {
2521
                            // Get through each subfolder
2522
                            $folders = $tree->getDescendants($array_category[$i], true);
2523
                            if (count($folders) > 0) {
2524
                                foreach ($folders as $folder) {
2525
                                    if (($folder->parent_id > 0 || $folder->parent_id == 0) && $folder->personal_folder != 1) {
2526
                                        //Store the deleted folder (recycled bin)
2527
                                        DB::insert(
2528
                                            prefix_table("misc"),
2529
                                            array(
2530
                                                'type' => 'folder_deleted',
2531
                                                'intitule' => "f".$array_category[$i],
2532
                                                'valeur' => $folder->id.', '.$folder->parent_id.', '.
2533
                                                    $folder->title.', '.$folder->nleft.', '.$folder->nright.', '.$folder->nlevel.', 0, 0, 0, 0'
2534
                                            )
2535
                                        );
2536
                                        //delete folder
2537
                                        DB::delete(prefix_table("nested_tree"), "id = %i", $folder->id);
2538
2539
                                        //delete items & logs
2540
                                        $items = DB::query(
2541
                                            "SELECT id
2542
                                            FROM ".prefix_table("items")."
2543
                                            WHERE id_tree=%i",
2544
                                            $folder->id
2545
                                        );
2546
                                        foreach ($items as $item) {
2547
                                            DB::update(
2548
                                                prefix_table("items"),
2549
                                                array(
2550
                                                    'inactif' => '1',
2551
                                                ),
2552
                                                "id = %i",
2553
                                                $item['id']
2554
                                            );
2555
                                            //log
2556
                                            DB::insert(
2557
                                                prefix_table("log_items"),
2558
                                                array(
2559
                                                    'id_item' => $item['id'],
2560
                                                    'date' => time(),
2561
                                                    'id_user' => $user_id,
2562
                                                    'action' => 'at_delete'
2563
                                                )
2564
                                            );
2565
                                        }
2566
                                        //Update CACHE table
2567
                                        updateCacheTable("delete_value", $array_category[$i]);
2568
                                    }
2569
                                }
2570
                            }
2571
                        } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
2572
                            // Folder doesn't exist
2573
                        }
2574
                    }
2575
                } else {
2576
                    restError('NO_CATEGORY');
2577
                }
2578
2579
                $json['status'] = 'OK';
2580
            } elseif ($GLOBALS['request'][1] == "item") {
2581
                $array_items = explode(';', $GLOBALS['request'][2]);
2582
2583
                // get user info
2584
                if (isset($GLOBALS['request'][3]) && !empty($GLOBALS['request'][3])) {
2585
                    $userData = DB::queryFirstRow(
2586
                        "SELECT `id` FROM ".$pre."users WHERE login = %s",
2587
                        $GLOBALS['request'][3]
2588
                    );
2589
                    if (DB::count() == 0) {
2590
                        $user_id = API_USER_ID;
2591
                    } else {
2592
                        $user_id = $userData['id'];
2593
                    }
2594
                }
2595
2596
                for ($i = 0, $c = count($array_items); $i < $c; $i++) {
2597
                    DB::update(
2598
                        prefix_table("items"),
2599
                        array(
2600
                            'inactif' => '1',
2601
                        ),
2602
                        "id = %i",
2603
                        $array_items[$i]
2604
                    );
2605
                    //log
2606
                    DB::insert(
2607
                        prefix_table("log_items"),
2608
                        array(
2609
                            'id_item' => $array_items[$i],
2610
                            'date' => time(),
2611
                            'id_user' => $user_id,
2612
                            'action' => 'at_delete'
2613
                        )
2614
                    );
2615
2616
                    //Update CACHE table
2617
                    updateCacheTable("delete_value", $array_items[$i]);
2618
                }
2619
2620
                $json['status'] = 'OK';
2621
            }
2622
2623
            if ($json) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $json does not seem to be defined for all execution paths leading up to this point.
Loading history...
2624
                echo json_encode($json);
2625
            } else {
2626
                restError('EMPTY');
2627
            }
2628
        } elseif ($GLOBALS['request'][0] == "new_password") {
2629
            if (!empty($GLOBALS['request'][1])) {
2630
                $params = explode(";", $GLOBALS['request'][1]);
2631
2632
                if (empty($params[0])) {
2633
                    $params[0] = 8;
2634
                }
2635
                if (empty($params[1])) {
2636
                    $params[1] = 0;
2637
                }
2638
                if (empty($params[2])) {
2639
                    $params[2] = 0;
2640
                }
2641
                if (empty($params[3])) {
2642
                    $params[3] = 0;
2643
                }
2644
                if (empty($params[4])) {
2645
                    $params[4] = 0;
2646
                }
2647
                if (empty($params[5])) {
2648
                    $params[5] = 0;
2649
                }
2650
                if (empty($params[6])) {
2651
                    $params[6] = 0;
2652
                }
2653
2654
                // Generate key
2655
                $pwd = GenerateCryptKey(
2656
                    $params[0],
2657
                    $params[1] === "1" ? true : false,
2658
                    $params[2] === "1" ? true : false,
2659
                    $params[3] === "1" ? true : false,
2660
                    $params[5] === "1" && $params[6] === "1" ? true : false
2661
                );
2662
2663
                // generate and send back (generate in base64 if symbols are asked)
2664
                if ($params[6] === "1") {
2665
                    echo '{"password" : "'.base64_encode($pwd).'"}';
2666
                } else {
2667
                    echo '{"password" : "'.$pwd.'"}';
2668
                }
2669
            } else {
2670
                restError('NO_PARAMETERS');
2671
            }
2672
        } elseif ($GLOBALS['request'][0] === "info") {
2673
            if ($GLOBALS['request'][1] === "complexicity_levels_list") {
2674
                require_once '../includes/language/english.php';
2675
                $json = array(
2676
                    0=> $LANG['complex_level0'],
2677
                    25=> $LANG['complex_level1'],
2678
                    50=> $LANG['complex_level2'],
2679
                    60=> $LANG['complex_level3'],
2680
                    70=> $LANG['complex_level4'],
2681
                    80=> $LANG['complex_level5'],
2682
                    90=> $LANG['complex_level6']
2683
                );
2684
2685
                echo json_encode($json);
2686
            } elseif ($GLOBALS['request'][1] === "folder") {
2687
                if (!empty($GLOBALS['request'][2]) && is_numeric($GLOBALS['request'][2])) {
2688
                    $data = DB::queryFirstRow(
2689
                        "SELECT * FROM ".$pre."nested_tree WHERE id = %i",
2690
                        $GLOBALS['request'][2]
2691
                    );
2692
                    if (DB::count() == 0) {
2693
                        restError('NOSUCHFOLDER');
2694
                    }
2695
2696
                    // form id_tree to full foldername
2697
                    require_once '../sources/SplClassLoader.php';
2698
                    //Load Tree
2699
                    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
2700
                    $tree->register();
2701
                    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
2702
2703
                    $folder = "";
2704
                    $arbo = $tree->getPath($GLOBALS['request'][2], true);
2705
                    foreach ($arbo as $elem) {
2706
                        if (empty($folder)) {
2707
                            $folder = stripslashes($elem->title);
2708
                        } else {
2709
                            $folder .= " > ".stripslashes($elem->title);
2710
                        }
2711
                    }
2712
2713
                    // prepare info
2714
                    $json = array(
2715
                        "title" => $data['title'],
2716
                        "personal_folder" => $data['personal_folder'],
2717
                        "renewal_period" => $data['renewal_period'],
2718
                        "parent_id" => $data['parent_id'],
2719
                        "path" => $folder,
2720
                    );
2721
2722
                    echo json_encode($json);
2723
                } else {
2724
                    restError('NO_PARAMETERS');
2725
                }
2726
            } elseif ($GLOBALS['request'][1] === "version") {
2727
                echo '{"api-version":"'.$api_version.'"}';
2728
            } else {
2729
                restError('NO_PARAMETERS');
2730
            }
2731
        } else {
2732
            restError('METHOD');
2733
        }
2734
    }
2735
}
2736
2737
/**
2738
 * Undocumented function
2739
 *
2740
 * @return void
2741
 */
2742
function restPut()
2743
{
2744
    if (!@count($GLOBALS['request']) == 0) {
2745
        $request_uri = $GLOBALS['_SERVER']['REQUEST_URI'];
2746
        preg_match('/\/api(\/index.php|)\/(.*)\?apikey=(.*)/', $request_uri, $matches);
2747
        if (count($matches) == 0) {
2748
            restError('REQUEST_SENT_NOT_UNDERSTANDABLE');
2749
        }
2750
        $GLOBALS['request'] = explode('/', $matches[2]);
2751
    }
2752
    if (apikeyChecker($GLOBALS['apikey'])) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of apikeyChecker($GLOBALS['apikey']) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
2753
        teampassConnect();
2754
    }
2755
}
2756
2757
/**
2758
 * Return correct error message
2759
 *
2760
 * @param  string $type
2761
 * @param  string $detail
2762
 * @return void
2763
 */
2764
function restError($type, $detail = 'N/A')
2765
{
2766
    switch ($type) {
2767
        case 'APIKEY':
2768
            $message = array('err' => 'This api_key '.$GLOBALS['apikey'].' doesn\'t exist', 'code' => 'API_KEY_NOT_FOUND');
2769
            header('HTTP/1.1 405 Method Not Allowed');
2770
            break;
2771
        case 'NO_CATEGORY':
2772
            $message = array('err' => 'No folder specified');
2773
            break;
2774
        case 'NO_ITEM':
2775
            $message = array('err' => 'No item specified');
2776
            break;
2777
        case 'EMPTY':
2778
            $message = array('err' => 'No results');
2779
            break;
2780
        case 'IPWHITELIST':
2781
            $message = array('err' => 'Ip address not allowed.');
2782
            header('HTTP/1.1 405 Method Not Allowed');
2783
            break;
2784
        case 'MYSQLERR':
2785
            $message = array('err' => $detail);
2786
            header('HTTP/1.1 500 Internal Server Error');
2787
            break;
2788
        case 'METHOD':
2789
            $message = array('err' => 'Method not authorized', 'code' => 'METHOD_NOT_AUTHORIZED');
2790
            header('HTTP/1.1 405 Method Not Allowed');
2791
            break;
2792
        case 'ITEMBADDEFINITION':
2793
            $message = array('err' => 'Item definition not complete');
2794
            header('HTTP/1.1 405 Method Not Allowed');
2795
            break;
2796
        case 'ITEM_MALFORMED':
2797
            $message = array('err' => 'Item definition not numeric');
2798
            header('HTTP/1.1 405 Method Not Allowed');
2799
            break;
2800
        case 'USERBADDEFINITION':
2801
            $message = array('err' => 'User definition not complete');
2802
            header('HTTP/1.1 405 Method Not Allowed');
2803
            break;
2804
        case 'USERLOGINEMPTY':
2805
            $message = array('err' => 'Empty Login given');
2806
            header('HTTP/1.1 405 Method Not Allowed');
2807
            break;
2808
        case 'USERALREADYEXISTS':
2809
            $message = array('err' => 'User already exists');
2810
            header('HTTP/1.1 405 Method Not Allowed');
2811
            break;
2812
        case 'REQUEST_SENT_NOT_UNDERSTANDABLE':
2813
            $message = array('err' => 'URL format is not following requirements');
2814
            break;
2815
        case 'AUTH_NOT_GRANTED':
2816
            $message = array('err' => 'Bad credentials for user', 'code' => 'AUTH_NOT_GRANTED');
2817
            header('HTTP/1.1 404 Error');
2818
            break;
2819
        case 'AUTH_NO_URL':
2820
            $message = array('err' => 'URL needed to grant access');
2821
            break;
2822
        case 'AUTH_NO_IDENTIFIER':
2823
            $message = array('err' => 'Credentials needed to grant access', 'code' => 'AUTH_NO_IDENTIFIER');
2824
            break;
2825
        case 'AUTH_NO_DATA':
2826
            $message = array('err' => 'Data not allowed for the user', 'code' => 'AUTH_NO_DATA');
2827
            break;
2828
        case 'AUTH_PSK_ERROR':
2829
            $message = array('err' => 'Personal Saltkey is wrong', 'code' => 'AUTH_PSK_ERROR');
2830
            header('HTTP/1.1 404 Error');
2831
            break;
2832
        case 'NO_DATA_EXIST':
2833
            $message = array('err' => 'No data exists', 'code' => 'NO_DATA_EXIST');
2834
            break;
2835
        case 'NO_DESTINATION_FOLDER':
2836
            $message = array('err' => 'No destination folder provided');
2837
            break;
2838
        case 'PASSWORDTOOLONG':
2839
            $message = array('err' => 'Password is too long');
2840
            break;
2841
        case 'NOSUCHFOLDER':
2842
            $message = array('err' => 'Folder ID does not exist');
2843
            break;
2844
        case 'PASSWORDEMPTY':
2845
            $message = array('err' => 'Password is empty');
2846
            break;
2847
        case 'ITEMEXISTS':
2848
            $message = array('err' => 'Label already exists');
2849
            break;
2850
        case 'ITEMMISSINGDATA':
2851
            $message = array('err' => 'Label or Password or Folder ID is missing');
2852
            break;
2853
        case 'SET_NO_DATA':
2854
            $message = array('err' => 'No data to be stored');
2855
            break;
2856
        case 'NO_PF_EXIST_FOR_USER':
2857
            $message = array('err' => 'No Personal Folder exists for this user');
2858
            break;
2859
        case 'HTML_CODES_NOT_ALLOWED':
2860
            $message = array('err' => 'HTML tags not allowed');
2861
            break;
2862
        case 'TITLE_ONLY_WITH_NUMBERS':
2863
            $message = array('err' => 'Title only with numbers not allowed');
2864
            break;
2865
        case 'ALREADY_EXISTS':
2866
            $message = array('err' => 'Data already exists');
2867
            break;
2868
        case 'COMPLEXICITY_LEVEL_NOT_REACHED':
2869
            $message = array('err' => 'complexity level was not reached');
2870
            break;
2871
        case 'NO_PARAMETERS':
2872
            $message = array('err' => 'No parameters given');
2873
            break;
2874
        case 'USER_NOT_EXISTS':
2875
            $message = array('err' => 'User does not exist');
2876
            break;
2877
        case 'NO_PSALTK_PROVIDED':
2878
            $message = array('err' => 'No Personal saltkey provided');
2879
            break;
2880
        case 'EXPECTED_PARAMETER_NOT_PROVIDED':
2881
            $message = array('err' => 'Provided parameters are not correct');
2882
            break;
2883
        default:
2884
            $message = array('err' => 'Something happen ... but what ?');
2885
            header('HTTP/1.1 500 Internal Server Error');
2886
            break;
2887
    }
2888
2889
    echo json_encode($message);
2890
    exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
2891
}
2892
2893
/**
2894
 * Is it a valid api key?
2895
 *
2896
 * @param  string $apikey_used
2897
 * @return void
2898
 */
2899
function apikeyChecker($apikey_used)
2900
{
2901
    teampassConnect();
2902
    $apikey_pool = teampassGetKeys();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $apikey_pool is correct as teampassGetKeys() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
2903
2904
    // if needed extract key from credentials
2905
    if (strlen($apikey_used) > 40) {
2906
        $userCredentials = urlSafeB64Decode(substr($apikey_used, 40));
0 ignored issues
show
Unused Code introduced by
The assignment to $userCredentials is dead and can be removed.
Loading history...
2907
        $apikey_used = substr($apikey_used, 0, 39);
2908
    }
2909
2910
    if (in_array($apikey_used, $apikey_pool)) {
0 ignored issues
show
Bug introduced by
$apikey_pool of type void is incompatible with the type array expected by parameter $haystack of in_array(). ( Ignorable by Annotation )

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

2910
    if (in_array($apikey_used, /** @scrutinizer ignore-type */ $apikey_pool)) {
Loading history...
2911
        return(1);
0 ignored issues
show
Bug Best Practice introduced by
The expression return 1 returns the type integer which is incompatible with the documented return type void.
Loading history...
2912
    } else {
2913
        restError('APIKEY', $apikey_used);
2914
    }
2915
}
2916
2917
/**
2918
 * Permits to hash parameters
2919
 *
2920
 * @param  string $var_p
2921
 * @param  string $var_s
2922
 * @param  string $var_c
2923
 * @param  string $var_kl
2924
 * @param  integer $var_st
2925
 * @param  string $var_a
2926
 * @return void
2927
 */
2928
function teampassPbkdf2Hash($var_p, $var_s, $var_c, $var_kl, $var_st = 0, $var_a = 'sha256')
2929
{
2930
    $var_kb = $var_st + $var_kl;
2931
    $var_dk = '';
2932
2933
    for ($block = 1; $block <= $var_kb; $block++) {
2934
        $var_ib = $var_h = hash_hmac($var_a, $var_s.pack('N', $block), $var_p, true);
2935
        for ($var_i = 1; $var_i < $var_c; $var_i++) {
2936
            $var_ib ^= ($var_h = hash_hmac($var_a, $var_h, $var_p, true));
2937
        }
2938
        $var_dk .= $var_ib;
2939
    }
2940
2941
    return substr($var_dk, $var_st, $var_kl);
0 ignored issues
show
Bug Best Practice introduced by
The expression return substr($var_dk, $var_st, $var_kl) returns the type string which is incompatible with the documented return type void.
Loading history...
Bug introduced by
$var_kl of type string is incompatible with the type integer expected by parameter $length of substr(). ( Ignorable by Annotation )

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

2941
    return substr($var_dk, $var_st, /** @scrutinizer ignore-type */ $var_kl);
Loading history...
2942
}
2943