• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NexusPHP / framework / 14369703574

29 Mar 2025 05:15PM UTC coverage: 100.0%. Remained the same
14369703574

push

github

paulbalandan
Fix phpstan error

958 of 958 relevant lines covered (100.0%)

7.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/Nexus/Password/Hash/AbstractArgon2Hash.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of the Nexus framework.
7
 *
8
 * (c) John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Nexus\Password\Hash;
15

16
use Nexus\Password\Algorithm;
17
use Nexus\Password\HashException;
18

19
abstract readonly class AbstractArgon2Hash extends AbstractHash
20
{
21
    private const int MINIMUM_MEMORY_COST = 7 * 1024;
22
    private const int MINIMUM_TIME_COST = 1;
23
    private const int MINIMUM_THREADS = 1;
24

25
    /**
26
     * @var int<self::MINIMUM_MEMORY_COST, max>
27
     */
28
    private int $memoryCost;
29

30
    /**
31
     * @var int<self::MINIMUM_TIME_COST, max>
32
     */
33
    private int $timeCost;
34

35
    /**
36
     * @var int<self::MINIMUM_THREADS, max>
37
     */
38
    private int $threads;
39

40
    /**
41
     * @param array{
42
     *  memory_cost?: int,
43
     *  time_cost?: int,
44
     *  threads?: int,
45
     * } $options
46
     *
47
     * @throws HashException
48
     */
49
    public function __construct(
50
        public Algorithm $algorithm,
51
        array $options = [],
52
    ) {
53
        ['memory_cost' => $this->memoryCost, 'time_cost' => $this->timeCost, 'threads' => $this->threads] = $this->validatedOptions(
68✔
54
            $options,
68✔
55
            PASSWORD_ARGON2_DEFAULT_MEMORY_COST,
68✔
56
            PASSWORD_ARGON2_DEFAULT_TIME_COST,
68✔
57
            PASSWORD_ARGON2_DEFAULT_THREADS,
68✔
58
        );
68✔
59
    }
60

61
    /**
62
     * @param array{
63
     *  memory_cost?: int,
64
     *  threads?: int,
65
     *  time_cost?: int,
66
     * } $options
67
     */
68
    public function hash(#[\SensitiveParameter] string $password, array $options = []): string
69
    {
70
        if (! $this->isValidPassword($password)) {
32✔
71
            throw new HashException('Invalid password provided.');
16✔
72
        }
73

74
        return password_hash(
16✔
75
            $password,
16✔
76
            $this->algorithm->value,
16✔
77
            $this->validatedOptions(
16✔
78
                $options,
16✔
79
                $this->memoryCost,
16✔
80
                $this->timeCost,
16✔
81
                $this->threads,
16✔
82
            ),
16✔
83
        );
16✔
84
    }
85

86
    /**
87
     * @param array{
88
     *  memory_cost?: int,
89
     *  threads?: int,
90
     *  time_cost?: int,
91
     * } $options
92
     */
93
    public function needsRehash(string $hash, array $options = []): bool
94
    {
95
        return password_needs_rehash(
12✔
96
            $hash,
12✔
97
            $this->algorithm->value,
12✔
98
            $this->validatedOptions(
12✔
99
                $options,
12✔
100
                $this->memoryCost,
12✔
101
                $this->timeCost,
12✔
102
                $this->threads,
12✔
103
            ),
12✔
104
        );
12✔
105
    }
106

107
    public function verify(string $password, string $hash): bool
108
    {
109
        if (! $this->isValidPassword($password)) {
24✔
110
            return false;
16✔
111
        }
112

113
        return password_verify($password, $hash);
8✔
114
    }
115

116
    /**
117
     * @param array{
118
     *  memory_cost?: int,
119
     *  time_cost?: int,
120
     *  threads?: int,
121
     * } $options
122
     *
123
     * @return array{
124
     *  memory_cost: int<self::MINIMUM_MEMORY_COST, max>,
125
     *  time_cost: int<self::MINIMUM_TIME_COST, max>,
126
     *  threads: int<self::MINIMUM_THREADS, max>,
127
     * }
128
     *
129
     * @throws HashException
130
     */
131
    private function validatedOptions(array $options, int $memoryCost, int $timeCost, int $threads): array
132
    {
133
        $memoryCost = $options['memory_cost'] ?? $memoryCost;
68✔
134
        $timeCost = $options['time_cost'] ?? $timeCost;
68✔
135
        $threads = $options['threads'] ?? $threads;
68✔
136

137
        if ($memoryCost < self::MINIMUM_MEMORY_COST) {
68✔
138
            throw new HashException(\sprintf(
4✔
139
                'Memory cost should be %sKiB or greater, %sKiB given.',
4✔
140
                number_format(self::MINIMUM_MEMORY_COST / 1024),
4✔
141
                number_format($memoryCost / 1024),
4✔
142
            ));
4✔
143
        }
144

145
        if ($timeCost < self::MINIMUM_TIME_COST) {
64✔
146
            throw new HashException(\sprintf(
4✔
147
                'Time cost should be %d or greater, %d given.',
4✔
148
                self::MINIMUM_TIME_COST,
4✔
149
                $timeCost,
4✔
150
            ));
4✔
151
        }
152

153
        if ($threads < self::MINIMUM_THREADS) {
60✔
154
            throw new HashException(\sprintf(
4✔
155
                'Number of threads should be %d or greater, %d given.',
4✔
156
                self::MINIMUM_THREADS,
4✔
157
                $threads,
4✔
158
            ));
4✔
159
        }
160

161
        return [
56✔
162
            'memory_cost' => $memoryCost,
56✔
163
            'time_cost' => $timeCost,
56✔
164
            'threads' => $threads,
56✔
165
        ];
56✔
166
    }
167
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc