NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky

Passkeys::fake() nahradí relying party triedou PasskeysFake — programovateľnou náhradou bez kryptografie, naviazanou na kontrakt PasskeyService — a vráti ju na asercie. Registračné a prihlasovacie controllery tak otestujete bez simulovania kryptografie autentifikátora. Nevykonáva dekódovanie CBOR/COSE, overenie podpisu ani kontrolu challenge a platí len pre daný test. Vidí ju fasáda, injektovaný PasskeyService aj metódy modelu:

  • Ceremónie sa zaznamenajú, nevykonajú: register() uloží kľúč z factory, authenticate() vráti naprogramovaný výsledok a volania možností vrátia pripravené možnosti s uplatnenými nastaveniami. Pripravené možnosti registrácie dekódujú identifikátor používateľa rovnako ako skutočná služba, takže poškodený identifikátor sa odmietne aj tu.
  • Zaznamenajú sa aj volania cez metódy modelu (registerPasskey() a ďalšie) — idú cez Passkeys::for($this).
  • rename() a revoke() stále spúšťajú skutočné akcie s kontrolou vlastníctva — vrátane zápisov a udalostí PasskeyRenamed / PasskeyRevoked — a po úspechu sa zaznamenajú.
  • Čítanie (all(), find(), count(), exists()) ide do databázy; attestationFormats() vráti formáty skutočného registra.
use RoundlyConsulting\Passkeys\Facades\Passkeys;

$fake = Passkeys::fake();

// The fake skips the crypto, not your controller's parsing: RegistrationResponseData::fromArray()
// still needs the browser's shape with base64url members — any bytes will do.
$this->postJson('/passkeys', [
    'id' => 'AAAA',
    'rawId' => 'AAAA',
    'type' => 'public-key',
    'response' => ['clientDataJSON' => 'e30', 'attestationObject' => 'oA'],
])->assertCreated();

$fake->assertRegisteredFor($user);

$this->deleteJson("/passkeys/{$passkey->id}")->assertNoContent();
$fake->assertRevoked($passkey);
$fake->assertNothingRenamed();

// programmable outcomes:
Passkeys::fake()->rejectAuthentication();          // authenticate() throws CredentialNotFound
Passkeys::fake()->authenticatesAs($passkey);       // authenticate() returns this exact credential
Passkeys::fake()->failRegistrationWith($exception);

Programovateľné výsledky

MetódaEfekt
acceptRegistration()register() uloží pre používateľa kľúč ES256 z factory (predvolené).
failRegistrationWith($e)register() namiesto uloženia vyhodí zadanú PasskeyException.
acceptAuthentication()authenticate() uspeje (predvolené).
rejectAuthentication()authenticate() vyhodí CredentialNotFound.
authenticatesAs($passkey)authenticate() vráti presne tento kľúč.

Asercie

AserciaPrejde, keď
assertRegistered()Zaznamenala sa aspoň jedna registrácia.
assertRegisteredFor($user)Zaznamenala sa registrácia pre $user.
assertNothingRegistered()Nezaznamenala sa žiadna registrácia.
assertRegistrationCount($n)Zaznamenalo sa presne $n registrácií.
assertAuthenticated()Zaznamenalo sa aspoň jedno úspešné prihlásenie.
assertAuthenticatedFor($user)Zaznamenalo sa úspešné prihlásenie pre $user.
assertAuthenticationFailed()Aspoň jedno prihlásenie zlyhalo.
assertAuthenticationCount($n)Zaznamenalo sa presne $n prihlásení.
assertRenamed(?$passkey, ?$name)Zaznamenalo sa premenovanie — tohto kľúča a/alebo na tento názov, ak ich zadáte.
assertNothingRenamed()Nezaznamenalo sa žiadne premenovanie.
assertRevoked(?$passkey)Zaznamenalo sa odvolanie — tohto kľúča, ak ho zadáte.
assertNothingRevoked()Nezaznamenalo sa žiadne odvolanie.

Asercie vyhadzujú PasskeyAssertionFailed — výnimku balíka, nie PHPUnit aserciu — takže fungujú v akomkoľvek test runneri. Náhrada rešpektuje AuthenticationExpectation rovnako ako skutočné overovanie a for($user)->authenticate() viaže výsledok na daný účet — kľúč nesprávneho vlastníka sa zaznamená ako neúspech a vyhodí CredentialNotFound:

use RoundlyConsulting\Passkeys\Exceptions\CredentialAlreadyRegistered;
use RoundlyConsulting\Passkeys\Models\Passkey;

// A rejected sign-in
$fake = Passkeys::fake()->rejectAuthentication();
$this->postJson('/login/passkey', $payload)->assertUnauthorized();
$fake->assertAuthenticationFailed();

// A registration failure surfaced to the client
$fake = Passkeys::fake()->failRegistrationWith(CredentialAlreadyRegistered::make());
$this->actingAs($user)->postJson('/passkeys', $payload)->assertStatus(422);
$fake->assertNothingRegistered();

// Sign-in resolves to a specific credential
$passkey = Passkey::factory()->es256()->forAuthenticatable($user)->create();
Passkeys::fake()->authenticatesAs($passkey);
$this->postJson('/login/passkey', $payload)->assertOk();

Skutočné ceremónie s virtuálnym autentifikátorom

Ak chcete v testoch skutočné overovanie — challenge, origin, hash RP ID, príznaky, podpis, počítadlo, viazanie na používateľa — použite VirtualAuthenticator, softvérový autentifikátor ES256 s atestáciou none:

use RoundlyConsulting\Passkeys\DataTransferObjects\AuthenticationOptionsOverrides;
use RoundlyConsulting\Passkeys\Enums\UserVerification;
use RoundlyConsulting\Passkeys\Facades\Passkeys;
use RoundlyConsulting\Passkeys\Testing\VirtualAuthenticator;

$authenticator = VirtualAuthenticator::es256();   // rpId from the options, origin from config
$keys = Passkeys::for($user);

$keys->register($authenticator->register($keys->registrationOptions()));

$passkey = $keys->authenticate($authenticator->assert($keys->authenticationOptions()));

// Prove your step-up really demands user verification:
$options = $keys->authenticationOptions(new AuthenticationOptionsOverrides(userVerification: UserVerification::Required));
$keys->authenticate($authenticator->assert($options, userVerified: false)); // UserVerificationRequired

$authenticator->assert($options, signCount: 3);   // explicit counter, e.g. a cloned key
$authenticator->credentialId();                   // base64url, as stored in credential_id
  • register($options, residentKey: false) simuluje neobjaviteľný kľúč bez userHandle v odpovediach — rovnako ako so skutočným prehliadačom teda odpovie len na možnosti vydané pre jeho používateľa (Passkeys::for($user)->authenticationOptions()); ceremónia bez mena ho odmietne.
  • Počítadlo sa pri každom assert() zvýši o jedna, pokiaľ nezadáte signCount; userVerified: false pošle len prítomnosť používateľa.
  • Odpovie na akékoľvek možnosti, takže test môže hrať aj útočníka a dokázať, že server odmietne.
  • Len na testy: jeho kľúč je jednorazový materiál z TestKeys v crypto-for-laravel, v produkčnom kóde ho nikdy nepoužívajte. V runtime autoloade je len preto, aby ho mohli použiť testy iných balíkov — rovnako ako Passkeys::fake(). Na macOS s PHP z Homebrew môže generovanie kľúča vyžadovať OPENSSL_CONF nasmerované na openssl.cnf z Homebrew.

Factory

Passkey::factory() vytvára platné uložené kľúče pre vaše testy s použitím nakonfigurovaného modelu:

use RoundlyConsulting\Passkeys\Models\Passkey;

$passkey = Passkey::factory()->es256()->forAuthenticatable($user)->create();
$rsa     = Passkey::factory()->rs256()->neverUsed()->forAuthenticatable($user)->create();
StavEfekt
es256()Platný verejný COSE kľúč ES256 (P-256).
rs256()Platný verejný COSE kľúč RS256 (RSA-2048).
withCredentialId($id)Kľúč s explicitným ID a jeho hashom.
forAuthenticatable($model)Kľúč vlastnený konkrétnym modelom.
neverUsed()sign_count = 0, last_used_at = null.

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.