GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Password::isStrongPassword()   F
last analyzed

Complexity

Conditions 47
Paths > 20000

Size

Total Lines 233
Code Lines 171

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 47
eloc 171
nc 4753728
nop 4
dl 0
loc 233
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php namespace Myth\Auth;
2
/**
3
 * Sprint
4
 *
5
 * A set of power tools to enhance the CodeIgniter framework and provide consistent workflow.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 *
25
 * @package     Sprint
26
 * @author      Lonnie Ezell
27
 * @copyright   Copyright 2014-2015, New Myth Media, LLC (http://newmythmedia.com)
28
 * @license     http://opensource.org/licenses/MIT  (MIT)
29
 * @link        http://sprintphp.com
30
 * @since       Version 1.0
31
 */
32
33
define('DICTIONARY_PATH', dirname(__FILE__) .'/dictionary.txt');
34
35
/**
36
 * Class Password
37
 *
38
 * Provides methods to determine how secure a password is. Uses code from
39
 * Barebones CMS's SSO - licensed MIT.
40
 * See their download page at http://barebonescms.com/documentation/sso/
41
 * for details on the licensing.
42
 *
43
 * For information and background on the algorithm they implemented,
44
 * see the following blog posts:
45
 *
46
 *      Part 1 - http://cubicspot.blogspot.com/2011/11/how-to-calculate-password-strength.html
47
 *      Part 2 - http://cubicspot.blogspot.com/2012/01/how-to-calculate-password-strength-part.html
48
 *      Part 3 - http://cubicspot.blogspot.com/2012/06/how-to-calculate-password-strength-part.html
49
 *
50
 * @package Myth\Auth
51
 */
52
class Password {
53
54
    /**
55
     * A standardized method for hasing a password before storing
56
     * in the database.
57
     *
58
     * @param $password
59
     * @return bool|mixed|string
60
     */
61
    public static function hashPassword($password)
62
    {
63
        if (! config_item('auth.hash_cost'))
64
        {
65
            get_instance()->load->config('auth');
66
        }
67
68
        return password_hash($password, PASSWORD_DEFAULT, ['cost' => config_item('auth.hash_cost')]);
69
    }
70
71
    //--------------------------------------------------------------------
72
73
    /**
74
     * Determines the number of entropy bits a password has based on
75
     *
76
     *
77
     * @param $password
78
     * @param bool $repeatcalc
79
     * @return int
80
     */
81
    public static function getNISTNumBits($password, $repeatcalc = false)
82
    {
83
        $y = strlen($password);
84
        if ($repeatcalc)
85
        {
86
            // Variant on NIST rules to reduce long sequences of repeated characters.
87
            $result = 0;
88
            $charmult = array_fill(0, 256, 1);
89
            for ($x = 0; $x < $y; $x++)
90
            {
91
                $tempchr = ord(substr($password, $x, 1));
92
                if ($x > 19)  $result += $charmult[$tempchr];
93
                else if ($x > 7)  $result += $charmult[$tempchr] * 1.5;
94
                else if ($x > 0)  $result += $charmult[$tempchr] * 2;
95
                else  $result += 4;
96
97
                $charmult[$tempchr] *= 0.75;
98
            }
99
100
            return $result;
101
        }
102
        else
103
        {
104 View Code Duplication
            if ($y > 20)  return 4 + (7 * 2) + (12 * 1.5) + $y - 20;
105 View Code Duplication
            if ($y > 8)  return 4 + (7 * 2) + (($y - 8) * 1.5);
106
            if ($y > 1)  return 4 + (($y - 1) * 2);
107
108
            return ($y == 1 ? 4 : 0);
109
        }
110
    }
111
112
    //--------------------------------------------------------------------
113
114
    /**
115
     * Determines whether a password is strong enough to use. You should check
116
     * the password against this method and reject it if the password is not
117
     * strong enough.
118
     *
119
     * The following guidelines come from the author's tests against 10.4 million actual passwords
120
     * ( see post: http://cubicspot.blogspot.com/2012/01/how-to-calculate-password-strength-part.html )
121
     * and represents the suggested minimum entropy bits for different types of sites:
122
     *
123
     *      - 18 bits of entropy = minimum for ANY website.
124
     *      - 25 bits of entropy = minimum for a general purpose web service used relatively widely (e.g. Hotmail).
125
     *      - 30 bits of entropy = minimum for a web service with business critical applications (e.g. SAAS).
126
     *      - 40 bits of entropy = minimum for a bank or other financial service.
127
     *
128
     * The algorithm is based upon a modified version of the NIST rules which suggest the following:
129
     *
130
     *      - The first byte counts as 4 bits.
131
     *      - The next 7 bytes count as 2 bits each.
132
     *      - The next 12 bytes count as 1.5 bits each.
133
     *      - Anything beyond that counts as 1 bit each.
134
     *      - Mixed case + non-alphanumeric = up to 6 extra bits.
135
     *
136
     * @param string    $password   - The password to check
137
     * @param int       $minbits    - Minimum "entropy bits" that is allowed
138
     * @param bool      $usedict    - Should we check the password against a 300,000 word English dictionary?
139
     * @param int       $minwordlen -
140
     * @return bool
141
     */
142
    public static function isStrongPassword($password, $minbits = 18, $usedict = false, $minwordlen = 4)
143
    {
144
        // NIST password strength rules allow up to 6 extra bits for mixed case and non-alphabetic.
145
        $upper = false;
146
        $lower = false;
147
        $numeric = false;
148
        $other = false;
149
        $space = false;
150
        $y = strlen($password);
151
        for ($x = 0; $x < $y; $x++)
152
        {
153
            $tempchr = ord(substr($password, $x, 1));
154
            if ($tempchr >= ord("A") && $tempchr <= ord("Z"))  $upper = true;
155
            else if ($tempchr >= ord("a") && $tempchr <= ord("z"))  $lower = true;
156
            else if ($tempchr >= ord("0") && $tempchr <= ord("9"))  $numeric = true;
157
            else if ($tempchr == ord(" "))  $space = true;
158
            else  $other = true;
159
        }
160
        $extrabits = ($upper && $lower && $other ? ($numeric ? 6 : 5) : ($numeric && !$upper && !$lower ? ($other ? -2 : -6) : 0));
161
        if (!$space)  $extrabits -= 2;
162
        else if (count(explode(" ", preg_replace('/\s+/', " ", $password))) > 3)  $extrabits++;
163
        $result = self::getNISTNumBits($password, true) + $extrabits;
164
165
        $password = strtolower($password);
166
        $revpassword = strrev($password);
167
        $numbits = self::getNISTNumBits($password) + $extrabits;
168
        if ($result > $numbits)  $result = $numbits;
169
170
        // Remove QWERTY strings.
171
        $qwertystrs = array(
172
            "1234567890-qwertyuiopasdfghjkl;zxcvbnm,./",
173
            "1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik,9ol.0p;/-['=]:?_{\"+}",
174
            "1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik9ol0p",
175
            "qazwsxedcrfvtgbyhnujmik,ol.p;/-['=]:?_{\"+}",
176
            "qazwsxedcrfvtgbyhnujmikolp",
177
            "]\"/=[;.-pl,0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1",
178
            "pl0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1",
179
            "]\"/[;.pl,okmijnuhbygvtfcrdxeszwaq",
180
            "plokmijnuhbygvtfcrdxeszwaq",
181
            "014725836914702583697894561230258/369*+-*/",
182
            "abcdefghijklmnopqrstuvwxyz"
183
        );
184
        foreach ($qwertystrs as $qwertystr)
185
        {
186
            $qpassword = $password;
187
            $qrevpassword = $revpassword;
188
            $z = 6;
189
            do
190
            {
191
                $y = strlen($qwertystr) - $z;
192
                for ($x = 0; $x < $y; $x++)
193
                {
194
                    $str = substr($qwertystr, $x, $z);
195
                    $qpassword = str_replace($str, "*", $qpassword);
196
                    $qrevpassword = str_replace($str, "*", $qrevpassword);
197
                }
198
199
                $z--;
200
            } while ($z > 2);
201
202
            $numbits = self::getNISTNumBits($qpassword) + $extrabits;
203
            if ($result > $numbits)  $result = $numbits;
204
            $numbits = self::getNISTNumBits($qrevpassword) + $extrabits;
205
            if ($result > $numbits)  $result = $numbits;
206
207
            if ($result < $minbits)  return false;
208
        }
209
210
        if ($usedict && $result >= $minbits)
211
        {
212
            $passwords = array();
213
214
            // Add keyboard shifting password variants.
215
            $keyboardmap_down_noshift = array(
216
                "z" => "", "x" => "", "c" => "", "v" => "", "b" => "", "n" => "", "m" => "", "," => "", "." => "", "/" => "", "<" => "", ">" => "", "?" => ""
217
            );
218
            if ($password == str_replace(array_keys($keyboardmap_down_noshift), array_values($keyboardmap_down_noshift), $password))
219
            {
220
                $keyboardmap_downright = array(
221
                    "a" => "z",
222
                    "q" => "a",
223
                    "1" => "q",
224
                    "s" => "x",
225
                    "w" => "s",
226
                    "2" => "w",
227
                    "d" => "c",
228
                    "e" => "d",
229
                    "3" => "e",
230
                    "f" => "v",
231
                    "r" => "f",
232
                    "4" => "r",
233
                    "g" => "b",
234
                    "t" => "g",
235
                    "5" => "t",
236
                    "h" => "n",
237
                    "y" => "h",
238
                    "6" => "y",
239
                    "j" => "m",
240
                    "u" => "j",
241
                    "7" => "u",
242
                    "i" => "k",
243
                    "8" => "i",
244
                    "o" => "l",
245
                    "9" => "o",
246
                    "0" => "p",
247
                );
248
249
                $keyboardmap_downleft = array(
250
                    "2" => "q",
251
                    "w" => "a",
252
                    "3" => "w",
253
                    "s" => "z",
254
                    "e" => "s",
255
                    "4" => "e",
256
                    "d" => "x",
257
                    "r" => "d",
258
                    "5" => "r",
259
                    "f" => "c",
260
                    "t" => "f",
261
                    "6" => "t",
262
                    "g" => "v",
263
                    "y" => "g",
264
                    "7" => "y",
265
                    "h" => "b",
266
                    "u" => "h",
267
                    "8" => "u",
268
                    "j" => "n",
269
                    "i" => "j",
270
                    "9" => "i",
271
                    "k" => "m",
272
                    "o" => "k",
273
                    "0" => "o",
274
                    "p" => "l",
275
                    "-" => "p",
276
                );
277
278
                $password2 = str_replace(array_keys($keyboardmap_downright), array_values($keyboardmap_downright), $password);
279
                $passwords[] = $password2;
280
                $passwords[] = strrev($password2);
281
282
                $password2 = str_replace(array_keys($keyboardmap_downleft), array_values($keyboardmap_downleft), $password);
283
                $passwords[] = $password2;
284
                $passwords[] = strrev($password2);
285
            }
286
287
            // Deal with LEET-Speak substitutions.
288
            $leetspeakmap = array(
289
                "@" => "a",
290
                "!" => "i",
291
                "$" => "s",
292
                "1" => "i",
293
                "2" => "z",
294
                "3" => "e",
295
                "4" => "a",
296
                "5" => "s",
297
                "6" => "g",
298
                "7" => "t",
299
                "8" => "b",
300
                "9" => "g",
301
                "0" => "o"
302
            );
303
304
            $password2 = str_replace(array_keys($leetspeakmap), array_values($leetspeakmap), $password);
305
            $passwords[] = $password2;
306
            $passwords[] = strrev($password2);
307
308
            $leetspeakmap["1"] = "l";
309
            $password3 = str_replace(array_keys($leetspeakmap), array_values($leetspeakmap), $password);
310
            if ($password3 != $password2)
311
            {
312
                $passwords[] = $password3;
313
                $passwords[] = strrev($password3);
314
            }
315
316
            // Process the password, while looking for words in the dictionary.
317
            $a = ord("a");
318
            $z = ord("z");
319
            $data = file_get_contents(DICTIONARY_PATH);
320
            foreach ($passwords as $num => $password)
321
            {
322
                $y = strlen($password);
323
                for ($x = 0; $x < $y; $x++)
324
                {
325
                    $tempchr = ord(substr($password, $x, 1));
326
                    if ($tempchr >= $a && $tempchr <= $z)
327
                    {
328
                        for ($x2 = $x + 1; $x2 < $y; $x2++)
329
                        {
330
                            $tempchr = ord(substr($password, $x2, 1));
331
                            if ($tempchr < $a || $tempchr > $z)  break;
332
                        }
333
334
                        $found = false;
335
                        while (!$found && $x2 - $x >= $minwordlen)
336
                        {
337
                            $word = "/\\n" . substr($password, $x, $minwordlen);
338
                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= "(" . $password{$x3};
339
                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= ")?";
340
                            $word .= "\\n/";
341
342
                            preg_match_all($word, $data, $matches);
343
                            if (!count($matches[0]))
344
                            {
345
                                $password{$x} = "*";
346
                                $x++;
347
                                $numbits = self::getNISTNumBits(substr($password, 0, $x)) + $extrabits;
348
                                if ($numbits >= $minbits)  $found = true;
349
                            }
350
                            else
351
                            {
352
                                foreach ($matches[0] as $match)
353
                                {
354
                                    $password2 = str_replace(trim($match), "*", $password);
355
                                    $numbits = self::getNISTNumBits($password2) + $extrabits;
356
                                    if ($result > $numbits)  $result = $numbits;
357
358
                                    if ($result < $minbits)  return false;
359
                                }
360
361
                                $found = true;
362
                            }
363
                        }
364
365
                        if ($found)  break;
366
367
                        $x = $x2 - 1;
368
                    }
369
                }
370
            }
371
        }
372
373
        return $result >= $minbits;
374
    }
375
}
376