Adds tests for trait, fixing some methods.

This commit is contained in:
Italo Israel Baeza Cabrera
2022-11-11 18:26:07 -03:00
parent afa5b62107
commit 89f15373bc
2 changed files with 271 additions and 14 deletions

View File

@@ -7,7 +7,6 @@ use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Date;
use JetBrains\PhpStorm\ArrayShape; use JetBrains\PhpStorm\ArrayShape;
use Laragear\WebAuthn\Models\WebAuthnCredential; use Laragear\WebAuthn\Models\WebAuthnCredential;
use function in_array;
/** /**
* @property-read \Illuminate\Database\Eloquent\Collection<int, \Laragear\WebAuthn\Models\WebAuthnCredential> $webAuthnCredentials * @property-read \Illuminate\Database\Eloquent\Collection<int, \Laragear\WebAuthn\Models\WebAuthnCredential> $webAuthnCredentials
@@ -39,20 +38,17 @@ trait WebAuthnAuthentication
*/ */
public function flushCredentials(string ...$except): void public function flushCredentials(string ...$except): void
{ {
if ($this->relationLoaded('webAuthnCredentials') && $this->webAuthnCredentials instanceof Collection) { if (! $this->relationLoaded('webAuthnCredentials')) {
$partitioned = $this->webAuthnCredentials $this->webAuthnCredentials()->whereKeyNot($except)->delete();
->partition(static function (WebAuthnCredential $credential) use ($except): bool {
return in_array($credential->getKey(), $except, true);
});
$partitioned->first()->each->delete();
$this->setRelation('webAuthnCredentials', $partitioned->last());
return; return;
} }
$this->webAuthnCredentials()->whereKeyNot($except)->delete(); if ($this->webAuthnCredentials instanceof Collection && $this->webAuthnCredentials->isNotEmpty()) {
$this->webAuthnCredentials->whereNotIn('id', $except)->each->delete();
$this->setRelation('webAuthnCredentials', $this->webAuthnCredentials->whereIn('id', $except));
}
} }
/** /**
@@ -65,13 +61,14 @@ trait WebAuthnAuthentication
{ {
if ($this->relationLoaded('webAuthnCredentials') && $this->webAuthnCredentials instanceof Collection) { if ($this->relationLoaded('webAuthnCredentials') && $this->webAuthnCredentials instanceof Collection) {
$this->webAuthnCredentials $this->webAuthnCredentials
->each(static function (WebAuthnCredential $credential) use ($except): bool { ->when($except)->whereNotIn('id', $except)
if ($credential->isEnabled() && in_array($credential->getKey(), $except, true)) { ->each(static function (WebAuthnCredential $credential): void {
if ($credential->isEnabled()) {
$credential->disable(); $credential->disable();
} }
}); });
} else { } else {
$this->webAuthnCredentials()->whereKeyNot($except)->update(['disabled_at' => Date::now()]); $this->webAuthnCredentials()->whereKeyNot($except)->whereEnabled()->update(['disabled_at' => Date::now()]);
} }
} }

View File

@@ -0,0 +1,260 @@
<?php
namespace Tests;
use Illuminate\Support\Carbon;
use Laragear\WebAuthn\Models\WebAuthnCredential;
use Ramsey\Uuid\Uuid;
use function now;
class WebAuthnAuthenticationTest extends TestCase
{
protected Stubs\WebAuthnAuthenticatableUser $user;
protected function afterRefreshingDatabase(): void
{
$this->user = Stubs\WebAuthnAuthenticatableUser::forceCreate([
'name' => FakeAuthenticator::ATTESTATION_USER['displayName'],
'email' => FakeAuthenticator::ATTESTATION_USER['name'],
'password' => 'test_password',
]);
$this->user->webAuthnCredentials()->make()->forceFill([
'id' => 'test_id',
'user_id' => Uuid::NIL,
'counter' => 0,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost:8000',
'aaguid' => Uuid::NIL,
'public_key' => 'test_key',
'attestation_format' => 'none',
])->save();
}
public function test_shows_webauthn_data(): void
{
static::assertSame([
'name' => FakeAuthenticator::ATTESTATION_USER['name'],
'displayName' => FakeAuthenticator::ATTESTATION_USER['displayName'],
], $this->user->webAuthnData());
}
public function test_flushes_all_credentials(): void
{
$this->user->webAuthnCredentials()->make()->forceFill([
'id' => 'test_id_2',
'user_id' => Uuid::NIL,
'counter' => 10,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost:8000',
'aaguid' => Uuid::NIL,
'public_key' => 'test_key',
'attestation_format' => 'none',
'disabled_at' => now()
])->save();
$this->user->flushCredentials();
$this->assertDatabaseCount(WebAuthnCredential::class, 0);
}
public function test_flushes_all_credentials_using_loaded_relation(): void
{
$this->user->webAuthnCredentials()->make()->forceFill([
'id' => 'test_id_2',
'user_id' => Uuid::NIL,
'counter' => 10,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost:8000',
'aaguid' => Uuid::NIL,
'public_key' => 'test_key',
'attestation_format' => 'none',
'disabled_at' => now()
])->save();
$this->user->load('webAuthnCredentials');
static::assertCount(2, $this->user->webAuthnCredentials);
$this->user->flushCredentials();
static::assertEmpty($this->user->webAuthnCredentials);
$this->assertDatabaseCount(WebAuthnCredential::class, 0);
}
public function test_flushes_all_credentials_except_given_id(): void
{
$this->user->webAuthnCredentials()->make()->forceFill([
'id' => 'test_id_2',
'user_id' => Uuid::NIL,
'counter' => 10,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost:8000',
'aaguid' => Uuid::NIL,
'public_key' => 'test_key',
'attestation_format' => 'none',
'disabled_at' => now()
])->save();
$this->user->flushCredentials('test_id_2');
$this->assertDatabaseCount(WebAuthnCredential::class, 1);
$this->assertDatabaseMissing(WebAuthnCredential::class, [
'id' => 'test_id'
]);
}
public function test_flushes_all_credentials_using_loaded_relation_except_given_id(): void
{
$this->user->webAuthnCredentials()->make()->forceFill([
'id' => 'test_id_2',
'user_id' => Uuid::NIL,
'counter' => 10,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost:8000',
'aaguid' => Uuid::NIL,
'public_key' => 'test_key',
'attestation_format' => 'none',
'disabled_at' => now()
])->save();
$this->user->load('webAuthnCredentials');
static::assertCount(2, $this->user->webAuthnCredentials);
$this->user->flushCredentials('test_id_2');
static::assertCount(1, $this->user->webAuthnCredentials);
static::assertTrue($this->user->webAuthnCredentials->contains('id', 'test_id_2'));
$this->assertDatabaseCount(WebAuthnCredential::class, 1);
$this->assertDatabaseMissing(WebAuthnCredential::class, [
'id' => 'test_id'
]);
}
public function test_disables_all_credentials(): void
{
$this->travelTo(Carbon::now()->startOfSecond());
$this->user->webAuthnCredentials()->make()->forceFill([
'id' => 'test_id_2',
'user_id' => Uuid::NIL,
'counter' => 10,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost:8000',
'aaguid' => Uuid::NIL,
'public_key' => 'test_key',
'attestation_format' => 'none',
'disabled_at' => now()->subMinute()
])->save();
$this->user->disableAllCredentials();
$this->assertDatabaseCount(WebAuthnCredential::class, 2);
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => 'test_id',
'disabled_at' => now()->toDateTimeString(),
]);
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => 'test_id_2',
'disabled_at' => now()->subMinute()->toDateTimeString(),
]);
}
public function test_disables_all_credentials_with_loaded_relation(): void
{
$this->travelTo(Carbon::now()->startOfSecond());
$this->user->webAuthnCredentials()->make()->forceFill([
'id' => 'test_id_2',
'user_id' => Uuid::NIL,
'counter' => 10,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost:8000',
'aaguid' => Uuid::NIL,
'public_key' => 'test_key',
'attestation_format' => 'none',
'disabled_at' => now()->subMinute()
])->save();
$this->user->load('webAuthnCredentials');
$this->user->disableAllCredentials();
static::assertTrue($this->user->webAuthnCredentials->firstWhere('id', 'test_id')->isDisabled());
static::assertTrue($this->user->webAuthnCredentials->firstWhere('id', 'test_id_2')->isDisabled());
$this->assertDatabaseCount(WebAuthnCredential::class, 2);
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => 'test_id',
'disabled_at' => now()->toDateTimeString(),
]);
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => 'test_id_2',
'disabled_at' => now()->subMinute()->toDateTimeString(),
]);
}
public function test_disables_all_credentials_except_one(): void
{
$this->travelTo(Carbon::now()->startOfSecond());
$this->user->webAuthnCredentials()->make()->forceFill([
'id' => 'test_id_2',
'user_id' => Uuid::NIL,
'counter' => 10,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost:8000',
'aaguid' => Uuid::NIL,
'public_key' => 'test_key',
'attestation_format' => 'none',
])->save();
$this->user->disableAllCredentials('test_id');
$this->assertDatabaseCount(WebAuthnCredential::class, 2);
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => 'test_id',
'disabled_at' => null,
]);
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => 'test_id_2',
'disabled_at' => now()->toDateTimeString(),
]);
}
public function test_disables_all_credentials_with_loaded_relation_except_one(): void
{
$this->travelTo(Carbon::now()->startOfSecond());
$this->user->webAuthnCredentials()->make()->forceFill([
'id' => 'test_id_2',
'user_id' => Uuid::NIL,
'counter' => 10,
'rp_id' => 'http://localhost',
'origin' => 'http://localhost:8000',
'aaguid' => Uuid::NIL,
'public_key' => 'test_key',
'attestation_format' => 'none',
])->save();
$this->user->load('webAuthnCredentials');
$this->user->disableAllCredentials('test_id_2');
static::assertTrue($this->user->webAuthnCredentials->firstWhere('id', 'test_id')->isDisabled());
static::assertFalse($this->user->webAuthnCredentials->firstWhere('id', 'test_id_2')->isDisabled());
$this->assertDatabaseCount(WebAuthnCredential::class, 2);
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => 'test_id',
'disabled_at' => now()->toDateTimeString(),
]);
$this->assertDatabaseHas(WebAuthnCredential::class, [
'id' => 'test_id_2',
'disabled_at' => null,
]);
}
}