Completed
Push — development ( 813154...a4b5b1 )
by Nils
07:28
created

functions.php ➔ teampass_get_ips()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 0
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 * @file          (api)functions.php
5
 * @author        Nils Laumaillé
6
 * @version       2.0
7
 * @copyright     (c) 2009-2017 Nils Laumaillé
8
 * @licensing     GNU AFFERO GPL 3.0
9
 * @link          http://www.teampass.net
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 */
15
16
$api_version = "2.0";
17
$_SESSION['CPM'] = 1;
18
require_once "../includes/config/include.php";
19
require_once "../sources/main.functions.php";
20
21
function get_ip() {
22
    if (function_exists('apache_request_headers')) {
23
        $headers = apache_request_headers();
24
    } else {
25
        $headers = $_SERVER;
26
    }
27
    if (array_key_exists('X-Forwarded-For', $headers) && filter_var($headers['X-Forwarded-For'], FILTER_VALIDATE_IP)) {
28
        $the_ip = $headers['X-Forwarded-For'];
29
    } elseif (array_key_exists('HTTP_X_FORWARDED_FOR', $headers) && filter_var($headers['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP)) {
30
        $the_ip = $headers['HTTP_X_FORWARDED_FOR'];
31
    } else {
32
        $the_ip = filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP);
33
    }
34
    return $the_ip;
35
}
36
37
38
function teampass_api_enabled() {
39
    teampass_connect();
40
    $response = DB::queryFirstRow(
41
        "SELECT `valeur` FROM ".prefix_table("misc")." WHERE type = %s AND intitule = %s",
42
        "admin",
43
        "api"
44
    );
45
    return $response['valeur'];
46
}
47
48
function teampass_whitelist() {
49
    teampass_connect();
50
    $apiip_pool = teampass_get_ips();
51
    if (count($apiip_pool) > 0 && array_search(get_ip(), $apiip_pool) === false) {
52
        rest_error('IPWHITELIST');
53
    }
54
}
55
56
function teampass_connect()
57
{
58
    global $server, $user, $pass, $database, $link, $port, $encoding;
59
    require_once("../includes/config/settings.php");
60
    require_once('../includes/libraries/Database/Meekrodb/db.class.php');
61
    DB::$host = $server;
62
    DB::$user = $user;
63
    DB::$password = $pass;
64
    DB::$dbName = $database;
65
    DB::$port = $port;
66
    DB::$encoding = $encoding;
67
    DB::$error_handler = 'db_error_handler';
0 ignored issues
show
Documentation Bug introduced by
The property $error_handler was declared of type boolean, but 'db_error_handler' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
68
    $link = mysqli_connect($server, $user, $pass, $database, $port);
69
    $link->set_charset($encoding);
70
}
71
72
function teampass_get_ips() {
73
    global $server, $user, $pass, $database, $link;
74
    $array_of_results = array();
75
    teampass_connect();
76
    $response = DB::query("select value from ".prefix_table("api")." WHERE type = %s", "ip");
77
    foreach ($response as $data)
78
    {
79
        array_push($array_of_results, $data['value']);
80
    }
81
82
    return $array_of_results;
83
}
84
85
function teampass_get_keys() {
86
    global $server, $user, $pass, $database, $link;
87
    teampass_connect();
88
    $response = DB::queryOneColumn("value", "select * from ".prefix_table("api")." WHERE type = %s", "key");
89
90
    return $response;
91
}
92
93
function rest_head() {
94
    header('HTTP/1.1 402 Payment Required');
95
}
96
97
function addToCacheTable($id)
98
{
99
    global $server, $user, $pass, $database, $link;
100
    teampass_connect();
101
    // get data
102
    $data = DB::queryfirstrow(
103
        "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
104
        FROM ".prefix_table("items")." AS i
105
        AND ".prefix_table("log_items")." AS l ON (l.id_item = i.id)
106
        WHERE i.id = %i
107
        AND l.action = %s",
108
        intval($id),
109
        at_creation
110
    );
111
112
    // Get all TAGS
113
    $tags = "";
114
    $data_tags = DB::query("SELECT tag FROM ".prefix_table("tags")." WHERE item_id=%i", $id);
115
    foreach ($data_tags as $itemTag) {
116
        if (!empty($itemTag['tag'])) {
117
            $tags .= $itemTag['tag']." ";
118
        }
119
    }
120
121
    // finaly update
122
    DB::insert(
123
        prefix_table("cache"),
124
        array(
125
            "id" => $data['id'],
126
            "label" => $data['label'],
127
            "description" => $data['description'],
128
            "tags" => $tags,
129
            "id_tree" => $data['id_tree'],
130
            "perso" => $data['perso'],
131
            "restricted_to" => $data['restricted_to'],
132
            "login" => $data['login'],
133
            "folder" => "",
134
            //"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...
135
            "author" => API_USER_ID,
136
            "renewal_period" => 0,
137
            "timestamp" => time(),
138
            "url" => 0
139
        )
140
    );
141
}
142
143
144
/**
145
 * @param string $setting
146
 */
147
function getSettingValue($setting) {
148
149
    // get default language
150
    $set = DB::queryFirstRow(
151
        "SELECT `valeur` FROM ".prefix_table("misc")." WHERE type = %s AND intitule = %s",
152
        "admin",
153
        $setting
154
    );
155
156
    return $set['valeur'];
157
}
158
159
function rest_delete() {
160 View Code Duplication
    if (!@count($GLOBALS['request']) == 0) {
161
        $request_uri = $GLOBALS['_SERVER']['REQUEST_URI'];
162
        preg_match('/\/api(\/index.php|)\/(.*)\?apikey=(.*)/', $request_uri, $matches);
163
        if (count($matches) == 0) {
164
            rest_error('REQUEST_SENT_NOT_UNDERSTANDABLE');
165
        }
166
        $GLOBALS['request'] = explode('/', $matches[2]);
167
    }
168
    if (apikey_checker($GLOBALS['apikey'])) {
169
        global $server, $user, $pass, $database, $pre, $link;
170
        include "../sources/main.functions.php";
171
        teampass_connect();
172
        $category_query = "";
173
174
        if ($GLOBALS['request'][0] == "write") {
175
            if ($GLOBALS['request'][1] == "category") {
176
                $array_category = explode(';', $GLOBALS['request'][2]);
177
178
                foreach ($array_category as $category) {
179
                    if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $category, $result)) {
180
                        rest_error('CATEGORY_MALFORMED');
181
                    }
182
                }
183
184 View Code Duplication
                if (count($array_category) > 1 && count($array_category) < 5) {
185
                    for ($i = count($array_category); $i > 0; $i--) {
186
                        $slot = $i - 1;
187
                        if (!$slot) {
188
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".$array_category[$slot]."' AND parent_id = 0";
189
                        } else {
190
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".$array_category[$slot]."' AND parent_id = (";
191
                        }
192
                    }
193
                    for ($i = 1; $i < count($array_category); $i++) { $category_query .= ")"; }
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...
194
                } elseif (count($array_category) == 1) {
195
                    $category_query = "select id from ".prefix_table("nested_tree")." where title LIKE '".$array_category[0]."' AND parent_id = 0";
196
                } else {
197
                    rest_error('NO_CATEGORY');
198
                }
199
200
                // Delete items which in category
201
                $response = DB::delete(prefix_table("items"), "id_tree = (".$category_query.")");
0 ignored issues
show
Unused Code introduced by
$response is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
202
                // Delete sub-categories which in category
203
                $response = DB::delete(prefix_table("nested_tree"), "parent_id = (".$category_query.")");
0 ignored issues
show
Unused Code introduced by
$response is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
204
                // Delete category
205
                $response = DB::delete(prefix_table("nested_tree"), "id = (".$category_query.")");
206
207
                $json['type'] = 'category';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$json was never initialized. Although not strictly required by PHP, it is generally a good practice to add $json = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
208
                $json['category'] = $GLOBALS['request'][2];
209
                if ($response) {
210
                    $json['status'] = 'OK';
211
                } else {
212
                    $json['status'] = 'KO';
213
                }
214
215
            } elseif ($GLOBALS['request'][1] == "item") {
216
                $array_category = explode(';', $GLOBALS['request'][2]);
217
                $item = $GLOBALS['request'][3];
218
219
                foreach ($array_category as $category) {
220
                    if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $category, $result)) {
221
                        rest_error('CATEGORY_MALFORMED');
222
                    }
223
                }
224
225 View Code Duplication
                if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $item, $result)) {
226
                    rest_error('ITEM_MALFORMED');
227
                } elseif (empty($item) || count($array_category) == 0) {
228
                    rest_error('MALFORMED');
229
                }
230
231 View Code Duplication
                if (count($array_category) > 1 && count($array_category) < 5) {
232
                    for ($i = count($array_category); $i > 0; $i--) {
233
                        $slot = $i - 1;
234
                        if (!$slot) {
235
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".$array_category[$slot]."' AND parent_id = 0";
236
                        } else {
237
                            $category_query .= "select id from ".prefix_table("nested_tree")." where title LIKE '".$array_category[$slot]."' AND parent_id = (";
238
                        }
239
                    }
240
                    for ($i = 1; $i < count($array_category); $i++) { $category_query .= ")"; }
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...
241
                } elseif (count($array_category) == 1) {
242
                    $category_query = "select id from ".prefix_table("nested_tree")." where title LIKE '".$array_category[0]."' AND parent_id = 0";
243
                } else {
244
                    rest_error('NO_CATEGORY');
245
                }
246
247
                // Delete item
248
                $response = DB::delete(prefix_table("items"), "id_tree = (".$category_query.") and label LIKE '".$item."'");
249
                $json['type'] = 'item';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$json was never initialized. Although not strictly required by PHP, it is generally a good practice to add $json = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
250
                $json['item'] = $item;
251
                $json['category'] = $GLOBALS['request'][2];
252
                if ($response) {
253
                    $json['status'] = 'OK';
254
                } else {
255
                    $json['status'] = 'KO';
256
                }
257
            }
258
259
            if ($json) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $json of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
260
                echo json_encode($json);
0 ignored issues
show
Bug introduced by
The variable $json does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
261
            } else {
262
                rest_error('EMPTY');
263
            }
264
        } else {
265
            rest_error('METHOD');
266
        }
267
    }
268
}
269
270
function rest_get() {
271
    global $api_version;
272
273 View Code Duplication
    if (!@count($GLOBALS['request']) == 0) {
274
        $request_uri = $GLOBALS['_SERVER']['REQUEST_URI'];
275
        preg_match('/\/api(\/index.php|)\/(.*)\?apikey=(.*)/', $request_uri, $matches);
276
        if (count($matches) == 0) {
277
            rest_error('REQUEST_SENT_NOT_UNDERSTANDABLE');
278
        }
279
        $GLOBALS['request'] = explode('/', $matches[2]);
280
    }
281
282
    if (apikey_checker($GLOBALS['apikey'])) {
283
        global $server, $user, $pass, $database, $pre, $link;
284
        teampass_connect();
285
        $category_query = "";
0 ignored issues
show
Unused Code introduced by
$category_query is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
286
287
        // define the API user through the LABEL of apikey
288
        $api_info = DB::queryFirstRow(
289
            "SELECT label
290
            FROM ".prefix_table("api")."
291
            WHERE value = %s",
292
            $GLOBALS['apikey']
293
        );
294
295
        if ($GLOBALS['request'][0] == "read") {
296
            if ($GLOBALS['request'][1] == "folder") {
297
                /*
298
                * READ FOLDERS
299
                */
300
301
                // load library
302
                require_once '../sources/SplClassLoader.php';
303
                //Load Tree
304
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
305
                $tree->register();
306
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
0 ignored issues
show
Security Bug introduced by
It seems like prefix_table('nested_tree') targeting prefix_table() can also be of type false; however, Tree\NestedTree\NestedTree::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
307
308
                // get ids
309
                if (strpos($GLOBALS['request'][2], ";") > 0) {
310
                    $condition = "id_tree IN %ls";
311
                    $condition_value = explode(';', $GLOBALS['request'][2]);
312
                } else {
313
                    $condition = "id_tree = %s";
314
                    $condition_value = $GLOBALS['request'][2];
315
                }
316
317
                // get items in this folder
318
                $response = DB::query(
319
                    "SELECT id, label, login, pw, pw_iv, url, id_tree, description, email
320
                    FROM ".prefix_table("items")."
321
                    WHERE inactif='0' AND ".$condition, $condition_value
322
                );
323
                $x = 0;
324 View Code Duplication
                foreach ($response as $data)
325
                {
326
                    // build the path to the Item
327
                    $path = "";
328
                    $arbo = $tree->getPath($data['id_tree'], true);
329
                    foreach ($arbo as $elem) {
330
                        if (empty($path)) {
331
                            $path = stripslashes($elem->title);
332
                        } else {
333
                            $path .= " > ".stripslashes($elem->title);
334
                        }
335
                    }
336
337
                    // prepare output
338
                    $json[$x]['id'] = $data['id'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$json was never initialized. Although not strictly required by PHP, it is generally a good practice to add $json = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
339
                    $json[$x]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
0 ignored issues
show
Bug introduced by
The variable $json does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
340
                    $json[$x]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
341
                    $json[$x]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
342
                    $json[$x]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
343
                    $json[$x]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
344
                    $crypt_pw = cryption(
345
                        $data['pw'],
346
                        "",
347
                        "decrypt"
348
                    );
349
                    $json[$x]['pw'] = $crypt_pw['string'];
350
                    $json[$x]['folder_id'] = $data['id_tree'];
351
                    $json[$x]['path'] = $path;
352
353
                    $x++;
354
                }
355
            } else if ($GLOBALS['request'][1] == "userpw") {
356
                /*
357
                * READ USER ITEMS
358
                */
359
360
                // load library
361
                require_once '../sources/SplClassLoader.php';
362
                //Load Tree
363
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
364
                $tree->register();
365
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
0 ignored issues
show
Security Bug introduced by
It seems like prefix_table('nested_tree') targeting prefix_table() can also be of type false; however, Tree\NestedTree\NestedTree::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
366
367
                // about the user
368
                $username = $GLOBALS['request'][2];
369
                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...
370
                    // forbid admin access
371
                }
372
                $response = DB::query("SELECT fonction_id FROM ".prefix_table("users")." WHERE login='".$username."'");
373
                if (count($response) === 0) {
374
                    rest_error('USER_NOT_EXISTS');
375
                }
376
                foreach ($response as $data)
377
                {
378
                    $role_str = $data['fonction_id'];
379
                }
380
                $folder_arr = array();
381
                $roles = explode(";", $role_str);
0 ignored issues
show
Bug introduced by
The variable $role_str does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
382
                foreach ($roles as $role)
383
                {
384
                    $response = DB::query("SELECT folder_id FROM ".prefix_table("roles_values")." WHERE role_id='".$role."'");
385
                    foreach ($response as $data)
386
                    {
387
                        $folder_id = $data['folder_id'];
388
                        if (!array_key_exists($folder_id, $folder_arr)) {
389
                            array_push($folder_arr, $folder_id);
390
                        }
391
                    }
392
                }
393
                $folder_str = array_filter($folder_arr);
394
395
                // get ids
396
                if (is_array($folder_str)) {
397
                    $condition = "id_tree IN %ls";
398
                    $condition_value = $folder_str;
399
                } else {
400
                    $condition = "id_tree = %s";
401
                    $condition_value = $folder_str;
402
                }
403
404
                $data = "";
405
                // get items in this module
406
                $response = DB::query(
407
                    "SELECT id,label,url,login,pw, pw_iv, url, id_tree, description, email
408
                    FROM ".prefix_table("items")."
409
                    WHERE inactif='0' AND ".$condition, $condition_value
410
                );
411
                $x = 0;
412
                foreach ($response as $data)
413
                {
414
                    // build the path to the Item
415
                    $path = "";
416
                    $arbo = $tree->getPath($data['id_tree'], true);
417
                    foreach ($arbo as $elem) {
418
                        if (empty($path)) {
419
                            $path = stripslashes($elem->title);
420
                        } else {
421
                            $path .= " > ".stripslashes($elem->title);
422
                        }
423
                    }
424
425
                    // prepare output
426
                    $json[$data['id']]['id'] = $data['id'];
427
                    $json[$data['id']]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
428
                    $json[$data['id']]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
429
                    $json[$data['id']]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
430
                    $json[$data['id']]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
431
                    $json[$data['id']]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
432
                    $crypt_pw = cryption($data['pw'], "", "decrypt");
433
                    $json[$data['id']]['pw'] = $crypt_pw['string'];
434
                    $json[$data['id']]['folder_id'] = $data['id_tree'];
435
                    $json[$data['id']]['path'] = $path;
436
437
                    $x++;
438
                }
439
            } else if ($GLOBALS['request'][1] == "userfolders") {
440
                /*
441
                * READ USER FOLDERS
442
                * Sends back a list of folders
443
                */
444
                $json = "";
445
                $username = $GLOBALS['request'][2];
446
                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...
447
                    // forbid admin access
448
                }
449
                $response = DB::query("SELECT fonction_id FROM ".prefix_table("users")." WHERE login='".$username."'");
450
                if (count($response) === 0) {
451
                    rest_error('USER_NOT_EXISTS');
452
                }
453
                foreach ($response as $data)
454
                {
455
                    $role_str = $data['fonction_id'];
456
                }
457
458
                $folder_arr = array();
459
                $roles = explode(";", $role_str);
460
                $x = 0;
461
                foreach ($roles as $role)
462
                {
463
                    $response = DB::query("SELECT folder_id, type FROM ".prefix_table("roles_values")." WHERE role_id='".$role."'");
464
                    foreach ($response as $data)
465
                    {
466
                        $folder_id = $data['folder_id'];
467
                        if (!array_key_exists($folder_id, $folder_arr)) {
468
                            array_push($folder_arr, $folder_id);
469
470
                            $response2 = DB::queryFirstRow("SELECT title, nlevel FROM ".prefix_table("nested_tree")." WHERE id='".$folder_id."'");
471
472
                            if (!empty($response2['title'])) {
473
                                $json[$folder_id]['id'] = $folder_id;
474
                                $json[$folder_id]['title'] = $response2['title'];
475
                                $json[$folder_id]['level'] = $response2['nlevel'];
476
                                $json[$folder_id]['access_type'] = $data['type'];
477
                                $x++;
478
                            }
479
                        }
480
                    }
481
                }
482
            } elseif ($GLOBALS['request'][1] == "items") {
483
                /*
484
                * READ ITEMS asked
485
                */
486
487
                // load library
488
                require_once '../sources/SplClassLoader.php';
489
                //Load Tree
490
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
491
                $tree->register();
492
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
0 ignored issues
show
Security Bug introduced by
It seems like prefix_table('nested_tree') targeting prefix_table() can also be of type false; however, Tree\NestedTree\NestedTree::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
493
494
                // get parameters
495
                $array_items = explode(';', $GLOBALS['request'][2]);
496
497
                // check if not empty
498
                if (count($array_items) == 0) {
499
                    rest_error('NO_ITEM');
500
                }
501
502
                // only accepts numeric
503
                foreach ($array_items as $item) {
504
                    if (!is_numeric($item)) {
505
                        rest_error('ITEM_MALFORMED');
506
                    }
507
                }
508
509
                $response = DB::query(
510
                    "SELECT id,label,login,pw, pw_iv, url, id_tree, description, email
511
                    FROM ".prefix_table("items")."
512
                    WHERE inactif = %i AND id IN %ls", "0", $array_items
513
                );
514
                $x = 0;
515 View Code Duplication
                foreach ($response as $data)
516
                {
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[$x]['id'] = $data['id'];
530
                    $json[$x]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
531
                    $json[$x]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
532
                    $json[$x]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
533
                    $json[$x]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
534
                    $json[$x]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
535
                    $crypt_pw = cryption($data['pw'], "", "decrypt");
536
                    $json[$x]['pw'] = $crypt_pw['string'];
537
                    $json[$x]['folder_id'] = $data['id_tree'];
538
                    $json[$x]['path'] = $path;
539
540
                    $x++;
541
                }
542
            }
543
544
            if (isset($json) && $json) {
545
                echo json_encode($json);
546
            } else {
547
                rest_error('EMPTY');
548
            }
549
        } elseif ($GLOBALS['request'][0] == "find") {
550
            if ($GLOBALS['request'][1] == "item") {
551
                /*
552
                * FIND ITEMS in FOLDERS
553
                */
554
555
                // load library
556
                require_once '../sources/SplClassLoader.php';
557
                //Load Tree
558
                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
559
                $tree->register();
560
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
0 ignored issues
show
Security Bug introduced by
It seems like prefix_table('nested_tree') targeting prefix_table() can also be of type false; however, Tree\NestedTree\NestedTree::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
561
562
                // get parameters
563
                $array_category = explode(';', $GLOBALS['request'][2]);
564
                $item = $GLOBALS['request'][3];
565
                foreach ($array_category as $category) {
566
                    if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $category, $result)) {
567
                        rest_error('CATEGORY_MALFORMED');
568
                    }
569
                }
570
571 View Code Duplication
                if (!preg_match_all("/^([\w\:\'\-\sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ]+)$/i", $item, $result)) {
572
                    rest_error('ITEM_MALFORMED');
573
                } elseif (empty($item) || count($array_category) == 0) {
574
                    rest_error('MALFORMED');
575
                }
576
577
                if (count($array_category) === 0) {
578
                    rest_error('NO_CATEGORY');
579
                }
580
581
                DB::debugMode(false);
582
                $response = DB::query(
583
                    "SELECT id, label, login, pw, pw_iv, url, id_tree, description, email
584
                    FROM ".prefix_table("items")."
585
                    WHERE
586
                    inactif = %i
587
                    AND id_tree IN %ls
588
                    AND label LIKE %ss",
589
                    "0",
590
                    $array_category,
591
                    $item
592
                );
593
                $x = 0;
594
                foreach ($response as $data) {
595
                    // build the path to the Item
596
                    $path = "";
597
                    $arbo = $tree->getPath($data['id_tree'], true);
598
                    foreach ($arbo as $elem) {
599
                        if (empty($path)) {
600
                            $path = stripslashes($elem->title);
601
                        } else {
602
                            $path .= " > ".stripslashes($elem->title);
603
                        }
604
                    }
605
606
                    // prepare output
607
                    $json[$x]['id'] = mb_convert_encoding($data['id'], mb_detect_encoding($data['id']), 'UTF-8');
608
                    $json[$x]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
609
                    $json[$x]['description'] = mb_convert_encoding($data['description'], mb_detect_encoding($data['description']), 'UTF-8');
610
                    $json[$x]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
611
                    $json[$x]['email'] = mb_convert_encoding($data['email'], mb_detect_encoding($data['email']), 'UTF-8');
612
                    $json[$x]['url'] = mb_convert_encoding($data['url'], mb_detect_encoding($data['url']), 'UTF-8');
613
                    $crypt_pw = cryption($data['pw'], "", "decrypt");
614
                    $json[$x]['pw'] = $crypt_pw['string'];
615
                    $json[$x]['folder_id'] = $data['id_tree'];
616
                    $json[$x]['path'] = $path;
617
                    $json[$x]['status'] = utf8_encode("OK");
618
619
                    $x++;
620
                }
621
                if (isset($json) && $json) {
622
                    echo json_encode($json);
623
                } else {
624
                    rest_error('EMPTY');
625
                }
626
            }
627
        } elseif ($GLOBALS['request'][0] == "add") {
628
            if ($GLOBALS['request'][1] == "item") {
629
                // get sent parameters
630
                $params = explode(';', base64_decode($GLOBALS['request'][2]));
631
                if (count($params) != 9) {
632
                    rest_error('ITEMBADDEFINITION');
633
                }
634
635
                $item_label = $params[0];
636
                $item_pwd = $params[1];
637
                $item_desc = $params[2];
638
                $item_folder_id = $params[3];
639
                $item_login = $params[4];
640
                $item_email = $params[5];
641
                $item_url = $params[6];
642
                $item_tags = $params[7];
643
                $item_anyonecanmodify = $params[8];
644
645
                // do some checks
646
                if (!empty($item_label) && !empty($item_pwd) && !empty($item_folder_id)) {
647
                    // Check length
648
                    if (strlen($item_pwd) > 50) {
649
                        rest_error('PASSWORDTOOLONG');
650
                    }
651
652
                    // Check Folder ID
653
                    DB::query("SELECT * FROM ".prefix_table("nested_tree")." WHERE id = %i", $item_folder_id);
654
                    $counter = DB::count();
655
                    if ($counter == 0) {
656
                        rest_error('NOSUCHFOLDER');
657
                    }
658
659
                    // check if element doesn't already exist
660
                    $item_duplicate_allowed = getSettingValue("duplicate_item");
661
                    if ($item_duplicate_allowed !== "1") {
662
                        DB::query("SELECT * FROM ".prefix_table("items")." WHERE label = %s AND inactif = %i", addslashes($item_label), "0");
663
                        $counter = DB::count();
664
                        if ($counter != 0) {
665
                            $itemExists = 1;
666
                            // prevent the error if the label already exists
667
                            // so lets just add the time() as a random factor
668
                            $item_label .= " (".time().")";
669
                        } else {
670
                            $itemExists = 0;
671
                        }
672
                    } else {
673
                        $itemExists = 0;
674
                    }
675
                    if ($itemExists === 0) {
676
                        $encrypt = cryption(
677
                            $item_pwd,
678
                            "",
679
                            "encrypt"
680
                        );
681
                        if (empty($encrypt['string'])) {
682
                            rest_error('PASSWORDEMPTY');
683
                        }
684
685
                        // ADD item
686
                        try {
687
                            DB::insert(
688
                                prefix_table("items"),
689
                                array(
690
                                    "label" => $item_label,
691
                                    "description" => $item_desc,
692
                                    'pw' => $encrypt['string'],
693
                                    'pw_iv' => '',
694
                                    "email" => $item_email,
695
                                    "url" => $item_url,
696
                                    "id_tree" => intval($item_folder_id),
697
                                    "login" => $item_login,
698
                                    "inactif" => 0,
699
                                    "restricted_to" => "",
700
                                    "perso" => 0,
701
                                    "anyone_can_modify" => intval($item_anyonecanmodify)
702
                                )
703
                            );
704
                            $newID = DB::InsertId();
705
706
                            // log
707
                            DB::insert(
708
                                prefix_table("log_items"),
709
                                array(
710
                                    "id_item" => $newID,
711
                                    "date" => time(),
712
                                    "id_user" => API_USER_ID,
713
                                    "action" => "at_creation",
714
                                    "raison" => $api_info['label']
715
                                )
716
                            );
717
718
                            // Add tags
719
                            $tags = explode(' ', $item_tags);
720 View Code Duplication
                            foreach ((array) $tags as $tag) {
721
                                if (!empty($tag)) {
722
                                    DB::insert(
723
                                        prefix_table("tags"),
724
                                        array(
725
                                            "item_id" => $newID,
726
                                            "tag" => strtolower($tag)
727
                                        )
728
                                    );
729
                                }
730
                            }
731
732
                            // Update CACHE table
733
                            DB::insert(
734
                                prefix_table("cache"),
735
                                array(
736
                                    "id" => $newID,
737
                                    "label" => $item_label,
738
                                    "description" => $item_desc,
739
                                    "tags" => $item_tags,
740
                                    "id_tree" => $item_folder_id,
741
                                    "perso" => "0",
742
                                    "restricted_to" => "",
743
                                    "login" => $item_login,
744
                                    "folder" => "",
745
                                    "author" => API_USER_ID,
746
                                    "renewal_period" => "0",
747
                                    "timestamp" => time(),
748
                                    "url" => "0"
749
                                )
750
                            );
751
752
                            echo '{"status":"item added" , "new_item_id" : "'.$newID.'"}';
753
                        } catch (PDOException $ex) {
754
                            echo '<br />'.$ex->getMessage();
755
                        }
756
                    } else {
757
                        rest_error('ITEMEXISTS');
758
                    }
759
                } else {
760
                    rest_error('ITEMMISSINGDATA');
761
                }
762
            }
763
            /*
764
             * Case where a new user has to be added
765
             *
766
             * 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>
767
             * with:
768
             * for READ_ONLY, IS_ADMIN, IS_MANAGER, PERSONAL_FOLDER, accepted value is 1 for TRUE and 0 for FALSE
769
             * for ADMINISTRATEDBY and ROLE1, accepted value is the real label (not the IDs)
770
             *
771
             * Example: /api/index.php/add/user/U4;Nils;Laumaille;test;[email protected];Users;0;Managers,Users;0;1;1?apikey=sae6iekahxiseL3viShoo0chahc1ievei8aequi
772
             *
773
             */
774
            elseif ($GLOBALS['request'][1] == "user") {
775
776
                // get user definition
777
                $array_user = explode(';', base64_decode($GLOBALS['request'][2]));
778
                if (count($array_user) != 11) {
779
                    rest_error('USERBADDEFINITION');
780
                }
781
782
                $login = $array_user[0];
783
                $name = $array_user[1];
784
                $lastname = $array_user[2];
785
                $password = $array_user[3];
786
                $email = $array_user[4];
787
                $adminby = urldecode($array_user[5]);
788
                $isreadonly = urldecode($array_user[6]);
789
                $roles = urldecode($array_user[7]);
790
                $isadmin = $array_user[8];
791
                $ismanager = $array_user[9];
792
                $haspf = $array_user[10];
793
794
                // Empty user
795
                if (mysqli_escape_string($link, htmlspecialchars_decode($login)) == "") {
796
                    rest_error('USERLOGINEMPTY');
797
                }
798
                // Check if user already exists
799
                $data = DB::query(
0 ignored issues
show
Unused Code introduced by
$data is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
800
                    "SELECT id, fonction_id, groupes_interdits, groupes_visibles FROM ".prefix_table("users")."
801
            WHERE login LIKE %ss",
802
                    mysqli_escape_string($link, stripslashes($login))
803
                );
804
805
                if (DB::count() == 0) {
806
                    try {
807
                        // find AdminRole code in DB
808
                        $resRole = DB::queryFirstRow(
809
                            "SELECT id
810
                            FROM ".prefix_table("roles_title")."
811
                            WHERE title LIKE %ss",
812
                            mysqli_escape_string($link, stripslashes($adminby))
813
                        );
814
815
                        // get default language
816
                        $lang = DB::queryFirstRow(
817
                            "SELECT `valeur` FROM ".prefix_table("misc")." WHERE type = %s AND intitule = %s",
818
                            "admin",
819
                            "default_language"
820
                        );
821
822
                        // prepare roles list
823
                        $rolesList = "";
824
                        foreach (explode(',', $roles) as $role) {//echo $role."-";
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...
825
                            $tmp = DB::queryFirstRow(
826
                                "SELECT `id` FROM ".prefix_table("roles_title")." WHERE title = %s",
827
                                $role
828
                            );
829
                            if (empty($rolesList)) {
830
                                $rolesList = $tmp['id'];
831
                            } else {
832
                                $rolesList .= ";".$tmp['id'];
833
                            }
834
                        }
835
836
                        // Add user in DB
837
                        DB::insert(
838
                            prefix_table("users"),
839
                            array(
840
                                'login' => $login,
841
                                'name' => $name,
842
                                'lastname' => $lastname,
843
                                'pw' => bCrypt(stringUtf8Decode($password), COST),
844
                                'email' => $email,
845
                                'admin' => intval($isadmin),
846
                                'gestionnaire' => intval($ismanager),
847
                                'read_only' => intval($isreadonly),
848
                                'personal_folder' => intval($haspf),
849
                                'user_language' => $lang['valeur'],
850
                                'fonction_id' => $rolesList,
851
                                'groupes_interdits' => '0',
852
                                'groupes_visibles' => '0',
853
                                'isAdministratedByRole' => empty($resRole) ? '0' : $resRole['id']
854
                            )
855
                        );
856
                        $new_user_id = DB::insertId();
857
                        // Create personnal folder
858
                        if (intval($haspf) == 1) {
859
                            DB::insert(
860
                                prefix_table("nested_tree"),
861
                                array(
862
                                    'parent_id' => '0',
863
                                    'title' => $new_user_id,
864
                                    'bloquer_creation' => '0',
865
                                    'bloquer_modification' => '0',
866
                                    'personal_folder' => '1'
867
                                )
868
                            );
869
                        }
870
871
                        // load settings
872
                        loadSettings();
873
874
                        // Send email to new user
875
                        @sendEmail(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
876
                            $LANG['email_subject_new_user'],
0 ignored issues
show
Bug introduced by
The variable $LANG does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
877
                            str_replace(
878
                                array('#tp_login#', '#tp_pw#', '#tp_link#'),
879
                                array(" ".addslashes($login), addslashes($password), $_SESSION['settings']['email_server_url']), $LANG['email_new_user_mail']),
880
                            $email,
881
                            ""
882
                        );
883
884
                        // update LOG
885
                        logEvents('user_mngt', 'at_user_added', 'api - '.$GLOBALS['apikey'], $new_user_id, "");
886
887
                        echo '{"status":"user added"}';
888
                    } catch (PDOException $ex) {
889
                        echo '<br />'.$ex->getMessage();
890
                    }
891
                } else {
892
                    rest_error('USERALREADYEXISTS');
893
                }
894
            }
895
            /*
896
            * ADDING A FOLDER
897
            * <url to teampass>/api/index.php/add/folder/<title>;<complexity_level>;<parent_id>;<renewal_period>;<personal>?apikey=<valid api key>
898
            */
899
            elseif ($GLOBALS['request'][1] == "folder") {
900
                if (!empty($GLOBALS['request'][2])) {
901
                    // get sent parameters
902
                    $params = explode(';', base64_decode($GLOBALS['request'][2]));
903
904
                    if (!empty($params[0]) && !empty($params[1])) {
905
                        if (empty($params[3])) {
906
                            $params[3] = 0;
907
                        }
908
                        if (empty($params[4])) {
909
                            $params[4] = 0;
910
                        }
911
                        if ($params[2] < 0) {
912
                            rest_error('NO_DATA_EXIST');
913
                        }
914
915
                        //Check if title doesn't contains html codes
916
                        if (preg_match_all("|<[^>]+>(.*)</[^>]+>|U", $params[0], $out)) {
917
                            rest_error('HTML_CODES_NOT_ALLOWED');
918
                        }
919
920
                        // check if title is numeric
921
                        if (is_numeric($params[0]) === true) {
922
                            rest_error('TITLE_ONLY_WITH_NUMBERS');
923
                        }
924
925
                        //Check if duplicate folders name are allowed
926
                        $data = DB::queryfirstrow(
927
                            "SELECT valeur
928
                            FROM ".prefix_table("misc")."
929
                            WHERE type = %s AND intitule = %s",
930
                            "admin",
931
                            "duplicate_folder"
932
                        );
933
                        // if valeur = 0 then duplicate folders not allowed
934
                        if ($data === 0) {
935
                            DB::query("SELECT * FROM ".prefix_table("nested_tree")." WHERE title = %s", $params[0]);
936
                            $counter = DB::count();
937
                            if ($counter != 0) {
938
                                rest_error('ALREADY_EXISTS');
939
                            }
940
                        }
941
942
                        //check if parent folder is personal
943
                        $data = DB::queryfirstrow(
944
                            "SELECT personal_folder
945
                            FROM ".prefix_table("nested_tree")."
946
                            WHERE id = %i",
947
                            $params[2]
948
                        );
949
                        if ($data['personal_folder'] === "1") {
950
                            $isPersonal = 1;
951
                        } else {
952
                            if ($params[4] === 1) {
953
                                $isPersonal = 1;
954
                            } else {
955
                                $isPersonal = 0;
956
                            }
957
958
                            // get complexity level for this folder
959
                            $data = DB::queryfirstrow(
960
                                "SELECT valeur
961
                                FROM ".prefix_table("misc")."
962
                                WHERE intitule = %i AND type = %s",
963
                                $params[2],
964
                                "complex"
965
                            );
966
                            if (intval($params[1]) < intval($data['valeur'])) {
967
                                rest_error('COMPLEXICITY_LEVEL_NOT_REACHED');
968
                            }
969
                        }
970
971
                        try {
972
                            //create folder
973
                            DB::insert(
974
                                prefix_table("nested_tree"),
975
                                array(
976
                                    'parent_id' => $params[2],
977
                                    'title' => $params[0],
978
                                    'personal_folder' => $isPersonal,
979
                                    'renewal_period' => $params[3],
980
                                    'bloquer_creation' => '0',
981
                                    'bloquer_modification' => '0'
982
                                )
983
                            );
984
                            $newId = DB::insertId();
985
986
                            //Add complexity
987
                            DB::insert(
988
                                prefix_table("misc"),
989
                                array(
990
                                    'type' => 'complex',
991
                                    'intitule' => $newId,
992
                                    'valeur' => $params[1]
993
                                )
994
                            );
995
996
                            echo '{"status":"folder created" , "new_folder_id":"'.$newId.'"}';
997
                        } catch (PDOException $ex) {
998
                            echo '<br />'.$ex->getMessage();
999
                        }
1000
                    } else {
1001
                        rest_error('NO_DATA_EXIST');
1002
                    }
1003
                } else {
1004
                    rest_error('SET_NO_DATA');
1005
                }
1006
            }
1007
        } elseif ($GLOBALS['request'][0] == "update") {
1008
            /*
1009
            * Section dedicated for UPDATING
1010
            */
1011
            if ($GLOBALS['request'][1] == "item") {
1012
                /*
1013
                * 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>
1014
                */
1015
                if ($GLOBALS['request'][2] !== "" && is_numeric($GLOBALS['request'][2])) {
1016
                    // get sent parameters
1017
                    $params = explode(';', base64_decode($GLOBALS['request'][3]));
1018
1019
                    if (!empty($params[0]) && !empty($params[1]) && !empty($params[3])) {
1020
                        // Check length
1021
                        if (strlen($params[1]) > 50) {
1022
                            rest_error('PASSWORDTOOLONG');
1023
                        }
1024
1025
                        // Check Folder ID
1026
                        DB::query("SELECT * FROM ".prefix_table("nested_tree")." WHERE id = %i", $params[3]);
1027
                        $counter = DB::count();
1028
                        if ($counter == 0) {
1029
                            rest_error('NOSUCHFOLDER');
1030
                        }
1031
1032
                        // check if item exists
1033
                        DB::query(
1034
                            "SELECT * FROM ".prefix_table("items")." WHERE id = %i",
1035
                            $GLOBALS['request'][2]
1036
                        );
1037
                        $counter = DB::count();
1038
                        if ($counter > 0) {
1039
                            // encrypt pwd
1040
                            $encrypt = cryption(
1041
                                $params[1],
1042
                                "",
1043
                                "encrypt"
1044
                            );
1045
                            if (empty($encrypt['string'])) {
1046
                                rest_error('PASSWORDEMPTY');
1047
                            }
1048
1049
                            // ADD item
1050
                            try {
1051
                                DB::update(
1052
                                    prefix_table("items"),
1053
                                    array(
1054
                                        "label" => $params[0],
1055
                                        "description" => $params[2],
1056
                                        'pw' => $encrypt['string'],
1057
                                        'pw_iv' => '',
1058
                                        "email" => $params[5],
1059
                                        "url" => $params[6],
1060
                                        "id_tree" => intval($params[3]),
1061
                                        "login" => $params[4],
1062
                                        "anyone_can_modify" => intval($params[8])
1063
                                    ),
1064
                                    "id = %i",
1065
                                    $GLOBALS['request'][2]
1066
                                );
1067
1068
                                // log
1069
                                DB::insert(
1070
                                    prefix_table("log_items"),
1071
                                    array(
1072
                                        "id_item" => $GLOBALS['request'][2],
1073
                                        "date" => time(),
1074
                                        "id_user" => API_USER_ID,
1075
                                        "action" => "at_modification"
1076
                                    )
1077
                                );
1078
1079
                                // Add tags
1080
                                $tags = explode(' ', $params[7]);
1081
                                foreach ((array) $tags as $tag) {
1082
                                    if (!empty($tag)) {
1083
                                        // check if already exists
1084
                                        DB::query(
1085
                                            "SELECT * FROM ".prefix_table("tags")." WHERE tag = %s AND item_id = %i",
1086
                                            strtolower($tag),
1087
                                            $GLOBALS['request'][2]
1088
                                        );
1089
                                        $counter = DB::count();
1090
                                        if ($counter === 0) {
1091
                                            DB::insert(
1092
                                                prefix_table("tags"),
1093
                                                array(
1094
                                                    "item_id" => $GLOBALS['request'][2],
1095
                                                    "tag" => strtolower($tag)
1096
                                                )
1097
                                            );
1098
                                        }
1099
                                    }
1100
                                }
1101
1102
                                // Update CACHE table
1103
                                DB::update(
1104
                                    prefix_table("cache"),
1105
                                    array(
1106
                                        "label" => $params[0],
1107
                                        "description" => $params[2],
1108
                                        "tags" => $params[7],
1109
                                        "id_tree" => intval($params[3]),
1110
                                        "perso" => "0",
1111
                                        "restricted_to" => "",
1112
                                        "login" => $params[4],
1113
                                        "folder" => "",
1114
                                        "author" => API_USER_ID,
1115
                                        "renewal_period" => "0",
1116
                                        "timestamp" => time(),
1117
                                        "url" => $params[6],
1118
                                    ),
1119
                                    "id = %i",
1120
                                    $GLOBALS['request'][2]
1121
                                );
1122
1123
                                echo '{"status":"item updated"}';
1124
                            } catch (PDOException $ex) {
1125
                                echo '<br />'.$ex->getMessage();
1126
                            }
1127
                        } else {
1128
                            rest_error('NO_DATA_EXIST');
1129
                        }
1130
                    } else {
1131
                        rest_error('ITEMMISSINGDATA');
1132
                    }
1133
                } else {
1134
                    rest_error('NO_ITEM');
1135
                }
1136
            }
1137
            /*
1138
            * UPDATING A FOLDER
1139
            * <url to teampass>/api/index.php/update/folder/<folder_id>/<title>;<complexity_level>;<renewal_period>?apikey=<valid api key>
1140
            */
1141
            else if ($GLOBALS['request'][1] == "folder") {
1142
                if ($GLOBALS['request'][2] !== "" && is_numeric($GLOBALS['request'][2])) {
1143
                    // get sent parameters
1144
                    $params = explode(';', base64_decode($GLOBALS['request'][3]));
1145
1146
                    if (!empty($params[0])) {
1147
                        if ($params[1] < 0) {
1148
                            rest_error('NO_DATA_EXIST');
1149
                        }
1150
                        if (empty($params[2])) {
1151
                            $params[2] = 0;
1152
                        }
1153
1154
                        // check if folder exists and get folder data
1155
                        $data_folder = DB::queryfirstrow("SELECT * FROM ".prefix_table("nested_tree")." WHERE id = %s", $GLOBALS['request'][2]);
1156
                        $counter = DB::count();
1157
                        if ($counter === 0) {
1158
                            rest_error('NO_DATA_EXIST');
1159
                        }
1160
1161
                        //Check if title doesn't contains html codes
1162
                        if (preg_match_all("|<[^>]+>(.*)</[^>]+>|U", $params[0], $out)) {
1163
                            rest_error('HTML_CODES_NOT_ALLOWED');
1164
                        }
1165
1166
                        // check if title is numeric
1167
                        if (is_numeric($params[0]) === true) {
1168
                            rest_error('TITLE_ONLY_WITH_NUMBERS');
1169
                        }
1170
1171
                        // get complexity level for this folder
1172
                        $data = DB::queryfirstrow(
1173
                            "SELECT valeur
1174
                            FROM ".prefix_table("misc")."
1175
                            WHERE intitule = %i AND type = %s",
1176
                            $data_folder['parent_id'],
1177
                            "complex"
1178
                        );
1179
                        if (intval($params[1]) < intval($data['valeur'])) {
1180
                            rest_error('COMPLEXICITY_LEVEL_NOT_REACHED');
1181
                        }
1182
1183
                        try {
1184
                            DB::update(
1185
                                prefix_table("nested_tree"),
1186
                                array(
1187
                                    'parent_id' => $data_folder['parent_id'],
1188
                                    'title' => $params[0],
1189
                                    'personal_folder' => 0,
1190
                                    'renewal_period' => $params[2],
1191
                                    'bloquer_creation' => '0',
1192
                                    'bloquer_modification' => '0'
1193
                                ),
1194
                                "id = %i",
1195
                                $GLOBALS['request'][2]
1196
                            );
1197
1198
                            //Add complexity
1199
                            DB::update(
1200
                                prefix_table("misc"),
1201
                                array(
1202
                                    'valeur' => $params[1]
1203
                                ),
1204
                                "intitule = %s AND type = %s",
1205
                                $GLOBALS['request'][2],
1206
                                "complex"
1207
                            );
1208
1209
                            echo '{"status":"folder updated"}';
1210
                        } catch (PDOException $ex) {
1211
                            echo '<br />'.$ex->getMessage();
1212
                        }
1213
                    } else {
1214
                        rest_error('ITEMMISSINGDATA');
1215
                    }
1216
                } else {
1217
                    rest_error('NO_ITEM');
1218
                }
1219
            }
1220
        } elseif ($GLOBALS['request'][0] == "auth") {
1221
            /*
1222
            ** FOR SECURITY PURPOSE, it is mandatory to use SSL to connect your teampass instance. The user password is not encrypted!
1223
            **
1224
            **
1225
            ** Expected call format: .../api/index.php/auth/<PROTOCOL>/<URL>/<login>/<password>?apikey=<VALID API KEY>
1226
            ** Example: https://127.0.0.1/teampass/api/index.php/auth/http/www.zadig-tge.adp.com/U1/test/76?apikey=chahthait5Aidood6johh6Avufieb6ohpaixain
1227
            ** RESTRICTIONS:
1228
            **              - <PROTOCOL>        ==> http|https|ftp|...
1229
            **              - <URL>             ==> encode URL without protocol (example: http://www.teampass.net becomes www.teampass.net)
1230
            **              - <login>           ==> user's login
1231
            **              - <password>        ==> currently clear password
1232
            **
1233
            ** RETURNED ANSWER:
1234
            **              - format sent back is JSON
1235
            **              - Example: {"<item_id>":{"label":"<pass#1>","login":"<login#1>","pw":"<pwd#1>"},"<item_id>":{"label":"<pass#2>","login":"<login#2>","pw":"<pwd#2>"}}
1236
            **
1237
            */
1238
            // get user credentials
1239
            if (isset($GLOBALS['request'][3]) && isset($GLOBALS['request'][4])) {
1240
                // get url
1241
                if (isset($GLOBALS['request'][1]) && isset($GLOBALS['request'][2])) {
1242
                    // is user granted?
1243
                    $userData = DB::queryFirstRow(
1244
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id` FROM ".$pre."users WHERE login = %s",
1245
                        $GLOBALS['request'][3]
1246
                    );
1247
1248
                    // load passwordLib library
1249
                    $_SESSION['settings']['cpassman_dir'] = "..";
1250
                    require_once '../sources/SplClassLoader.php';
1251
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1252
                    $pwdlib->register();
1253
                    $pwdlib = new PasswordLib\PasswordLib();
1254
1255
                    if ($pwdlib->verifyPasswordHash($GLOBALS['request'][4], $userData['pw']) === true) {
1256
                        // define the restriction of "id_tree" of this user
1257
                        //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...
1258
                        $userDef = DB::queryOneColumn('folder_id',
1259
                            "SELECT DISTINCT folder_id
1260
                            FROM ".prefix_table("roles_values")."
1261
                            WHERE type IN ('R', 'W', 'ND', 'NE', 'NDNE', 'NEND') ", empty($userData['groupes_interdits']) ? "" : "
1262
                            AND folder_id NOT IN (".str_replace(";", ",", $userData['groupes_interdits']).")", "
1263
                            AND role_id IN %ls
1264
                            GROUP BY folder_id",
1265
                            explode(";", $userData['groupes_interdits'])
1266
                        );
1267
                        // complete with "groupes_visibles"
1268
                        foreach (explode(";", $userData['groupes_visibles']) as $v) {
1269
                            array_push($userDef, $v);
1270
                        }
1271
1272
                        // find the item associated to the url
1273
                        $response = DB::query(
1274
                            "SELECT id, label, login, pw, pw_iv, id_tree, restricted_to
1275
                            FROM ".prefix_table("items")."
1276
                            WHERE url LIKE %s
1277
                            AND id_tree IN (".implode(",", $userDef).")
1278
                            ORDER BY id DESC",
1279
                            $GLOBALS['request'][1]."://".urldecode($GLOBALS['request'][2].'%')
1280
                        );
1281
                        $counter = DB::count();
1282
1283
                        if ($counter > 0) {
1284
                            $json = "";
1285
                            foreach ($response as $data) {
1286
                                // check if item visible
1287
                                if (
1288
                                    empty($data['restricted_to']) ||
1289
                                    ($data['restricted_to'] != "" && in_array($userData['id'], explode(";", $data['restricted_to'])))
1290
                                ) {
1291
                                    // prepare export
1292
                                    $json[$data['id']]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
1293
                                    $json[$data['id']]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
1294
                                    $crypt_pw = cryption(
1295
                                        $data['pw'],
1296
                                        "",
1297
                                        "decrypt"
1298
                                    );
1299
                                    $json[$data['id']]['pw'] = $crypt_pw['string'];
1300
                                }
1301
                            }
1302
                            // prepare answer. If no access then inform
1303
                            if (empty($json)) {
1304
                                rest_error('AUTH_NO_DATA');
1305
                            } else {
1306
                                echo json_encode($json);
1307
                            }
1308
                        } else {
1309
                            rest_error('NO_DATA_EXIST');
1310
                        }
1311
                    } else {
1312
                        rest_error('AUTH_NOT_GRANTED');
1313
                    }
1314
                } else {
1315
                    rest_error('AUTH_NO_URL');
1316
                }
1317
            } else {
1318
                rest_error('AUTH_NO_IDENTIFIER');
1319
            }
1320
        } elseif ($GLOBALS['request'][0] == "auth_tpc") {
1321
            /*
1322
            ** TO BE USED ONLY BY TEAMPASS-CONNECT
1323
            **
1324
            */
1325
            // get user credentials
1326
            if (isset($GLOBALS['request'][2]) && isset($GLOBALS['request'][3]) && isset($GLOBALS['request'][4])) {
1327
                // get url
1328
                if (isset($GLOBALS['request'][1])) {
1329
                    // decode base64 criterium
1330
                    $tpc_url = base64_decode($GLOBALS['request'][1]);
1331
                    $user_pwd = base64_decode($GLOBALS['request'][3]);
1332
                    $user_saltkey = base64_decode($GLOBALS['request'][4]);
1333
1334
                    // is user granted?
1335
                    //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...
1336
                    $userData = DB::queryFirstRow(
1337
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`, `encrypted_psk` FROM ".$pre."users WHERE login = %s",
1338
                        $GLOBALS['request'][2]
1339
                    );
1340
1341
                    // check if psk is correct.
1342
                    $user_saltkey = defuse_validate_personal_key(
1343
                        $user_saltkey,
1344
                        $userData['encrypted_psk']
1345
                    );
1346
                    if (strpos($user_saltkey, "Error ") !== false) {
1347
                        // error
1348
                        rest_error('AUTH_NO_DATA');
1349
                    }
1350
1351
                    // load passwordLib library
1352
                    $_SESSION['settings']['cpassman_dir'] = "..";
1353
                    require_once '../sources/SplClassLoader.php';
1354
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1355
                    $pwdlib->register();
1356
                    $pwdlib = new PasswordLib\PasswordLib();
1357
1358
                    if ($pwdlib->verifyPasswordHash($user_pwd, $userData['pw']) === true) {
1359
                        // define the restriction of "id_tree" of this user
1360
                        //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...
1361
                        $userDef = DB::queryOneColumn('folder_id',
1362
                            "SELECT DISTINCT folder_id
1363
                            FROM ".prefix_table("roles_values")."
1364
                            WHERE type IN ('R', 'W', 'ND', 'NE', 'NDNE', 'NEND') ", empty($userData['groupes_interdits']) ? "" : "
1365
                            AND folder_id NOT IN (".str_replace(";", ",", $userData['groupes_interdits']).")", "
1366
                            AND role_id IN %ls
1367
                            GROUP BY folder_id",
1368
                            explode(";", $userData['groupes_interdits'])
1369
                        );
1370
                        // complete with "groupes_visibles"
1371
                        foreach (explode(";", $userData['groupes_visibles']) as $v) {
1372
                            array_push($userDef, $v);
1373
                        }
1374
1375
                        // add PF
1376
                        $userpf = DB::queryFirstRow(
1377
                            "SELECT `id` FROM ".$pre."nested_tree WHERE title = %s",
1378
                            $userData['id']
1379
                        );
1380
                        array_push($userDef, $userpf['id']);
1381
1382
                        // find the item associated to the url
1383
                        $response = DB::query(
1384
                            "SELECT id, label, login, pw, pw_iv, id_tree, restricted_to, perso
1385
                            FROM ".prefix_table("items")."
1386
                            WHERE url LIKE %s
1387
                            AND id_tree IN (".implode(",", array_filter($userDef)).")
1388
                            AND inactif = %i
1389
                            ORDER BY id DESC",
1390
                            $tpc_url.'%',
1391
                            0
1392
                        );
1393
                        $counter = DB::count();
1394
1395
                        if ($counter > 0) {
1396
                            $json = "";
1397
                            foreach ($response as $data) {
1398
                                // check if item visible
1399
                                if (
1400
                                    empty($data['restricted_to']) ||
1401
                                    ($data['restricted_to'] != "" && in_array($userData['id'], explode(";", $data['restricted_to'])))
1402
                                ) {
1403
                                    // prepare export
1404
                                    $json[$data['id']]['label'] = mb_convert_encoding($data['label'], mb_detect_encoding($data['label']), 'UTF-8');
1405
                                    $json[$data['id']]['login'] = mb_convert_encoding($data['login'], mb_detect_encoding($data['login']), 'UTF-8');
1406
                                    if ($data['perso'] === "0") {
1407
                                        $crypt_pw = cryption(
1408
                                            $data['pw'],
1409
                                            "",
1410
                                            "decrypt"
1411
                                        );
1412
                                    } else if (empty($user_saltkey)) {
1413
                                        $crypt_pw['string'] = "no_psk";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$crypt_pw was never initialized. Although not strictly required by PHP, it is generally a good practice to add $crypt_pw = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1414
                                    } else {
1415
                                        $crypt_pw = cryption(
1416
                                            $data['pw'],
1417
                                            $user_saltkey,
1418
                                            "decrypt"
1419
                                        );
1420
                                    }
1421
                                    $json[$data['id']]['pw'] = mb_detect_encoding($crypt_pw['string'], 'UTF-8', true) ? $crypt_pw['string'] : "not_utf8";
0 ignored issues
show
Bug introduced by
The variable $crypt_pw does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1422
                                    $json[$data['id']]['perso'] = $data['perso'];
1423
                                }
1424
                            }
1425
                            // prepare answer. If no access then inform
1426
                            if (empty($json)) {
1427
                                rest_error('AUTH_NO_DATA');
1428
                            } else {
1429
                                echo json_encode($json);
1430
                            }
1431
                        } else {
1432
                            rest_error('NO_DATA_EXIST');
1433
                        }
1434
                    } else {
1435
                        rest_error('AUTH_NOT_GRANTED');
1436
                    }
1437
                } else {
1438
                    rest_error('AUTH_NO_URL');
1439
                }
1440
            } else {
1441
                rest_error('AUTH_NO_IDENTIFIER');
1442
            }
1443
        } elseif ($GLOBALS['request'][0] == "set") {
1444
            /*
1445
             * Expected call format: .../api/index.php/set/<login_to_save>/<password_to_save>/<url>/<user_login>/<user_password>/<label>/<protocol>?apikey=<VALID API KEY>
1446
             * Example: https://127.0.0.1/teampass/api/index.php/set/newLogin/newPassword/newUrl/myLogin/myPassword?apikey=gu6Eexaewaishooph6iethoh5woh0yoit6ohquo
1447
             *
1448
             * NEW ITEM WILL BE STORED IN SPECIFIC FOLDER
1449
             */
1450
            // get user credentials
1451
            if (isset($GLOBALS['request'][4]) && isset($GLOBALS['request'][5])) {
1452
                // get url
1453
                if (isset($GLOBALS['request'][1]) && isset($GLOBALS['request'][2]) && isset($GLOBALS['request'][3])) {
1454
                    // is user granted?
1455
                    $userData = DB::queryFirstRow(
1456
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id` FROM ".$pre."users WHERE login = %s",
1457
                        $GLOBALS['request'][4]
1458
                    );
1459
                    if (DB::count() == 0) {
1460
                        rest_error('AUTH_NO_IDENTIFIER');
1461
                    }
1462
1463
                    // load passwordLib library
1464
                    $_SESSION['settings']['cpassman_dir'] = "..";
1465
                    require_once '../sources/SplClassLoader.php';
1466
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1467
                    $pwdlib->register();
1468
                    $pwdlib = new PasswordLib\PasswordLib();
1469
1470
                    // is user identified?
1471
                    if ($pwdlib->verifyPasswordHash($GLOBALS['request'][5], $userData['pw']) === true) {
1472
                        // does the personal folder of this user exists?
1473
                        DB::queryFirstRow(
1474
                            "SELECT `id`
1475
                            FROM " . $pre."nested_tree
1476
                            WHERE title = %s AND personal_folder = 1",
1477
                            $userData['id']
1478
                        );
1479
                        if (DB::count() > 0) {
1480
                            // check if "teampass-connect" folder exists
1481
                            // if not create it
1482
                            $folder = DB::queryFirstRow(
1483
                                "SELECT `id`
1484
                                FROM " . $pre."nested_tree
1485
                                WHERE title = %s",
1486
                                "teampass-connect"
1487
                            );
1488 View Code Duplication
                            if (DB::count() == 0) {
1489
                                DB::insert(
1490
                                    prefix_table("nested_tree"),
1491
                                    array(
1492
                                        'parent_id' => '0',
1493
                                        'title' => "teampass-connect"
1494
                                    )
1495
                                );
1496
                                $tpc_folder_id = DB::insertId();
1497
1498
                                //Add complexity
1499
                                DB::insert(
1500
                                    prefix_table("misc"),
1501
                                    array(
1502
                                        'type' => 'complex',
1503
                                        'intitule' => $tpc_folder_id,
1504
                                        'valeur' => '0'
1505
                                    )
1506
                                );
1507
1508
                                // rebuild tree
1509
                                $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1510
                                $tree->register();
1511
                                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
0 ignored issues
show
Security Bug introduced by
It seems like prefix_table('nested_tree') targeting prefix_table() can also be of type false; however, Tree\NestedTree\NestedTree::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1512
                                $tree->rebuild();
1513
                            } else {
1514
                                $tpc_folder_id = $folder['id'];
1515
                            }
1516
1517
                            // encrypt password
1518
                            $encrypt = cryption(
1519
                                $GLOBALS['request'][2],
1520
                                "",
1521
                                "encrypt"
1522
                            );
1523
1524
                            // is there a protocol?
1525
                            if (isset($GLOBALS['request'][7]) || empty($GLOBALS['request'][7])) {
1526
                                $protocol = "http://";
0 ignored issues
show
Unused Code introduced by
$protocol is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1527
                            } else {
1528
                                $protocol = urldecode($GLOBALS['request'][7])."://";
0 ignored issues
show
Unused Code introduced by
$protocol is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1529
                            }
1530
1531
                            // add new item
1532
                            DB::insert(
1533
                                prefix_table("items"),
1534
                                array(
1535
                                    'label' => "Credentials for ".urldecode($GLOBALS['request'][3]),
1536
                                    'description' => "Imported with Teampass-Connect",
1537
                                    'pw' => $encrypt['string'],
1538
                                    'pw_iv' => "",
1539
                                    'email' => "",
1540
                                    'url' => urldecode($GLOBALS['request'][3]),
1541
                                    'id_tree' => $tpc_folder_id,
1542
                                    'login' => $GLOBALS['request'][1],
1543
                                    'inactif' => '0',
1544
                                    'restricted_to' => $userData['id'],
1545
                                    'perso' => '0',
1546
                                    'anyone_can_modify' => '0',
1547
                                    'complexity_level' => '0'
1548
                                )
1549
                            );
1550
                            $newID = DB::insertId();
1551
1552
                            // log
1553
                            logItems(
1554
                                $newID,
1555
                                "Credentials for ".urldecode($GLOBALS['request'][3].'%'),
1556
                                $userData['id'],
1557
                                'at_creation',
1558
                                $GLOBALS['request'][1]
1559
                            );
1560
1561
                            $json['status'] = "ok";
1562
                            // prepare answer. If no access then inform
1563
                            if (empty($json)) {
1564
                                rest_error('AUTH_NO_DATA');
1565
                            } else {
1566
                                echo json_encode($json);
1567
                            }
1568
                        } else {
1569
                            rest_error('NO_PF_EXIST_FOR_USER');
1570
                        }
1571
                    } else {
1572
                        rest_error('AUTH_NOT_GRANTED');
1573
                    }
1574
                } else {
1575
                    rest_error('SET_NO_DATA');
1576
                }
1577
            } else {
1578
                rest_error('AUTH_NO_IDENTIFIER');
1579
            }
1580
        } elseif ($GLOBALS['request'][0] == "set_tpc") {
1581
            /*
1582
             * TO BE USED ONLY BY TEAMPASS-CONNECT
1583
             */
1584
            // get user credentials
1585
            if (isset($GLOBALS['request'][2]) && isset($GLOBALS['request'][3])) {
1586
                // get url
1587
                if (isset($GLOBALS['request'][1])) {
1588
                    // is user granted?
1589
                    $userData = DB::queryFirstRow(
1590
                        "SELECT `id`, `pw`, `groupes_interdits`, `groupes_visibles`, `fonction_id`, `encrypted_psk` FROM ".$pre."users WHERE login = %s",
1591
                        $GLOBALS['request'][2]
1592
                    );
1593
                    if (DB::count() == 0) {
1594
                        rest_error('AUTH_NO_IDENTIFIER');
1595
                    }
1596
1597
                    // load passwordLib library
1598
                    $_SESSION['settings']['cpassman_dir'] = "..";
1599
                    require_once '../sources/SplClassLoader.php';
1600
                    $pwdlib = new SplClassLoader('PasswordLib', '../includes/libraries');
1601
                    $pwdlib->register();
1602
                    $pwdlib = new PasswordLib\PasswordLib();
1603
1604
                    // prepare TPC parameters
1605
                    $tpc_param = explode(';@;', base64_decode($GLOBALS['request'][1]));
1606
                    $tpc_param[5] = base64_decode($tpc_param[5]);
1607
1608
                    // is user identified?
1609
                    if ($pwdlib->verifyPasswordHash(base64_decode($GLOBALS['request'][3]), $userData['pw']) === true) {
1610
                        //
1611
                        if ($tpc_param[4] !== "0") {
1612
                            // it is not a personal folder
1613
                            $salt = "";
1614
                            $tpc_folder_id = $tpc_param[4];
1615
                            $perso = '0';
1616
                            $restricted_to = $userData['id'];
1617
1618
                        } else if ($tpc_param[4] === "0" && $tpc_param[5] !== "") {
1619
                            // it is a personal folder
1620
                            $salt = $tpc_param[5];
1621
1622
                            // check if psk is correct.
1623
                            $salt = defuse_validate_personal_key(
1624
                                $salt,
1625
                                $userData['encrypted_psk']
1626
                            );
1627
                            if (strpos($user_key_encoded, "Error ") !== false) {
0 ignored issues
show
Bug introduced by
The variable $user_key_encoded does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1628
                                // error
1629
                                rest_error('AUTH_NO_DATA');
1630
                            }
1631
1632
1633
                            $perso = '1';
1634
                            $restricted_to = "";
1635
1636
                            // does the personal folder of this user exists?
1637
                            $user_folder = DB::queryFirstRow(
1638
                                "SELECT `id`
1639
                                FROM " . $pre."nested_tree
1640
                                WHERE title = %s AND personal_folder = 1",
1641
                                $userData['id']
1642
                            );
1643
                            if (DB::count() === 0) {
1644
                                // check if "teampass-connect" folder exists
1645
                                // if not create it
1646
                                $folder = DB::queryFirstRow(
1647
                                    "SELECT `id`
1648
                                    FROM " . $pre."nested_tree
1649
                                    WHERE title = %s",
1650
                                    "teampass-connect"
1651
                                );
1652 View Code Duplication
                                if (DB::count() == 0) {
1653
                                    DB::insert(
1654
                                        prefix_table("nested_tree"),
1655
                                        array(
1656
                                            'parent_id' => '0',
1657
                                            'title' => "teampass-connect"
1658
                                        )
1659
                                    );
1660
                                    $tpc_folder_id = DB::insertId();
1661
1662
                                    //Add complexity
1663
                                    DB::insert(
1664
                                        prefix_table("misc"),
1665
                                        array(
1666
                                            'type' => 'complex',
1667
                                            'intitule' => $tpc_folder_id,
1668
                                            'valeur' => '0'
1669
                                        )
1670
                                    );
1671
1672
                                    // rebuild tree
1673
                                    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1674
                                    $tree->register();
1675
                                    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
0 ignored issues
show
Security Bug introduced by
It seems like prefix_table('nested_tree') targeting prefix_table() can also be of type false; however, Tree\NestedTree\NestedTree::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1676
                                    $tree->rebuild();
1677
                                } else {
1678
                                    $tpc_folder_id = $folder['id'];
1679
                                }
1680
                            } else {
1681
                                $tpc_folder_id = $user_folder['id'];
1682
                            }
1683
                        } else {
1684
                            // there is an error in PSALT
1685
                            rest_error('NO_PSALTK_PROVIDED');
1686
                        }
1687
1688
                        // now we continue
1689
                        // encrypt password
1690
                        $encrypt = cryption(
1691
                            urldecode($tpc_param[1]),
1692
                            $salt,
0 ignored issues
show
Bug introduced by
The variable $salt does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1693
                            "encrypt"
1694
                        );
1695
1696
                        // is there a label?
1697
                        if (empty($tpc_param[3])) {
1698
                            $label = "Credentials for ".urldecode($tpc_param[2]);
1699
                        } else {
1700
                            $label = urldecode($tpc_param[3]);
1701
                        }
1702
1703
                        // add new item
1704
                        DB::insert(
1705
                            prefix_table("items"),
1706
                            array(
1707
                                'label' => $label,
1708
                                'description' => "Imported with Teampass-Connect",
1709
                                'pw' => $encrypt['string'],
1710
                                'pw_iv' => "",
1711
                                'email' => "",
1712
                                'url' => urldecode($tpc_param[2]),
1713
                                'id_tree' => $tpc_folder_id,
0 ignored issues
show
Bug introduced by
The variable $tpc_folder_id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1714
                                'login' => urldecode($tpc_param[0]),
1715
                                'inactif' => '0',
1716
                                'restricted_to' => $restricted_to,
0 ignored issues
show
Bug introduced by
The variable $restricted_to does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1717
                                'perso' => $perso,
0 ignored issues
show
Bug introduced by
The variable $perso does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1718
                                'anyone_can_modify' => '0',
1719
                                'complexity_level' => '0'
1720
                            )
1721
                        );
1722
                        $newID = DB::insertId();
1723
1724
                        // log
1725
                        logItems(
1726
                            $newID,
1727
                            $label,
1728
                            $userData['id'],
1729
                            'at_creation',
1730
                            ''
1731
                        );
1732
1733
                        $json['status'] = "ok";
1734
                        $json['new_item_id'] = $newID;
1735
                        // prepare answer. If no access then inform
1736
                        if (empty($json)) {
1737
                            rest_error('AUTH_NO_DATA');
1738
                        } else {
1739
                            echo json_encode($json);
1740
                        }
1741
                    } else {
1742
                        rest_error('AUTH_NOT_GRANTED');
1743
                    }
1744
                } else {
1745
                    rest_error('SET_NO_DATA');
1746
                }
1747
            } else {
1748
                rest_error('AUTH_NO_IDENTIFIER');
1749
            }
1750
        }
1751
        /*
1752
        * DELETE
1753
        *
1754
        * Expected call format: .../api/index.php/delete/folder/<folder_id1;folder_id2;folder_id3>?apikey=<VALID API KEY>
1755
        * Expected call format: .../api/index.php/delete/item>/<item_id1;item_id2;item_id3>?apikey=<VALID API KEY>
1756
        */
1757
        elseif ($GLOBALS['request'][0] == "delete") {
1758
            $_SESSION['settings']['cpassman_dir'] = "..";
1759
            if ($GLOBALS['request'][1] == "folder") {
1760
                $array_category = explode(';', $GLOBALS['request'][2]);
1761
1762
                // get user info
1763 View Code Duplication
                if (isset($GLOBALS['request'][3]) && !empty($GLOBALS['request'][3])) {
1764
                    $userData = DB::queryFirstRow(
1765
                        "SELECT `id` FROM ".$pre."users WHERE login = %s",
1766
                        $GLOBALS['request'][3]
1767
                    );
1768
                    if (DB::count() == 0) {
1769
                        $user_id = API_USER_ID;
1770
                    } else {
1771
                        $user_id = $userData['id'];
1772
                    }
1773
                } else {
1774
                    $user_id = API_USER_ID;
1775
                }
1776
1777
                if (count($array_category) > 0 && count($array_category) < 5) {
1778
                    // load passwordLib library
1779
                    require_once '../sources/SplClassLoader.php';
1780
1781
                    // prepare tree
1782
                    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1783
                    $tree->register();
1784
                    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title', 'personal_folder');
0 ignored issues
show
Security Bug introduced by
It seems like prefix_table('nested_tree') targeting prefix_table() can also be of type false; however, Tree\NestedTree\NestedTree::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
Unused Code introduced by
The call to NestedTree::__construct() has too many arguments starting with 'personal_folder'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1785
1786
                    // this will delete all sub folders and items associated
1787
                    for ($i = 0; $i < count($array_category); $i++) {echo "\n".$array_category[$i]."\n";
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...
1788
                        // Get through each subfolder
1789
                        $folders = $tree->getDescendants($array_category[$i], true);
1790
                        print_r($folders);
1791
                        if (count($folders) > 0) {
1792
                            foreach ($folders as $folder) {
1793
                                if (($folder->parent_id > 0 || $folder->parent_id == 0) && $folder->personal_folder != 1) {
1794
                                    //Store the deleted folder (recycled bin)
1795
                                    DB::insert(
1796
                                        prefix_table("misc"),
1797
                                        array(
1798
                                            'type' => 'folder_deleted',
1799
                                            'intitule' => "f".$array_category[$i],
1800
                                            'valeur' => $folder->id.', '.$folder->parent_id.', '.
1801
                                                $folder->title.', '.$folder->nleft.', '.$folder->nright.', '.$folder->nlevel.', 0, 0, 0, 0'
1802
                                        )
1803
                                    );
1804
                                    //delete folder
1805
                                    DB::delete(prefix_table("nested_tree"), "id = %i", $folder->id);
1806
1807
                                    //delete items & logs
1808
                                    $items = DB::query(
1809
                                        "SELECT id
1810
                                        FROM ".prefix_table("items")."
1811
                                        WHERE id_tree=%i",
1812
                                        $folder->id
1813
                                    );
1814
                                    foreach ($items as $item) {
1815
                                        DB::update(
1816
                                            prefix_table("items"),
1817
                                            array(
1818
                                                'inactif' => '1',
1819
                                            ),
1820
                                            "id = %i",
1821
                                            $item['id']
1822
                                        );
1823
                                        //log
1824
                                        DB::insert(
1825
                                            prefix_table("log_items"),
1826
                                            array(
1827
                                                'id_item' => $item['id'],
1828
                                                'date' => time(),
1829
                                                'id_user' => $user_id,
1830
                                                'action' => 'at_delete'
1831
                                            )
1832
                                        );
1833
                                    }
1834
                                    //Update CACHE table
1835
                                    updateCacheTable("delete_value", $array_category[$i]);
1836
                                }
1837
                            }
1838
                        }
1839
                    }
1840
                } else {
1841
                    rest_error('NO_CATEGORY');
1842
                }
1843
1844
                $json['status'] = 'OK';
1845
1846
            } elseif ($GLOBALS['request'][1] == "item") {
1847
                $array_items = explode(';', $GLOBALS['request'][2]);
1848
1849
                // get user info
1850 View Code Duplication
                if (isset($GLOBALS['request'][3]) && !empty($GLOBALS['request'][3])) {
1851
                    $userData = DB::queryFirstRow(
1852
                        "SELECT `id` FROM ".$pre."users WHERE login = %s",
1853
                        $GLOBALS['request'][3]
1854
                    );
1855
                    if (DB::count() == 0) {
1856
                        $user_id = API_USER_ID;
1857
                    } else {
1858
                        $user_id = $userData['id'];
1859
                    }
1860
                }
1861
1862
                for ($i = 0; $i < count($array_items); $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...
1863
                    DB::update(
1864
                        prefix_table("items"),
1865
                        array(
1866
                            'inactif' => '1',
1867
                        ),
1868
                        "id = %i",
1869
                        $array_items[$i]
1870
                    );
1871
                    //log
1872
                    DB::insert(
1873
                        prefix_table("log_items"),
1874
                        array(
1875
                            'id_item' => $array_items[$i],
1876
                            'date' => time(),
1877
                            'id_user' => $user_id,
0 ignored issues
show
Bug introduced by
The variable $user_id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1878
                            'action' => 'at_delete'
1879
                        )
1880
                    );
1881
1882
                    //Update CACHE table
1883
                    updateCacheTable("delete_value", $array_items[$i]);
1884
                }
1885
1886
                $json['status'] = 'OK';
1887
            }
1888
1889
            if ($json) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $json of type array<string,string> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1890
                echo json_encode($json);
1891
            } else {
1892
                rest_error('EMPTY');
1893
            }
1894
        } else if ($GLOBALS['request'][0] == "new_password") {
1895
            if (!empty($GLOBALS['request'][1])) {
1896
                $params = explode(";", $GLOBALS['request'][1]);
1897
1898
                if (empty($params[0])) {
1899
                    $params[0] = 8;
1900
                }
1901
                if (empty($params[1])) {
1902
                    $params[1] = 0;
1903
                }
1904
                if (empty($params[2])) {
1905
                    $params[2] = 0;
1906
                }
1907
                if (empty($params[3])) {
1908
                    $params[3] = 0;
1909
                }
1910
                if (empty($params[4])) {
1911
                    $params[4] = 0;
1912
                }
1913
                if (empty($params[5])) {
1914
                    $params[5] = 0;
1915
                }
1916
                if (empty($params[6])) {
1917
                    $params[6] = 0;
1918
                }
1919
1920
                // load library
1921
                require_once '../sources/SplClassLoader.php';
1922
                $pwgen = new SplClassLoader('Encryption\PwGen', '../includes/libraries');
1923
                $pwgen->register();
1924
                $pwgen = new Encryption\PwGen\pwgen();
1925
1926
                // init
1927
                $pwgen->setLength($params[0]);
1928
                if ($params[1] === "1") {
1929
                    $pwgen->setSecure(true);
1930
                }
1931
                if ($params[2] === "1") {
1932
                    $pwgen->setNumerals(true);
1933
                }
1934
                if ($params[3] === "1") {
1935
                    $pwgen->setCapitalize(true);
1936
                }
1937
                if ($params[4] === "1") {
1938
                    $pwgen->setAmbiguous(true);
1939
                }
1940
                if ($params[5] === "1" && $params[6] === "1") {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $params[6] (integer) and '1' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1941
                    $pwgen->setSymbols(true);
1942
                }
1943
1944
                // generate and send back (generate in base64 if symbols are asked)
1945
                if ($params[6] === "1") {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $params[6] (integer) and '1' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1946
                    echo '{"password" : "'.base64_encode($pwgen->generate()).'"}';
1947
                } else {
1948
                    echo '{"password" : "'.($pwgen->generate()).'"}';
1949
                }
1950
            } else {
1951
                rest_error('NO_PARAMETERS');
1952
            }
1953
        } else if ($GLOBALS['request'][0] === "info") {
1954
            if ($GLOBALS['request'][1] === "complexicity_levels_list") {
1955
1956
                require_once '../includes/language/english.php';
1957
                $json = array(
1958
                    0=> $LANG['complex_level0'],
1959
                    25=> $LANG['complex_level1'],
1960
                    50=> $LANG['complex_level2'],
1961
                    60=> $LANG['complex_level3'],
1962
                    70=> $LANG['complex_level4'],
1963
                    80=> $LANG['complex_level5'],
1964
                    90=> $LANG['complex_level6']
1965
                );
1966
1967
                echo json_encode($json);
1968
            } else if ($GLOBALS['request'][1] === "folder") {
1969
                if (!empty($GLOBALS['request'][2]) && is_numeric($GLOBALS['request'][2])) {
1970
                    $data = DB::queryFirstRow(
1971
                        "SELECT * FROM ".$pre."nested_tree WHERE id = %i",
1972
                        $GLOBALS['request'][2]
1973
                    );
1974
                    if (DB::count() == 0) {
1975
                        rest_error('NOSUCHFOLDER');
1976
                    }
1977
1978
                    // form id_tree to full foldername
1979
                    require_once '../sources/SplClassLoader.php';
1980
                    //Load Tree
1981
                    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1982
                    $tree->register();
1983
                    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
0 ignored issues
show
Security Bug introduced by
It seems like prefix_table('nested_tree') targeting prefix_table() can also be of type false; however, Tree\NestedTree\NestedTree::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1984
1985
                    $folder = "";
1986
                    $arbo = $tree->getPath($GLOBALS['request'][2], true);
1987
                    foreach ($arbo as $elem) {
1988
                        if (empty($folder)) {
1989
                            $folder = stripslashes($elem->title);
1990
                        } else {
1991
                            $folder .= " > ".stripslashes($elem->title);
1992
                        }
1993
                    }
1994
1995
                    // prepare info
1996
                    $json = array(
1997
                        "title" => $data['title'],
1998
                        "personal_folder" => $data['personal_folder'],
1999
                        "renewal_period" => $data['renewal_period'],
2000
                        "parent_id" => $data['parent_id'],
2001
                        "path" => $folder,
2002
                    );
2003
2004
                    echo json_encode($json);
2005
                } else {
2006
                    rest_error('NO_PARAMETERS');
2007
                }
2008
            } else if ($GLOBALS['request'][1] === "version") {
2009
                echo '{"api-version":"'.$api_version.'"}';
2010
            } else {
2011
                rest_error('NO_PARAMETERS');
2012
            }
2013
        } else {
2014
            rest_error('METHOD');
2015
        }
2016
    }
2017
}
2018
2019
function rest_put() {
2020 View Code Duplication
    if (!@count($GLOBALS['request']) == 0) {
2021
        $request_uri = $GLOBALS['_SERVER']['REQUEST_URI'];
2022
        preg_match('/\/api(\/index.php|)\/(.*)\?apikey=(.*)/', $request_uri, $matches);
2023
        if (count($matches) == 0) {
2024
            rest_error('REQUEST_SENT_NOT_UNDERSTANDABLE');
2025
        }
2026
        $GLOBALS['request'] = explode('/', $matches[2]);
2027
    }
2028
    if (apikey_checker($GLOBALS['apikey'])) {
2029
        global $server, $user, $pass, $database, $pre, $link;
2030
        teampass_connect();
2031
2032
    }
2033
}
2034
2035
/**
2036
 * @param string $type
2037
 */
2038
function rest_error($type, $detail = 'N/A') {
2039
    switch ($type) {
2040
        case 'APIKEY':
2041
            $message = Array('err' => 'This api_key '.$GLOBALS['apikey'].' doesn\'t exist');
2042
            header('HTTP/1.1 405 Method Not Allowed');
2043
            break;
2044
        case 'NO_CATEGORY':
2045
            $message = Array('err' => 'No folder specified');
2046
            break;
2047
        case 'NO_ITEM':
2048
            $message = Array('err' => 'No item specified');
2049
            break;
2050
        case 'EMPTY':
2051
            $message = Array('err' => 'No results');
2052
            break;
2053
        case 'IPWHITELIST':
2054
            $message = Array('err' => 'Ip address not allowed.');
2055
            header('HTTP/1.1 405 Method Not Allowed');
2056
            break;
2057
        case 'MYSQLERR':
2058
            $message = Array('err' => $detail);
2059
            header('HTTP/1.1 500 Internal Server Error');
2060
            break;
2061
        case 'METHOD':
2062
            $message = Array('err' => 'Method not authorized');
2063
            header('HTTP/1.1 405 Method Not Allowed');
2064
            break;
2065
        case 'ITEMBADDEFINITION':
2066
            $message = Array('err' => 'Item definition not complete');
2067
            header('HTTP/1.1 405 Method Not Allowed');
2068
            break;
2069
        case 'ITEM_MALFORMED':
2070
            $message = Array('err' => 'Item definition not numeric');
2071
            header('HTTP/1.1 405 Method Not Allowed');
2072
            break;
2073
        case 'USERBADDEFINITION':
2074
            $message = Array('err' => 'User definition not complete');
2075
            header('HTTP/1.1 405 Method Not Allowed');
2076
            break;
2077
        case 'USERLOGINEMPTY':
2078
            $message = Array('err' => 'Empty Login given');
2079
            header('HTTP/1.1 405 Method Not Allowed');
2080
            break;
2081
        case 'USERALREADYEXISTS':
2082
            $message = Array('err' => 'User already exists');
2083
            header('HTTP/1.1 405 Method Not Allowed');
2084
            break;
2085
        case 'REQUEST_SENT_NOT_UNDERSTANDABLE':
2086
            $message = Array('err' => 'URL format is not following requirements');
2087
            break;
2088
        case 'AUTH_NOT_GRANTED':
2089
            $message = Array('err' => 'Bad credentials for user');
2090
            break;
2091
        case 'AUTH_NO_URL':
2092
            $message = Array('err' => 'URL needed to grant access');
2093
            break;
2094
        case 'AUTH_NO_IDENTIFIER':
2095
            $message = Array('err' => 'Credentials needed to grant access');
2096
            break;
2097
        case 'AUTH_NO_DATA':
2098
            $message = Array('err' => 'Data not allowed for the user');
2099
            break;
2100
        case 'NO_DATA_EXIST':
2101
            $message = Array('err' => 'No data exists');
2102
            break;
2103
        case 'PASSWORDTOOLONG':
2104
            $message = Array('err' => 'Password is too long');
2105
            break;
2106
        case 'NOSUCHFOLDER':
2107
            $message = Array('err' => 'Folder ID does not exist');
2108
            break;
2109
        case 'PASSWORDEMPTY':
2110
            $message = Array('err' => 'Password is empty');
2111
            break;
2112
        case 'ITEMEXISTS':
2113
            $message = Array('err' => 'Label already exists');
2114
            break;
2115
        case 'ITEMMISSINGDATA':
2116
            $message = Array('err' => 'Label or Password or Folder ID is missing');
2117
            break;
2118
        case 'SET_NO_DATA':
2119
            $message = Array('err' => 'No data to be stored');
2120
            break;
2121
        case 'NO_PF_EXIST_FOR_USER':
2122
            $message = Array('err' => 'No Personal Folder exists for this user');
2123
            break;
2124
        case 'HTML_CODES_NOT_ALLOWED':
2125
            $message = Array('err' => 'HTML tags not allowed');
2126
            break;
2127
        case 'TITLE_ONLY_WITH_NUMBERS':
2128
            $message = Array('err' => 'Title only with numbers not allowed');
2129
            break;
2130
        case 'ALREADY_EXISTS':
2131
            $message = Array('err' => 'Data already exists');
2132
            break;
2133
        case 'COMPLEXICITY_LEVEL_NOT_REACHED':
2134
            $message = Array('err' => 'complexity level was not reached');
2135
            break;
2136
        case 'NO_PARAMETERS':
2137
            $message = Array('err' => 'No parameters given');
2138
            break;
2139
        case 'USER_NOT_EXISTS':
2140
            $message = Array('err' => 'User does not exist');
2141
            break;
2142
        case 'NO_PSALTK_PROVIDED':
2143
            $message = Array('err' => 'No Personal saltkey provided');
2144
            break;
2145
        default:
2146
            $message = Array('err' => 'Something happen ... but what ?');
2147
            header('HTTP/1.1 500 Internal Server Error');
2148
            break;
2149
    }
2150
2151
    echo json_encode($message);
2152
    exit(0);
2153
}
2154
2155
function apikey_checker($apikey_used) {
2156
    teampass_connect();
2157
    $apikey_pool = teampass_get_keys();
2158
    if (in_array($apikey_used, $apikey_pool)) {
2159
        return(1);
2160
    } else {
2161
        rest_error('APIKEY', $apikey_used);
2162
    }
2163
}
2164
2165 View Code Duplication
function teampass_pbkdf2_hash($p, $s, $c, $kl, $st = 0, $a = 'sha256')
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2166
{
2167
    $kb = $st + $kl;
2168
    $dk = '';
2169
2170
    for ($block = 1; $block <= $kb; $block++) {
2171
        $ib = $h = hash_hmac($a, $s.pack('N', $block), $p, true);
2172
        for ($i = 1; $i < $c; $i++) {
2173
            $ib ^= ($h = hash_hmac($a, $h, $p, true));
2174
        }
2175
        $dk .= $ib;
2176
    }
2177
2178
    return substr($dk, $st, $kl);
2179
}
2180