114 lines
4.0 KiB
PHP
114 lines
4.0 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
use App\Models\Tenant;
|
||
|
|
use App\Models\User;
|
||
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||
|
|
use Illuminate\Support\Facades\Hash;
|
||
|
|
use Illuminate\Support\Facades\Password;
|
||
|
|
|
||
|
|
uses(DatabaseTransactions::class);
|
||
|
|
|
||
|
|
beforeEach(function () {
|
||
|
|
$this->tenant = Tenant::factory()->create();
|
||
|
|
$this->user = User::factory()->create([
|
||
|
|
'tenant_id' => $this->tenant->id,
|
||
|
|
'email' => 'reset@example.ru',
|
||
|
|
'password_hash' => Hash::make('old-password-1234'),
|
||
|
|
]);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('POST /api/auth/reset-password успешно меняет password_hash и удаляет token', function () {
|
||
|
|
$token = Password::createToken($this->user);
|
||
|
|
|
||
|
|
$r = $this->postJson('/api/auth/reset-password', [
|
||
|
|
'token' => $token,
|
||
|
|
'email' => 'reset@example.ru',
|
||
|
|
'password' => 'new-strong-password-1234',
|
||
|
|
'password_confirmation' => 'new-strong-password-1234',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$r->assertOk();
|
||
|
|
expect($r->json('message'))->toContain('успешно');
|
||
|
|
|
||
|
|
// Password::reset обновляет hash через callback.
|
||
|
|
$this->user->refresh();
|
||
|
|
expect(Hash::check('new-strong-password-1234', $this->user->password_hash))->toBeTrue();
|
||
|
|
expect(Hash::check('old-password-1234', $this->user->password_hash))->toBeFalse();
|
||
|
|
});
|
||
|
|
|
||
|
|
test('POST /api/auth/reset-password 422 при невалидном token', function () {
|
||
|
|
$r = $this->postJson('/api/auth/reset-password', [
|
||
|
|
'token' => 'fake-bad-token-zzz',
|
||
|
|
'email' => 'reset@example.ru',
|
||
|
|
'password' => 'new-strong-password-1234',
|
||
|
|
'password_confirmation' => 'new-strong-password-1234',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$r->assertStatus(422);
|
||
|
|
expect($r->json('message'))->toContain('недействительна');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('POST /api/auth/reset-password 422 при mismatch password_confirmation', function () {
|
||
|
|
$token = Password::createToken($this->user);
|
||
|
|
|
||
|
|
$r = $this->postJson('/api/auth/reset-password', [
|
||
|
|
'token' => $token,
|
||
|
|
'email' => 'reset@example.ru',
|
||
|
|
'password' => 'new-strong-password-1234',
|
||
|
|
'password_confirmation' => 'different-typo-zzz-9876',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$r->assertStatus(422);
|
||
|
|
expect($r->json('errors.password'))->not->toBeEmpty();
|
||
|
|
});
|
||
|
|
|
||
|
|
test('POST /api/auth/reset-password 422 при коротком пароле (<10 символов по ТЗ §22.4.1)', function () {
|
||
|
|
$token = Password::createToken($this->user);
|
||
|
|
|
||
|
|
$r = $this->postJson('/api/auth/reset-password', [
|
||
|
|
'token' => $token,
|
||
|
|
'email' => 'reset@example.ru',
|
||
|
|
'password' => 'short9',
|
||
|
|
'password_confirmation' => 'short9',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$r->assertStatus(422);
|
||
|
|
expect($r->json('errors.password'))->not->toBeEmpty();
|
||
|
|
});
|
||
|
|
|
||
|
|
test('POST /api/auth/reset-password 422 для несуществующего email', function () {
|
||
|
|
$r = $this->postJson('/api/auth/reset-password', [
|
||
|
|
'token' => 'any-token',
|
||
|
|
'email' => 'nobody@example.ru',
|
||
|
|
'password' => 'new-strong-password-1234',
|
||
|
|
'password_confirmation' => 'new-strong-password-1234',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$r->assertStatus(422);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('POST /api/auth/reset-password rate-limit: 5 неудачных → 6-я = 429', function () {
|
||
|
|
// Все 5 попыток с заведомо невалидным token → 422.
|
||
|
|
for ($i = 1; $i <= 5; $i++) {
|
||
|
|
$this->postJson('/api/auth/reset-password', [
|
||
|
|
'token' => 'bad-token-fixed-12345',
|
||
|
|
'email' => 'reset@example.ru',
|
||
|
|
'password' => 'new-strong-password-1234',
|
||
|
|
'password_confirmation' => 'new-strong-password-1234',
|
||
|
|
])->assertStatus(422);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 6-я → 429 (token throttle key — sha256(token)+ip, тот же token = тот же key).
|
||
|
|
$r = $this->postJson('/api/auth/reset-password', [
|
||
|
|
'token' => 'bad-token-fixed-12345',
|
||
|
|
'email' => 'reset@example.ru',
|
||
|
|
'password' => 'new-strong-password-1234',
|
||
|
|
'password_confirmation' => 'new-strong-password-1234',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$r->assertStatus(429);
|
||
|
|
expect($r->headers->get('Retry-After'))->not->toBeNull();
|
||
|
|
});
|