Passed
Push — devel-3.0 ( 6b6d4a...0e3c8b )
by Rubén
03:12
created

Util::unserialize()   B

Complexity

Conditions 9
Paths 8

Size

Total Lines 38
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 19
nc 8
nop 3
dl 0
loc 38
rs 8.0555
c 0
b 0
f 0
1
<?php
2
/**
3
 * sysPass
4
 *
5
 * @author    nuxsmin
6
 * @link      https://syspass.org
7
 * @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
8
 *
9
 * This file is part of sysPass.
10
 *
11
 * sysPass is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation, either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * sysPass is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 *  along with sysPass.  If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
namespace SP\Util;
26
27
use Defuse\Crypto\Core;
28
use Defuse\Crypto\Encoding;
29
30
defined('APP_ROOT') || die();
31
32
/**
33
 * Clase con utilizades para la aplicación
34
 */
35
final class Util
36
{
37
    /**
38
     * Generar una clave aleatoria
39
     *
40
     * @param int  $length     Longitud de la clave
41
     * @param bool $useNumbers Usar números
42
     * @param bool $useSpecial Usar carácteres especiales
43
     * @param bool $checKStrength
44
     *
45
     * @return string
46
     */
47
    public static function randomPassword($length = 16, $useNumbers = true, $useSpecial = true, $checKStrength = true)
48
    {
49
        $charsLower = 'abcdefghijklmnopqrstuwxyz';
50
        $charsUpper = 'ABCDEFGHIJKLMNOPQRSTUWXYZ';
51
52
        $alphabet = $charsLower . $charsUpper;
53
54
        if ($useSpecial === true) {
55
            $charsSpecial = '@$%&/()!_:.;{}^';
56
            $alphabet .= $charsSpecial;
57
        }
58
59
        if ($useNumbers === true) {
60
            $charsNumbers = '0123456789';
61
            $alphabet .= $charsNumbers;
62
        }
63
64
        /**
65
         * @return array
66
         */
67
        $passGen = function () use ($alphabet, $length) {
68
            $pass = [];
69
            $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
70
71
            for ($i = 0; $i < $length; $i++) {
72
                $n = mt_rand(0, $alphaLength);
73
                $pass[] = $alphabet[$n];
74
            }
75
76
            return $pass;
77
        };
78
79
        if ($checKStrength === true) {
80
            do {
81
                $pass = $passGen();
82
                $strength = ['lower' => 0, 'upper' => 0, 'special' => 0, 'number' => 0];
83
84
                foreach ($pass as $char) {
85
                    if (strpos($charsLower, $char) !== false) {
86
                        $strength['lower']++;
87
                    } elseif (strpos($charsUpper, $char) !== false) {
88
                        $strength['upper']++;
89
                    } elseif ($useSpecial === true && strpos($charsSpecial, $char) !== false) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $charsSpecial does not seem to be defined for all execution paths leading up to this point.
Loading history...
90
                        $strength['special']++;
91
                    } elseif ($useNumbers === true && strpos($charsNumbers, $char) !== false) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $charsNumbers does not seem to be defined for all execution paths leading up to this point.
Loading history...
92
                        $strength['number']++;
93
                    }
94
                }
95
96
                if ($useSpecial === false) {
97
                    unset($strength['special']);
98
                }
99
100
                if ($useNumbers === false) {
101
                    unset($strength['number']);
102
                }
103
            } while (in_array(0, $strength, true));
104
105
            return implode($pass);
106
        }
107
108
        return implode($passGen());
109
    }
110
111
    /**
112
     * Generar una cadena aleatoria usuando criptografía.
113
     *
114
     * @param int $length opcional, con la longitud de la cadena
115
     *
116
     * @return string
117
     * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
118
     */
119
    public static function generateRandomBytes($length = 30)
120
    {
121
        return Encoding::binToHex(Core::secureRandom($length));
122
    }
123
124
    /**
125
     * Comprueba y devuelve un directorio temporal válido
126
     *
127
     * @return bool|string
128
     */
129
    public static function getTempDir()
130
    {
131
        $sysTmp = sys_get_temp_dir();
132
        $appTmp = APP_PATH . DIRECTORY_SEPARATOR . 'temp';
133
        $file = 'syspass.test';
134
135
        $checkDir = function ($dir) use ($file) {
136
            if (file_exists($dir . DIRECTORY_SEPARATOR . $file)) {
137
                return $dir;
138
            }
139
140
            if (is_dir($dir) || @mkdir($dir)) {
141
                if (touch($dir . DIRECTORY_SEPARATOR . $file)) {
142
                    return $dir;
143
                }
144
            }
145
146
            return false;
147
        };
148
149
        if ($checkDir($appTmp)) {
150
            return $appTmp;
151
        }
152
153
        return $checkDir($sysTmp);
154
    }
155
156
    /**
157
     * Realiza el proceso de logout.
158
     *
159
     * FIXME
160
     */
161
    public static function logout()
162
    {
163
        exit('<script>sysPassApp.actions.main.logout();</script>');
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...
164
    }
165
166
    /**
167
     * Obtener el tamaño máximo de subida de PHP.
168
     */
169
    public static function getMaxUpload()
170
    {
171
        $max_upload = (int)ini_get('upload_max_filesize');
172
        $max_post = (int)ini_get('post_max_size');
173
        $memory_limit = (int)ini_get('memory_limit');
174
175
        return min($max_upload, $max_post, $memory_limit);
176
    }
177
178
    /**
179
     * Checks a variable to see if it should be considered a boolean true or false.
180
     * Also takes into account some text-based representations of true of false,
181
     * such as 'false','N','yes','on','off', etc.
182
     *
183
     * @author Samuel Levy <[email protected]>
184
     *
185
     * @param mixed $in     The variable to check
186
     * @param bool  $strict If set to false, consider everything that is not false to
187
     *                      be true.
188
     *
189
     * @return bool The boolean equivalent or null (if strict, and no exact equivalent)
190
     */
191
    public static function boolval($in, $strict = false)
192
    {
193
        $in = is_string($in) ? strtolower($in) : $in;
194
195
        // if not strict, we only have to check if something is false
196
        if (in_array($in, ['false', 'no', 'n', '0', 'off', false, 0], true) || !$in) {
197
            return false;
198
        }
199
200
        if ($strict && in_array($in, ['true', 'yes', 'y', '1', 'on', true, 1], true)) {
201
            return true;
202
        }
203
204
        // not strict? let the regular php bool check figure it out (will
205
        // largely default to true)
206
        return ($in ? true : false);
207
    }
208
209
    /**
210
     * Cast an object to another class, keeping the properties, but changing the methods
211
     *
212
     * @param string        $dstClass Destination class name
213
     * @param string|object $serialized
214
     * @param string        $srcClass Old class name for removing from private methods
215
     *
216
     * @return mixed
217
     */
218
    public static function unserialize($dstClass, $serialized, $srcClass = null)
219
    {
220
        if (!is_object($serialized)) {
221
            $match = preg_match_all('/O:\d+:"(?P<class>[^"]++)"/', $serialized, $matches);
222
223
            $process = false;
224
225
            if ($match) {
226
                foreach ($matches['class'] as $class) {
227
                    if (!class_exists($class)
228
                        || $class !== $dstClass
229
                    ) {
230
                        $process = true;
231
                    }
232
                }
233
234
                if ($process === false) {
235
                    return unserialize($serialized);
236
                }
237
            }
238
239
            // Serialized data needs to be processed to change the class name
240
            if ($process === true) {
241
                // If source class is set, it will try to clean up the class name from private methods
242
                if ($srcClass !== null) {
243
                    $serialized = preg_replace_callback(
244
                        '/:\d+:"\x00' . preg_quote($srcClass, '/') . '\x00(\w+)"/',
245
                        function ($matches) {
246
                            return ':' . strlen($matches[1]) . ':"' . $matches[1] . '"';
247
                        },
248
                        $serialized);
249
                }
250
251
                return self::castToClass($serialized, $dstClass);
252
            }
253
        }
254
255
        return $serialized;
256
    }
257
258
    /**
259
     * Cast an object to another class
260
     *
261
     * @param $cast
262
     * @param $class
263
     *
264
     * @return mixed
265
     */
266
    public static function castToClass($cast, $class)
267
    {
268
        // TODO: should avoid '__PHP_Incomplete_Class'?
269
270
        $cast = is_object($cast) ? serialize($cast) : $cast;
271
272
        return unserialize(preg_replace('/O:\d+:"[^"]++"/', 'O:' . strlen($class) . ':"' . $class . '"', $cast));
273
    }
274
275
    /**
276
     * Bloquear la aplicación
277
     *
278
     * @param int    $userId
279
     * @param string $subject
280
     *
281
     * @return bool
282
     */
283
    public static function lockApp($userId, $subject)
284
    {
285
        $data = ['time' => time(), 'userId' => (int)$userId, 'subject' => $subject];
286
287
        return file_put_contents(LOCK_FILE, json_encode($data));
0 ignored issues
show
Bug Best Practice introduced by
The expression return file_put_contents...LE, json_encode($data)) returns the type integer which is incompatible with the documented return type boolean.
Loading history...
288
    }
289
290
    /**
291
     * Desbloquear la aplicación
292
     *
293
     * @return bool
294
     */
295
    public static function unlockApp()
296
    {
297
        return @unlink(LOCK_FILE);
298
    }
299
300
    /**
301
     * Comprueba si la aplicación está bloqueada
302
     *
303
     * @return int
304
     */
305
    public static function getAppLock()
306
    {
307
        if (file_exists(LOCK_FILE)
308
            && ($data = file_get_contents(LOCK_FILE)) !== false
309
        ) {
310
            return json_decode($data) ?: false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return json_decode($data) ?: false could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
311
        }
312
313
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
314
    }
315
316
    /**
317
     * Devolver el tiempo aproximado en segundos de una operación
318
     *
319
     * @param $startTime
320
     * @param $numItems
321
     * @param $totalItems
322
     *
323
     * @return array Con el tiempo estimado y los elementos por segundo
324
     */
325
    public static function getETA($startTime, $numItems, $totalItems)
326
    {
327
        if ($numItems > 0 && $totalItems > 0) {
328
            $runtime = time() - $startTime;
329
            $eta = (int)((($totalItems * $runtime) / $numItems) - $runtime);
330
331
            return [$eta, $numItems / $runtime];
332
        }
333
334
        return [0, 0];
335
    }
336
337
    /**
338
     * Adaptador para convertir una cadena de IDs a un array
339
     *
340
     * @param string $itemsId
341
     * @param string $delimiter
342
     *
343
     * @return array
344
     */
345
    public static function itemsIdAdapter(string $itemsId, $delimiter = ','): array
346
    {
347
        return array_map(function ($value) {
348
            return intval($value);
349
        }, explode($delimiter, $itemsId));
350
    }
351
}
352