Passed
Push — master ( 8acaa0...e8a952 )
by Sebastian
03:47
created

Password   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Test Coverage

Coverage 61.53%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 8
eloc 27
c 2
b 0
f 0
dl 0
loc 154
ccs 16
cts 26
cp 0.6153
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getInfo() 0 3 1
A hash() 0 3 1
A __construct() 0 29 4
A verify() 0 3 1
A needsRehash() 0 3 1
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
/**
15
 * Provide methods for manage password, this class use PHP password hashing function,
16
 * see php documentation for more information.
17
 * <a href="http://php.net/manual/en/book.password.php">http://php.net/manual/en/book.password.php</a>
18
 */
19
class Password
20
{
21
    /**
22
     * @var array An associative array containing options
23
     *
24
     * http://php.net/manual/en/function.password-hash.php
25
     */
26
    protected $options = [
27
        PASSWORD_DEFAULT => ['cost' => 11],
28
    ];
29
30
    /**
31
     * @var array An associate array containing algorithm constants
32
     */
33
    protected $algoLists = [
34
        PASSWORD_BCRYPT,
35
        PASSWORD_DEFAULT
36
    ];
37
38
    /**
39
     * @var int Password default algorithm
40
     */
41
    protected $algo = PASSWORD_DEFAULT;
42
43
    /**
44
     * Class constructor.
45
     * <p>For password algorithm constants see <a href="http://php.net/manual/en/password.constants.php">Password Constants</a>.</p>
46
     * <pre><code class="php">//Options passed to class constructor as ['key' => 'value'] array.
47
     * $password = new Password(PASSWORD_DEFAULT, [
48
     *     'cost' => 11
49
     * ]);
50
     * </code></pre>
51
     *
52
     * @param int   $algo
53
     * @param array $options
54
     *
55
     * @throws \InvalidArgumentException
56
     */
57 19
    public function __construct(int $algo = PASSWORD_DEFAULT, array $options = [])
58
    {
59
        //necessary for avoid errors if Argon2 library not enabled
60
        //PASSWORD_ARGON2ID const only present since 7.3 PHP version
61 19
        if (\defined('PASSWORD_ARGON2I')) {
62
            $this->algoLists[] = PASSWORD_ARGON2I;
63
            $this->options[PASSWORD_ARGON2I] = [
64
                'memory_cost' => PASSWORD_ARGON2_DEFAULT_MEMORY_COST,
65
                'time_cost' => PASSWORD_ARGON2_DEFAULT_TIME_COST,
66
                'threads' => PASSWORD_ARGON2_DEFAULT_THREADS
67
            ];
68
        }
69
70 19
        if (\defined('PASSWORD_ARGON2ID')) {
71
            $this->algoLists[] = PASSWORD_ARGON2ID;
72
            $this->options[PASSWORD_ARGON2ID] = [
73
                'memory_cost' => PASSWORD_ARGON2_DEFAULT_MEMORY_COST,
74
                'time_cost' => PASSWORD_ARGON2_DEFAULT_TIME_COST,
75
                'threads' => PASSWORD_ARGON2_DEFAULT_THREADS
76
            ];
77
        }
78
79 19
        if (empty($this->algoLists[$algo])) {
80 1
            throw new \InvalidArgumentException('The password algorithm name is invalid');
81
        }
82
83 18
        $this->algo = $algo;
84
85 18
        $this->options[$algo] = \array_replace_recursive($this->options[$algo], $options);
86 18
    }
87
88
    /**
89
     * Verifies if a password matches an hash and return the result as boolean.
90
     * <pre><code class="php">$password = new Password();
91
     *
92
     * $storedHash = '$2y$11$cq3ZWO18l68X7pGs9Y1fveTGcNJ/iyehrDZ10BAvbY8LaBXNvnyk6';
93
     * $password = 'FooPassword';
94
     *
95
     * $verified = $password->verify($password, $storedHash);
96
     * </code></pre>
97
     *
98
     * @param string $password
99
     * @param string $hash
100
     *
101
     * @return bool True if password match, false if not.
102
     */
103 45
    public function verify(string $password, string $hash): bool
104
    {
105 45
        return \password_verify($password, $hash);
106
    }
107
108
    /**
109
     * Create password hash from the given string and return it.
110
     * <pre><code class="php">$password = new Password();
111
     *
112
     * $hash = $password->hash('FooPassword');
113
     *
114
     * //var_dump result
115
     * //$2y$11$cq3ZWO18l68X7pGs9Y1fveTGcNJ/iyehrDZ10BAvbY8LaBXNvnyk6
116
     * var_dump($hash)
117
     * </code></pre>
118
     *
119
     * @param string $password
120
     *
121
     * @return string Hashed password.
122
     */
123 21
    public function hash(string $password): string
124
    {
125 21
        return \password_hash($password, $this->algo, $this->options[$this->algo]);
126
    }
127
128
    /**
129
     * Checks if the given hash matches the algorithm and the options provided.
130
     * <pre><code class="php">$password = new Password();
131
     *
132
     * $hash = '$2y$11$cq3ZWO18l68X7pGs9Y1fveTGcNJ/iyehrDZ10BAvbY8LaBXNvnyk6';
133
     *
134
     * //true if rehash is needed, false if no
135
     * $rehashCheck = $password->needsRehash($hash);
136
     * </code></pre>
137
     *
138
     * @param string $hash
139
     *
140
     * @return bool
141
     */
142 2
    public function needsRehash(string $hash): bool
143
    {
144 2
        return \password_needs_rehash($hash, $this->algo, $this->options[$this->algo]);
145
    }
146
147
    /**
148
     * Returns information about the given hash.
149
     * <pre><code class="php">$password = new Password();
150
     *
151
     * $hash = '$2y$11$cq3ZWO18l68X7pGs9Y1fveTGcNJ/iyehrDZ10BAvbY8LaBXNvnyk6';
152
     *
153
     * $info = $password->getInfo($hash);
154
     *
155
     * //var_dump result
156
     * //[
157
     * //    'algo' => 1,
158
     * //    'algoName' => 'bcrypt',
159
     * //    'options' => [
160
     * //        'cost' => int 11
161
     * //    ]
162
     * //]
163
     * var_dump($info);
164
     * </code></pre>
165
     *
166
     * @param string $hash
167
     *
168
     * @return array
169
     */
170 2
    public function getInfo(string $hash): array
171
    {
172 2
        return \password_get_info($hash);
173
    }
174
}
175