Passed
Push — development ( 73e070...4defef )
by Nils
05:38
created

obfuscate_email()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 17
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 25
rs 8.8571
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 14 and the first side effect is on line 17.

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

100
                /** @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...
101
                    MCRYPT_RIJNDAEL_256,
102
                    $personalSalt,
103
                    $text,
104
                    MCRYPT_MODE_ECB,
105
                    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

105
                    /** @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...
106
                        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

106
                        /** @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...
107
                        MCRYPT_RAND
108
                    )
109
                )
110
            )
111
        );
112
    }
113
114
    // If $personalSalt is not empty
115
    return trim(
116
        base64_encode(
117
            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

117
            /** @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...
118
                MCRYPT_RIJNDAEL_256,
119
                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...
120
                $text,
121
                MCRYPT_MODE_ECB,
122
                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

122
                /** @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...
123
                    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

123
                    /** @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...
124
                    MCRYPT_RAND
125
                )
126
            )
127
        )
128
    );
129
}
130
131
/**
132
 * decryptOld()
133
 *
134
 * decrypt a crypted string
135
 */
136
function decryptOld($text, $personalSalt = "")
137
{
138
    if (!empty($personalSalt)) {
139
        return trim(
140
            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

140
            /** @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...
141
                MCRYPT_RIJNDAEL_256,
142
                $personalSalt,
143
                base64_decode($text),
144
                MCRYPT_MODE_ECB,
145
                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

145
                /** @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...
146
                    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

146
                    /** @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...
147
                    MCRYPT_RAND
148
                )
149
            )
150
        );
151
    }
152
153
    // No personal SK
154
    return trim(
155
        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

155
        /** @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...
156
            MCRYPT_RIJNDAEL_256,
157
            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...
158
            base64_decode($text),
159
            MCRYPT_MODE_ECB,
160
            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

160
            /** @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...
161
                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

161
                /** @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...
162
                MCRYPT_RAND
163
            )
164
        )
165
    );
166
}
167
168
/**
169
 * encrypt()
170
 *
171
 * crypt a string
172
 * @param string $decrypted
173
 */
174
function encrypt($decrypted, $personalSalt = "")
175
{
176
    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...
177
178
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
179
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
180
    } else {
181
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
182
    }
183
184
    if (!empty($personalSalt)) {
185
        $staticSalt = $personalSalt;
186
    } else {
187
        $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...
188
    }
189
190
    //set our salt to a variable
191
    // Get 64 random bits for the salt for pbkdf2
192
    $pbkdf2Salt = getBits(64);
193
    // generate a pbkdf2 key to use for the encryption.
194
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
195
    // Build $init_vect and $ivBase64.  We use a block size of 256 bits (AES compliant)
196
    // and CTR mode.  (Note: ECB mode is inadequate as IV is not used.)
197
    $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

197
    $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

197
    $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...
198
199
    //base64 trim
200
    if (strlen($ivBase64 = rtrim(base64_encode($init_vect), '=')) != 43) {
201
        return false;
202
    }
203
    // Encrypt $decrypted
204
    $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

204
    $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...
205
    // MAC the encrypted text
206
    $mac = hash_hmac('sha256', $encrypted, $staticSalt);
207
    // We're done!
208
    return base64_encode($ivBase64.$encrypted.$mac.$pbkdf2Salt);
209
}
210
211
/**
212
 * decrypt()
213
 *
214
 * decrypt a crypted string
215
 */
216
function decrypt($encrypted, $personalSalt = "")
217
{
218
    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...
219
220
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
221
        include_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
222
    } else {
223
        include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
224
    }
225
226
    if (!empty($personalSalt)) {
227
        $staticSalt = $personalSalt;
228
    } else {
229
        $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...
230
    }
231
    //base64 decode the entire payload
232
    $encrypted = base64_decode($encrypted);
233
    // get the salt
234
    $pbkdf2Salt = substr($encrypted, -64);
235
    //remove the salt from the string
236
    $encrypted = substr($encrypted, 0, -64);
237
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
238
    // Retrieve $init_vect which is the first 22 characters plus ==, base64_decoded.
239
    $init_vect = base64_decode(substr($encrypted, 0, 43).'==');
240
    // Remove $init_vect from $encrypted.
241
    $encrypted = substr($encrypted, 43);
242
    // Retrieve $mac which is the last 64 characters of $encrypted.
243
    $mac = substr($encrypted, -64);
244
    // Remove the last 64 chars from encrypted (remove MAC)
245
    $encrypted = substr($encrypted, 0, -64);
246
    //verify the sha256hmac from the encrypted data before even trying to decrypt it
247
    if (hash_hmac('sha256', $encrypted, $staticSalt) != $mac) {
248
        return false;
249
    }
250
    // Decrypt the data.
251
    $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

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

281
            return /** @scrutinizer ignore-call */ defuse_crypto(
Loading history...
282
                $message,
283
                $saltkey,
284
                $type
285
            );
286
        } else {
287
            return defuse_crypto(
288
                $message,
289
                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...
290
                $type
291
            );
292
        }
293
    } else {
294
        return cryption_phpCrypt($message, $saltkey, $init_vect, $type);
295
    }
296
}
297
298
/*
299
 * cryption() - Encrypt and decrypt string based upon phpCrypt library
300
 *
301
 * Using AES_128 and mode CBC
302
 *
303
 * $key and $init_vect have to be given in hex format
304
 */
305
function cryption_phpCrypt($string, $key, $init_vect, $type)
306
{
307
    // manage key origin
308
    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...
309
        // check key (AES-128 requires a 16 bytes length key)
310
        if (strlen($key) < 16) {
311
            for ($inc = strlen($key) + 1; $inc <= 16; $inc++) {
312
                $key .= chr(0);
313
            }
314
        } elseif (strlen($key) > 16) {
315
            $key = substr($key, 16);
316
        }
317
    }
318
319
    // load crypt
320
    $crypt = new PHP_Crypt($key, PHP_Crypt::CIPHER_AES_128, PHP_Crypt::MODE_CBC);
321
322
    if ($type == "encrypt") {
323
        // generate IV and encrypt
324
        $init_vect = $crypt->createIV();
325
        $encrypt = $crypt->encrypt($string);
326
        // return
327
        return array(
328
            "string" => bin2hex($encrypt),
329
            "iv" => bin2hex($init_vect),
330
            "error" => empty($encrypt) ? "ERR_ENCRYPTION_NOT_CORRECT" : ""
331
        );
332
    } elseif ($type == "decrypt") {
333
        // case if IV is empty
334
        if (empty($init_vect)) {
335
                    return array(
336
                'string' => "",
337
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
338
            );
339
        }
340
341
        // convert
342
        try {
343
            $string = testHex2Bin(trim($string));
344
            $init_vect = testHex2Bin($init_vect);
345
        } catch (Exception $e) {
346
            return array(
347
                'string' => "",
348
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
349
            );
350
        }
351
352
        // load IV
353
        $crypt->IV($init_vect);
354
        // decrypt
355
        $decrypt = $crypt->decrypt($string);
356
        // return
357
        return array(
358
            'string' => str_replace(chr(0), "", $decrypt),
359
            'error' => ""
360
        );
361
    }
362
}
363
364
function testHex2Bin($val)
365
{
366
    if (!@hex2bin($val)) {
367
        throw new Exception("ERROR");
368
    }
369
    return hex2bin($val);
370
}
371
372
/**
373
 * @param string $ascii_key
374
 * @param string $type
375
 */
376
function cryption($message, $ascii_key, $type) //defuse_crypto
377
{
378
    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...
379
380
    // load PhpEncryption library
381
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
382
        $path = '../includes/libraries/Encryption/Encryption/';
383
    } else {
384
        $path = $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/';
385
    }
386
387
    require_once $path.'Crypto.php';
388
    require_once $path.'Encoding.php';
389
    require_once $path.'DerivedKeys.php';
390
    require_once $path.'Key.php';
391
    require_once $path.'KeyOrPassword.php';
392
    require_once $path.'File.php';
393
    require_once $path.'RuntimeTests.php';
394
    require_once $path.'KeyProtectedByPassword.php';
395
    require_once $path.'Core.php';
396
397
    // init
398
    $err = '';
399
    if (empty($ascii_key)) {
400
        $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...
401
    }
402
403
    // convert KEY
404
    $key = \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key);
405
406
    try {
407
        if ($type === "encrypt") {
408
            $text = \Defuse\Crypto\Crypto::encrypt($message, $key);
409
        } elseif ($type === "decrypt") {
410
            $text = \Defuse\Crypto\Crypto::decrypt($message, $key);
411
        }
412
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
413
        $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.";
414
    } catch (Defuse\Crypto\Exception\BadFormatException $ex) {
415
        $err = $ex;
416
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
417
        $err = $ex;
418
    } catch (Defuse\Crypto\Exception\CryptoException $ex) {
419
        $err = $ex;
420
    } catch (Defuse\Crypto\Exception\IOException $ex) {
421
        $err = $ex;
422
    }
423
424
    return array(
425
        'string' => isset($text) ? $text : "",
426
        'error' => $err
427
    );
428
}
429
430
function defuse_generate_key()
431
{
432
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
433
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
434
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
435
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
436
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
437
    require_once '../includes/libraries/Encryption/Encryption/File.php';
438
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
439
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
440
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
441
442
    $key = \Defuse\Crypto\Key::createNewRandomKey();
443
    $key = $key->saveToAsciiSafeString();
444
    return $key;
445
}
446
447
function defuse_generate_personal_key($psk)
448
{
449
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
450
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
451
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
452
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
453
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
454
    require_once '../includes/libraries/Encryption/Encryption/File.php';
455
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
456
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
457
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
458
459
    $protected_key = \Defuse\Crypto\KeyProtectedByPassword::createRandomPasswordProtectedKey($psk);
460
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
461
462
    return $protected_key_encoded; // save this in user table
463
}
464
465
/**
466
 * @param string $psk
467
 */
468
function defuse_validate_personal_key($psk, $protected_key_encoded)
469
{
470
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
471
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
472
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
473
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
474
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
475
    require_once '../includes/libraries/Encryption/Encryption/File.php';
476
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
477
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
478
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
479
480
    try {
481
        $protected_key = \Defuse\Crypto\KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
482
        $user_key = $protected_key->unlockKey($psk);
483
        $user_key_encoded = $user_key->saveToAsciiSafeString();
484
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
485
        return "Error - Major issue as the encryption is broken.";
486
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
487
        return "Error - The saltkey is not the correct one.";
488
    }
489
490
    return $user_key_encoded; // store it in session once user has entered his psk
491
}
492
493
/**
494
 * Decrypt a defuse string if encrypted
495
 * @param  [type] $value Encrypted string
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...
496
 * @return [type]        Decrypted string
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
 */
498
function defuse_return_decrypted($value)
499
{
500
    if (substr($value, 0, 3) === "def") {
501
        $value = cryption($value, "", "decrypt")['string'];
502
    }
503
    return $value;
504
}
505
506
/**
507
 * trimElement()
508
 *
509
 * trim a string depending on a specific string
510
 * @param string $element
511
 * @return string
512
 */
513
function trimElement($chaine, $element)
514
{
515
    if (!empty($chaine)) {
516
        if (is_array($chaine) === true) {
517
            $chaine = implode(";", $chaine);
518
        }
519
        $chaine = trim($chaine);
520
        if (substr($chaine, 0, 1) == $element) {
521
            $chaine = substr($chaine, 1);
522
        }
523
        if (substr($chaine, strlen($chaine) - 1, 1) == $element) {
524
            $chaine = substr($chaine, 0, strlen($chaine) - 1);
525
        }
526
    }
527
    return $chaine;
528
}
529
530
/**
531
 * cleanString()
532
 *
533
 * permits to suppress all "special" characters from string
534
 */
535
function cleanString($string, $special = false)
536
{
537
    // Create temporary table for special characters escape
538
    $tabSpecialChar = array();
539
    for ($i = 0; $i <= 31; $i++) {
540
        $tabSpecialChar[] = chr($i);
541
    }
542
    array_push($tabSpecialChar, "<br />");
543
    if ($special == "1") {
544
        $tabSpecialChar = array_merge($tabSpecialChar, array("</li>", "<ul>", "<ol>"));
545
    }
546
547
    return str_replace($tabSpecialChar, "\n", $string);
548
}
549
550
function db_error_handler($params)
551
{
552
    echo "Error: ".$params['error']."<br>\n";
553
    echo "Query: ".$params['query']."<br>\n";
554
    throw new Exception("Error - Query", 1);
555
}
556
557
/**
558
 * [identifyUserRights description]
559
 * @param  string $groupesVisiblesUser  [description]
560
 * @param  string $groupesInterditsUser [description]
561
 * @param  string $isAdmin              [description]
562
 * @param  string $idFonctions          [description]
563
 * @return string                       [description]
564
 */
565
function identifyUserRights(
566
    $groupesVisiblesUser,
567
    $groupesInterditsUser,
568
    $isAdmin,
569
    $idFonctions,
570
    $server,
571
    $user,
572
    $pass,
573
    $database,
574
    $port,
575
    $encoding,
576
    $SETTINGS
577
) {
578
    //load ClassLoader
579
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
580
581
    //Connect to DB
582
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
583
    $pass = defuse_return_decrypted($pass);
584
    DB::$host = $server;
585
    DB::$user = $user;
586
    DB::$password = $pass;
587
    DB::$dbName = $database;
588
    DB::$port = $port;
589
    DB::$encoding = $encoding;
590
    DB::$error_handler = true;
591
    $link = mysqli_connect($server, $user, $pass, $database, $port);
592
    $link->set_charset($encoding);
593
594
    //Build tree
595
    $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'].'/includes/libraries');
596
    $tree->register();
597
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
598
599
    // Check if user is ADMINISTRATOR
600
    if ($isAdmin === '1') {
601
        $groupesVisibles = array();
602
        $_SESSION['personal_folders'] = array();
603
        $_SESSION['groupes_visibles'] = array();
604
        $_SESSION['groupes_interdits'] = array();
605
        $_SESSION['personal_visible_groups'] = array();
606
        $_SESSION['read_only_folders'] = array();
607
        $_SESSION['list_restricted_folders_for_items'] = array();
608
        $_SESSION['list_folders_editable_by_role'] = array();
609
        $_SESSION['list_folders_limited'] = array();
610
        $_SESSION['no_access_folders'] = array();
611
        $_SESSION['groupes_visibles_list'] = "";
612
        $rows = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i", 0);
613
        foreach ($rows as $record) {
614
            array_push($groupesVisibles, $record['id']);
615
        }
616
        $_SESSION['groupes_visibles'] = $groupesVisibles;
617
        $_SESSION['all_non_personal_folders'] = $groupesVisibles;
618
        // Exclude all PF
619
        $_SESSION['forbiden_pfs'] = array();
620
        $where = new WhereClause('and'); // create a WHERE statement of pieces joined by ANDs
621
        $where->add('personal_folder=%i', 1);
622
        if (isset($SETTINGS['enable_pf_feature']) && $SETTINGS['enable_pf_feature'] == 1) {
623
            $where->add('title=%s', $_SESSION['user_id']);
624
            $where->negateLast();
625
        }
626
        // Get ID of personal folder
627
        $persfld = DB::queryfirstrow(
628
            "SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s",
629
            $_SESSION['user_id']
630
        );
631
        if (!empty($persfld['id'])) {
632
            if (!in_array($persfld['id'], $_SESSION['groupes_visibles'])) {
633
                array_push($_SESSION['groupes_visibles'], $persfld['id']);
634
                array_push($_SESSION['personal_visible_groups'], $persfld['id']);
635
                // get all descendants
636
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
637
                $tree->rebuild();
638
                $tst = $tree->getDescendants($persfld['id']);
639
                foreach ($tst as $t) {
640
                    array_push($_SESSION['groupes_visibles'], $t->id);
641
                    array_push($_SESSION['personal_visible_groups'], $t->id);
642
                }
643
            }
644
        }
645
646
        // get complete list of ROLES
647
        $tmp = explode(";", $idFonctions);
648
        $rows = DB::query(
649
            "SELECT * FROM ".prefix_table("roles_title")."
650
            ORDER BY title ASC"
651
        );
652
        foreach ($rows as $record) {
653
            if (!empty($record['id']) && !in_array($record['id'], $tmp)) {
654
                array_push($tmp, $record['id']);
655
            }
656
        }
657
        $_SESSION['fonction_id'] = implode(";", $tmp);
658
659
        $_SESSION['groupes_visibles_list'] = implode(',', $_SESSION['groupes_visibles']);
660
        $_SESSION['is_admin'] = $isAdmin;
661
        // Check if admin has created Folders and Roles
662
        DB::query("SELECT * FROM ".prefix_table("nested_tree")."");
663
        $_SESSION['nb_folders'] = DB::count();
664
        DB::query("SELECT * FROM ".prefix_table("roles_title"));
665
        $_SESSION['nb_roles'] = DB::count();
666
    } else {
667
        // init
668
        $_SESSION['groupes_visibles'] = array();
669
        $_SESSION['personal_folders'] = array();
670
        $_SESSION['groupes_interdits'] = array();
671
        $_SESSION['personal_visible_groups'] = array();
672
        $_SESSION['read_only_folders'] = array();
673
        $_SESSION['fonction_id'] = $idFonctions;
674
        $groupesInterdits = array();
675
        if (is_array($groupesInterditsUser) === false) {
0 ignored issues
show
introduced by
The condition is_array($groupesInterditsUser) === false is always true.
Loading history...
676
            $groupesInterditsUser = explode(';', trimElement($groupesInterditsUser, ";"));
677
        }
678
        if (!empty($groupesInterditsUser) && count($groupesInterditsUser) > 0) {
679
            $groupesInterdits = $groupesInterditsUser;
680
        }
681
        $_SESSION['is_admin'] = $isAdmin;
682
        $fonctionsAssociees = explode(';', trimElement($idFonctions, ";"));
683
684
        $listAllowedFolders = $listFoldersLimited = $listFoldersEditableByRole = $listRestrictedFoldersForItems = $listReadOnlyFolders = array();
685
686
        // rechercher tous les groupes visibles en fonction des roles de l'utilisateur
687
        foreach ($fonctionsAssociees as $roleId) {
688
            if (empty($roleId) === false) {
689
                // Get allowed folders for each Role
690
                $rows = DB::query(
691
                    "SELECT folder_id FROM ".prefix_table("roles_values")." WHERE role_id=%i",
692
                    $roleId
693
                );
694
695
                if (DB::count() > 0) {
696
                    $tmp = DB::queryfirstrow(
697
                        "SELECT allow_pw_change FROM ".prefix_table("roles_title")." WHERE id = %i",
698
                        $roleId
699
                    );
700
                    foreach ($rows as $record) {
701
                        if (isset($record['folder_id']) && in_array($record['folder_id'], $listAllowedFolders) === false) {
702
                            array_push($listAllowedFolders, $record['folder_id']);
703
                        }
704
                        // Check if this group is allowed to modify any pw in allowed folders
705
                        if ($tmp['allow_pw_change'] == 1 && in_array($record['folder_id'], $listFoldersEditableByRole) === false) {
706
                            array_push($listFoldersEditableByRole, $record['folder_id']);
707
                        }
708
                    }
709
                    // Check for the users roles if some specific rights exist on items
710
                    $rows = DB::query(
711
                        "SELECT i.id_tree, r.item_id
712
                        FROM ".prefix_table("items")." as i
713
                        INNER JOIN ".prefix_table("restriction_to_roles")." as r ON (r.item_id=i.id)
714
                        WHERE r.role_id=%i
715
                        ORDER BY i.id_tree ASC",
716
                        $roleId
717
                    );
718
                    $inc = 0;
719
                    foreach ($rows as $record) {
720
                        if (isset($record['id_tree'])) {
721
                            $listFoldersLimited[$record['id_tree']][$inc] = $record['item_id'];
722
                            $inc++;
723
                        }
724
                    }
725
                }
726
            }
727
        }
728
        
729
        // Clean arrays
730
        $listAllowedFolders = array_unique($listAllowedFolders);
731
        $groupesVisiblesUser = explode(';', trimElement($groupesVisiblesUser, ";"));
732
        
733
        // Does this user is allowed to see other items
734
        $inc = 0;
735
        $rows = DB::query(
736
            "SELECT id, id_tree FROM ".prefix_table("items")."
737
            WHERE restricted_to LIKE %ss AND inactif=%s",
738
            $_SESSION['user_id'].';',
739
            '0'
740
        );
741
        foreach ($rows as $record) {
742
            // Exclude restriction on item if folder is fully accessible
743
            if (in_array($record['id_tree'], $listAllowedFolders) === false) {
744
                $listRestrictedFoldersForItems[$record['id_tree']][$inc] = $record['id'];
745
                $inc++;
746
            }
747
        }
748
        
749
        // => Build final lists
750
        // Add user allowed folders
751
        $allowedFoldersTmp = array_unique(
752
            array_merge($listAllowedFolders, $groupesVisiblesUser)
753
        );
754
        // Exclude from allowed folders all the specific user forbidden folders
755
        $allowedFolders = array();
756
        foreach ($allowedFoldersTmp as $ident) {
757
            if (!in_array($ident, $groupesInterditsUser) && !empty($ident)) {
758
                array_push($allowedFolders, $ident);
759
            }
760
        }
761
762
        // Clean array
763
        $listAllowedFolders = array_filter(array_unique($allowedFolders));
764
765
        // Exclude all PF
766
        $_SESSION['forbiden_pfs'] = array();
767
768
        $where = new WhereClause('and');
769
        $where->add('personal_folder=%i', 1);
770
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
771
            && isset($_SESSION['personal_folder']) === true && $_SESSION['personal_folder'] === '1'
772
        ) {
773
            $where->add('title=%s', $_SESSION['user_id']);
774
            $where->negateLast();
775
        }
776
777
        $persoFlds = DB::query(
778
            "SELECT id
779
            FROM ".prefix_table("nested_tree")."
780
            WHERE %l",
781
            $where
782
        );
783
        foreach ($persoFlds as $persoFldId) {
784
            array_push($_SESSION['forbiden_pfs'], $persoFldId['id']);
785
        }
786
        // Get IDs of personal folders
787
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
788
            && isset($_SESSION['personal_folder']) === true &&  $_SESSION['personal_folder'] === '1'
789
        ) {
790
            $persoFld = DB::queryfirstrow(
791
                "SELECT id
792
                FROM ".prefix_table("nested_tree")."
793
                WHERE title = %s AND personal_folder = %i",
794
                $_SESSION['user_id'],
795
                1
796
            );
797
            if (empty($persoFld['id']) === false) {
798
                if (in_array($persoFld['id'], $listAllowedFolders) === false) {
799
                    array_push($_SESSION['personal_folders'], $persoFld['id']);
800
                    array_push($listAllowedFolders, $persoFld['id']);
801
                    array_push($_SESSION['personal_visible_groups'], $persoFld['id']);
802
                    // get all descendants
803
                    $ids = $tree->getChildren($persoFld['id']);
804
                    foreach ($ids as $ident) {
805
                        array_push($listAllowedFolders, $ident->id);
806
                        array_push($_SESSION['personal_visible_groups'], $ident->id);
807
                        array_push($_SESSION['personal_folders'], $ident->id);
808
                    }
809
                }
810
            }
811
            // get list of readonly folders when pf is disabled.
812
            $_SESSION['personal_folders'] = array_unique($_SESSION['personal_folders']);
813
            // rule - if one folder is set as W or N in one of the Role, then User has access as W
814
            foreach ($listAllowedFolders as $folderId) {
815
                if (in_array($folderId, array_unique(array_merge($listReadOnlyFolders, $_SESSION['personal_folders']))) === false) {
816
                    DB::query(
817
                        "SELECT *
818
                        FROM ".prefix_table("roles_values")."
819
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
820
                        $folderId,
821
                        $fonctionsAssociees,
822
                        array("W", "ND", "NE", "NDNE")
823
                    );
824
                    if (DB::count() === 0 && in_array($folderId, $groupesVisiblesUser) === false) {
825
                        array_push($listReadOnlyFolders, $folderId);
826
                    }
827
                }
828
            }
829
        } else {
830
            // get list of readonly folders when pf is disabled.
831
            // rule - if one folder is set as W in one of the Role, then User has access as W
832
            foreach ($listAllowedFolders as $folderId) {
833
                if (in_array($folderId, $listReadOnlyFolders) === false) {
834
                    DB::query(
835
                        "SELECT *
836
                        FROM ".prefix_table("roles_values")."
837
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
838
                        $folderId,
839
                        $fonctionsAssociees,
840
                        array("W", "ND", "NE", "NDNE")
841
                    );
842
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
843
                        array_push($listReadOnlyFolders, $folderId);
844
                    }
845
                }
846
            }
847
        }
848
849
        // check if change proposals on User's items
850
        if (isset($SETTINGS['enable_suggestion']) === true && $SETTINGS['enable_suggestion'] === '1') {
851
            DB::query(
852
                "SELECT *
853
                FROM ".prefix_table("items_change")." AS c
854
                LEFT JOIN ".prefix_table("log_items")." AS i ON (c.item_id = i.id_item)
855
                WHERE i.action = %s AND i.id_user = %i",
856
                "at_creation",
857
                $_SESSION['user_id']
858
            );
859
            $_SESSION['nb_item_change_proposals'] = DB::count();
860
        } else {
861
            $_SESSION['nb_item_change_proposals'] = 0;
862
        }
863
864
        $_SESSION['all_non_personal_folders'] = $listAllowedFolders;
865
        $_SESSION['groupes_visibles'] = $listAllowedFolders;
866
        $_SESSION['groupes_visibles_list'] = implode(',', $listAllowedFolders);
867
        $_SESSION['personal_visible_groups_list'] = implode(',', $_SESSION['personal_visible_groups']);
868
        $_SESSION['read_only_folders'] = $listReadOnlyFolders;
869
        $_SESSION['no_access_folders'] = $groupesInterdits;
870
871
        $_SESSION['list_folders_limited'] = $listFoldersLimited;
872
        $_SESSION['list_folders_editable_by_role'] = $listFoldersEditableByRole;
873
        $_SESSION['list_restricted_folders_for_items'] = $listRestrictedFoldersForItems;
874
        // Folders and Roles numbers
875
        DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")."");
876
        $_SESSION['nb_folders'] = DB::count();
877
        DB::queryfirstrow("SELECT id FROM ".prefix_table("roles_title"));
878
        $_SESSION['nb_roles'] = DB::count();
879
    }
880
881
    // update user's timestamp
882
    DB::update(
883
        prefix_table('users'),
884
        array(
885
            'timestamp' => time()
886
        ),
887
        "id=%i",
888
        $_SESSION['user_id']
889
    );
890
}
891
892
/**
893
 * updateCacheTable()
894
 *
895
 * Update the CACHE table
896
 * @param string $action
897
 */
898
function updateCacheTable($action, $ident = "")
899
{
900
    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...
901
    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...
902
903
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
904
905
    //Connect to DB
906
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
907
    $pass = defuse_return_decrypted($pass);
908
    DB::$host = $server;
909
    DB::$user = $user;
910
    DB::$password = $pass;
911
    DB::$dbName = $database;
912
    DB::$port = $port;
913
    DB::$encoding = $encoding;
914
    DB::$error_handler = true;
915
    $link = mysqli_connect($server, $user, $pass, $database, $port);
916
    $link->set_charset($encoding);
917
918
    //Load Tree
919
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
920
    $tree->register();
921
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
922
923
    // Rebuild full cache table
924
    if ($action === "reload") {
925
        // truncate table
926
        DB::query("TRUNCATE TABLE ".prefix_table("cache"));
927
928
        // reload date
929
        $rows = DB::query(
930
            "SELECT *
931
            FROM ".prefix_table('items')." as i
932
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
933
            AND l.action = %s
934
            AND i.inactif = %i",
935
            'at_creation',
936
            0
937
        );
938
        foreach ($rows as $record) {
939
            if (empty($record['id_tree']) === false) {
940
                // Get all TAGS
941
                $tags = "";
942
                $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $record['id']);
943
                foreach ($itemTags as $itemTag) {
944
                    if (!empty($itemTag['tag'])) {
945
                        $tags .= $itemTag['tag']." ";
946
                    }
947
                }
948
                // Get renewal period
949
                $resNT = DB::queryfirstrow("SELECT renewal_period FROM ".prefix_table('nested_tree')." WHERE id=%i", $record['id_tree']);
950
951
                // form id_tree to full foldername
952
                $folder = "";
953
                $arbo = $tree->getPath($record['id_tree'], true);
954
                foreach ($arbo as $elem) {
955
                    if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
956
                        $elem->title = $_SESSION['login'];
957
                    }
958
                    if (empty($folder)) {
959
                        $folder = stripslashes($elem->title);
960
                    } else {
961
                        $folder .= " » ".stripslashes($elem->title);
962
                    }
963
                }
964
                // store data
965
                DB::insert(
966
                    prefix_table('cache'),
967
                    array(
968
                        'id' => $record['id'],
969
                        'label' => $record['label'],
970
                        'description' => isset($record['description']) ? $record['description'] : "",
971
                        'url' => (isset($record['url']) && !empty($record['url'])) ? $record['url'] : "0",
972
                        'tags' => $tags,
973
                        'id_tree' => $record['id_tree'],
974
                        'perso' => $record['perso'],
975
                        'restricted_to' => (isset($record['restricted_to']) && !empty($record['restricted_to'])) ? $record['restricted_to'] : "0",
976
                        'login' => isset($record['login']) ? $record['login'] : "",
977
                        'folder' => $folder,
978
                        'author' => $record['id_user'],
979
                        'renewal_period' => isset($resNT['renewal_period']) ? $resNT['renewal_period'] : "0",
980
                        'timestamp' => $record['date']
981
                        )
982
                );
983
            }
984
        }
985
        // UPDATE an item
986
    } elseif ($action === "update_value") {
987
        // get new value from db
988
        $data = DB::queryfirstrow(
989
            "SELECT label, description, id_tree, perso, restricted_to, login, url
990
            FROM ".prefix_table('items')."
991
            WHERE id=%i",
992
            $ident
993
        );
994
        // Get all TAGS
995
        $tags = "";
996
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $ident);
997
        foreach ($itemTags as $itemTag) {
998
            if (!empty($itemTag['tag'])) {
999
                $tags .= $itemTag['tag']." ";
1000
            }
1001
        }
1002
        // form id_tree to full foldername
1003
        $folder = "";
1004
        $arbo = $tree->getPath($data['id_tree'], true);
1005
        foreach ($arbo as $elem) {
1006
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1007
                $elem->title = $_SESSION['login'];
1008
            }
1009
            if (empty($folder)) {
1010
                $folder = stripslashes($elem->title);
1011
            } else {
1012
                $folder .= " » ".stripslashes($elem->title);
1013
            }
1014
        }
1015
        // finaly update
1016
        DB::update(
1017
            prefix_table('cache'),
1018
            array(
1019
                'label' => $data['label'],
1020
                'description' => $data['description'],
1021
                'tags' => $tags,
1022
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1023
                'id_tree' => $data['id_tree'],
1024
                'perso' => $data['perso'],
1025
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1026
                'login' => isset($data['login']) ? $data['login'] : "",
1027
                'folder' => $folder,
1028
                'author' => $_SESSION['user_id'],
1029
                ),
1030
            "id = %i",
1031
            $ident
1032
        );
1033
        // ADD an item
1034
    } elseif ($action === "add_value") {
1035
        // get new value from db
1036
        $data = DB::queryFirstRow(
1037
            "SELECT i.label, i.description, i.id_tree as id_tree, i.perso, i.restricted_to, i.id, i.login, i.url, l.date
1038
            FROM ".prefix_table('items')." as i
1039
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
1040
            WHERE i.id = %i
1041
            AND l.action = %s",
1042
            $ident,
1043
            'at_creation'
1044
        );
1045
        // Get all TAGS
1046
        $tags = "";
1047
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id = %i", $ident);
1048
        foreach ($itemTags as $itemTag) {
1049
            if (!empty($itemTag['tag'])) {
1050
                $tags .= $itemTag['tag']." ";
1051
            }
1052
        }
1053
        // form id_tree to full foldername
1054
        $folder = "";
1055
        $arbo = $tree->getPath($data['id_tree'], true);
1056
        foreach ($arbo as $elem) {
1057
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1058
                $elem->title = $_SESSION['login'];
1059
            }
1060
            if (empty($folder)) {
1061
                $folder = stripslashes($elem->title);
1062
            } else {
1063
                $folder .= " » ".stripslashes($elem->title);
1064
            }
1065
        }
1066
        // finaly update
1067
        DB::insert(
1068
            prefix_table('cache'),
1069
            array(
1070
                'id' => $data['id'],
1071
                'label' => $data['label'],
1072
                'description' => $data['description'],
1073
                'tags' => (isset($tags) && !empty($tags)) ? $tags : "None",
1074
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1075
                'id_tree' => $data['id_tree'],
1076
                'perso' => (isset($data['perso']) && !empty($data['perso']) && $data['perso'] !== "None") ? $data['perso'] : "0",
1077
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1078
                'login' => isset($data['login']) ? $data['login'] : "",
1079
                'folder' => $folder,
1080
                'author' => $_SESSION['user_id'],
1081
                'timestamp' => $data['date']
1082
            )
1083
        );
1084
1085
        // DELETE an item
1086
    } elseif ($action === "delete_value") {
1087
        DB::delete(prefix_table('cache'), "id = %i", $ident);
1088
    }
1089
}
1090
1091
/*
1092
*
1093
*/
1094
function getStatisticsData()
1095
{
1096
    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...
1097
1098
    DB::query(
1099
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1100
        0
1101
    );
1102
    $counter_folders = DB::count();
1103
1104
    DB::query(
1105
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1106
        1
1107
    );
1108
    $counter_folders_perso = DB::count();
1109
1110
    DB::query(
1111
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1112
        0
1113
    );
1114
    $counter_items = DB::count();
1115
1116
    DB::query(
1117
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1118
        1
1119
    );
1120
    $counter_items_perso = DB::count();
1121
1122
    DB::query(
1123
        "SELECT id FROM ".prefix_table("users").""
1124
    );
1125
    $counter_users = DB::count();
1126
1127
    DB::query(
1128
        "SELECT id FROM ".prefix_table("users")." WHERE admin = %i",
1129
        1
1130
    );
1131
    $admins = DB::count();
1132
1133
    DB::query(
1134
        "SELECT id FROM ".prefix_table("users")." WHERE gestionnaire = %i",
1135
        1
1136
    );
1137
    $managers = DB::count();
1138
1139
    DB::query(
1140
        "SELECT id FROM ".prefix_table("users")." WHERE read_only = %i",
1141
        1
1142
    );
1143
    $readOnly = DB::count();
1144
1145
    // list the languages
1146
    $usedLang = [];
1147
    $tp_languages = DB::query(
1148
        "SELECT name FROM ".prefix_table("languages")
1149
    );
1150
    foreach ($tp_languages as $tp_language) {
1151
        DB::query(
1152
            "SELECT * FROM ".prefix_table("users")." WHERE user_language = %s",
1153
            $tp_language['name']
1154
        );
1155
        $usedLang[$tp_language['name']] = round((DB::count() * 100 / $counter_users), 0);
1156
    }
1157
1158
    // get list of ips
1159
    $usedIp = [];
1160
    $tp_ips = DB::query(
1161
        "SELECT user_ip FROM ".prefix_table("users")
1162
    );
1163
    foreach ($tp_ips as $ip) {
1164
        if (array_key_exists($ip['user_ip'], $usedIp)) {
1165
            $usedIp[$ip['user_ip']] = $usedIp[$ip['user_ip']] + 1;
1166
        } elseif (!empty($ip['user_ip']) && $ip['user_ip'] !== "none") {
1167
            $usedIp[$ip['user_ip']] = 1;
1168
        }
1169
    }
1170
1171
    return array(
1172
        "error" => "",
1173
        "stat_phpversion" => phpversion(),
1174
        "stat_folders" => $counter_folders,
1175
        "stat_folders_shared" => intval($counter_folders) - intval($counter_folders_perso),
1176
        "stat_items" => $counter_items,
1177
        "stat_items_shared" => intval($counter_items) - intval($counter_items_perso),
1178
        "stat_users" => $counter_users,
1179
        "stat_admins" => $admins,
1180
        "stat_managers" => $managers,
1181
        "stat_ro" => $readOnly,
1182
        "stat_kb" => $SETTINGS['enable_kb'],
1183
        "stat_pf" => $SETTINGS['enable_pf_feature'],
1184
        "stat_fav" => $SETTINGS['enable_favourites'],
1185
        "stat_teampassversion" => $SETTINGS['cpassman_version'],
1186
        "stat_ldap" => $SETTINGS['ldap_mode'],
1187
        "stat_agses" => $SETTINGS['agses_authentication_enabled'],
1188
        "stat_duo" => $SETTINGS['duo'],
1189
        "stat_suggestion" => $SETTINGS['enable_suggestion'],
1190
        "stat_api" => $SETTINGS['api'],
1191
        "stat_customfields" => $SETTINGS['item_extra_fields'],
1192
        "stat_syslog" => $SETTINGS['syslog_enable'],
1193
        "stat_2fa" => $SETTINGS['google_authentication'],
1194
        "stat_stricthttps" => $SETTINGS['enable_sts'],
1195
        "stat_mysqlversion" => DB::serverVersion(),
1196
        "stat_languages" => $usedLang,
1197
        "stat_country" => $usedIp
1198
    );
1199
}
1200
1201
/**
1202
 * Permits to send an email
1203
 *
1204
 * @param  string $subject     email subject
1205
 * @param  string $textMail    email message
1206
 * @param  string $email       email
1207
 * @param  array  $LANG        Language
1208
 * @param  array  $SETTINGS    settings
1209
 * @param  string $textMailAlt email message alt
1210
 * @return  string  some json info
1211
 */
1212
function sendEmail(
1213
    $subject,
1214
    $textMail,
1215
    $email,
1216
    $LANG,
1217
    $SETTINGS,
1218
    $textMailAlt = ""
1219
) {
1220
    // CAse where email not defined
1221
    if ($email === "none") {
1222
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1223
    }
1224
1225
    // Load settings
1226
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
1227
1228
    // Load superglobal
1229
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1230
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
1231
1232
    // Get user language
1233
    $session_user_language = $superGlobal->get("user_language", "SESSION");
1234
1235
    // Load library
1236
    $user_language = isset($session_user_language) ? $session_user_language : "english";
1237
    require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$user_language.'.php';
1238
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Email/Phpmailer/PHPMailerAutoload.php';
1239
1240
    // load PHPMailer
1241
    $mail = new PHPMailer();
1242
1243
    // send to user
1244
    $mail->setLanguage("en", "../includes/libraries/Email/Phpmailer/language/");
1245
    $mail->SMTPDebug = 0; //value 1 can be used to debug - 4 for debuging connections
1246
    $mail->Port = $SETTINGS['email_port']; //COULD BE USED
1247
    $mail->CharSet = "utf-8";
1248
    if ($SETTINGS['email_security'] === "tls" || $SETTINGS['email_security'] === "ssl") {
1249
        $mail->SMTPSecure = $SETTINGS['email_security'];
1250
        $SMTPAutoTLS = true;
1251
    } else {
1252
        $SMTPAutoTLS = false;
1253
        $mail->SMTPSecure = "";
1254
    }
1255
    $mail->SMTPAutoTLS = $SMTPAutoTLS;
1256
    $mail->isSmtp(); // send via SMTP
1257
    $mail->Host = $SETTINGS['email_smtp_server']; // SMTP servers
1258
    $mail->SMTPAuth = $SETTINGS['email_smtp_auth'] == '1' ? true : false; // turn on SMTP authentication
1259
    $mail->Username = $SETTINGS['email_auth_username']; // SMTP username
1260
    $mail->Password = $SETTINGS['email_auth_pwd']; // SMTP password
1261
    $mail->From = $SETTINGS['email_from'];
1262
    $mail->FromName = $SETTINGS['email_from_name'];
1263
1264
    // Prepare for each person
1265
    $dests = explode(",", $email);
1266
    foreach ($dests as $dest) {
1267
        $mail->addAddress($dest);
1268
    }
1269
1270
    // Prepare HTML
1271
    $text_html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.=
1272
    w3.org/TR/html4/loose.dtd"><html>
1273
    <head><title>Email Template</title>
1274
    <style type="text/css">
1275
    body { background-color: #f0f0f0; padding: 10px 0; margin:0 0 10px =0; }
1276
    </style></head>
1277
    <body style="-ms-text-size-adjust: none; size-adjust: none; margin: 0; padding: 10px 0; background-color: #f0f0f0;" bgcolor="#f0f0f0" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
1278
    <table border="0" width="100%" height="100%" cellpadding="0" cellspacing="0" bgcolor="#f0f0f0" style="border-spacing: 0;">
1279
    <tr><td style="border-collapse: collapse;"><br>
1280
        <table border="0" width="100%" cellpadding="0" cellspacing="0" bgcolor="#17357c" style="border-spacing: 0; margin-bottom: 25px;">
1281
        <tr><td style="border-collapse: collapse; padding: 11px 20px;">
1282
            <div style="max-width:150px; max-height:34px; color:#f0f0f0; font-weight:bold;">Teampass</div>
1283
        </td></tr></table></td>
1284
    </tr>
1285
    <tr><td align="center" valign="top" bgcolor="#f0f0f0" style="border-collapse: collapse; background-color: #f0f0f0;">
1286
        <table width="600" cellpadding="0" cellspacing="0" border="0" class="container" bgcolor="#ffffff" style="border-spacing: 0; border-bottom: 1px solid #e0e0e0; box-shadow: 0 0 3px #ddd; color: #434343; font-family: Helvetica, Verdana, sans-serif;">
1287
        <tr><td class="container-padding" bgcolor="#ffffff" style="border-collapse: collapse; border-left: 1px solid #e0e0e0; background-color: #ffffff; padding-left: 30px; padding-right: 30px;">
1288
        <br><div style="float:right;">'.
1289
    $textMail.
1290
    '<br><br></td></tr></table>
1291
    </td></tr></table>
1292
    <br></body></html>';
1293
1294
    $mail->WordWrap = 80; // set word wrap
1295
    $mail->isHtml(true); // send as HTML
1296
    $mail->Subject = $subject;
1297
    $mail->Body = $text_html;
1298
    $mail->AltBody = $textMailAlt;
1299
    // send email
1300
    if (!$mail->send()) {
1301
        return '"error":"error_mail_not_send" , "message":"'.str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo).'"';
1302
    } else {
1303
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1304
    }
1305
}
1306
1307
/**
1308
 * generateKey()
1309
 *
1310
 * @return
1311
 */
1312
function generateKey()
1313
{
1314
    return substr(md5(rand().rand()), 0, 15);
1315
}
1316
1317
/**
1318
 * dateToStamp()
1319
 *
1320
 * @return
1321
 */
1322
function dateToStamp($date)
1323
{
1324
    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...
1325
1326
    $date = date_parse_from_format($SETTINGS['date_format'], $date);
1327
    if ($date['warning_count'] == 0 && $date['error_count'] == 0) {
1328
        return mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
1329
    } else {
1330
        return false;
1331
    }
1332
}
1333
1334
function isDate($date)
1335
{
1336
    return (strtotime($date) !== false);
1337
}
1338
1339
/**
1340
 * isUTF8()
1341
 *
1342
 * @return integer is the string in UTF8 format.
1343
 */
1344
1345
function isUTF8($string)
1346
{
1347
    if (is_array($string) === true) {
1348
        $string = $string['string'];
1349
    }
1350
    return preg_match(
1351
        '%^(?:
1352
        [\x09\x0A\x0D\x20-\x7E] # ASCII
1353
        | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
1354
        | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
1355
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
1356
        | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
1357
        | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
1358
        | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
1359
        | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
1360
        )*$%xs',
1361
        $string
1362
    );
1363
}
1364
1365
/*
1366
* FUNCTION
1367
* permits to prepare data to be exchanged
1368
*/
1369
/**
1370
 * @param string $type
1371
 */
1372
function prepareExchangedData($data, $type)
1373
{
1374
    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...
1375
1376
    //load ClassLoader
1377
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1378
    //Load AES
1379
    $aes = new SplClassLoader('Encryption\Crypt', $SETTINGS['cpassman_dir'].'/includes/libraries');
1380
    $aes->register();
1381
1382
    if ($type == "encode") {
1383
        if (isset($SETTINGS['encryptClientServer'])
1384
            && $SETTINGS['encryptClientServer'] === "0"
1385
        ) {
1386
            return json_encode(
1387
                $data,
1388
                JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1389
            );
1390
        } else {
1391
            return Encryption\Crypt\aesctr::encrypt(
1392
                json_encode(
1393
                    $data,
1394
                    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1395
                ),
1396
                $_SESSION['key'],
1397
                256
1398
            );
1399
        }
1400
    } elseif ($type == "decode") {
1401
        if (isset($SETTINGS['encryptClientServer'])
1402
            && $SETTINGS['encryptClientServer'] === "0"
1403
        ) {
1404
            return json_decode(
1405
                $data,
1406
                true
1407
            );
1408
        } else {
1409
            return json_decode(
1410
                Encryption\Crypt\aesctr::decrypt(
1411
                    $data,
1412
                    $_SESSION['key'],
1413
                    256
1414
                ),
1415
                true
1416
            );
1417
        }
1418
    }
1419
}
1420
1421
function make_thumb($src, $dest, $desired_width)
1422
{
1423
    /* read the source image */
1424
    $source_image = imagecreatefrompng($src);
1425
    $width = imagesx($source_image);
1426
    $height = imagesy($source_image);
1427
1428
    /* find the "desired height" of this thumbnail, relative to the desired width  */
1429
    $desired_height = floor($height * ($desired_width / $width));
1430
1431
    /* create a new, "virtual" image */
1432
    $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

1432
    $virtual_image = imagecreatetruecolor($desired_width, /** @scrutinizer ignore-type */ $desired_height);
Loading history...
1433
1434
    /* copy source image at a resized size */
1435
    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

1435
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, /** @scrutinizer ignore-type */ $desired_height, $width, $height);
Loading history...
1436
1437
    /* create the physical thumbnail image to its destination */
1438
    imagejpeg($virtual_image, $dest);
1439
}
1440
1441
/*
1442
** check table prefix in SQL query
1443
*/
1444
/**
1445
 * @param string $table
1446
 */
1447
function prefix_table($table)
1448
{
1449
    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...
1450
    $safeTable = htmlspecialchars($pre.$table);
1451
    if (!empty($safeTable)) {
1452
        // sanitize string
1453
        return $safeTable;
1454
    } else {
1455
        // stop error no table
1456
        return "table_not_exists";
1457
    }
1458
}
1459
1460
/*
1461
 * Creates a KEY using PasswordLib
1462
 */
1463
function GenerateCryptKey($size = "", $secure = false, $numerals = false, $capitalize = false, $symbols = false)
1464
{
1465
    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...
1466
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1467
1468
    if ($secure === true) {
1469
        $numerals = true;
1470
        $capitalize = true;
1471
        $symbols = true;
1472
    }
1473
1474
    // Load libraries
1475
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
1476
    $generator->register();
1477
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
1478
1479
    // Can we use PHP7 random_int function?
1480
    if (version_compare(phpversion(), '7.0', '>=')) {
1481
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/PasswordGenerator/RandomGenerator/Php7RandomGenerator.php';
1482
         $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
1483
    }
1484
1485
    // init
1486
    if (!empty($size)) {
1487
        $generator->setLength(intval($size));
1488
    }
1489
    if (!empty($numerals)) {
1490
        $generator->setNumbers($numerals);
1491
    }
1492
    if (!empty($capitalize)) {
1493
        $generator->setUppercase($capitalize);
1494
    }
1495
    if (!empty($symbols)) {
1496
        $generator->setSymbols($symbols);
1497
    }
1498
1499
    // generate and send back
1500
    return $generator->generatePassword();
1501
}
1502
1503
/*
1504
* Send sysLOG message
1505
* @param string $message
1506
* @param string $host
1507
*/
1508
function send_syslog($message, $host, $port, $component = "teampass")
1509
{
1510
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
1511
    $syslog_message = "<123>".date('M d H:i:s ').$component.": ".$message;
1512
    socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $host, $port);
1513
    socket_close($sock);
1514
}
1515
1516
1517
1518
/**
1519
 * logEvents()
1520
 *
1521
 * permits to log events into DB
1522
 * @param string $type
1523
 * @param string $label
1524
 * @param string $field_1
1525
 */
1526
function logEvents($type, $label, $who, $login = "", $field_1 = null)
1527
{
1528
    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...
1529
    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...
1530
1531
    if (empty($who)) {
1532
        $who = get_client_ip_server();
1533
    }
1534
1535
    // include librairies & connect to DB
1536
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1537
    $pass = defuse_return_decrypted($pass);
1538
    DB::$host = $server;
1539
    DB::$user = $user;
1540
    DB::$password = $pass;
1541
    DB::$dbName = $database;
1542
    DB::$port = $port;
1543
    DB::$encoding = $encoding;
1544
    DB::$error_handler = true;
1545
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1546
    $link->set_charset($encoding);
1547
1548
    DB::insert(
1549
        prefix_table("log_system"),
1550
        array(
1551
            'type' => $type,
1552
            'date' => time(),
1553
            'label' => $label,
1554
            'qui' => $who,
1555
            'field_1' => $field_1 === null ? "" : $field_1
1556
        )
1557
    );
1558
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1559
        if ($type == "user_mngt") {
1560
            send_syslog(
1561
                'action='.str_replace('at_', '', $label).' attribute=user user='.$who.' userid="'.$login.'" change="'.$field_1.'" ',
1562
                $SETTINGS['syslog_host'],
1563
                $SETTINGS['syslog_port'],
1564
                "teampass"
1565
            );
1566
        } else {
1567
            send_syslog(
1568
                'action='.$type.' attribute='.$label.' user='.$who.' userid="'.$login.'" ',
1569
                $SETTINGS['syslog_host'],
1570
                $SETTINGS['syslog_port'],
1571
                "teampass"
1572
            );
1573
        }
1574
    }
1575
}
1576
1577
/**
1578
 * Logs sent events
1579
 *
1580
 * @param string $ident
1581
 * @param string $item
1582
 * @param string $id_user
1583
 * @param string $action
1584
 * @param string $login
1585
 * @param string $raison
1586
 * @param string $raison_iv
1587
 * @param string $encryption_type
1588
 * @return void
1589
 */
1590
function logItems($ident, $item, $id_user, $action, $login = "", $raison = null, $raison_iv = null, $encryption_type = "")
1591
{
1592
    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...
1593
    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...
1594
1595
    // include librairies & connect to DB
1596
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1597
    $pass = defuse_return_decrypted($pass);
1598
    DB::$host = $server;
1599
    DB::$user = $user;
1600
    DB::$password = $pass;
1601
    DB::$dbName = $database;
1602
    DB::$port = $port;
1603
    DB::$encoding = $encoding;
1604
    DB::$error_handler = true;
1605
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1606
    $link->set_charset($encoding);
1607
    DB::insert(
1608
        prefix_table("log_items"),
1609
        array(
1610
            'id_item' => $ident,
1611
            'date' => time(),
1612
            'id_user' => $id_user,
1613
            'action' => $action,
1614
            'raison' => $raison,
1615
            'raison_iv' => $raison_iv,
1616
            'encryption_type' => $encryption_type
1617
        )
1618
    );
1619
1620
    // Syslog
1621
    if (isset($SETTINGS['syslog_enable']) === true && $SETTINGS['syslog_enable'] === '1') {
1622
        // Extract reason
1623
        $attribute = explode(' : ', $raison);
1624
1625
        send_syslog(
1626
            'action='.str_replace('at_', '', $action).' attribute='.str_replace('at_', '', $attribute[0]).' itemno='.$ident.' user='.$login.' itemname="'.$item.'"',
1627
            $SETTINGS['syslog_host'],
1628
            $SETTINGS['syslog_port'],
1629
            "teampass"
1630
        );
1631
    }
1632
}
1633
1634
/*
1635
* Function to get the client ip address
1636
 */
1637
function get_client_ip_server()
1638
{
1639
    if (getenv('HTTP_CLIENT_IP')) {
1640
            $ipaddress = getenv('HTTP_CLIENT_IP');
1641
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
1642
            $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
1643
    } elseif (getenv('HTTP_X_FORWARDED')) {
1644
            $ipaddress = getenv('HTTP_X_FORWARDED');
1645
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
1646
            $ipaddress = getenv('HTTP_FORWARDED_FOR');
1647
    } elseif (getenv('HTTP_FORWARDED')) {
1648
            $ipaddress = getenv('HTTP_FORWARDED');
1649
    } elseif (getenv('REMOTE_ADDR')) {
1650
            $ipaddress = getenv('REMOTE_ADDR');
1651
    } else {
1652
            $ipaddress = 'UNKNOWN';
1653
    }
1654
1655
    return $ipaddress;
1656
}
1657
1658
/**
1659
 * Escape all HTML, JavaScript, and CSS
1660
 *
1661
 * @param string $input The input string
1662
 * @param string $encoding Which character encoding are we using?
1663
 * @return string
1664
 */
1665
function noHTML($input, $encoding = 'UTF-8')
1666
{
1667
    return htmlspecialchars($input, ENT_QUOTES | ENT_XHTML, $encoding, false);
1668
}
1669
1670
/**
1671
 * handleConfigFile()
1672
 *
1673
 * permits to handle the Teampass config file
1674
 * $action accepts "rebuild" and "update"
1675
 */
1676
function handleConfigFile($action, $field = null, $value = null)
1677
{
1678
    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...
1679
    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...
1680
1681
    $tp_config_file = "../includes/config/tp.config.php";
1682
1683
    // include librairies & connect to DB
1684
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1685
    $pass = defuse_return_decrypted($pass);
1686
    DB::$host = $server;
1687
    DB::$user = $user;
1688
    DB::$password = $pass;
1689
    DB::$dbName = $database;
1690
    DB::$port = $port;
1691
    DB::$encoding = $encoding;
1692
    DB::$error_handler = true;
1693
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1694
    $link->set_charset($encoding);
1695
1696
    if (!file_exists($tp_config_file) || $action == "rebuild") {
1697
        // perform a copy
1698
        if (file_exists($tp_config_file)) {
1699
            if (!copy($tp_config_file, $tp_config_file.'.'.date("Y_m_d_His", time()))) {
1700
                return "ERROR: Could not copy file '".$tp_config_file."'";
1701
            }
1702
        }
1703
1704
        // regenerate
1705
        $data = array();
1706
        $data[0] = "<?php\n";
1707
        $data[1] = "global \$SETTINGS;\n";
1708
        $data[2] = "\$SETTINGS = array (\n";
1709
        $rows = DB::query(
1710
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s",
1711
            "admin"
1712
        );
1713
        foreach ($rows as $record) {
1714
            array_push($data, "    '".$record['intitule']."' => '".$record['valeur']."',\n");
1715
        }
1716
        array_push($data, ");\n");
1717
        $data = array_unique($data);
1718
    } elseif ($action == "update" && empty($field) === false) {
1719
        $data = file($tp_config_file);
1720
        $inc = 0;
1721
        $bFound = false;
1722
        foreach ($data as $line) {
1723
            if (stristr($line, ");")) {
1724
                break;
1725
            }
1726
1727
            //
1728
            if (stristr($line, "'".$field."' => '")) {
1729
                $data[$inc] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n";
1730
                $bFound = true;
1731
                break;
1732
            }
1733
            $inc++;
1734
        }
1735
        if ($bFound === false) {
1736
            $data[($inc)] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n);\n";
1737
        }
1738
    }
1739
1740
    // update file
1741
    file_put_contents($tp_config_file, implode('', isset($data) ? $data : array()));
1742
1743
    return true;
1744
}
1745
1746
/*
1747
** Permits to replace &#92; to permit correct display
1748
*/
1749
/**
1750
 * @param string $input
1751
 */
1752
function handleBackslash($input)
1753
{
1754
    return str_replace("&amp;#92;", "&#92;", $input);
1755
}
1756
1757
/*
1758
** Permits to loas settings
1759
*/
1760
function loadSettings()
1761
{
1762
    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...
1763
1764
    /* LOAD CPASSMAN SETTINGS */
1765
    if (!isset($SETTINGS['loaded']) || $SETTINGS['loaded'] != 1) {
1766
        $SETTINGS['duplicate_folder'] = 0; //by default, this is set to 0;
1767
        $SETTINGS['duplicate_item'] = 0; //by default, this is set to 0;
1768
        $SETTINGS['number_of_used_pw'] = 5; //by default, this value is set to 5;
1769
        $settings = array();
1770
1771
        $rows = DB::query(
1772
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s_type OR type=%s_type2",
1773
            array(
1774
                'type' => "admin",
1775
                'type2' => "settings"
1776
            )
1777
        );
1778
        foreach ($rows as $record) {
1779
            if ($record['type'] == 'admin') {
1780
                $SETTINGS[$record['intitule']] = $record['valeur'];
1781
            } else {
1782
                $settings[$record['intitule']] = $record['valeur'];
1783
            }
1784
        }
1785
        $SETTINGS['loaded'] = 1;
1786
        $SETTINGS['default_session_expiration_time'] = 5;
1787
    }
1788
}
1789
1790
/*
1791
** check if folder has custom fields.
1792
** Ensure that target one also has same custom fields
1793
*/
1794
function checkCFconsistency($source_id, $target_id)
1795
{
1796
    $source_cf = array();
1797
    $rows = DB::QUERY(
1798
        "SELECT id_category
1799
        FROM ".prefix_table("categories_folders")."
1800
        WHERE id_folder = %i",
1801
        $source_id
1802
    );
1803
    foreach ($rows as $record) {
1804
        array_push($source_cf, $record['id_category']);
1805
    }
1806
1807
    $target_cf = array();
1808
    $rows = DB::QUERY(
1809
        "SELECT id_category
1810
        FROM ".prefix_table("categories_folders")."
1811
        WHERE id_folder = %i",
1812
        $target_id
1813
    );
1814
    foreach ($rows as $record) {
1815
        array_push($target_cf, $record['id_category']);
1816
    }
1817
1818
    $cf_diff = array_diff($source_cf, $target_cf);
1819
    if (count($cf_diff) > 0) {
1820
        return false;
1821
    }
1822
1823
    return true;
1824
}
1825
1826
/*
1827
*
1828
*/
1829
function encrypt_or_decrypt_file($filename_to_rework, $filename_status)
1830
{
1831
    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...
1832
    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...
1833
1834
    // Include librairies & connect to DB
1835
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1836
    $pass = defuse_return_decrypted($pass);
1837
    DB::$host = $server;
1838
    DB::$user = $user;
1839
    DB::$password = $pass;
1840
    DB::$dbName = $database;
1841
    DB::$port = $port;
1842
    DB::$encoding = $encoding;
1843
    DB::$error_handler = true;
1844
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1845
    $link->set_charset($encoding);
1846
1847
    // Get file info in DB
1848
    $fileInfo = DB::queryfirstrow(
1849
        "SELECT id FROM ".prefix_table("files")." WHERE file = %s",
1850
        filter_var($filename_to_rework, FILTER_SANITIZE_STRING)
1851
    );
1852
    if (empty($fileInfo['id']) === false) {
1853
        // Load PhpEncryption library
1854
        $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
1855
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
1856
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
1857
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
1858
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
1859
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
1860
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
1861
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
1862
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
1863
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
1864
1865
        // Get KEY
1866
        $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...
1867
1868
        if (isset($SETTINGS['enable_attachment_encryption'])
1869
            && $SETTINGS['enable_attachment_encryption'] === "1" &&
1870
            isset($filename_status)
1871
            && ($filename_status === "clear"
1872
                || $filename_status === "0")
1873
        ) {
1874
            // File needs to be encrypted
1875
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1876
                // Make a copy of file
1877
                if (!copy(
1878
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1879
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1880
                )) {
1881
                    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...
1882
                } else {
1883
                    // Do a bck
1884
                    copy(
1885
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1886
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1887
                    );
1888
                }
1889
1890
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1891
1892
                // Now encrypt the file with saltkey
1893
                $err = '';
1894
                try {
1895
                    \Defuse\Crypto\File::encryptFile(
1896
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1897
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1898
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1899
                    );
1900
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1901
                    $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.";
1902
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1903
                    $err = $ex;
1904
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1905
                    $err = $ex;
1906
                }
1907
                if (empty($err) === false) {
1908
                    echo $err;
1909
                }
1910
1911
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1912
1913
                // update table
1914
                DB::update(
1915
                    prefix_table('files'),
1916
                    array(
1917
                        'status' => 'encrypted'
1918
                        ),
1919
                    "id = %i",
1920
                    $fileInfo['id']
1921
                );
1922
            }
1923
        } elseif (isset($SETTINGS['enable_attachment_encryption'])
1924
            && $SETTINGS['enable_attachment_encryption'] === "0"
1925
            && isset($filename_status)
1926
            && $filename_status === "encrypted"
1927
        ) {
1928
            // file needs to be decrypted
1929
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1930
                // make a copy of file
1931
                if (!copy(
1932
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1933
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1934
                )) {
1935
                    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...
1936
                } else {
1937
                    // do a bck
1938
                    copy(
1939
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1940
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1941
                    );
1942
                }
1943
1944
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1945
1946
                // Now encrypt the file with saltkey
1947
                $err = '';
1948
                try {
1949
                    \Defuse\Crypto\File::decryptFile(
1950
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1951
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1952
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1953
                    );
1954
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1955
                    $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.";
1956
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1957
                    $err = $ex;
1958
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1959
                    $err = $ex;
1960
                }
1961
                if (empty($err) === false) {
1962
                    echo $err;
1963
                }
1964
1965
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1966
1967
                // update table
1968
                DB::update(
1969
                    prefix_table('files'),
1970
                    array(
1971
                        'status' => 'clear'
1972
                        ),
1973
                    "id = %i",
1974
                    $fileInfo['id']
1975
                );
1976
            }
1977
        }
1978
    }
1979
1980
    // Exit
1981
    return false;
1982
}
1983
1984
/**
1985
 * Will encrypte/decrypt a fil eusing Defuse
1986
 * @param  string $type        can be either encrypt or decrypt
1987
 * @param  string $source_file path to source file
1988
 * @param  string $target_file path to target file
1989
 * @return string              'true' is success or error message
1990
 */
1991
function prepareFileWithDefuse($type, $source_file, $target_file, $password = '')
1992
{
1993
    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...
1994
1995
    // Load AntiXSS
1996
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
1997
    $antiXss = new protect\AntiXSS\AntiXSS();
1998
1999
    // Protect against bad inputs
2000
    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...
2001
        return 'error_cannot_be_array';
2002
    }
2003
2004
    // Sanitize
2005
    $source_file = $antiXss->xss_clean($source_file);
2006
    $target_file = $antiXss->xss_clean($target_file);
2007
2008
    // load PhpEncryption library
2009
    $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
2010
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
2011
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
2012
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
2013
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
2014
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
2015
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
2016
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
2017
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
2018
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
2019
2020
    if (empty($password) === true) {
2021
    /*
2022
    File encryption/decryption is done with the SALTKEY
2023
     */
2024
2025
        // get KEY
2026
        $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...
2027
2028
        // Now perform action on the file
2029
        $err = '';
2030
        if ($type === 'decrypt') {
2031
            try {
2032
                \Defuse\Crypto\File::decryptFile(
2033
                    $source_file,
2034
                    $target_file,
2035
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2036
                );
2037
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2038
                $err = "decryption_not_possible";
2039
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2040
                $err = $ex;
2041
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2042
                $err = $ex;
2043
            }
2044
        } elseif ($type === 'encrypt') {
2045
            try {
2046
                \Defuse\Crypto\File::encryptFile(
2047
                    $source_file,
2048
                    $target_file,
2049
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2050
                );
2051
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2052
                $err = "encryption_not_possible";
2053
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2054
                $err = $ex;
2055
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2056
                $err = $ex;
2057
            }
2058
        }
2059
    } else {
2060
    /*
2061
    File encryption/decryption is done with special password and not the SALTKEY
2062
     */
2063
2064
        $err = '';
2065
        if ($type === 'decrypt') {
2066
            try {
2067
                \Defuse\Crypto\File::decryptFileWithPassword(
2068
                    $source_file,
2069
                    $target_file,
2070
                    $password
2071
                );
2072
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2073
                $err = "wrong_key";
2074
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2075
                $err = $ex;
2076
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2077
                $err = $ex;
2078
            }
2079
        } elseif ($type === 'encrypt') {
2080
            try {
2081
                \Defuse\Crypto\File::encryptFileWithPassword(
2082
                    $source_file,
2083
                    $target_file,
2084
                    $password
2085
                );
2086
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2087
                $err = "wrong_key";
2088
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2089
                $err = $ex;
2090
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2091
                $err = $ex;
2092
            }
2093
        }
2094
    }
2095
2096
    // return error
2097
    if (empty($err) === false) {
2098
        return $err;
2099
    } else {
2100
        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...
2101
    }
2102
}
2103
2104
/*
2105
* NOT TO BE USED
2106
*/
2107
function debugTeampass($text)
2108
{
2109
    $debugFile = fopen('D:/wamp64/www/TeamPass/debug.txt', 'r+');
2110
    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

2110
    fputs(/** @scrutinizer ignore-type */ $debugFile, $text);
Loading history...
2111
    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

2111
    fclose(/** @scrutinizer ignore-type */ $debugFile);
Loading history...
2112
}
2113
2114
2115
/**
2116
 * DELETE the file with expected command depending on server type
2117
 * @param  string $file Path to file
2118
 * @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...
2119
 */
2120
function fileDelete($file)
2121
{
2122
    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...
2123
2124
    // Load AntiXSS
2125
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2126
    $antiXss = new protect\AntiXSS\AntiXSS();
2127
2128
    $file = $antiXss->xss_clean($file);
2129
    if (is_file($file)) {
2130
        unlink($file);
2131
    }
2132
}
2133
2134
/*
2135
* Permits to extract the file extension
2136
*/
2137
function getFileExtension($file)
2138
{
2139
    if (strpos($file, '.') === false) {
2140
        return $file;
2141
    }
2142
2143
    return substr($file, strrpos($file, '.') + 1);
2144
}
2145
2146
/**
2147
 * array_map
2148
 * @param  [type] $func [description]
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...
2149
 * @param  [type] $arr  [description]
2150
 * @return [type]       [description]
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...
2151
 */
2152
function array_map_r($func, $arr)
2153
{
2154
    $newArr = array();
2155
2156
    foreach ($arr as $key => $value) {
2157
        $newArr[ $key ] = (is_array($value) ? array_map_r($func, $value) : ( is_array($func) ? call_user_func_array($func, $value) : $func( $value )));
2158
    }
2159
2160
    return $newArr;
2161
}
2162
2163
/**
2164
 * Permits to clean and sanitize text to be displayed
2165
 * @param  string $text text to clean
2166
 * @param  string $type what clean to perform
2167
 * @return string       text cleaned up
2168
 */
2169
function cleanText($string, $type = "")
2170
{
2171
    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...
2172
2173
    // Load AntiXSS
2174
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2175
    $antiXss = new protect\AntiXSS\AntiXSS();
2176
2177
    if ($type === "css") {
2178
        // Escape text and quotes in UTF8 format
2179
        return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
2180
    } elseif ($type === "html" || empty($type)) {
2181
        // Html cleaner
2182
        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...
2183
    }
2184
}
2185
2186
/**
2187
 * Performs chmod operation on subfolders
2188
 * @param  string  $dir             Parent folder
2189
 * @param  integer $dirPermissions  New permission on folders
2190
 * @param  integer $filePermissions New permission on files
2191
 * @return boolean                  Success/Failure
2192
 */
2193
function chmodRecursive($dir, $dirPermissions, $filePermissions)
2194
{
2195
    $pointer_dir = opendir($dir);
2196
    $res = true;
2197
    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

2197
    while ($file = readdir(/** @scrutinizer ignore-type */ $pointer_dir)) {
Loading history...
2198
        if (($file == ".") || ($file == "..")) {
2199
            continue;
2200
        }
2201
2202
        $fullPath = $dir."/".$file;
2203
2204
        if (is_dir($fullPath)) {
2205
            if ($res = @chmod($fullPath, $dirPermissions)) {
2206
                $res = @chmodRecursive($fullPath, $dirPermissions, $filePermissions);
2207
            }
2208
        } else {
2209
            $res = chmod($fullPath, $filePermissions);
2210
        }
2211
        if (!$res) {
2212
            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

2212
            closedir(/** @scrutinizer ignore-type */ $pointer_dir);
Loading history...
2213
            return false;
2214
        }
2215
    }
2216
    closedir($pointer_dir);
2217
    if (is_dir($dir) && $res) {
2218
        $res = @chmod($dir, $dirPermissions);
2219
    }
2220
2221
    return $res;
2222
}
2223
2224
/**
2225
 * Check if user can access to this item
2226
 * @param $item_id
2227
 */
2228
function accessToItemIsGranted($item_id)
2229
{
2230
    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...
2231
2232
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2233
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2234
2235
    // Prepare superGlobal variables
2236
    $session_groupes_visibles = $superGlobal->get("groupes_visibles", "SESSION");
2237
    $session_list_restricted_folders_for_items = $superGlobal->get("list_restricted_folders_for_items", "SESSION");
2238
2239
    // Load item data
2240
    $data = DB::queryFirstRow(
2241
        "SELECT id_tree
2242
        FROM ".prefix_table("items")."
2243
        WHERE id = %i",
2244
        $item_id
2245
    );
2246
2247
    // Check if user can access this folder
2248
    if (in_array($data['id_tree'], $session_groupes_visibles) === false) {
2249
        // Now check if this folder is restricted to user
2250
        if (isset($session_list_restricted_folders_for_items[$data['id_tree']])
2251
            && !in_array($item_id, $session_list_restricted_folders_for_items[$data['id_tree']])
2252
        ) {
2253
            return "ERR_FOLDER_NOT_ALLOWED";
2254
        } else {
2255
            return "ERR_FOLDER_NOT_ALLOWED";
2256
        }
2257
    }
2258
2259
    return true;
2260
}
2261
2262
/**
2263
 * Creates a unique key
2264
 * @lenght  integer $lenght key lenght
2265
 * @return string          key
2266
 */
2267
function uniqidReal($lenght = 13) {
2268
    // uniqid gives 13 chars, but you could adjust it to your needs.
2269
    if (function_exists("random_bytes")) {
2270
        $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

2270
        $bytes = random_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2271
    } elseif (function_exists("openssl_random_pseudo_bytes")) {
2272
        $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

2272
        $bytes = openssl_random_pseudo_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2273
    } else {
2274
        throw new Exception("no cryptographically secure random function available");
2275
    }
2276
    return substr(bin2hex($bytes), 0, $lenght);
2277
}
2278
2279
/**
2280
 * Obfuscate an email address
2281
 * @email {string}  email address
2282
 */
2283
function obfuscate_email($email)
2284
{
2285
    $prop = 2;
2286
    $domain = substr(strrchr($email, "@"), 1);
2287
    $mailname = str_replace($domain, '', $email);
2288
    $name_l = strlen($mailname);
2289
    $domain_l = strlen($domain);
2290
    for($i = 0; $i <= $name_l/$prop-1; $i++) {
2291
        $start .= 'x';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $start seems to be never defined.
Loading history...
2292
    }
2293
2294
    for($i = 0; $i <= $domain_l/$prop-1; $i++) {
2295
        $end .= 'x';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $end seems to be never defined.
Loading history...
2296
    }
2297
2298
    return substr_replace(
2299
        $mailname,
2300
        $start,
2301
        2,
2302
        $name_l/$prop
2303
    ).substr_replace(
2304
        $domain,
2305
        $end,
2306
        2,
2307
        $domain_l/$prop
2308
    ); 
2309
}
2310
2311