Passed
Branch development (e0e718)
by Nils
04:45
created

chmodRecursive()   D

Complexity

Conditions 9
Paths 13

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 18
nc 13
nop 3
dl 0
loc 29
rs 4.909
c 1
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 13 and the first side effect is on line 16.

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

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

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

Loading history...
2
/**
3
 *
4
 * @file          main.functions.php
5
 * @author        Nils Laumaillé
6
 * @version       2.1.27
7
 * @copyright     (c) 2009-2017 Nils Laumaillé
8
 * @licensing     GNU GPL-3.0
9
 * @link
10
 */
11
12
//define pbkdf2 iteration count
13
define('ITCOUNT', '2072');
14
15
if (!isset($_SESSION['CPM']) || $_SESSION['CPM'] != 1) {
16
    die('Hacking attempt...');
17
}
18
19
// Load config if $SETTINGS not defined
20
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
21
  if (file_exists('../includes/config/tp.config.php')) {
22
      require_once '../includes/config/tp.config.php';
23
  } elseif (file_exists('./includes/config/tp.config.php')) {
24
      require_once './includes/config/tp.config.php';
25
  } elseif (file_exists('../../includes/config/tp.config.php')) {
26
      require_once '../../includes/config/tp.config.php';
27
  } else {
28
      throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
29
  }
30
}
31
32
// load phpCrypt
33
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
34
    require_once '../includes/libraries/phpcrypt/phpCrypt.php';
35
    require_once '../includes/config/settings.php';
36
} else {
37
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/phpcrypt/phpCrypt.php';
38
    require_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
39
}
40
41
// Prepare PHPCrypt class calls
42
use PHP_Crypt\PHP_Crypt as PHP_Crypt;
43
44
// Prepare Encryption class calls
45
use \Defuse\Crypto\Crypto;
46
use \Defuse\Crypto\Exception as Ex;
47
48
//Generate N# of random bits for use as salt
49
/**
50
 * @param integer $size
51
 */
52
function getBits($size)
53
{
54
    $str = '';
55
    $var_x = $size + 10;
56
    for ($var_i = 0; $var_i < $var_x; $var_i++) {
57
        $str .= base_convert(mt_rand(1, 36), 10, 36);
58
    }
59
    return substr($str, 0, $size);
60
}
61
62
//generate pbkdf2 compliant hash
63
function strHashPbkdf2($var_p, $var_s, $var_c, $var_kl, $var_a = 'sha256', $var_st = 0)
64
{
65
    $var_kb = $var_st + $var_kl; // Key blocks to compute
66
    $var_dk = ''; // Derived key
67
68
    for ($block = 1; $block <= $var_kb; $block++) { // Create key
69
        $var_ib = $var_h = hash_hmac($var_a, $var_s.pack('N', $block), $var_p, true); // Initial hash for this block
70
        for ($var_i = 1; $var_i < $var_c; $var_i++) { // Perform block iterations
71
            $var_ib ^= ($var_h = hash_hmac($var_a, $var_h, $var_p, true)); // XOR each iterate
72
        }
73
        $var_dk .= $var_ib; // Append iterated block
74
    }
75
    return substr($var_dk, $var_st, $var_kl); // Return derived key of correct length
76
}
77
78
/**
79
 * stringUtf8Decode()
80
 *
81
 * utf8_decode
82
 */
83
function stringUtf8Decode($string)
84
{
85
    return str_replace(" ", "+", utf8_decode($string));
86
}
87
88
/**
89
 * encryptOld()
90
 *
91
 * crypt a string
92
 * @param string $text
93
 */
94
function encryptOld($text, $personalSalt = "")
95
{
96
    if (empty($personalSalt) === false) {
97
        return trim(
98
            base64_encode(
99
                mcrypt_encrypt(
1 ignored issue
show
Deprecated Code introduced by
The function mcrypt_encrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

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

99
                /** @scrutinizer ignore-deprecated */ mcrypt_encrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
100
                    MCRYPT_RIJNDAEL_256,
101
                    $personalSalt,
102
                    $text,
103
                    MCRYPT_MODE_ECB,
104
                    mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

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

104
                    /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
105
                        mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

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

105
                        /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
106
                        MCRYPT_RAND
107
                    )
108
                )
109
            )
110
        );
111
    }
112
113
    // If $personalSalt is not empty
114
    return trim(
115
        base64_encode(
116
            mcrypt_encrypt(
1 ignored issue
show
Deprecated Code introduced by
The function mcrypt_encrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

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

116
            /** @scrutinizer ignore-deprecated */ mcrypt_encrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
117
                MCRYPT_RIJNDAEL_256,
118
                SALT,
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
119
                $text,
120
                MCRYPT_MODE_ECB,
121
                mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

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

121
                /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
122
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

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

122
                    /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
123
                    MCRYPT_RAND
124
                )
125
            )
126
        )
127
    );
128
}
129
130
/**
131
 * decryptOld()
132
 *
133
 * decrypt a crypted string
134
 */
135
function decryptOld($text, $personalSalt = "")
136
{
137
    if (!empty($personalSalt)) {
138
        return trim(
139
            mcrypt_decrypt(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_decrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

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

139
            /** @scrutinizer ignore-deprecated */ mcrypt_decrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
140
                MCRYPT_RIJNDAEL_256,
141
                $personalSalt,
142
                base64_decode($text),
143
                MCRYPT_MODE_ECB,
144
                mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

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

144
                /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
145
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

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

145
                    /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
146
                    MCRYPT_RAND
147
                )
148
            )
149
        );
150
    }
151
152
    // No personal SK
153
    return trim(
154
        mcrypt_decrypt(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_decrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

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

154
        /** @scrutinizer ignore-deprecated */ mcrypt_decrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
155
            MCRYPT_RIJNDAEL_256,
156
            SALT,
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
157
            base64_decode($text),
158
            MCRYPT_MODE_ECB,
159
            mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

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

159
            /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
160
                mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

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

160
                /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
161
                MCRYPT_RAND
162
            )
163
        )
164
    );
165
}
166
167
/**
168
 * encrypt()
169
 *
170
 * crypt a string
171
 * @param string $decrypted
172
 */
173
function encrypt($decrypted, $personalSalt = "")
174
{
175
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
176
177
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
178
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
179
    } else {
180
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
181
    }
182
183
    if (!empty($personalSalt)) {
184
        $staticSalt = $personalSalt;
185
    } else {
186
        $staticSalt = SALT;
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
187
    }
188
189
    //set our salt to a variable
190
    // Get 64 random bits for the salt for pbkdf2
191
    $pbkdf2Salt = getBits(64);
192
    // generate a pbkdf2 key to use for the encryption.
193
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
194
    // Build $init_vect and $ivBase64.  We use a block size of 256 bits (AES compliant)
195
    // and CTR mode.  (Note: ECB mode is inadequate as IV is not used.)
196
    $init_vect = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

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

196
    $init_vect = /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

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

196
    $init_vect = mcrypt_create_iv(/** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
197
198
    //base64 trim
199
    if (strlen($ivBase64 = rtrim(base64_encode($init_vect), '=')) != 43) {
200
        return false;
201
    }
202
    // Encrypt $decrypted
203
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $decrypted, 'ctr', $init_vect);
1 ignored issue
show
Deprecated Code introduced by
The function mcrypt_encrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

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

203
    $encrypted = /** @scrutinizer ignore-deprecated */ mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $decrypted, 'ctr', $init_vect);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
204
    // MAC the encrypted text
205
    $mac = hash_hmac('sha256', $encrypted, $staticSalt);
206
    // We're done!
207
    return base64_encode($ivBase64.$encrypted.$mac.$pbkdf2Salt);
208
}
209
210
/**
211
 * decrypt()
212
 *
213
 * decrypt a crypted string
214
 */
215
function decrypt($encrypted, $personalSalt = "")
216
{
217
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
218
219
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
220
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
221
    } else {
222
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
223
    }
224
225
    if (!empty($personalSalt)) {
226
        $staticSalt = $personalSalt;
227
    } else {
228
        $staticSalt = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
229
    }
230
    //base64 decode the entire payload
231
    $encrypted = base64_decode($encrypted);
232
    // get the salt
233
    $pbkdf2Salt = substr($encrypted, -64);
234
    //remove the salt from the string
235
    $encrypted = substr($encrypted, 0, -64);
236
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
237
    // Retrieve $init_vect which is the first 22 characters plus ==, base64_decoded.
238
    $init_vect = base64_decode(substr($encrypted, 0, 43).'==');
239
    // Remove $init_vect from $encrypted.
240
    $encrypted = substr($encrypted, 43);
241
    // Retrieve $mac which is the last 64 characters of $encrypted.
242
    $mac = substr($encrypted, -64);
243
    // Remove the last 64 chars from encrypted (remove MAC)
244
    $encrypted = substr($encrypted, 0, -64);
245
    //verify the sha256hmac from the encrypted data before even trying to decrypt it
246
    if (hash_hmac('sha256', $encrypted, $staticSalt) != $mac) {
247
        return false;
248
    }
249
    // Decrypt the data.
250
    $decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, 'ctr', $init_vect), "\0\4");
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_decrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

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

250
    $decrypted = rtrim(/** @scrutinizer ignore-deprecated */ mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, 'ctr', $init_vect), "\0\4");

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
251
    // Yay!
252
    return $decrypted;
253
}
254
255
256
/**
257
 * genHash()
258
 *
259
 * Generate a hash for user login
260
 * @param string $password
261
 */
262
function bCrypt($password, $cost)
263
{
264
    $salt = sprintf('$2y$%02d$', $cost);
265
    if (function_exists('openssl_random_pseudo_bytes')) {
266
        $salt .= bin2hex(openssl_random_pseudo_bytes(11));
267
    } else {
268
        $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
269
        for ($i = 0; $i < 22; $i++) {
270
            $salt .= $chars[mt_rand(0, 63)];
271
        }
272
    }
273
    return crypt($password, $salt);
274
}
275
276
function cryption_before_defuse($message, $saltkey, $init_vect, $type = null, $scope = "public")
277
{
278
    if (DEFUSE_ENCRYPTION === true) {
0 ignored issues
show
introduced by
The condition DEFUSE_ENCRYPTION === true is always true.
Loading history...
279
        if ($scope === "perso") {
280
            return defuse_crypto(
0 ignored issues
show
Bug introduced by
The function defuse_crypto was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

280
            return /** @scrutinizer ignore-call */ defuse_crypto(
Loading history...
281
                $message,
282
                $saltkey,
283
                $type
284
            );
285
        } else {
286
            return defuse_crypto(
287
                $message,
288
                file_get_contents(SECUREPATH."/teampass-seckey.txt"),
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
289
                $type
290
            );
291
        }
292
    } else {
293
        return cryption_phpCrypt($message, $saltkey, $init_vect, $type);
294
    }
295
}
296
297
/*
298
 * cryption() - Encrypt and decrypt string based upon phpCrypt library
299
 *
300
 * Using AES_128 and mode CBC
301
 *
302
 * $key and $init_vect have to be given in hex format
303
 */
304
function cryption_phpCrypt($string, $key, $init_vect, $type)
305
{
306
    // manage key origin
307
    if (null != SALT && $key != SALT) {
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
308
        // check key (AES-128 requires a 16 bytes length key)
309
        if (strlen($key) < 16) {
310
            for ($inc = strlen($key) + 1; $inc <= 16; $inc++) {
311
                $key .= chr(0);
312
            }
313
        } elseif (strlen($key) > 16) {
314
            $key = substr($key, 16);
315
        }
316
    }
317
318
    // load crypt
319
    $crypt = new PHP_Crypt($key, PHP_Crypt::CIPHER_AES_128, PHP_Crypt::MODE_CBC);
320
321
    if ($type == "encrypt") {
322
        // generate IV and encrypt
323
        $init_vect = $crypt->createIV();
324
        $encrypt = $crypt->encrypt($string);
325
        // return
326
        return array(
327
            "string" => bin2hex($encrypt),
328
            "iv" => bin2hex($init_vect),
329
            "error" => empty($encrypt) ? "ERR_ENCRYPTION_NOT_CORRECT" : ""
330
        );
331
    } elseif ($type == "decrypt") {
332
        // case if IV is empty
333
        if (empty($init_vect)) {
334
                    return array(
335
                'string' => "",
336
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
337
            );
338
        }
339
340
        // convert
341
        try {
342
            $string = testHex2Bin(trim($string));
343
            $init_vect = testHex2Bin($init_vect);
344
        } catch (Exception $e) {
345
            return array(
346
                'string' => "",
347
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
348
            );
349
        }
350
351
        // load IV
352
        $crypt->IV($init_vect);
353
        // decrypt
354
        $decrypt = $crypt->decrypt($string);
355
        // return
356
        return array(
357
            'string' => str_replace(chr(0), "", $decrypt),
358
            'error' => ""
359
        );
360
    }
361
}
362
363
function testHex2Bin($val)
364
{
365
    if (!@hex2bin($val)) {
366
        throw new Exception("ERROR");
367
    }
368
    return hex2bin($val);
369
}
370
371
/**
372
 * @param string $ascii_key
373
 * @param string $type
374
 */
375
function cryption($message, $ascii_key, $type) //defuse_crypto
376
{
377
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
378
379
    // load PhpEncryption library
380
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
381
        $path = '../includes/libraries/Encryption/Encryption/';
382
    } else {
383
        $path = $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/';
384
    }
385
386
    require_once $path.'Crypto.php';
387
    require_once $path.'Encoding.php';
388
    require_once $path.'DerivedKeys.php';
389
    require_once $path.'Key.php';
390
    require_once $path.'KeyOrPassword.php';
391
    require_once $path.'File.php';
392
    require_once $path.'RuntimeTests.php';
393
    require_once $path.'KeyProtectedByPassword.php';
394
    require_once $path.'Core.php';
395
396
    // init
397
    $err = '';
398
    if (empty($ascii_key)) {
399
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
400
    }
401
402
    // convert KEY
403
    $key = \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key);
404
405
    try {
406
        if ($type === "encrypt") {
407
            $text = \Defuse\Crypto\Crypto::encrypt($message, $key);
408
        } elseif ($type === "decrypt") {
409
            $text = \Defuse\Crypto\Crypto::decrypt($message, $key);
410
        }
411
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
412
        $err = "an attack! either the wrong key was loaded, or the ciphertext has changed since it was created either corrupted in the database or intentionally modified by someone trying to carry out an attack.";
413
    } catch (Defuse\Crypto\Exception\BadFormatException $ex) {
414
        $err = $ex;
415
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
416
        $err = $ex;
417
    } catch (Defuse\Crypto\Exception\CryptoException $ex) {
418
        $err = $ex;
419
    } catch (Defuse\Crypto\Exception\IOException $ex) {
420
        $err = $ex;
421
    }
422
423
    return array(
424
        'string' => isset($text) ? $text : "",
425
        'error' => $err
426
    );
427
}
428
429
function defuse_generate_key()
430
{
431
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
432
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
433
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
434
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
435
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
436
    require_once '../includes/libraries/Encryption/Encryption/File.php';
437
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
438
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
439
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
440
441
    $key = \Defuse\Crypto\Key::createNewRandomKey();
442
    $key = $key->saveToAsciiSafeString();
443
    return $key;
444
}
445
446
function defuse_generate_personal_key($psk)
447
{
448
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
449
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
450
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
451
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
452
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
453
    require_once '../includes/libraries/Encryption/Encryption/File.php';
454
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
455
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
456
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
457
458
    $protected_key = \Defuse\Crypto\KeyProtectedByPassword::createRandomPasswordProtectedKey($psk);
459
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
460
461
    return $protected_key_encoded; // save this in user table
462
}
463
464
/**
465
 * @param string $psk
466
 */
467
function defuse_validate_personal_key($psk, $protected_key_encoded)
468
{
469
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
470
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
471
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
472
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
473
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
474
    require_once '../includes/libraries/Encryption/Encryption/File.php';
475
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
476
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
477
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
478
479
    try {
480
        $protected_key = \Defuse\Crypto\KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
481
        $user_key = $protected_key->unlockKey($psk);
482
        $user_key_encoded = $user_key->saveToAsciiSafeString();
483
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
484
        return "Error - Major issue as the encryption is broken.";
485
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
486
        return "Error - The saltkey is not the correct one.";
487
    }
488
489
    return $user_key_encoded; // store it in session once user has entered his psk
490
}
491
492
/**
493
 * Decrypt a defuse string if encrypted
494
 * @param  [type] $value Encrypted string
495
 * @return [type]        Decrypted string
496
 */
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
497
function defuse_return_decrypted($value)
498
{
499
    if (substr($value, 0, 3) === "def") {
500
        $value = cryption($value, "", "decrypt")['string'];
501
    }
502
    return $value;
503
}
504
505
/**
506
 * trimElement()
507
 *
508
 * trim a string depending on a specific string
509
 * @param string $element
510
 * @return string
511
 */
512
function trimElement($chaine, $element)
513
{
514
    if (!empty($chaine)) {
515
        if (is_array($chaine) === true) {
516
            $chaine = implode(";", $chaine);
517
        }
518
        $chaine = trim($chaine);
519
        if (substr($chaine, 0, 1) == $element) {
520
            $chaine = substr($chaine, 1);
521
        }
522
        if (substr($chaine, strlen($chaine) - 1, 1) == $element) {
523
            $chaine = substr($chaine, 0, strlen($chaine) - 1);
524
        }
525
    }
526
    return $chaine;
527
}
528
529
/**
530
 * cleanString()
531
 *
532
 * permits to suppress all "special" characters from string
533
 */
534
function cleanString($string, $special = false)
535
{
536
    // Create temporary table for special characters escape
537
    $tabSpecialChar = array();
538
    for ($i = 0; $i <= 31; $i++) {
539
        $tabSpecialChar[] = chr($i);
540
    }
541
    array_push($tabSpecialChar, "<br />");
542
    if ($special == "1") {
543
        $tabSpecialChar = array_merge($tabSpecialChar, array("</li>", "<ul>", "<ol>"));
544
    }
545
546
    return str_replace($tabSpecialChar, "\n", $string);
547
}
548
549
function db_error_handler($params)
550
{
551
    echo "Error: ".$params['error']."<br>\n";
552
    echo "Query: ".$params['query']."<br>\n";
553
    throw new Exception("Error - Query", 1);
554
}
555
556
/**
557
 * [identifyUserRights description]
558
 * @param  string $groupesVisiblesUser  [description]
559
 * @param  string $groupesInterditsUser [description]
560
 * @param  string $isAdmin              [description]
561
 * @param  string $idFonctions          [description]
562
 * @return string                       [description]
563
 */
564
function identifyUserRights($groupesVisiblesUser, $groupesInterditsUser, $isAdmin, $idFonctions)
565
{
566
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

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

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
568
569
    //load ClassLoader
570
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
571
572
    //Connect to DB
573
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
574
    $pass = defuse_return_decrypted($pass);
575
    DB::$host = $server;
576
    DB::$user = $user;
577
    DB::$password = $pass;
578
    DB::$dbName = $database;
579
    DB::$port = $port;
580
    DB::$encoding = $encoding;
581
    DB::$error_handler = true;
582
    $link = mysqli_connect($server, $user, $pass, $database, $port);
583
    $link->set_charset($encoding);
584
585
    //Build tree
586
    $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'].'/includes/libraries');
587
    $tree->register();
588
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
589
590
    // Check if user is ADMINISTRATOR
591
    if ($isAdmin === '1') {
592
        $groupesVisibles = array();
593
        $_SESSION['personal_folders'] = array();
594
        $_SESSION['groupes_visibles'] = array();
595
        $_SESSION['groupes_interdits'] = array();
596
        $_SESSION['personal_visible_groups'] = array();
597
        $_SESSION['read_only_folders'] = array();
598
        $_SESSION['list_restricted_folders_for_items'] = array();
599
        $_SESSION['list_folders_editable_by_role'] = array();
600
        $_SESSION['list_folders_limited'] = array();
601
        $_SESSION['no_access_folders'] = array();
602
        $_SESSION['groupes_visibles_list'] = "";
603
        $rows = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i", 0);
604
        foreach ($rows as $record) {
605
            array_push($groupesVisibles, $record['id']);
606
        }
607
        $_SESSION['groupes_visibles'] = $groupesVisibles;
608
        $_SESSION['all_non_personal_folders'] = $groupesVisibles;
609
        // Exclude all PF
610
        $_SESSION['forbiden_pfs'] = array();
611
        $where = new WhereClause('and'); // create a WHERE statement of pieces joined by ANDs
612
        $where->add('personal_folder=%i', 1);
613
        if (isset($SETTINGS['enable_pf_feature']) && $SETTINGS['enable_pf_feature'] == 1) {
614
            $where->add('title=%s', $_SESSION['user_id']);
615
            $where->negateLast();
616
        }
617
        // Get ID of personal folder
618
        $persfld = DB::queryfirstrow(
619
            "SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s",
620
            $_SESSION['user_id']
621
        );
622
        if (!empty($persfld['id'])) {
623
            if (!in_array($persfld['id'], $_SESSION['groupes_visibles'])) {
624
                array_push($_SESSION['groupes_visibles'], $persfld['id']);
625
                array_push($_SESSION['personal_visible_groups'], $persfld['id']);
626
                // get all descendants
627
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
628
                $tree->rebuild();
629
                $tst = $tree->getDescendants($persfld['id']);
630
                foreach ($tst as $t) {
631
                    array_push($_SESSION['groupes_visibles'], $t->id);
632
                    array_push($_SESSION['personal_visible_groups'], $t->id);
633
                }
634
            }
635
        }
636
637
        // get complete list of ROLES
638
        $tmp = explode(";", $idFonctions);
639
        $rows = DB::query(
640
            "SELECT * FROM ".prefix_table("roles_title")."
641
            ORDER BY title ASC"
642
        );
643
        foreach ($rows as $record) {
644
            if (!empty($record['id']) && !in_array($record['id'], $tmp)) {
645
                array_push($tmp, $record['id']);
646
            }
647
        }
648
        $_SESSION['fonction_id'] = implode(";", $tmp);
649
650
        $_SESSION['groupes_visibles_list'] = implode(',', $_SESSION['groupes_visibles']);
651
        $_SESSION['is_admin'] = $isAdmin;
652
        // Check if admin has created Folders and Roles
653
        DB::query("SELECT * FROM ".prefix_table("nested_tree")."");
654
        $_SESSION['nb_folders'] = DB::count();
655
        DB::query("SELECT * FROM ".prefix_table("roles_title"));
656
        $_SESSION['nb_roles'] = DB::count();
657
    } else {
658
        // init
659
        $_SESSION['groupes_visibles'] = array();
660
        $_SESSION['personal_folders'] = array();
661
        $_SESSION['groupes_interdits'] = array();
662
        $_SESSION['personal_visible_groups'] = array();
663
        $_SESSION['read_only_folders'] = array();
664
        $_SESSION['fonction_id'] = $idFonctions;
665
        $groupesInterdits = array();
666
        if (is_array($groupesInterditsUser) === false) {
0 ignored issues
show
introduced by
The condition is_array($groupesInterditsUser) === false is always true.
Loading history...
667
            $groupesInterditsUser = explode(';', trimElement($groupesInterditsUser, ";"));
668
        }
669
        if (!empty($groupesInterditsUser) && count($groupesInterditsUser) > 0) {
670
            $groupesInterdits = $groupesInterditsUser;
671
        }
672
        $_SESSION['is_admin'] = $isAdmin;
673
        $fonctionsAssociees = explode(';', trimElement($idFonctions, ";"));
674
675
        $listAllowedFolders = $listFoldersLimited = $listFoldersEditableByRole = $listRestrictedFoldersForItems = $listReadOnlyFolders = array();
676
677
        // rechercher tous les groupes visibles en fonction des roles de l'utilisateur
678
        foreach ($fonctionsAssociees as $roleId) {
679
            if (empty($roleId) === false) {
680
                // Get allowed folders for each Role
681
                $rows = DB::query(
682
                    "SELECT folder_id FROM ".prefix_table("roles_values")." WHERE role_id=%i",
683
                    $roleId
684
                );
685
686
                if (DB::count() > 0) {
687
                    $tmp = DB::queryfirstrow(
688
                        "SELECT allow_pw_change FROM ".prefix_table("roles_title")." WHERE id = %i",
689
                        $roleId
690
                    );
691
                    foreach ($rows as $record) {
692
                        if (isset($record['folder_id']) && in_array($record['folder_id'], $listAllowedFolders) === false) {
693
                            array_push($listAllowedFolders, $record['folder_id']);
694
                        }
695
                        // Check if this group is allowed to modify any pw in allowed folders
696
                        if ($tmp['allow_pw_change'] == 1 && in_array($record['folder_id'], $listFoldersEditableByRole) === false) {
697
                            array_push($listFoldersEditableByRole, $record['folder_id']);
698
                        }
699
                    }
700
                    // Check for the users roles if some specific rights exist on items
701
                    $rows = DB::query(
702
                        "SELECT i.id_tree, r.item_id
703
                        FROM ".prefix_table("items")." as i
704
                        INNER JOIN ".prefix_table("restriction_to_roles")." as r ON (r.item_id=i.id)
705
                        WHERE r.role_id=%i
706
                        ORDER BY i.id_tree ASC",
707
                        $roleId
708
                    );
709
                    $inc = 0;
710
                    foreach ($rows as $record) {
711
                        if (isset($record['id_tree'])) {
712
                            $listFoldersLimited[$record['id_tree']][$inc] = $record['item_id'];
713
                            $inc++;
714
                        }
715
                    }
716
                }
717
            }
718
        }
719
720
        // Does this user is allowed to see other items
721
        $inc = 0;
722
        $rows = DB::query(
723
            "SELECT id, id_tree FROM ".prefix_table("items")."
724
            WHERE restricted_to LIKE %ss AND inactif=%s",
725
            $_SESSION['user_id'].';',
726
            '0'
727
        );
728
        foreach ($rows as $record) {
729
            $listRestrictedFoldersForItems[$record['id_tree']][$inc] = $record['id'];
730
            $inc++;
731
        }
732
        // => Build final lists
733
        // Clean arrays
734
        $listAllowedFolders = array_unique($listAllowedFolders);
735
        $groupesVisiblesUser = explode(';', trimElement($groupesVisiblesUser, ";"));
736
        // Add user allowed folders
737
        $allowedFoldersTmp = array_unique(
738
            array_merge($listAllowedFolders, $groupesVisiblesUser)
739
        );
740
        // Exclude from allowed folders all the specific user forbidden folders
741
        $allowedFolders = array();
742
        foreach ($allowedFoldersTmp as $ident) {
743
            if (!in_array($ident, $groupesInterditsUser) && !empty($ident)) {
744
                array_push($allowedFolders, $ident);
745
            }
746
        }
747
748
        // Clean array
749
        $listAllowedFolders = array_filter(array_unique($allowedFolders));
750
751
        // Exclude all PF
752
        $_SESSION['forbiden_pfs'] = array();
753
754
        $where = new WhereClause('and');
755
        $where->add('personal_folder=%i', 1);
756
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
757
            && isset($_SESSION['personal_folder']) === true && $_SESSION['personal_folder'] === '1'
758
        ) {
759
            $where->add('title=%s', $_SESSION['user_id']);
760
            $where->negateLast();
761
        }
762
763
        $persoFlds = DB::query(
764
            "SELECT id
765
            FROM ".prefix_table("nested_tree")."
766
            WHERE %l",
767
            $where
768
        );
769
        foreach ($persoFlds as $persoFldId) {
770
            array_push($_SESSION['forbiden_pfs'], $persoFldId['id']);
771
        }
772
        // Get IDs of personal folders
773
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
774
            && isset($_SESSION['personal_folder']) === true &&  $_SESSION['personal_folder'] === '1'
775
        ) {
776
            $persoFld = DB::queryfirstrow(
777
                "SELECT id
778
                FROM ".prefix_table("nested_tree")."
779
                WHERE title = %s AND personal_folder = %i",
780
                $_SESSION['user_id'],
781
                1
782
            );
783
            if (empty($persoFld['id']) === false) {
784
                if (in_array($persoFld['id'], $listAllowedFolders) === false) {
785
                    array_push($_SESSION['personal_folders'], $persoFld['id']);
786
                    array_push($listAllowedFolders, $persoFld['id']);
787
                    array_push($_SESSION['personal_visible_groups'], $persoFld['id']);
788
                    // get all descendants
789
                    $ids = $tree->getChildren($persoFld['id']);
790
                    foreach ($ids as $ident) {
791
                        array_push($listAllowedFolders, $ident->id);
792
                        array_push($_SESSION['personal_visible_groups'], $ident->id);
793
                        array_push($_SESSION['personal_folders'], $ident->id);
794
                    }
795
                }
796
            }
797
            // get list of readonly folders when pf is disabled.
798
            $_SESSION['personal_folders'] = array_unique($_SESSION['personal_folders']);
799
            // rule - if one folder is set as W or N in one of the Role, then User has access as W
800
            foreach ($listAllowedFolders as $folderId) {
801
                if (in_array($folderId, array_unique(array_merge($listReadOnlyFolders, $_SESSION['personal_folders']))) === false) {
802
                    DB::query(
803
                        "SELECT *
804
                        FROM ".prefix_table("roles_values")."
805
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
806
                        $folderId,
807
                        $fonctionsAssociees,
808
                        array("W", "ND", "NE", "NDNE")
809
                    );
810
                    if (DB::count() === 0 && in_array($folderId, $groupesVisiblesUser) === false) {
811
                        array_push($listReadOnlyFolders, $folderId);
812
                    }
813
                }
814
            }
815
        } else {
816
            // get list of readonly folders when pf is disabled.
817
            // rule - if one folder is set as W in one of the Role, then User has access as W
818
            foreach ($listAllowedFolders as $folderId) {
819
                if (in_array($folderId, $listReadOnlyFolders) === false) {
820
                    DB::query(
821
                        "SELECT *
822
                        FROM ".prefix_table("roles_values")."
823
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
824
                        $folderId,
825
                        $fonctionsAssociees,
826
                        array("W", "ND", "NE", "NDNE")
827
                    );
828
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
829
                        array_push($listReadOnlyFolders, $folderId);
830
                    }
831
                }
832
            }
833
        }
834
835
        // check if change proposals on User's items
836
        if (isset($SETTINGS['enable_suggestion']) === true && $SETTINGS['enable_suggestion'] === '1') {
837
            DB::query(
838
                "SELECT *
839
                FROM ".prefix_table("items_change")." AS c
840
                LEFT JOIN ".prefix_table("log_items")." AS i ON (c.item_id = i.id_item)
841
                WHERE i.action = %s AND i.id_user = %i",
842
                "at_creation",
843
                $_SESSION['user_id']
844
            );
845
            $_SESSION['nb_item_change_proposals'] = DB::count();
846
        } else {
847
            $_SESSION['nb_item_change_proposals'] = 0;
848
        }
849
850
        $_SESSION['all_non_personal_folders'] = $listAllowedFolders;
851
        $_SESSION['groupes_visibles'] = $listAllowedFolders;
852
        $_SESSION['groupes_visibles_list'] = implode(',', $listAllowedFolders);
853
        $_SESSION['personal_visible_groups_list'] = implode(',', $_SESSION['personal_visible_groups']);
854
        $_SESSION['read_only_folders'] = $listReadOnlyFolders;
855
        $_SESSION['no_access_folders'] = $groupesInterdits;
856
857
        $_SESSION['list_folders_limited'] = $listFoldersLimited;
858
        $_SESSION['list_folders_editable_by_role'] = $listFoldersEditableByRole;
859
        $_SESSION['list_restricted_folders_for_items'] = $listRestrictedFoldersForItems;
860
        // Folders and Roles numbers
861
        DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")."");
862
        $_SESSION['nb_folders'] = DB::count();
863
        DB::queryfirstrow("SELECT id FROM ".prefix_table("roles_title"));
864
        $_SESSION['nb_roles'] = DB::count();
865
    }
866
867
    // update user's timestamp
868
    DB::update(
869
        prefix_table('users'),
870
        array(
871
            'timestamp' => time()
872
        ),
873
        "id=%i",
874
        $_SESSION['user_id']
875
    );
876
}
877
878
/**
879
 * updateCacheTable()
880
 *
881
 * Update the CACHE table
882
 * @param string $action
883
 */
884
function updateCacheTable($action, $ident = "")
885
{
886
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

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

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
888
889
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
890
891
    //Connect to DB
892
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
893
    $pass = defuse_return_decrypted($pass);
894
    DB::$host = $server;
895
    DB::$user = $user;
896
    DB::$password = $pass;
897
    DB::$dbName = $database;
898
    DB::$port = $port;
899
    DB::$encoding = $encoding;
900
    DB::$error_handler = true;
901
    $link = mysqli_connect($server, $user, $pass, $database, $port);
902
    $link->set_charset($encoding);
903
904
    //Load Tree
905
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
906
    $tree->register();
907
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
908
909
    // Rebuild full cache table
910
    if ($action === "reload") {
911
        // truncate table
912
        DB::query("TRUNCATE TABLE ".prefix_table("cache"));
913
914
        // reload date
915
        $rows = DB::query(
916
            "SELECT *
917
            FROM ".prefix_table('items')." as i
918
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
919
            AND l.action = %s
920
            AND i.inactif = %i",
921
            'at_creation',
922
            0
923
        );
924
        foreach ($rows as $record) {
925
            if (empty($record['id_tree']) === false) {
926
                // Get all TAGS
927
                $tags = "";
928
                $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $record['id']);
929
                foreach ($itemTags as $itemTag) {
930
                    if (!empty($itemTag['tag'])) {
931
                        $tags .= $itemTag['tag']." ";
932
                    }
933
                }
934
                // Get renewal period
935
                $resNT = DB::queryfirstrow("SELECT renewal_period FROM ".prefix_table('nested_tree')." WHERE id=%i", $record['id_tree']);
936
937
                // form id_tree to full foldername
938
                $folder = "";
939
                $arbo = $tree->getPath($record['id_tree'], true);
940
                foreach ($arbo as $elem) {
941
                    if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
942
                        $elem->title = $_SESSION['login'];
943
                    }
944
                    if (empty($folder)) {
945
                        $folder = stripslashes($elem->title);
946
                    } else {
947
                        $folder .= " » ".stripslashes($elem->title);
948
                    }
949
                }
950
                // store data
951
                DB::insert(
952
                    prefix_table('cache'),
953
                    array(
954
                        'id' => $record['id'],
955
                        'label' => $record['label'],
956
                        'description' => isset($record['description']) ? $record['description'] : "",
957
                        'url' => (isset($record['url']) && !empty($record['url'])) ? $record['url'] : "0",
958
                        'tags' => $tags,
959
                        'id_tree' => $record['id_tree'],
960
                        'perso' => $record['perso'],
961
                        'restricted_to' => (isset($record['restricted_to']) && !empty($record['restricted_to'])) ? $record['restricted_to'] : "0",
962
                        'login' => isset($record['login']) ? $record['login'] : "",
963
                        'folder' => $folder,
964
                        'author' => $record['id_user'],
965
                        'renewal_period' => isset($resNT['renewal_period']) ? $resNT['renewal_period'] : "0",
966
                        'timestamp' => $record['date']
967
                        )
968
                );
969
            }
970
        }
971
        // UPDATE an item
972
    } elseif ($action === "update_value") {
973
        // get new value from db
974
        $data = DB::queryfirstrow(
975
            "SELECT label, description, id_tree, perso, restricted_to, login, url
976
            FROM ".prefix_table('items')."
977
            WHERE id=%i",
978
            $ident
979
        );
980
        // Get all TAGS
981
        $tags = "";
982
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $ident);
983
        foreach ($itemTags as $itemTag) {
984
            if (!empty($itemTag['tag'])) {
985
                $tags .= $itemTag['tag']." ";
986
            }
987
        }
988
        // form id_tree to full foldername
989
        $folder = "";
990
        $arbo = $tree->getPath($data['id_tree'], true);
991
        foreach ($arbo as $elem) {
992
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
993
                $elem->title = $_SESSION['login'];
994
            }
995
            if (empty($folder)) {
996
                $folder = stripslashes($elem->title);
997
            } else {
998
                $folder .= " » ".stripslashes($elem->title);
999
            }
1000
        }
1001
        // finaly update
1002
        DB::update(
1003
            prefix_table('cache'),
1004
            array(
1005
                'label' => $data['label'],
1006
                'description' => $data['description'],
1007
                'tags' => $tags,
1008
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1009
                'id_tree' => $data['id_tree'],
1010
                'perso' => $data['perso'],
1011
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1012
                'login' => isset($data['login']) ? $data['login'] : "",
1013
                'folder' => $folder,
1014
                'author' => $_SESSION['user_id'],
1015
                ),
1016
            "id = %i",
1017
            $ident
1018
        );
1019
        // ADD an item
1020
    } elseif ($action === "add_value") {
1021
        // get new value from db
1022
        $data = DB::queryFirstRow(
1023
            "SELECT i.label, i.description, i.id_tree as id_tree, i.perso, i.restricted_to, i.id, i.login, i.url, l.date
1024
            FROM ".prefix_table('items')." as i
1025
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
1026
            WHERE i.id = %i
1027
            AND l.action = %s",
1028
            $ident,
1029
            'at_creation'
1030
        );
1031
        // Get all TAGS
1032
        $tags = "";
1033
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id = %i", $ident);
1034
        foreach ($itemTags as $itemTag) {
1035
            if (!empty($itemTag['tag'])) {
1036
                $tags .= $itemTag['tag']." ";
1037
            }
1038
        }
1039
        // form id_tree to full foldername
1040
        $folder = "";
1041
        $arbo = $tree->getPath($data['id_tree'], true);
1042
        foreach ($arbo as $elem) {
1043
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1044
                $elem->title = $_SESSION['login'];
1045
            }
1046
            if (empty($folder)) {
1047
                $folder = stripslashes($elem->title);
1048
            } else {
1049
                $folder .= " » ".stripslashes($elem->title);
1050
            }
1051
        }
1052
        // finaly update
1053
        DB::insert(
1054
            prefix_table('cache'),
1055
            array(
1056
                'id' => $data['id'],
1057
                'label' => $data['label'],
1058
                'description' => $data['description'],
1059
                'tags' => (isset($tags) && !empty($tags)) ? $tags : "None",
0 ignored issues
show
introduced by
The condition empty($tags) is always true.
Loading history...
1060
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1061
                'id_tree' => $data['id_tree'],
1062
                'perso' => (isset($data['perso']) && !empty($data['perso']) && $data['perso'] !== "None") ? $data['perso'] : "0",
1063
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1064
                'login' => isset($data['login']) ? $data['login'] : "",
1065
                'folder' => $folder,
1066
                'author' => $_SESSION['user_id'],
1067
                'timestamp' => $data['date']
1068
            )
1069
        );
1070
1071
        // DELETE an item
1072
    } elseif ($action === "delete_value") {
1073
        DB::delete(prefix_table('cache'), "id = %i", $ident);
1074
    }
1075
}
1076
1077
/*
1078
*
1079
*/
1080
function getStatisticsData()
1081
{
1082
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1083
1084
    DB::query(
1085
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1086
        0
1087
    );
1088
    $counter_folders = DB::count();
1089
1090
    DB::query(
1091
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1092
        1
1093
    );
1094
    $counter_folders_perso = DB::count();
1095
1096
    DB::query(
1097
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1098
        0
1099
    );
1100
    $counter_items = DB::count();
1101
1102
    DB::query(
1103
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1104
        1
1105
    );
1106
    $counter_items_perso = DB::count();
1107
1108
    DB::query(
1109
        "SELECT id FROM ".prefix_table("users").""
1110
    );
1111
    $counter_users = DB::count();
1112
1113
    DB::query(
1114
        "SELECT id FROM ".prefix_table("users")." WHERE admin = %i",
1115
        1
1116
    );
1117
    $admins = DB::count();
1118
1119
    DB::query(
1120
        "SELECT id FROM ".prefix_table("users")." WHERE gestionnaire = %i",
1121
        1
1122
    );
1123
    $managers = DB::count();
1124
1125
    DB::query(
1126
        "SELECT id FROM ".prefix_table("users")." WHERE read_only = %i",
1127
        1
1128
    );
1129
    $readOnly = DB::count();
1130
1131
    // list the languages
1132
    $usedLang = [];
1133
    $tp_languages = DB::query(
1134
        "SELECT name FROM ".prefix_table("languages")
1135
    );
1136
    foreach ($tp_languages as $tp_language) {
1137
        DB::query(
1138
            "SELECT * FROM ".prefix_table("users")." WHERE user_language = %s",
1139
            $tp_language['name']
1140
        );
1141
        $usedLang[$tp_language['name']] = round((DB::count() * 100 / $counter_users), 0);
1142
    }
1143
1144
    // get list of ips
1145
    $usedIp = [];
1146
    $tp_ips = DB::query(
1147
        "SELECT user_ip FROM ".prefix_table("users")
1148
    );
1149
    foreach ($tp_ips as $ip) {
1150
        if (array_key_exists($ip['user_ip'], $usedIp)) {
1151
            $usedIp[$ip['user_ip']] = $usedIp[$ip['user_ip']] + 1;
1152
        } elseif (!empty($ip['user_ip']) && $ip['user_ip'] !== "none") {
1153
            $usedIp[$ip['user_ip']] = 1;
1154
        }
1155
    }
1156
1157
    return array(
1158
        "error" => "",
1159
        "stat_phpversion" => phpversion(),
1160
        "stat_folders" => $counter_folders,
1161
        "stat_folders_shared" => intval($counter_folders) - intval($counter_folders_perso),
1162
        "stat_items" => $counter_items,
1163
        "stat_items_shared" => intval($counter_items) - intval($counter_items_perso),
1164
        "stat_users" => $counter_users,
1165
        "stat_admins" => $admins,
1166
        "stat_managers" => $managers,
1167
        "stat_ro" => $readOnly,
1168
        "stat_kb" => $SETTINGS['enable_kb'],
1169
        "stat_pf" => $SETTINGS['enable_pf_feature'],
1170
        "stat_fav" => $SETTINGS['enable_favourites'],
1171
        "stat_teampassversion" => $SETTINGS['cpassman_version'],
1172
        "stat_ldap" => $SETTINGS['ldap_mode'],
1173
        "stat_agses" => $SETTINGS['agses_authentication_enabled'],
1174
        "stat_duo" => $SETTINGS['duo'],
1175
        "stat_suggestion" => $SETTINGS['enable_suggestion'],
1176
        "stat_api" => $SETTINGS['api'],
1177
        "stat_customfields" => $SETTINGS['item_extra_fields'],
1178
        "stat_syslog" => $SETTINGS['syslog_enable'],
1179
        "stat_2fa" => $SETTINGS['google_authentication'],
1180
        "stat_stricthttps" => $SETTINGS['enable_sts'],
1181
        "stat_mysqlversion" => DB::serverVersion(),
1182
        "stat_languages" => $usedLang,
1183
        "stat_country" => $usedIp
1184
    );
1185
}
1186
1187
/**
1188
 * sendEmail()
1189
 *
1190
 * @return
1191
 */
1192
function sendEmail($subject, $textMail, $email, $textMailAlt = "")
1193
{
1194
    global $LANG;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

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

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1196
1197
    // CAse where email not defined
1198
    if ($email === "none") {
1199
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1200
    }
1201
1202
    // Load settings
1203
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
1204
1205
    // Load superglobal
1206
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1207
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
1208
1209
    // Get user language
1210
    $session_user_language = $superGlobal->get("user_language", "SESSION");
1211
1212
    // Load library
1213
    $user_language = isset($session_user_language) ? $session_user_language : "english";
1214
    require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$user_language.'.php';
1215
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Email/Phpmailer/PHPMailerAutoload.php';
1216
1217
    // load PHPMailer
1218
    $mail = new PHPMailer();
1219
1220
    // send to user
1221
    $mail->setLanguage("en", "../includes/libraries/Email/Phpmailer/language/");
1222
    $mail->SMTPDebug = 0; //value 1 can be used to debug - 4 for debuging connections
1223
    $mail->Port = $SETTINGS['email_port']; //COULD BE USED
1224
    $mail->CharSet = "utf-8";
1225
    if ($SETTINGS['email_security'] === "tls" || $SETTINGS['email_security'] === "ssl") {
1226
        $mail->SMTPSecure = $SETTINGS['email_security'];
1227
        $SMTPAutoTLS = true;
1228
    } else {
1229
        $SMTPAutoTLS = false;
1230
        $mail->SMTPSecure = "";
1231
    }
1232
    $mail->SMTPAutoTLS = $SMTPAutoTLS;
1233
    $mail->isSmtp(); // send via SMTP
1234
    $mail->Host = $SETTINGS['email_smtp_server']; // SMTP servers
1235
    $mail->SMTPAuth = $SETTINGS['email_smtp_auth'] == '1' ? true : false; // turn on SMTP authentication
1236
    $mail->Username = $SETTINGS['email_auth_username']; // SMTP username
1237
    $mail->Password = $SETTINGS['email_auth_pwd']; // SMTP password
1238
    $mail->From = $SETTINGS['email_from'];
1239
    $mail->FromName = $SETTINGS['email_from_name'];
1240
1241
    // Prepare for each person
1242
    $dests = explode(",", $email);
1243
    foreach ($dests as $dest) {
1244
        $mail->addAddress($dest);
1245
    }
1246
1247
    $mail->WordWrap = 80; // set word wrap
1248
    $mail->isHtml(true); // send as HTML
1249
    $mail->Subject = $subject;
1250
    $mail->Body = $textMail;
1251
    $mail->AltBody = $textMailAlt;
1252
    // send email
1253
    if (!$mail->send()) {
1254
        return '"error":"error_mail_not_send" , "message":"'.str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo).'"';
1255
    } else {
1256
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1257
    }
1258
}
1259
1260
/**
1261
 * generateKey()
1262
 *
1263
 * @return
1264
 */
1265
function generateKey()
1266
{
1267
    return substr(md5(rand().rand()), 0, 15);
1268
}
1269
1270
/**
1271
 * dateToStamp()
1272
 *
1273
 * @return
1274
 */
1275
function dateToStamp($date)
1276
{
1277
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1278
1279
    $date = date_parse_from_format($SETTINGS['date_format'], $date);
1280
    if ($date['warning_count'] == 0 && $date['error_count'] == 0) {
1281
        return mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
1282
    } else {
1283
        return false;
1284
    }
1285
}
1286
1287
function isDate($date)
1288
{
1289
    return (strtotime($date) !== false);
1290
}
1291
1292
/**
1293
 * isUTF8()
1294
 *
1295
 * @return integer is the string in UTF8 format.
1296
 */
1297
1298
function isUTF8($string)
1299
{
1300
    if (is_array($string) === true) {
1301
        $string = $string['string'];
1302
    }
1303
    return preg_match(
1304
        '%^(?:
1305
        [\x09\x0A\x0D\x20-\x7E] # ASCII
1306
        | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
1307
        | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
1308
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
1309
        | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
1310
        | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
1311
        | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
1312
        | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
1313
        )*$%xs',
1314
        $string
1315
    );
1316
}
1317
1318
/*
1319
* FUNCTION
1320
* permits to prepare data to be exchanged
1321
*/
1322
/**
1323
 * @param string $type
1324
 */
1325
function prepareExchangedData($data, $type)
1326
{
1327
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1328
1329
    //load ClassLoader
1330
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1331
    //Load AES
1332
    $aes = new SplClassLoader('Encryption\Crypt', $SETTINGS['cpassman_dir'].'/includes/libraries');
1333
    $aes->register();
1334
1335
    if ($type == "encode") {
1336
        if (isset($SETTINGS['encryptClientServer'])
1337
            && $SETTINGS['encryptClientServer'] === "0"
1338
        ) {
1339
            return json_encode(
1340
                $data,
1341
                JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1342
            );
1343
        } else {
1344
            return Encryption\Crypt\aesctr::encrypt(
1345
                json_encode(
1346
                    $data,
1347
                    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1348
                ),
1349
                $_SESSION['key'],
1350
                256
1351
            );
1352
        }
1353
    } elseif ($type == "decode") {
1354
        if (isset($SETTINGS['encryptClientServer'])
1355
            && $SETTINGS['encryptClientServer'] === "0"
1356
        ) {
1357
            return json_decode(
1358
                $data,
1359
                true
1360
            );
1361
        } else {
1362
            return json_decode(
1363
                Encryption\Crypt\aesctr::decrypt(
1364
                    $data,
1365
                    $_SESSION['key'],
1366
                    256
1367
                ),
1368
                true
1369
            );
1370
        }
1371
    }
1372
}
1373
1374
function make_thumb($src, $dest, $desired_width)
1375
{
1376
    /* read the source image */
1377
    $source_image = imagecreatefrompng($src);
1378
    $width = imagesx($source_image);
1379
    $height = imagesy($source_image);
1380
1381
    /* find the "desired height" of this thumbnail, relative to the desired width  */
1382
    $desired_height = floor($height * ($desired_width / $width));
1383
1384
    /* create a new, "virtual" image */
1385
    $virtual_image = imagecreatetruecolor($desired_width, $desired_height);
0 ignored issues
show
Bug introduced by
$desired_height of type double is incompatible with the type integer expected by parameter $height of imagecreatetruecolor(). ( Ignorable by Annotation )

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

1385
    $virtual_image = imagecreatetruecolor($desired_width, /** @scrutinizer ignore-type */ $desired_height);
Loading history...
1386
1387
    /* copy source image at a resized size */
1388
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
0 ignored issues
show
Bug introduced by
$desired_height of type double is incompatible with the type integer expected by parameter $dst_h of imagecopyresampled(). ( Ignorable by Annotation )

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

1388
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, /** @scrutinizer ignore-type */ $desired_height, $width, $height);
Loading history...
1389
1390
    /* create the physical thumbnail image to its destination */
1391
    imagejpeg($virtual_image, $dest);
1392
}
1393
1394
/*
1395
** check table prefix in SQL query
1396
*/
1397
/**
1398
 * @param string $table
1399
 */
1400
function prefix_table($table)
1401
{
1402
    global $pre;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1403
    $safeTable = htmlspecialchars($pre.$table);
1404
    if (!empty($safeTable)) {
1405
        // sanitize string
1406
        return $safeTable;
1407
    } else {
1408
        // stop error no table
1409
        return "table_not_exists";
1410
    }
1411
}
1412
1413
/*
1414
 * Creates a KEY using PasswordLib
1415
 */
1416
function GenerateCryptKey($size = "", $secure = false, $numerals = false, $capitalize = false, $symbols = false)
1417
{
1418
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1419
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1420
1421
    if ($secure === true) {
1422
        $numerals = true;
1423
        $capitalize = true;
1424
        $symbols = true;
1425
    }
1426
1427
    // Load libraries
1428
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
1429
    $generator->register();
1430
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
1431
1432
    // Can we use PHP7 random_int function?
1433
    if (version_compare(phpversion(), '7.0', '>=')) {
1434
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/PasswordGenerator/RandomGenerator/Php7RandomGenerator.php';
1435
         $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
1436
    }
1437
1438
    // init
1439
    if (!empty($size)) {
1440
        $generator->setLength(intval($size));
1441
    }
1442
    if (!empty($numerals)) {
1443
        $generator->setNumbers($numerals);
1444
    }
1445
    if (!empty($capitalize)) {
1446
        $generator->setUppercase($capitalize);
1447
    }
1448
    if (!empty($symbols)) {
1449
        $generator->setSymbols($symbols);
1450
    }
1451
1452
    // generate and send back
1453
    return $generator->generatePassword();
1454
}
1455
1456
/*
1457
* Send sysLOG message
1458
* @param string $message
1459
* @param string $host
1460
*/
1461
function send_syslog($message, $host, $port, $component = "teampass")
1462
{
1463
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
1464
    $syslog_message = "<123>".date('M d H:i:s ').$component.": ".$message;
1465
    socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $host, $port);
1466
    socket_close($sock);
1467
}
1468
1469
1470
1471
/**
1472
 * logEvents()
1473
 *
1474
 * permits to log events into DB
1475
 * @param string $type
1476
 * @param string $label
1477
 * @param string $field_1
1478
 */
1479
function logEvents($type, $label, $who, $login = "", $field_1 = null)
1480
{
1481
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

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

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1483
1484
    if (empty($who)) {
1485
        $who = get_client_ip_server();
1486
    }
1487
1488
    // include librairies & connect to DB
1489
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1490
    $pass = defuse_return_decrypted($pass);
1491
    DB::$host = $server;
1492
    DB::$user = $user;
1493
    DB::$password = $pass;
1494
    DB::$dbName = $database;
1495
    DB::$port = $port;
1496
    DB::$encoding = $encoding;
1497
    DB::$error_handler = true;
1498
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1499
    $link->set_charset($encoding);
1500
1501
    DB::insert(
1502
        prefix_table("log_system"),
1503
        array(
1504
            'type' => $type,
1505
            'date' => time(),
1506
            'label' => $label,
1507
            'qui' => $who,
1508
            'field_1' => $field_1 === null ? "" : $field_1
1509
        )
1510
    );
1511
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1512
        if ($type == "user_mngt") {
1513
            send_syslog(
1514
                "The User ".$login." performed the action of ".$label." to the user ".$field_1." - ".$type,
1515
                $SETTINGS['syslog_host'],
1516
                $SETTINGS['syslog_port'],
1517
                "teampass"
1518
            );
1519
        } else {
1520
            send_syslog(
1521
                "The User ".$login." performed the action of ".$label." - ".$type,
1522
                $SETTINGS['syslog_host'],
1523
                $SETTINGS['syslog_port'],
1524
                "teampass"
1525
            );
1526
        }
1527
    }
1528
}
1529
1530
/**
1531
 * @param string $item
1532
 * @param string $action
1533
 */
1534
function logItems($ident, $item, $id_user, $action, $login = "", $raison = null, $raison_iv = null, $encryption_type = "")
1535
{
1536
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

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

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1538
1539
    // include librairies & connect to DB
1540
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1541
    $pass = defuse_return_decrypted($pass);
1542
    DB::$host = $server;
1543
    DB::$user = $user;
1544
    DB::$password = $pass;
1545
    DB::$dbName = $database;
1546
    DB::$port = $port;
1547
    DB::$encoding = $encoding;
1548
    DB::$error_handler = true;
1549
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1550
    $link->set_charset($encoding);
1551
    DB::insert(
1552
        prefix_table("log_items"),
1553
        array(
1554
            'id_item' => $ident,
1555
            'date' => time(),
1556
            'id_user' => $id_user,
1557
            'action' => $action,
1558
            'raison' => $raison,
1559
            'raison_iv' => $raison_iv,
1560
            'encryption_type' => $encryption_type
1561
        )
1562
    );
1563
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1564
        send_syslog(
1565
            "The Item ".$item." was ".$action." by ".$login." ".$raison,
1566
            $SETTINGS['syslog_host'],
1567
            $SETTINGS['syslog_port'],
1568
            "teampass"
1569
        );
1570
    }
1571
}
1572
1573
/*
1574
* Function to get the client ip address
1575
 */
1576
function get_client_ip_server()
1577
{
1578
    if (getenv('HTTP_CLIENT_IP')) {
1579
            $ipaddress = getenv('HTTP_CLIENT_IP');
1580
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
1581
            $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
1582
    } elseif (getenv('HTTP_X_FORWARDED')) {
1583
            $ipaddress = getenv('HTTP_X_FORWARDED');
1584
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
1585
            $ipaddress = getenv('HTTP_FORWARDED_FOR');
1586
    } elseif (getenv('HTTP_FORWARDED')) {
1587
            $ipaddress = getenv('HTTP_FORWARDED');
1588
    } elseif (getenv('REMOTE_ADDR')) {
1589
            $ipaddress = getenv('REMOTE_ADDR');
1590
    } else {
1591
            $ipaddress = 'UNKNOWN';
1592
    }
1593
1594
    return $ipaddress;
1595
}
1596
1597
/**
1598
 * Escape all HTML, JavaScript, and CSS
1599
 *
1600
 * @param string $input The input string
1601
 * @param string $encoding Which character encoding are we using?
1602
 * @return string
1603
 */
1604
function noHTML($input, $encoding = 'UTF-8')
1605
{
1606
    return htmlspecialchars($input, ENT_QUOTES | ENT_XHTML, $encoding, false);
1607
}
1608
1609
/**
1610
 * handleConfigFile()
1611
 *
1612
 * permits to handle the Teampass config file
1613
 * $action accepts "rebuild" and "update"
1614
 */
1615
function handleConfigFile($action, $field = null, $value = null)
1616
{
1617
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

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

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1619
1620
    $tp_config_file = "../includes/config/tp.config.php";
1621
1622
    // include librairies & connect to DB
1623
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1624
    $pass = defuse_return_decrypted($pass);
1625
    DB::$host = $server;
1626
    DB::$user = $user;
1627
    DB::$password = $pass;
1628
    DB::$dbName = $database;
1629
    DB::$port = $port;
1630
    DB::$encoding = $encoding;
1631
    DB::$error_handler = true;
1632
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1633
    $link->set_charset($encoding);
1634
1635
    if (!file_exists($tp_config_file) || $action == "rebuild") {
1636
        // perform a copy
1637
        if (file_exists($tp_config_file)) {
1638
            if (!copy($tp_config_file, $tp_config_file.'.'.date("Y_m_d_His", time()))) {
1639
                return "ERROR: Could not copy file '".$tp_config_file."'";
1640
            }
1641
        }
1642
1643
        // regenerate
1644
        $data = array();
1645
        $data[0] = "<?php\n";
1646
        $data[1] = "global \$SETTINGS;\n";
1647
        $data[2] = "\$SETTINGS = array (\n";
1648
        $rows = DB::query(
1649
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s",
1650
            "admin"
1651
        );
1652
        foreach ($rows as $record) {
1653
            array_push($data, "    '".$record['intitule']."' => '".$record['valeur']."',\n");
1654
        }
1655
        array_push($data, ");\n");
1656
        $data = array_unique($data);
1657
    } elseif ($action == "update" && empty($field) === false) {
1658
        $data = file($tp_config_file);
1659
        $inc = 0;
1660
        $bFound = false;
1661
        foreach ($data as $line) {
1662
            if (stristr($line, ");")) {
1663
                break;
1664
            }
1665
1666
            //
1667
            if (stristr($line, "'".$field."' => '")) {
1668
                $data[$inc] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n";
1669
                $bFound = true;
1670
                break;
1671
            }
1672
            $inc++;
1673
        }
1674
        if ($bFound === false) {
1675
            $data[($inc)] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n);\n";
1676
        }
1677
    }
1678
1679
    // update file
1680
    file_put_contents($tp_config_file, implode('', isset($data) ? $data : array()));
1681
1682
    return true;
1683
}
1684
1685
/*
1686
** Permits to replace &#92; to permit correct display
1687
*/
1688
/**
1689
 * @param string $input
1690
 */
1691
function handleBackslash($input)
1692
{
1693
    return str_replace("&amp;#92;", "&#92;", $input);
1694
}
1695
1696
/*
1697
** Permits to loas settings
1698
*/
1699
function loadSettings()
1700
{
1701
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1702
1703
    /* LOAD CPASSMAN SETTINGS */
1704
    if (!isset($SETTINGS['loaded']) || $SETTINGS['loaded'] != 1) {
1705
        $SETTINGS['duplicate_folder'] = 0; //by default, this is set to 0;
1706
        $SETTINGS['duplicate_item'] = 0; //by default, this is set to 0;
1707
        $SETTINGS['number_of_used_pw'] = 5; //by default, this value is set to 5;
1708
        $settings = array();
1709
1710
        $rows = DB::query(
1711
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s_type OR type=%s_type2",
1712
            array(
1713
                'type' => "admin",
1714
                'type2' => "settings"
1715
            )
1716
        );
1717
        foreach ($rows as $record) {
1718
            if ($record['type'] == 'admin') {
1719
                $SETTINGS[$record['intitule']] = $record['valeur'];
1720
            } else {
1721
                $settings[$record['intitule']] = $record['valeur'];
1722
            }
1723
        }
1724
        $SETTINGS['loaded'] = 1;
1725
        $SETTINGS['default_session_expiration_time'] = 5;
1726
    }
1727
}
1728
1729
/*
1730
** check if folder has custom fields.
1731
** Ensure that target one also has same custom fields
1732
*/
1733
function checkCFconsistency($source_id, $target_id)
1734
{
1735
    $source_cf = array();
1736
    $rows = DB::QUERY(
1737
        "SELECT id_category
1738
        FROM ".prefix_table("categories_folders")."
1739
        WHERE id_folder = %i",
1740
        $source_id
1741
    );
1742
    foreach ($rows as $record) {
1743
        array_push($source_cf, $record['id_category']);
1744
    }
1745
1746
    $target_cf = array();
1747
    $rows = DB::QUERY(
1748
        "SELECT id_category
1749
        FROM ".prefix_table("categories_folders")."
1750
        WHERE id_folder = %i",
1751
        $target_id
1752
    );
1753
    foreach ($rows as $record) {
1754
        array_push($target_cf, $record['id_category']);
1755
    }
1756
1757
    $cf_diff = array_diff($source_cf, $target_cf);
1758
    if (count($cf_diff) > 0) {
1759
        return false;
1760
    }
1761
1762
    return true;
1763
}
1764
1765
/*
1766
*
1767
*/
1768
function encrypt_or_decrypt_file($filename_to_rework, $filename_status)
1769
{
1770
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

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

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1772
1773
    // Include librairies & connect to DB
1774
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1775
    $pass = defuse_return_decrypted($pass);
1776
    DB::$host = $server;
1777
    DB::$user = $user;
1778
    DB::$password = $pass;
1779
    DB::$dbName = $database;
1780
    DB::$port = $port;
1781
    DB::$encoding = $encoding;
1782
    DB::$error_handler = true;
1783
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1784
    $link->set_charset($encoding);
1785
1786
    // Get file info in DB
1787
    $fileInfo = DB::queryfirstrow(
1788
        "SELECT id FROM ".prefix_table("files")." WHERE file = %s",
1789
        filter_var($filename_to_rework, FILTER_SANITIZE_STRING)
1790
    );
1791
    if (empty($fileInfo['id']) === false) {
1792
        // Load PhpEncryption library
1793
        $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
1794
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
1795
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
1796
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
1797
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
1798
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
1799
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
1800
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
1801
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
1802
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
1803
1804
        // Get KEY
1805
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1806
1807
        if (isset($SETTINGS['enable_attachment_encryption'])
1808
            && $SETTINGS['enable_attachment_encryption'] === "1" &&
1809
            isset($filename_status)
1810
            && ($filename_status === "clear"
1811
                || $filename_status === "0")
1812
        ) {
1813
            // File needs to be encrypted
1814
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1815
                // Make a copy of file
1816
                if (!copy(
1817
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1818
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1819
                )) {
1820
                    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
1821
                } else {
1822
                    // Do a bck
1823
                    copy(
1824
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1825
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1826
                    );
1827
                }
1828
1829
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1830
1831
                // Now encrypt the file with saltkey
1832
                $err = '';
1833
                try {
1834
                    \Defuse\Crypto\File::encryptFile(
1835
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1836
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1837
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1838
                    );
1839
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1840
                    $err = "An attack! Either the wrong key was loaded, or the ciphertext has changed since it was created either corrupted in the database or intentionally modified by someone trying to carry out an attack.";
1841
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1842
                    $err = $ex;
1843
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1844
                    $err = $ex;
1845
                }
1846
                if (empty($err) === false) {
1847
                    echo $err;
1848
                }
1849
1850
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1851
1852
                // update table
1853
                DB::update(
1854
                    prefix_table('files'),
1855
                    array(
1856
                        'status' => 'encrypted'
1857
                        ),
1858
                    "id = %i",
1859
                    $fileInfo['id']
1860
                );
1861
            }
1862
        } elseif (isset($SETTINGS['enable_attachment_encryption'])
1863
            && $SETTINGS['enable_attachment_encryption'] === "0"
1864
            && isset($filename_status)
1865
            && $filename_status === "encrypted"
1866
        ) {
1867
            // file needs to be decrypted
1868
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1869
                // make a copy of file
1870
                if (!copy(
1871
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1872
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1873
                )) {
1874
                    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
1875
                } else {
1876
                    // do a bck
1877
                    copy(
1878
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1879
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1880
                    );
1881
                }
1882
1883
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1884
1885
                // Now encrypt the file with saltkey
1886
                $err = '';
1887
                try {
1888
                    \Defuse\Crypto\File::decryptFile(
1889
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1890
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1891
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1892
                    );
1893
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1894
                    $err = "An attack! Either the wrong key was loaded, or the ciphertext has changed since it was created either corrupted in the database or intentionally modified by someone trying to carry out an attack.";
1895
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1896
                    $err = $ex;
1897
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1898
                    $err = $ex;
1899
                }
1900
                if (empty($err) === false) {
1901
                    echo $err;
1902
                }
1903
1904
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1905
1906
                // update table
1907
                DB::update(
1908
                    prefix_table('files'),
1909
                    array(
1910
                        'status' => 'clear'
1911
                        ),
1912
                    "id = %i",
1913
                    $fileInfo['id']
1914
                );
1915
            }
1916
        }
1917
    }
1918
1919
    // Exit
1920
    return false;
1921
}
1922
1923
/**
1924
 * Will encrypte/decrypt a fil eusing Defuse
1925
 * @param  string $type        can be either encrypt or decrypt
1926
 * @param  string $source_file path to source file
1927
 * @param  string $target_file path to target file
1928
 * @return string              'true' is success or error message
1929
 */
1930
function prepareFileWithDefuse($type, $source_file, $target_file, $password = '')
1931
{
1932
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
1933
1934
    // Load AntiXSS
1935
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
1936
    $antiXss = new protect\AntiXSS\AntiXSS();
1937
1938
    // Protect against bad inputs
1939
    if (is_array($source_file) ||is_array($target_file)) {
0 ignored issues
show
introduced by
The condition is_array($target_file) is always false.
Loading history...
1940
        return 'error_cannot_be_array';
1941
    }
1942
1943
    // Sanitize
1944
    $source_file = $antiXss->xss_clean($source_file);
1945
    $target_file = $antiXss->xss_clean($target_file);
1946
1947
    // load PhpEncryption library
1948
    $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
1949
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
1950
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
1951
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
1952
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
1953
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
1954
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
1955
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
1956
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
1957
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
1958
1959
    if (empty($password) === true) {
1960
    /*
1961
    File encryption/decryption is done with the SALTKEY
1962
     */
1963
1964
        // get KEY
1965
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1966
1967
        // Now perform action on the file
1968
        $err = '';
1969
        if ($type === 'decrypt') {
1970
            try {
1971
                \Defuse\Crypto\File::decryptFile(
1972
                    $source_file,
1973
                    $target_file,
1974
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1975
                );
1976
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1977
                $err = "decryption_not_possible";
1978
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1979
                $err = $ex;
1980
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1981
                $err = $ex;
1982
            }
1983
        } elseif ($type === 'encrypt') {
1984
            try {
1985
                \Defuse\Crypto\File::encryptFile(
1986
                    $source_file,
1987
                    $target_file,
1988
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1989
                );
1990
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1991
                $err = "encryption_not_possible";
1992
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1993
                $err = $ex;
1994
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1995
                $err = $ex;
1996
            }
1997
        }
1998
    } else {
1999
    /*
2000
    File encryption/decryption is done with special password and not the SALTKEY
2001
     */
2002
2003
        $err = '';
2004
        if ($type === 'decrypt') {
2005
            try {
2006
                \Defuse\Crypto\File::decryptFileWithPassword(
2007
                    $source_file,
2008
                    $target_file,
2009
                    $password
2010
                );
2011
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2012
                $err = "wrong_key";
2013
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2014
                $err = $ex;
2015
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2016
                $err = $ex;
2017
            }
2018
        } elseif ($type === 'encrypt') {
2019
            try {
2020
                \Defuse\Crypto\File::encryptFileWithPassword(
2021
                    $source_file,
2022
                    $target_file,
2023
                    $password
2024
                );
2025
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2026
                $err = "wrong_key";
2027
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2028
                $err = $ex;
2029
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2030
                $err = $ex;
2031
            }
2032
        }
2033
    }
2034
2035
    // return error
2036
    if (empty($err) === false) {
2037
        return $err;
2038
    } else {
2039
        return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type string.
Loading history...
2040
    }
2041
}
2042
2043
/*
2044
* NOT TO BE USED
2045
*/
2046
function debugTeampass($text)
2047
{
2048
    $debugFile = fopen('D:/wamp64/www/TeamPass/debug.txt', 'r+');
2049
    fputs($debugFile, $text);
0 ignored issues
show
Bug introduced by
It seems like $debugFile can also be of type false; however, parameter $handle of fputs() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

2049
    fputs(/** @scrutinizer ignore-type */ $debugFile, $text);
Loading history...
2050
    fclose($debugFile);
0 ignored issues
show
Bug introduced by
It seems like $debugFile can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

2050
    fclose(/** @scrutinizer ignore-type */ $debugFile);
Loading history...
2051
}
2052
2053
2054
/**
2055
 * DELETE the file with expected command depending on server type
2056
 * @param  string $file Path to file
2057
 * @return              Nothing
0 ignored issues
show
Bug introduced by
The type Nothing was not found. Maybe you did not declare it correctly or list all dependencies?

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

filter:
    dependency_paths: ["lib/*"]

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

Loading history...
2058
 */
2059
function fileDelete($file)
2060
{
2061
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
2062
2063
    // Load AntiXSS
2064
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2065
    $antiXss = new protect\AntiXSS\AntiXSS();
2066
2067
    $file = $antiXss->xss_clean($file);
2068
    if (is_file($file)) {
2069
        unlink($file);
2070
    }
2071
}
2072
2073
/*
2074
* Permits to extract the file extension
2075
*/
2076
function getFileExtension($file)
2077
{
2078
    if (strpos($file, '.') === false) {
2079
        return $file;
2080
    }
2081
2082
    return substr($file, strrpos($file, '.') + 1);
2083
}
2084
2085
/**
2086
 * array_map
2087
 * @param  [type] $func [description]
2088
 * @param  [type] $arr  [description]
2089
 * @return [type]       [description]
2090
 */
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
2091
function array_map_r($func, $arr)
2092
{
2093
    $newArr = array();
2094
2095
    foreach ($arr as $key => $value) {
2096
        $newArr[ $key ] = (is_array($value) ? array_map_r($func, $value) : ( is_array($func) ? call_user_func_array($func, $value) : $func( $value )));
2097
    }
2098
2099
    return $newArr;
2100
}
2101
2102
/**
2103
 * Permits to clean and sanitize text to be displayed
2104
 * @param  string $text text to clean
2105
 * @param  string $type what clean to perform
2106
 * @return string       text cleaned up
2107
 */
2108
function cleanText($string, $type = "")
2109
{
2110
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
2111
2112
    // Load AntiXSS
2113
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2114
    $antiXss = new protect\AntiXSS\AntiXSS();
2115
2116
    if ($type === "css") {
2117
        // Escape text and quotes in UTF8 format
2118
        return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
2119
    } elseif ($type === "html" || empty($type)) {
2120
        // Html cleaner
2121
        return $antiXss->xss_clean($string);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $antiXss->xss_clean($string) also could return the type array which is incompatible with the documented return type string.
Loading history...
2122
    }
2123
}
2124
2125
/**
2126
 * Performs chmod operation on subfolders
2127
 * @param  string  $dir             Parent folder
2128
 * @param  integer $dirPermissions  New permission on folders
2129
 * @param  integer $filePermissions New permission on files
2130
 * @return boolean                  Success/Failure
2131
 */
2132
function chmodRecursive($dir, $dirPermissions, $filePermissions)
2133
{
2134
    $pointer_dir = opendir($dir);
2135
    $res = true;
2136
    while ($file = readdir($pointer_dir)) {
0 ignored issues
show
Bug introduced by
It seems like $pointer_dir can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

2136
    while ($file = readdir(/** @scrutinizer ignore-type */ $pointer_dir)) {
Loading history...
2137
        if (($file == ".") || ($file == "..")) {
2138
            continue;
2139
        }
2140
2141
        $fullPath = $dir."/".$file;
2142
2143
        if (is_dir($fullPath)) {
2144
            if ($res = @chmod($fullPath, $dirPermissions)) {
2145
                $res = @chmodRecursive($fullPath, $dirPermissions, $filePermissions);
2146
            }
2147
        } else {
2148
            $res = chmod($fullPath, $filePermissions);
2149
        }
2150
        if (!$res) {
2151
            closedir($pointer_dir);
0 ignored issues
show
Bug introduced by
It seems like $pointer_dir can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

2151
            closedir(/** @scrutinizer ignore-type */ $pointer_dir);
Loading history...
2152
            return false;
2153
        }
2154
    }
2155
    closedir($pointer_dir);
2156
    if (is_dir($dir) && $res) {
2157
        $res = @chmod($dir, $dirPermissions);
2158
    }
2159
2160
    return $res;
2161
}
2162
2163
/**
2164
 * Check if user can access to this item
2165
 * @param $item_id
2166
 */
2167
function accessToItemIsGranted($item_id)
2168
{
2169
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

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

1. Pass all data via parameters

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

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

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

    public function myFunction() {
        // Do something
    }
}
Loading history...
2170
2171
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2172
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2173
2174
    // Prepare superGlobal variables
2175
    $session_groupes_visibles = $superGlobal->get("groupes_visibles", "SESSION");
2176
    $session_list_restricted_folders_for_items = $superGlobal->get("list_restricted_folders_for_items", "SESSION");
2177
2178
    // Load item data
2179
    $data = DB::queryFirstRow(
2180
        "SELECT id_tree
2181
        FROM ".prefix_table("items")."
2182
        WHERE id = %i",
2183
        $item_id
2184
    );
2185
2186
    // Check if user can access this folder
2187
    if (in_array($data['id_tree'], $session_groupes_visibles) === false) {
2188
        // Now check if this folder is restricted to user
2189
        if (isset($session_list_restricted_folders_for_items[$data['id_tree']])
2190
            && !in_array($item_id, $session_list_restricted_folders_for_items[$data['id_tree']])
2191
        ) {
2192
            return "ERR_FOLDER_NOT_ALLOWED";
2193
        } else {
2194
            return "ERR_FOLDER_NOT_ALLOWED";
2195
        }
2196
    }
2197
2198
    return true;
2199
}
2200
2201
/**
2202
 * Creates a unique key
2203
 * @param  integer $lenght key lenght
2204
 * @return string          key
2205
 */
2206
function uniqidReal($lenght = 13) {
2207
    // uniqid gives 13 chars, but you could adjust it to your needs.
2208
    if (function_exists("random_bytes")) {
2209
        $bytes = random_bytes(ceil($lenght / 2));
0 ignored issues
show
Bug introduced by
ceil($lenght / 2) of type double is incompatible with the type integer expected by parameter $length of random_bytes(). ( Ignorable by Annotation )

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

2209
        $bytes = random_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2210
    } elseif (function_exists("openssl_random_pseudo_bytes")) {
2211
        $bytes = openssl_random_pseudo_bytes(ceil($lenght / 2));
0 ignored issues
show
Bug introduced by
ceil($lenght / 2) of type double is incompatible with the type integer expected by parameter $length of openssl_random_pseudo_bytes(). ( Ignorable by Annotation )

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

2211
        $bytes = openssl_random_pseudo_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2212
    } else {
2213
        throw new Exception("no cryptographically secure random function available");
2214
    }
2215
    return substr(bin2hex($bytes), 0, $lenght);
2216
}
2217