diff --git a/apps/browser/src/browser/webauthn-utils.ts b/apps/browser/src/browser/webauthn-utils.ts index dc83fe381bc..e21fb898dbe 100644 --- a/apps/browser/src/browser/webauthn-utils.ts +++ b/apps/browser/src/browser/webauthn-utils.ts @@ -6,32 +6,6 @@ import { } from "@bitwarden/common/fido2/abstractions/fido2-client.service.abstraction"; import { Fido2Utils } from "@bitwarden/common/fido2/abstractions/fido2-utils"; -class BitAuthenticatorAttestationResponse implements AuthenticatorAttestationResponse { - clientDataJSON: ArrayBuffer; - attestationObject: ArrayBuffer; - - constructor(private result: CreateCredentialResult) { - this.clientDataJSON = Fido2Utils.stringToBuffer(result.clientDataJSON); - this.attestationObject = Fido2Utils.stringToBuffer(result.attestationObject); - } - - getAuthenticatorData(): ArrayBuffer { - return Fido2Utils.stringToBuffer(this.result.authData); - } - - getPublicKey(): ArrayBuffer { - return null; - } - - getPublicKeyAlgorithm(): number { - return this.result.publicKeyAlgorithm; - } - - getTransports(): string[] { - return this.result.transports; - } -} - export class WebauthnUtils { static mapCredentialCreationOptions( options: CredentialCreationOptions, @@ -77,14 +51,41 @@ export class WebauthnUtils { } static mapCredentialRegistrationResult(result: CreateCredentialResult): PublicKeyCredential { - return { + const credential = { id: result.credentialId, rawId: Fido2Utils.stringToBuffer(result.credentialId), type: "public-key", authenticatorAttachment: "cross-platform", - response: new BitAuthenticatorAttestationResponse(result), + response: { + clientDataJSON: Fido2Utils.stringToBuffer(result.clientDataJSON), + attestationObject: Fido2Utils.stringToBuffer(result.attestationObject), + + getAuthenticatorData(): ArrayBuffer { + return Fido2Utils.stringToBuffer(this.result.authData); + }, + + getPublicKey(): ArrayBuffer { + return null; + }, + + getPublicKeyAlgorithm(): number { + return this.result.publicKeyAlgorithm; + }, + + getTransports(): string[] { + return this.result.transports; + }, + } as AuthenticatorAttestationResponse, getClientExtensionResults: () => ({}), - } as any; + } as PublicKeyCredential; + + // Modify prototype chains to fix `instanceof` calls. + // This makes these objects indistinguishable from the native classes. + // Unfortunately PublicKeyCredential does not have a javascript constructor so `extends` does not work here. + Object.setPrototypeOf(credential.response, AuthenticatorAttestationResponse.prototype); + Object.setPrototypeOf(credential, PublicKeyCredential.prototype); + + return credential; } static mapCredentialRequestOptions( @@ -111,7 +112,7 @@ export class WebauthnUtils { } static mapCredentialAssertResult(result: AssertCredentialResult): PublicKeyCredential { - return { + const credential = { id: result.credentialId, rawId: Fido2Utils.stringToBuffer(result.credentialId), type: "public-key", @@ -123,6 +124,14 @@ export class WebauthnUtils { } as AuthenticatorAssertionResponse, getClientExtensionResults: () => ({}), authenticatorAttachment: "hybrid", - }; + } as PublicKeyCredential; + + // Modify prototype chains to fix `instanceof` calls. + // This makes these objects indistinguishable from the native classes. + // Unfortunately PublicKeyCredential does not have a javascript constructor so `extends` does not work here. + Object.setPrototypeOf(credential.response, AuthenticatorAssertionResponse.prototype); + Object.setPrototypeOf(credential, PublicKeyCredential.prototype); + + return credential; } } diff --git a/apps/browser/src/fido2/content/page-script.ts b/apps/browser/src/fido2/content/page-script.ts index e9e8501903d..2a3a58ef7d2 100644 --- a/apps/browser/src/fido2/content/page-script.ts +++ b/apps/browser/src/fido2/content/page-script.ts @@ -4,8 +4,10 @@ import { MessageType } from "./messaging/message"; import { Messenger } from "./messaging/messenger"; const browserCredentials = { - create: navigator.credentials.create.bind(navigator.credentials), - get: navigator.credentials.get.bind(navigator.credentials), + create: navigator.credentials.create.bind( + navigator.credentials + ) as typeof navigator.credentials.create, + get: navigator.credentials.get.bind(navigator.credentials) as typeof navigator.credentials.get, }; const messenger = Messenger.forDOMCommunication(window);