PasswordGenerator::getTopology()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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