First release

This commit is contained in:
Italo
2022-06-14 05:17:04 -04:00
commit b60b829b96
119 changed files with 9412 additions and 0 deletions

View File

@@ -0,0 +1,278 @@
<?php
namespace Tests\Http\Requests;
use Illuminate\Auth\Events\Login;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Route;
use Laragear\WebAuthn\Assertion\Validator\AssertionValidator;
use Laragear\WebAuthn\ByteBuffer;
use Laragear\WebAuthn\Challenge;
use Laragear\WebAuthn\Http\Requests\AssertedRequest;
use Mockery;
use Ramsey\Uuid\Uuid;
use Tests\FakeAuthenticator;
use Tests\Stubs\WebAuthnAuthenticatableUser;
use Tests\TestCase;
use function array_merge;
use function base64_decode;
use function config;
use function now;
use function session;
class AssertedRequestTest extends TestCase
{
protected function afterRefreshingDatabase(): void
{
WebAuthnAuthenticatableUser::forceCreate([
'name' => FakeAuthenticator::ATTESTATION_USER['displayName'],
'email' => FakeAuthenticator::ATTESTATION_USER['name'],
'password' => 'test_password',
]);
DB::table('webauthn_credentials')->insert([
'id' => FakeAuthenticator::CREDENTIAL_ID,
'authenticatable_type' => WebAuthnAuthenticatableUser::class,
'authenticatable_id' => 1,
'user_id' => 'e8af6f703f8042aa91c30cf72289aa07',
'counter' => 0,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost',
'aaguid' => Uuid::NIL,
'attestation_format' => 'none',
'public_key' => 'eyJpdiI6Imp0U0NVeFNNbW45KzEvMXpad2p2SUE9PSIsInZhbHVlIjoic0VxZ2I1WnlHM2lJakhkWHVkK2kzMWtibk1IN2ZlaExGT01qOElXMDdRTjhnVlR0TDgwOHk1S0xQUy9BQ1JCWHRLNzRtenNsMml1dVQydWtERjFEU0h0bkJGT2RwUXE1M1JCcVpablE2Y2VGV2YvVEE2RGFIRUE5L0x1K0JIQXhLVE1aNVNmN3AxeHdjRUo2V0hwREZSRTJYaThNNnB1VnozMlVXZEVPajhBL3d3ODlkTVN3bW54RTEwSG0ybzRQZFFNNEFrVytUYThub2IvMFRtUlBZamoyZElWKzR1bStZQ1IwU3FXbkYvSm1FU2FlMTFXYUo0SG9kc1BDME9CNUNKeE9IelE5d2dmNFNJRXBKNUdlVzJ3VHUrQWJZRFluK0hib0xvVTdWQ0ZISjZmOWF3by83aVJES1dxbU9Zd1lhRTlLVmhZSUdlWmlBOUFtcTM2ZVBaRWNKNEFSQUhENk5EaC9hN3REdnVFbm16WkRxekRWOXd4cVcvZFdKa2tlWWJqZWlmZnZLS0F1VEVCZEZQcXJkTExiNWRyQmxsZWtaSDRlT3VVS0ZBSXFBRG1JMjRUMnBKRXZxOUFUa2xxMjg2TEplUzdscVo2UytoVU5SdXk1OE1lcFN6aU05ZkVXTkdIM2tKM3Q5bmx1TGtYb1F5bGxxQVR3K3BVUVlia1VybDFKRm9lZDViNzYraGJRdmtUb2FNTEVGZmZYZ3lYRDRiOUVjRnJpcTVvWVExOHJHSTJpMnVBZ3E0TmljbUlKUUtXY2lSWDh1dE5MVDNRUzVRSkQrTjVJUU8rSGhpeFhRRjJvSEdQYjBoVT0iLCJtYWMiOiI5MTdmNWRkZGE5OTEwNzQ3MjhkYWVhYjRlNjk0MWZlMmI5OTQ4YzlmZWI1M2I4OGVkMjE1MjMxNjUwOWRmZTU2IiwidGFnIjoiIn0=',
'updated_at' => now(),
'created_at' => now(),
]);
}
protected function defineEnvironment($app): void
{
$app->make('config')->set('auth.providers.users.driver', 'eloquent-webauthn');
$app->make('config')->set('auth.providers.users.model', WebAuthnAuthenticatableUser::class);
}
protected function defineWebRoutes($router): void
{
$router->post('test', static function (AssertedRequest $request): void {
$request->login();
});
}
public function test_verifies_and_logs_in_user(): void
{
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
$this->postJson('test', FakeAuthenticator::assertionResponse())->assertOk();
$this->assertAuthenticatedAs(WebAuthnAuthenticatableUser::find(1));
}
public function test_pulls_challenge_session_key(): void
{
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
$this->postJson('test', FakeAuthenticator::assertionResponse())->assertOk();
static::assertNull(session('_webauthn'));
}
public function test_logs_in_with_remember_header_x_webauthn_remember(): void
{
$event = Event::fake(Login::class);
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
$this->postJson('test', FakeAuthenticator::assertionResponse(), [
'X-WebAuthn-Remember' => 1
])->assertOk();
$event->assertDispatched(Login::class, static function (Login $event): bool {
return $event->remember;
});
}
public function test_logs_in_with_remember_header_webauthn_remember(): void
{
$event = Event::fake(Login::class);
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
$this->postJson('test', FakeAuthenticator::assertionResponse(), [
'WebAuthn-Remember' => 1
])->assertOk();
$event->assertDispatched(Login::class, static function (Login $event): bool {
return $event->remember;
});
}
public function test_logs_in_with_remember_input(): void
{
$event = Event::fake(Login::class);
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
$this->postJson('test', array_merge(FakeAuthenticator::assertionResponse(), [
'remember' => 'on'
]))->assertOk();
$event->assertDispatched(Login::class, static function (Login $event): bool {
return $event->remember;
});
}
public function test_logs_in_with_manual_remember_true(): void
{
$event = Event::fake(Login::class);
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
Route::middleware('web')->post('remember', function (AssertedRequest $request) {
$request->login(null, true);
});
$this->postJson('remember', FakeAuthenticator::assertionResponse())->assertOk();
$event->assertDispatched(Login::class, static function (Login $event): bool {
return $event->remember;
});
}
public function test_logs_in_with_manual_remember_false(): void
{
$event = Event::fake(Login::class);
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
Route::middleware('web')->post('remember', function (AssertedRequest $request) {
$request->login(null, false);
});
$this->postJson('remember', FakeAuthenticator::assertionResponse())->assertOk();
$event->assertDispatched(Login::class, static function (Login $event): bool {
return ! $event->remember;
});
}
public function test_uses_custom_session_key(): void
{
config(['webauthn.challenge.key' => 'foo']);
$this->session(['foo' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
$this->postJson('test', array_merge(FakeAuthenticator::assertionResponse(), [
'remember' => 'on'
]))->assertOk();
$this->assertAuthenticatedAs(WebAuthnAuthenticatableUser::find(1));
}
public function test_logs_in_with_custom_guard(): void
{
$guard = Auth::guard('web');
Auth::expects('guard')->with('foo')->twice()->andReturn($guard);
Route::middleware('web')->post('custom', function (AssertedRequest $request) {
$request->login('foo');
});
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
$this->postJson('custom', FakeAuthenticator::assertionResponse())->assertOk();
$this->assertAuthenticatedAs(WebAuthnAuthenticatableUser::find(1), 'foo');
}
public function test_logs_in_returns_user(): void
{
Route::middleware('web')->post('custom', function (AssertedRequest $request) {
static::assertTrue(WebAuthnAuthenticatableUser::find(1)->is($request->login()));
});
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
$this->postJson('custom', FakeAuthenticator::assertionResponse())->assertOk();
}
public function test_fails_validation_if_a_member_is_missing(): void
{
$this->postJson('test', [
'id' => 'test_id',
'response' => [
'authenticatorData' => 'test',
'clientDataJSON' => 'test',
'signature' => 'test',
'userHandle' => 'test',
],
'type' => 'test'
])
->assertJsonValidationErrorFor('rawId');
}
public function test_asserts_with_missing_user_handle(): void
{
$response = FakeAuthenticator::assertionResponse();
Arr::forget($response, 'response.userHandle');
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ASSERTION_CHALLENGE)), 60, false,
)]);
// We know it's going to fail since the user is not in the validation object, this is just for show.
$this->mock(AssertionValidator::class)
->expects('send->thenReturn')
->andReturn();
$this->postJson('test', $response)->assertOk();
$this->assertAuthenticatedAs(WebAuthnAuthenticatableUser::find(1));
}
public function test_destroy_session_on_regeneration(): void
{
Route::middleware('web')->post('custom', function (AssertedRequest $request) {
$request->login(destroySession: true);
});
$session = Mockery::mock(\Illuminate\Contracts\Session\Session::class);
$session->expects('regenerate')->with(true)->andReturn();
$this->app->resolving(AssertedRequest::class, function (AssertedRequest $request) use ($session): void {
$request->setLaravelSession($session);
});
$this->mock(AssertionValidator::class)
->expects('send->thenReturn')
->andReturn();
$this->postJson('custom', FakeAuthenticator::assertionResponse())->assertOk();
}
}

View File

@@ -0,0 +1,229 @@
<?php
namespace Tests\Http\Requests;
use Illuminate\Foundation\Auth\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Laragear\WebAuthn\Assertion\Creator\AssertionCreation;
use Laragear\WebAuthn\Assertion\Creator\AssertionCreator;
use Laragear\WebAuthn\Challenge;
use Laragear\WebAuthn\Http\Requests\AssertionRequest;
use Laragear\WebAuthn\JsonTransport;
use Tests\FakeAuthenticator;
use Tests\Stubs\WebAuthnAuthenticatableUser;
use Tests\TestCase;
use function config;
use function session;
use function strlen;
class AssertionRequestTest extends TestCase
{
protected function afterRefreshingDatabase(): void
{
WebAuthnAuthenticatableUser::forceCreate([
'name' => FakeAuthenticator::ATTESTATION_USER['displayName'],
'email' => FakeAuthenticator::ATTESTATION_USER['name'],
'password' => 'test_password',
]);
}
protected function defineEnvironment($app): void
{
$app->make('config')->set('auth.providers.users.driver', 'eloquent-webauthn');
$app->make('config')->set('auth.providers.users.model', WebAuthnAuthenticatableUser::class);
}
public function test_creates_assertion(): void
{
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->toVerify();
});
$this->postJson('test')
->assertSessionHas('_webauthn', function (Challenge $challenge): bool {
return !$challenge->verify;
})
->assertJson([
'timeout' => 60000,
'challenge' => session('_webauthn')->data->toBase64Url()
]);
}
public function test_uses_custom_timeout(): void
{
config(['webauthn.challenge.timeout' => 120]);
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->toVerify();
});
$this->postJson('test')
->assertJson([
'timeout' => 120000,
'challenge' => session('_webauthn')->data->toBase64Url()
]);
}
public function test_uses_custom_length(): void
{
config(['webauthn.challenge.bytes' => 32]);
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->toVerify();
});
$this->postJson('test')
->assertJson([
'timeout' => 60000,
'challenge' => session('_webauthn')->data->toBase64Url()
]);
static::assertSame(64, strlen(session('_webauthn')->data->toHex()));
}
public function test_uses_custom_session_key(): void
{
config(['webauthn.challenge.key' => 'foo']);
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->toVerify();
});
$this->postJson('test')->assertSessionHas('foo');
}
public function test_uses_custom_guard(): void
{
$guard = Auth::guard('web');
Auth::partialMock()->expects('guard')->with('foo')->andReturn($guard);
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->guard('foo')->toVerify(['email' => FakeAuthenticator::ATTESTATION_USER['name']]);
});
$this->postJson('test')
->assertOk()
->assertJson([
'timeout' => 60000,
'challenge' => session('_webauthn')->data->toBase64Url()
]);
}
public function test_guard_fails_if_user_not_webauthn_authenticatable(): void
{
config(['auth.providers.users.driver' => 'eloquent']);
config(['auth.providers.users.model' => User::class]);
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->guard('web')->toVerify(['email' => FakeAuthenticator::ATTESTATION_USER['name']]);
});
$this->postJson('test')
->assertStatus(500)
->assertSee('The user found for the [web] auth guard is not an instance of [WebAuthnAuthenticatable].');
}
public function test_uses_fast_login(): void
{
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->fastLogin()->toVerify();
});
$this->postJson('test')->assertJson([
'timeout' => 60000,
'userVerification' => 'discouraged',
'challenge' => session('_webauthn')->data->toBase64Url()
]);
static::assertFalse(session('_webauthn')->verify);
}
public function test_uses_secure_login(): void
{
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->secureLogin()->toVerify();
});
$this->postJson('test')->assertJson([
'timeout' => 60000,
'userVerification' => 'required',
'challenge' => session('_webauthn')->data->toBase64Url()
]);
static::assertTrue(session('_webauthn')->verify);
}
public function test_uses_verify_with_already_instanced_user(): void
{
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->toVerify(WebAuthnAuthenticatableUser::find(1));
});
$creator = $this->mock(AssertionCreator::class);
$creator->expects('send')->withArgs(function (AssertionCreation $creation): bool {
return $creation->user->getKey() === 1;
})
->andReturnSelf();
$creator->expects('then')->andReturn(new JsonTransport());
$this->postJson('test')->assertOk();
}
public function test_uses_verify_with_user_id(): void
{
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->toVerify(1);
});
$creator = $this->mock(AssertionCreator::class);
$creator->expects('send')->withArgs(function (AssertionCreation $creation): bool {
return $creation->user->getKey() === 1;
})
->andReturnSelf();
$creator->expects('then')->andReturn(new JsonTransport());
$this->postJson('test')->assertOk();
}
public function test_uses_verify_with_bad_id_returning_null_user(): void
{
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->toVerify(99);
});
$creator = $this->mock(AssertionCreator::class);
$creator->expects('send')->withArgs(function (AssertionCreation $creation): bool {
return ! $creation->user;
})
->andReturnSelf();
$creator->expects('then')->andReturn(new JsonTransport());
$this->postJson('test')->assertOk();
}
public function test_uses_verify_with_bad_credentials_returning_null_user(): void
{
Route::middleware('web')->post('test', function (AssertionRequest $request) {
return $request->toVerify(['email' => 'invalid@email.com']);
});
$creator = $this->mock(AssertionCreator::class);
$creator->expects('send')->withArgs(function (AssertionCreation $creation): bool {
return ! $creation->user;
})
->andReturnSelf();
$creator->expects('then')->andReturn(new JsonTransport());
$this->postJson('test')->assertOk();
}
}

View File

@@ -0,0 +1,149 @@
<?php
namespace Tests\Http\Requests;
use Illuminate\Foundation\Auth\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Laragear\WebAuthn\Challenge;
use Laragear\WebAuthn\Http\Requests\AttestationRequest;
use Laragear\WebAuthn\Models\WebAuthnCredential;
use Ramsey\Uuid\Uuid;
use Tests\FakeAuthenticator;
use Tests\Stubs\WebAuthnAuthenticatableUser;
use Tests\TestCase;
use function config;
class AttestationRequestTest extends TestCase
{
protected function afterRefreshingDatabase(): void
{
$this->be(
WebAuthnAuthenticatableUser::forceCreate([
'name' => FakeAuthenticator::ATTESTATION_USER['displayName'],
'email' => FakeAuthenticator::ATTESTATION_USER['name'],
'password' => 'test_password',
])
);
}
public function test_forbidden_if_user_not_authenticated(): void
{
Auth::logout();
Route::middleware('web')->post('test', function (AttestationRequest $request) {
return $request->toCreate();
});
$this->postJson('test')->assertForbidden();
}
public function test_forbidden_if_user_not_webauthn_authenticatable(): void
{
$this->be(new User());
Route::middleware('web')->post('test', function (AttestationRequest $request) {
return $request->toCreate();
});
$this->postJson('test')->assertForbidden();
}
public function test_returns_response_and_saves_challenge(): void
{
Route::middleware('web')->post('test', function (AttestationRequest $request) {
return $request->toCreate();
});
$this->postJson('test')
->assertSessionHas('_webauthn', static function (Challenge $challenge): bool {
static::assertFalse($challenge->verify);
return true;
});
}
public function test_uses_custom_session_key(): void
{
config(['webauthn.challenge.key' => 'foo']);
Route::middleware('web')->post('test', function (AttestationRequest $request) {
return $request->toCreate();
});
$this->postJson('test')->assertSessionHas('foo');
}
public function test_uses_fast_registration(): void
{
Route::middleware('web')->post('test', function (AttestationRequest $request) {
return $request->fastRegistration()->toCreate();
});
$this->postJson('test')
->assertSessionHas('_webauthn', static function (Challenge $challenge): bool {
static::assertFalse($challenge->verify);
return true;
})
->assertJsonPath('authenticatorSelection.userVerification', 'discouraged');
}
public function test_uses_secure_registration(): void
{
Route::middleware('web')->post('test', function (AttestationRequest $request) {
return $request->secureRegistration()->toCreate();
});
$this->postJson('test')
->assertSessionHas('_webauthn', static function (Challenge $challenge): bool {
static::assertTrue($challenge->verify);
return true;
})
->assertJsonPath('authenticatorSelection.userVerification', 'required');
}
public function test_uses_userless_and_verifies_user(): void
{
Route::middleware('web')->post('test', function (AttestationRequest $request) {
return $request->userless()->toCreate();
});
$this->postJson('test')
->assertSessionHas('_webauthn', static function (Challenge $challenge): bool {
static::assertTrue($challenge->verify);
return true;
})
->assertJsonFragment([
'authenticatorSelection' => [
'residentKey' => 'required',
'requireResidentKey' => true,
'userVerification' => 'required'
],
]);
}
public function test_allows_duplicates(): void
{
Route::middleware('web')->post('test', function (AttestationRequest $request) {
return $request->allowDuplicates()->toCreate();
});
WebAuthnCredential::forceCreate([
'id' => 'test_id',
'authenticatable_type' => WebAuthnAuthenticatableUser::class,
'authenticatable_id' => 1,
'user_id' => 'e8af6f703f8042aa91c30cf72289aa07',
'counter' => 0,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost',
'aaguid' => Uuid::NIL,
'attestation_format' => 'none',
'public_key' => 'test_key',
]);
$this->postJson('test')->assertJsonMissingPath('excludeCredentials');
}
}

View File

@@ -0,0 +1,176 @@
<?php
namespace Tests\Http\Requests;
use Illuminate\Foundation\Auth\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Route;
use Laragear\WebAuthn\ByteBuffer;
use Laragear\WebAuthn\Challenge;
use Laragear\WebAuthn\Events\CredentialCreated;
use Laragear\WebAuthn\Http\Requests\AttestedRequest;
use Laragear\WebAuthn\Models\WebAuthnCredential;
use Tests\FakeAuthenticator;
use Tests\Stubs\WebAuthnAuthenticatableUser;
use Tests\TestCase;
use function base64_decode;
use function config;
class AttestedRequestTest extends TestCase
{
protected function afterRefreshingDatabase(): void
{
$this->be(
WebAuthnAuthenticatableUser::forceCreate([
'name' => FakeAuthenticator::ATTESTATION_USER['displayName'],
'email' => FakeAuthenticator::ATTESTATION_USER['name'],
'password' => 'test_password',
])
);
}
protected function defineWebRoutes($router): void
{
$router->post('test', static function (AttestedRequest $request): void {
$request->save();
});
}
public function test_forbidden_if_user_not_authenticated(): void
{
Auth::logout();
$this->postJson('test')->assertForbidden();
}
public function test_forbidden_if_user_not_webauthn_authenticatable(): void
{
$this->be(new User());
$this->postJson('test')->assertForbidden();
}
public function test_invalid_if_web_authn_response_not_structured(): void
{
$this->postJson('test', [
'id' => 'test',
'rawId' => 'test',
'response' => [
'clientDataJSON' => 'test',
],
'type' => 'test',
])->assertJsonValidationErrorFor('response.attestationObject');
}
public function test_calls_validator_if_valid_and_authorized(): void
{
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(
base64_decode(FakeAuthenticator::ATTESTATION_CHALLENGE)),
60,
false,
['user_uuid' => FakeAuthenticator::ATTESTATION_USER['id']]
)
]);
$event = Event::fake(CredentialCreated::class);
$this->postJson('test', FakeAuthenticator::attestationResponse())->assertOk();
$event->assertDispatched(CredentialCreated::class, function (CredentialCreated $event): bool {
return FakeAuthenticator::CREDENTIAL_ID === $event->credential->getKey();
});
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => FakeAuthenticator::CREDENTIAL_ID,
'authenticatable_type' => WebAuthnAuthenticatableUser::class,
'authenticatable_id' => 1,
]);
}
public function test_uses_custom_session_key(): void
{
config(['webauthn.challenge.key' => 'foo']);
$this->session(['foo' => new Challenge(
new ByteBuffer(
base64_decode(FakeAuthenticator::ATTESTATION_CHALLENGE)),
60,
false,
['user_uuid' => FakeAuthenticator::ATTESTATION_USER['id']]
)
]);
$this->postJson('test', FakeAuthenticator::attestationResponse())->assertOk();
}
public function test_saves_with_array(): void
{
Route::middleware('web')->post('test', static function (AttestedRequest $request): void {
$request->save(['alias' => 'foo']);
});
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(
base64_decode(FakeAuthenticator::ATTESTATION_CHALLENGE)),
60,
false,
['user_uuid' => FakeAuthenticator::ATTESTATION_USER['id']]
)
]);
$this->postJson('test', FakeAuthenticator::attestationResponse())->assertOk();
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => FakeAuthenticator::CREDENTIAL_ID,
'authenticatable_type' => WebAuthnAuthenticatableUser::class,
'authenticatable_id' => 1,
'alias' => 'foo',
]);
}
public function test_saves_with_callable(): void
{
Route::middleware('web')->post('test', static function (AttestedRequest $request): void {
$request->save(function ($credential) {
$credential->alias = 'foo';
});
});
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ATTESTATION_CHALLENGE)),
60,
false,
['user_uuid' => FakeAuthenticator::ATTESTATION_USER['id']]
)
]);
$this->postJson('test', FakeAuthenticator::attestationResponse())->assertOk();
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => FakeAuthenticator::CREDENTIAL_ID,
'authenticatable_type' => WebAuthnAuthenticatableUser::class,
'authenticatable_id' => 1,
'alias' => 'foo',
]);
}
public function test_saves_return_credential_key(): void
{
$this->session(['_webauthn' => new Challenge(
new ByteBuffer(base64_decode(FakeAuthenticator::ATTESTATION_CHALLENGE)),
60,
false,
['user_uuid' => FakeAuthenticator::ATTESTATION_USER['id']]
)
]);
Route::middleware('web')->post('test', static function (AttestedRequest $request): array {
return [$request->save()];
});
$this->postJson('test', FakeAuthenticator::attestationResponse())
->assertJson([FakeAuthenticator::CREDENTIAL_ID]);
}
}