Skip to content

Commit caae608

Browse files
Merge pull request #50 from ssntpl/bugs/password_history_blocks_registration
Fix PasswordHistory rule blocking first-time registration
2 parents 896aae3 + 5cb97f5 commit caae608

4 files changed

Lines changed: 33 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
- **`PasswordHistory` rule blocked first-time registration** — with the default `neev.password` rules, `PasswordHistory::notReused()` failed with "Unable to verify password history." whenever no user could be resolved, which is exactly the first-time-signup case (no authenticated user; the submitted email belongs to nobody yet). The rule now passes vacuously when there is no user — there is no history to reuse. Reported by a consuming-app developer
12+
1013
## [0.5.0] - 2026-07-02
1114

1215
### Added

src/Rules/PasswordHistory.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ public function validate(string $attribute, mixed $value, Closure $fail): void
4040
}
4141

4242
if (!$user) {
43-
$fail('Unable to verify password history.');
43+
// No resolvable user means there is no history to reuse —
44+
// first-time registration lands here (no authenticated user,
45+
// and the submitted email belongs to nobody yet). The check
46+
// is vacuously satisfied; failing would block every
47+
// registration under the default password rules.
4448
return;
4549
}
4650

tests/Feature/Auth/RegistrationTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,26 @@ protected function setUp(): void
2121
config(['neev.password' => ['required', 'confirmed']]);
2222
}
2323

24+
public function test_registration_succeeds_with_the_default_password_rules(): void
25+
{
26+
// Regression: PasswordHistory::notReused() used to fail with
27+
// "Unable to verify password history." for first-time signups
28+
// (no resolvable user), blocking every registration under the
29+
// shipped default config. This test runs WITHOUT the simplified
30+
// rules from setUp().
31+
config(['neev.password' => (require dirname(__DIR__, 3) . '/config/neev.php')['password']]);
32+
33+
$response = $this->postJson('/neev/register', [
34+
'name' => 'Default Rules',
35+
'email' => 'default-rules@company.com',
36+
'password' => 'Str0ng@Passw0rd!',
37+
'password_confirmation' => 'Str0ng@Passw0rd!',
38+
]);
39+
40+
$response->assertOk();
41+
$response->assertJsonPath('auth_state', 'authenticated');
42+
}
43+
2444
public function test_api_registration_returns_token(): void
2545
{
2646
$response = $this->postJson('/neev/register', [

tests/Unit/Rules/PasswordHistoryTest.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,19 @@ public function test_not_reused_creates_instance_with_custom_count(): void
6161
}
6262

6363
// -----------------------------------------------------------------
64-
// Fails when no user is found (rule rejects)
64+
// Passes when no user is found — no history exists to reuse.
65+
// First-time registration lands here; failing would block every
66+
// registration under the default password rules.
6567
// -----------------------------------------------------------------
6668

67-
public function test_fails_when_no_user_found(): void
69+
public function test_passes_when_no_user_found(): void
6870
{
6971
// No authenticated user, no email input
7072
$rule = PasswordHistory::notReused(5);
7173

7274
$failed = $this->runRule($rule, 'anything');
7375

74-
$this->assertTrue($failed);
76+
$this->assertFalse($failed);
7577
}
7678

7779
// -----------------------------------------------------------------

0 commit comments

Comments
 (0)