Test Failed
Pull Request — main (#59)
by Dimitri
06:14
created

BcryptHandler::needsRehash()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Security\Hashing\Handlers;
13
14
use BlitzPHP\Contracts\Security\HasherInterface;
15
use Error;
16
use RuntimeException;
17
18
/**
19
 * Gestionnaire de hashage basé sur Bcrypt
20
 *
21
 * @credit <a href="http://www.laravel.com">Laravel 11 - \Illuminate\Hashing\BcryptHasher</a>
22
 */
23
class BcryptHandler extends BaseHandler implements HasherInterface
24
{
25
    /**
26
     * Le facteur de coût par défaut.
27
     */
28
    protected int $rounds = 12;
29
30
    /**
31
     * Indique s'il faut effectuer une vérification de l'algorithme.
32
     */
33
    protected bool $verifyAlgorithm = false;
34
35
    /**
36
     * Créer une nouvelle instance de Hacheur.
37
     */
38
    public function __construct(array $options = [])
39
    {
40
        $this->rounds          = $options['rounds'] ?? $this->rounds;
41
        $this->verifyAlgorithm = $options['verify'] ?? $this->verifyAlgorithm;
42
    }
43
44
    /**
45
     * {@inheritDoc}
46
     *
47
     * @throws RuntimeException
48
     */
49
    public function make(string $value, array $options = []): string
50
    {
51
        try {
52
            $hash = password_hash($value, PASSWORD_BCRYPT, [
53
                'cost' => $this->cost($options),
54
            ]);
55
        } catch (Error) {
56
            throw new RuntimeException("Le hachage Bcrypt n'est pas supporté.");
57
        }
58
59
        return $hash;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $hash could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
60
    }
61
62
    /**
63
     * {@inheritDoc}
64
     *
65
     * @throws RuntimeException
66
     */
67
    public function check(string $value, string $hashedValue, array $options = []): bool
68
    {
69
        if ($hashedValue === '') {
70
            return false;
71
        }
72
73
        if ($this->verifyAlgorithm && ! $this->isUsingCorrectAlgorithm($hashedValue)) {
74
            throw new RuntimeException("Ce mot de passe n'utilise pas l'algorithme Bcrypt.");
75
        }
76
77
        return parent::check($value, $hashedValue, $options);
78
    }
79
80
    /**
81
     * {@inheritDoc}
82
     */
83
    public function needsRehash(string $hashedValue, array $options = []): bool
84
    {
85
        return password_needs_rehash($hashedValue, PASSWORD_BCRYPT, [
86
            'cost' => $this->cost($options),
87
        ]);
88
    }
89
90
    /**
91
     * Vérifie que la configuration est inférieure ou égale à ce qui est configuré.
92
     *
93
     * @internal
94
     */
95
    public function verifyConfiguration(string $value): bool
96
    {
97
        return $this->isUsingCorrectAlgorithm($value) && $this->isUsingValidOptions($value);
98
    }
99
100
    /**
101
     * Vérifie l'algorithme de la valeur hachée.
102
     */
103
    protected function isUsingCorrectAlgorithm(string $hashedValue): bool
104
    {
105
        return $this->info($hashedValue)['algoName'] === 'bcrypt';
106
    }
107
108
    /**
109
     * Vérifie les options de la valeur hachée.
110
     */
111
    protected function isUsingValidOptions(string $hashedValue): bool
112
    {
113
        ['options' => $options] = $this->info($hashedValue);
114
115
        if (! is_int($options['cost'] ?? null)) {
116
            return false;
117
        }
118
119
        return ! ($options['cost'] > $this->rounds);
120
    }
121
122
    /**
123
     * Défini le facteur de travail du mot de passe par défaut.
124
     */
125
    public function setRounds(int $rounds): self
126
    {
127
        $this->rounds = (int) $rounds;
128
129
        return $this;
130
    }
131
132
    /**
133
     * Extrait la valeur du coût a partir du tableau d'options.
134
     */
135
    protected function cost(array $options = []): int
136
    {
137
        return $options['rounds'] ?? $this->rounds;
138
    }
139
}
140