Completed
Push — master ( 847eff...05e202 )
by Sebastian
05:45
created

PasswordGenerator::inRanges()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 4
nc 3
nop 2
crap 4
1
<?php
2
3
/**
4
 * Linna Framework.
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2018, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types=1);
11
12
namespace Linna\Authentication;
13
14
use InvalidArgumentException;
15
16
/**
17
 * Generate random password with random topology, this class use php7
18
 * random_int() function for generate random numbers.
19
 */
20
class PasswordGenerator
21
{
22
    /**
23
     * @var array Characters intervall
24
     */
25
    private $chars = [
26
        'ABCDEFGHIJKLMNOPQRSTUVWXYZ', //u 117
27
        'abcdefghijklmnopqrstuvwxyz', //l 108
28
        '0123456789', //d 100
29
        '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' //s 115
30
    ];
31
32
    /**
33
     * Generate a random password.
34
     * <pre><code class="php">use Linna\Auth\PasswordGenerator;
35
     *
36
     * $passwordGenerator = new PasswordGenerator();
37
     * $random = $passwordGenerator->getFromRandom(20);
38
     *
39
     * //var_dump result
40
     * //r4Q,1J*tM7D_99q0u>61
41
     * var_dump($random);
42
     * </code></pre>
43
     *
44
     * @param int $length Desiderated password length.
45
     *
46
     * @return string Random password.
47
     */
48 8
    public function getFromRandom(int $length): string
49
    {
50 8
        $password = [];
51
52 8
        while ($length) {
53 8
            $password[] = $this->getRandomChar($this->chars[\random_int(0, 3)]);
54
55 8
            $length--;
56
        }
57
58 8
        return \implode($password);
59
    }
60
61
    /**
62
     * Return topology for given password.
63
     * <pre><code class="php">use Linna\Auth\PasswordGenerator;
64
     *
65
     * $passwordGenerator = new PasswordGenerator();
66
     * $topology = $passwordGenerator->getTopology('r4Q,1J*tM7D_99q0u>61');
67
     *
68
     * //var_dump result
69
     * //ldusdusludusddldlsdd
70
     * var_dump($topology);
71
     * </code></pre>
72
     * @param string $password Password.
73
     *
74
     * @return string Topology for the argument passed password.
75
     */
76 26
    public function getTopology(string $password): string
77
    {
78 26
        $array = \str_split($password);
79 26
        $topology = [];
80
81 26
        foreach ($array as $char) {
82 26
            $topology[] = $this->getTopologyGroup($char);
83
        }
84
85 25
        return \implode($topology);
86
    }
87
88
    /**
89
     * Return topology group for the given char.
90
     *
91
     * @param string $char
92
     *
93
     * @return string
94
     *
95
     * @throws InvalidArgumentException If char provided isn't inside any group
96
     */
97 26
    private function getTopologyGroup(string $char): string
98
    {
99 26
        $groups = $this->chars;
100
101 26
        if (\strpos($groups[0], $char) !== false) {
102 25
            return 'u';
103
        }
104
105 26
        if (\strpos($groups[1], $char) !== false) {
106 26
            return 'l';
107
        }
108
109 26
        if (\strpos($groups[2], $char) !== false) {
110 25
            return 'd';
111
        }
112
113 26
        if (\strpos($groups[3], $char) !== false) {
114 25
            return 's';
115
        }
116
117 1
        throw new InvalidArgumentException('Out of group character provided.');
118
    }
119
120
    /**
121
     * Generate a random password corresponding at the given topology.
122
     * <pre><code class="php">use Linna\Auth\PasswordGenerator;
123
     *
124
     * $passwordGenerator = new PasswordGenerator();
125
     * $random = $passwordGenerator->getFromTopology('ldusdusludusddldlsdd');
126
     *
127
     * //var_dump result
128
     * //r4Q,1J*tM7D_99q0u>61
129
     * var_dump($random);
130
     * </code></pre>
131
     *
132
     * @param string $topology Topology for generate password.
133
     *
134
     * @return string Random password corresponding the given topology.
135
     *
136
     * @throws InvalidArgumentException If invalid pattern is provided.
137
     */
138 16
    public function getFromTopology(string $topology): string
139
    {
140 16
        $array = \str_split(\strtolower($topology));
141 16
        $groups = [117 => 0, 108 => 1, 100 => 2, 115 => 3];
142 16
        $password = [];
143
144 16
        foreach ($array as $char) {
145 16
            $int = \ord($char);
146
147 16
            if (isset($groups[$int])) {
148 13
                $password[] = $this->getRandomChar($this->chars[$groups[$int]]);
149
150 13
                continue;
151
            }
152
153 6
            throw new InvalidArgumentException('Invalid pattern provided, accepted only u, l, d and s.');
154
        }
155
156 10
        return \implode($password);
157
    }
158
159
    /**
160
     * Get random char between.
161
     *
162
     * @param string $interval
163
     *
164
     * @return string
165
     */
166 21
    private function getRandomChar(string $interval): string
167
    {
168 21
        $size = \strlen($interval) - 1;
169 21
        $int = \random_int(0, $size);
170
171 21
        return $interval[$int];
172
    }
173
}
174