fix(auth): reject signup with an existing customer email (account-claim guard)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat/portal-design
nexxo 2026-07-25 18:29:35 +02:00
parent 507ab485a0
commit 39a1f708a1
2 changed files with 16 additions and 0 deletions

View File

@ -2,6 +2,7 @@
namespace App\Actions\Fortify;
use App\Models\Customer;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
@ -30,6 +31,10 @@ class CreateNewUser implements CreatesNewUsers
'email',
'max:255',
Rule::unique(User::class),
// Never let public signup claim an existing (possibly not-yet-
// provisioned) customer's email — ensureUser() would later link
// that account and hand over the customer's portal.
Rule::unique(Customer::class, 'email'),
],
'password' => $this->passwordRules(),
])->validate();

View File

@ -24,6 +24,17 @@ it('registers a new account and signs in', function () {
$this->assertAuthenticatedAs($user);
});
it('refuses to register with an existing customer email (account-claim guard)', function () {
\App\Models\Customer::factory()->create(['email' => 'claim@signup.test']);
$this->post(route('register.store'), [
'name' => 'Claimer', 'email' => 'claim@signup.test',
'password' => 'password1234', 'password_confirmation' => 'password1234',
])->assertSessionHasErrors('email');
expect(User::query()->where('email', 'claim@signup.test')->exists())->toBeFalse();
});
it('rejects a mismatched password confirmation', function () {
$this->post(route('register.store'), [
'name' => 'X',