diff options
Diffstat (limited to 'packages/browser/src/helpers')
12 files changed, 56 insertions, 41 deletions
diff --git a/packages/browser/src/helpers/__jest__/generateCustomError.ts b/packages/browser/src/helpers/__jest__/generateCustomError.ts index 55f6acf..25609fa 100644 --- a/packages/browser/src/helpers/__jest__/generateCustomError.ts +++ b/packages/browser/src/helpers/__jest__/generateCustomError.ts @@ -10,7 +10,10 @@ type WebAuthnErrorName = | 'SecurityError' | 'UnknownError'; -export function generateCustomError(name: WebAuthnErrorName, message = ''): Error { +export function generateCustomError( + name: WebAuthnErrorName, + message = '', +): Error { const customError = new Error(); customError.name = name; customError.message = message; diff --git a/packages/browser/src/helpers/browserSupportsWebAuthn.test.ts b/packages/browser/src/helpers/browserSupportsWebAuthn.test.ts index 20d96c2..dcd5c7c 100644 --- a/packages/browser/src/helpers/browserSupportsWebAuthn.test.ts +++ b/packages/browser/src/helpers/browserSupportsWebAuthn.test.ts @@ -10,13 +10,19 @@ test('should return true when browser supports WebAuthn', () => { }); test('should return false when browser does not support WebAuthn', () => { - delete (window as any).PublicKeyCredential; + // This looks weird but it appeases the linter so it's _fiiiine_ + delete (window as { PublicKeyCredential: unknown }).PublicKeyCredential; expect(browserSupportsWebAuthn()).toBe(false); }); test('should return false when window is undefined', () => { // Make window undefined as it is in node environments. - const windowSpy = jest.spyOn<any, 'window'>(global, 'window', 'get'); + const windowSpy = jest.spyOn<typeof globalThis, 'window'>( + global, + 'window', + 'get', + ); + // @ts-ignore: Intentionally making window unavailable windowSpy.mockImplementation(() => undefined); expect(window).toBe(undefined); diff --git a/packages/browser/src/helpers/browserSupportsWebAuthn.ts b/packages/browser/src/helpers/browserSupportsWebAuthn.ts index 79fe673..706862d 100644 --- a/packages/browser/src/helpers/browserSupportsWebAuthn.ts +++ b/packages/browser/src/helpers/browserSupportsWebAuthn.ts @@ -3,6 +3,7 @@ */ export function browserSupportsWebAuthn(): boolean { return ( - window?.PublicKeyCredential !== undefined && typeof window.PublicKeyCredential === 'function' + window?.PublicKeyCredential !== undefined && + typeof window.PublicKeyCredential === 'function' ); } diff --git a/packages/browser/src/helpers/browserSupportsWebAuthnAutofill.ts b/packages/browser/src/helpers/browserSupportsWebAuthnAutofill.ts index afc1176..cfdfb52 100644 --- a/packages/browser/src/helpers/browserSupportsWebAuthnAutofill.ts +++ b/packages/browser/src/helpers/browserSupportsWebAuthnAutofill.ts @@ -4,18 +4,19 @@ import { PublicKeyCredentialFuture } from '@simplewebauthn/typescript-types'; * Determine if the browser supports conditional UI, so that WebAuthn credentials can * be shown to the user in the browser's typical password autofill popup. */ -export async function browserSupportsWebAuthnAutofill(): Promise<boolean> { +export function browserSupportsWebAuthnAutofill(): Promise<boolean> { /** * I don't like the `as unknown` here but there's a `declare var PublicKeyCredential` in * TS' DOM lib that's making it difficult for me to just go `as PublicKeyCredentialFuture` as I * want. I think I'm fine with this for now since it's _supposed_ to be temporary, until TS types * have a chance to catch up. */ - const globalPublicKeyCredential = - window.PublicKeyCredential as unknown as PublicKeyCredentialFuture; + const globalPublicKeyCredential = window + .PublicKeyCredential as unknown as PublicKeyCredentialFuture; - return ( - globalPublicKeyCredential.isConditionalMediationAvailable !== undefined && - globalPublicKeyCredential.isConditionalMediationAvailable() - ); + if (globalPublicKeyCredential.isConditionalMediationAvailable === undefined) { + return new Promise((resolve) => resolve(false)); + } + + return globalPublicKeyCredential.isConditionalMediationAvailable(); } diff --git a/packages/browser/src/helpers/identifyAuthenticationError.ts b/packages/browser/src/helpers/identifyAuthenticationError.ts index d8d6960..78732b2 100644 --- a/packages/browser/src/helpers/identifyAuthenticationError.ts +++ b/packages/browser/src/helpers/identifyAuthenticationError.ts @@ -57,7 +57,8 @@ export function identifyAuthenticationError({ // https://www.w3.org/TR/webauthn-2/#sctn-op-get-assertion (Step 1) // https://www.w3.org/TR/webauthn-2/#sctn-op-get-assertion (Step 12) return new WebAuthnError({ - message: 'The authenticator was unable to process the specified options, or could not create a new assertion signature', + message: + 'The authenticator was unable to process the specified options, or could not create a new assertion signature', code: 'ERROR_AUTHENTICATOR_GENERAL_ERROR', cause: error, }); diff --git a/packages/browser/src/helpers/identifyRegistrationError.ts b/packages/browser/src/helpers/identifyRegistrationError.ts index 02c9dac..59533da 100644 --- a/packages/browser/src/helpers/identifyRegistrationError.ts +++ b/packages/browser/src/helpers/identifyRegistrationError.ts @@ -30,11 +30,14 @@ export function identifyRegistrationError({ if (publicKey.authenticatorSelection?.requireResidentKey === true) { // https://www.w3.org/TR/webauthn-2/#sctn-op-make-cred (Step 4) return new WebAuthnError({ - message: 'Discoverable credentials were required but no available authenticator supported it', + message: + 'Discoverable credentials were required but no available authenticator supported it', code: 'ERROR_AUTHENTICATOR_MISSING_DISCOVERABLE_CREDENTIAL_SUPPORT', cause: error, }); - } else if (publicKey.authenticatorSelection?.userVerification === 'required') { + } else if ( + publicKey.authenticatorSelection?.userVerification === 'required' + ) { // https://www.w3.org/TR/webauthn-2/#sctn-op-make-cred (Step 5) return new WebAuthnError({ message: 'User verification was required but no available authenticator supported it', @@ -48,7 +51,7 @@ export function identifyRegistrationError({ return new WebAuthnError({ message: 'The authenticator was previously registered', code: 'ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED', - cause: error + cause: error, }); } else if (error.name === 'NotAllowedError') { /** @@ -62,7 +65,7 @@ export function identifyRegistrationError({ }); } else if (error.name === 'NotSupportedError') { const validPubKeyCredParams = publicKey.pubKeyCredParams.filter( - param => param.type === 'public-key', + (param) => param.type === 'public-key', ); if (validPubKeyCredParams.length === 0) { @@ -76,7 +79,8 @@ export function identifyRegistrationError({ // https://www.w3.org/TR/webauthn-2/#sctn-op-make-cred (Step 2) return new WebAuthnError({ - message: 'No available authenticator supported any of the specified pubKeyCredParams algorithms', + message: + 'No available authenticator supported any of the specified pubKeyCredParams algorithms', code: 'ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG', cause: error, }); @@ -87,7 +91,7 @@ export function identifyRegistrationError({ return new WebAuthnError({ message: `${window.location.hostname} is an invalid domain`, code: 'ERROR_INVALID_DOMAIN', - cause: error + cause: error, }); } else if (publicKey.rp.id !== effectiveDomain) { // https://www.w3.org/TR/webauthn-2/#sctn-createCredential (Step 8) @@ -110,7 +114,8 @@ export function identifyRegistrationError({ // https://www.w3.org/TR/webauthn-2/#sctn-op-make-cred (Step 1) // https://www.w3.org/TR/webauthn-2/#sctn-op-make-cred (Step 8) return new WebAuthnError({ - message: 'The authenticator was unable to process the specified options, or could not create a new credential', + message: + 'The authenticator was unable to process the specified options, or could not create a new credential', code: 'ERROR_AUTHENTICATOR_GENERAL_ERROR', cause: error, }); diff --git a/packages/browser/src/helpers/isValidDomain.ts b/packages/browser/src/helpers/isValidDomain.ts index 4d2eedd..22f045f 100644 --- a/packages/browser/src/helpers/isValidDomain.ts +++ b/packages/browser/src/helpers/isValidDomain.ts @@ -9,6 +9,7 @@ export function isValidDomain(hostname: string): boolean { return ( // Consider localhost valid as well since it's okay wrt Secure Contexts - hostname === 'localhost' || /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(hostname) + hostname === 'localhost' || + /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(hostname) ); } diff --git a/packages/browser/src/helpers/platformAuthenticatorIsAvailable.test.ts b/packages/browser/src/helpers/platformAuthenticatorIsAvailable.test.ts index 3e0b65b..6f2b91d 100644 --- a/packages/browser/src/helpers/platformAuthenticatorIsAvailable.test.ts +++ b/packages/browser/src/helpers/platformAuthenticatorIsAvailable.test.ts @@ -7,8 +7,8 @@ beforeEach(() => { // @ts-ignore 2741 window.PublicKeyCredential = jest.fn().mockReturnValue(() => {}); - window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable = - mockIsUVPAA.mockResolvedValue(true); + window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable = mockIsUVPAA + .mockResolvedValue(true); }); test('should return true when platform authenticator is available', async () => { @@ -26,7 +26,8 @@ test('should return false when platform authenticator is unavailable', async () }); test('should return false when browser does not support WebAuthn', async () => { - delete (window as any).PublicKeyCredential; + // This looks weird but it appeases the linter so it's _fiiiine_ + delete (window as { PublicKeyCredential: unknown }).PublicKeyCredential; const isAvailable = await platformAuthenticatorIsAvailable(); expect(isAvailable).toEqual(false); diff --git a/packages/browser/src/helpers/platformAuthenticatorIsAvailable.ts b/packages/browser/src/helpers/platformAuthenticatorIsAvailable.ts index 7dc1505..269789c 100644 --- a/packages/browser/src/helpers/platformAuthenticatorIsAvailable.ts +++ b/packages/browser/src/helpers/platformAuthenticatorIsAvailable.ts @@ -6,9 +6,9 @@ import { browserSupportsWebAuthn } from './browserSupportsWebAuthn'; * * This method will _not_ be able to tell you the name of the platform authenticator. */ -export async function platformAuthenticatorIsAvailable(): Promise<boolean> { +export function platformAuthenticatorIsAvailable(): Promise<boolean> { if (!browserSupportsWebAuthn()) { - return false; + return new Promise((resolve) => resolve(false)); } return PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); diff --git a/packages/browser/src/helpers/webAuthnAbortService.test.ts b/packages/browser/src/helpers/webAuthnAbortService.test.ts index 98c1ccd..506bb2a 100644 --- a/packages/browser/src/helpers/webAuthnAbortService.test.ts +++ b/packages/browser/src/helpers/webAuthnAbortService.test.ts @@ -13,7 +13,7 @@ test('should call abort() with AbortError on existing controller when creating a // Spy on the existing instance of AbortController const abortSpy = jest.fn(); - // @ts-ignore + // @ts-ignore: Ignore the fact that `controller` is private webauthnAbortService.controller.abort = abortSpy; // Generate a new signal, which should call `abort()` on the existing controller diff --git a/packages/browser/src/helpers/webAuthnAbortService.ts b/packages/browser/src/helpers/webAuthnAbortService.ts index f90b263..50e00ba 100644 --- a/packages/browser/src/helpers/webAuthnAbortService.ts +++ b/packages/browser/src/helpers/webAuthnAbortService.ts @@ -12,7 +12,9 @@ class WebAuthnAbortService { createNewAbortSignal() { // Abort any existing calls to navigator.credentials.create() or navigator.credentials.get() if (this.controller) { - const abortError = new Error('Cancelling existing WebAuthn API call for new one'); + const abortError = new Error( + 'Cancelling existing WebAuthn API call for new one', + ); abortError.name = 'AbortError'; this.controller.abort(abortError); } diff --git a/packages/browser/src/helpers/webAuthnError.ts b/packages/browser/src/helpers/webAuthnError.ts index 1debec0..fb1def5 100644 --- a/packages/browser/src/helpers/webAuthnError.ts +++ b/packages/browser/src/helpers/webAuthnError.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ /** * A custom Error used to return a more nuanced error detailing _why_ one of the eight documented * errors in the spec was raised after calling `navigator.credentials.create()` or @@ -25,24 +24,20 @@ export class WebAuthnError extends Error { cause, name, }: { - message: string, - code: WebAuthnErrorCode, - cause: Error, - name?: string, + message: string; + code: WebAuthnErrorCode; + cause: Error; + name?: string; }) { - /** - * `cause` is supported in evergreen browsers, but not IE10, so this ts-ignore is to - * help Rollup complete the ES5 build. - */ - // @ts-ignore - super(message, { cause }) + // @ts-ignore: help Rollup understand that `cause` is okay to set + super(message, { cause }); this.name = name ?? cause.name; this.code = code; } } export type WebAuthnErrorCode = - 'ERROR_CEREMONY_ABORTED' + | 'ERROR_CEREMONY_ABORTED' | 'ERROR_INVALID_DOMAIN' | 'ERROR_INVALID_RP_ID' | 'ERROR_INVALID_USER_ID_LENGTH' @@ -52,5 +47,4 @@ export type WebAuthnErrorCode = | 'ERROR_AUTHENTICATOR_MISSING_USER_VERIFICATION_SUPPORT' | 'ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED' | 'ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG' - | 'ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY' - ; + | 'ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY'; |