Passed
Push — master ( 20c13f...eb0a46 )
by Sebastian
02:11
created

Password::__construct()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.1755

Importance

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