{"version":3,"file":"passkeys.mjs","names":[],"sources":["../../../src/internal/clerk-js/passkeys.ts"],"sourcesContent":["import type { ClerkRuntimeError } from '../../error';\nimport { ClerkWebAuthnError } from '../../error';\nimport type {\n  CredentialReturn,\n  PublicKeyCredentialCreationOptionsJSON,\n  PublicKeyCredentialCreationOptionsWithoutExtensions,\n  PublicKeyCredentialRequestOptionsJSON,\n  PublicKeyCredentialRequestOptionsWithoutExtensions,\n  PublicKeyCredentialWithAuthenticatorAssertionResponse,\n  PublicKeyCredentialWithAuthenticatorAttestationResponse,\n} from '../../types';\n\ntype WebAuthnCreateCredentialReturn = CredentialReturn<PublicKeyCredentialWithAuthenticatorAttestationResponse>;\ntype WebAuthnGetCredentialReturn = CredentialReturn<PublicKeyCredentialWithAuthenticatorAssertionResponse>;\n\nclass Base64Converter {\n  static encode(buffer: ArrayBuffer): string {\n    return btoa(String.fromCharCode(...new Uint8Array(buffer)))\n      .replace(/\\+/g, '-')\n      .replace(/\\//g, '_')\n      .replace(/=+$/, '');\n  }\n\n  static decode(base64url: string): ArrayBuffer {\n    const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');\n\n    const binaryString = atob(base64);\n    const length = binaryString.length;\n    const bytes = new Uint8Array(length);\n    for (let i = 0; i < length; i++) {\n      bytes[i] = binaryString.charCodeAt(i);\n    }\n    return bytes.buffer;\n  }\n}\n\nasync function webAuthnCreateCredential(\n  publicKeyOptions: PublicKeyCredentialCreationOptionsWithoutExtensions,\n): Promise<WebAuthnCreateCredentialReturn> {\n  try {\n    // Typescript types are not aligned with the spec. These type assertions are required to comply with the spec.\n    const credential = (await navigator.credentials.create({\n      publicKey: publicKeyOptions,\n    })) as PublicKeyCredentialWithAuthenticatorAttestationResponse | null;\n\n    if (!credential) {\n      return {\n        error: new ClerkWebAuthnError('Browser failed to create credential', {\n          code: 'passkey_registration_failed',\n        }),\n        publicKeyCredential: null,\n      };\n    }\n\n    return { publicKeyCredential: credential, error: null };\n  } catch (e) {\n    return { error: handlePublicKeyCreateError(e as Error), publicKeyCredential: null };\n  }\n}\n\nclass WebAuthnAbortService {\n  private controller: AbortController | undefined;\n\n  private __abort() {\n    if (!this.controller) {\n      return;\n    }\n    const abortError = new Error();\n    abortError.name = 'AbortError';\n    this.controller.abort(abortError);\n  }\n\n  createAbortSignal() {\n    this.__abort();\n    const newController = new AbortController();\n    this.controller = newController;\n    return newController.signal;\n  }\n\n  abort() {\n    this.__abort();\n    this.controller = undefined;\n  }\n}\n\nconst __internal_WebAuthnAbortService = new WebAuthnAbortService();\n\nasync function webAuthnGetCredential({\n  publicKeyOptions,\n  conditionalUI,\n}: {\n  publicKeyOptions: PublicKeyCredentialRequestOptionsWithoutExtensions;\n  conditionalUI: boolean;\n}): Promise<WebAuthnGetCredentialReturn> {\n  try {\n    // Typescript types are not aligned with the spec. These type assertions are required to comply with the spec.\n    const credential = (await navigator.credentials.get({\n      publicKey: publicKeyOptions,\n      mediation: conditionalUI ? 'conditional' : 'optional',\n      signal: __internal_WebAuthnAbortService.createAbortSignal(),\n    })) as PublicKeyCredentialWithAuthenticatorAssertionResponse | null;\n\n    if (!credential) {\n      return {\n        error: new ClerkWebAuthnError('Browser failed to get credential', { code: 'passkey_retrieval_failed' }),\n        publicKeyCredential: null,\n      };\n    }\n\n    return { publicKeyCredential: credential, error: null };\n  } catch (e) {\n    return { error: handlePublicKeyGetError(e as Error), publicKeyCredential: null };\n  }\n}\n\nfunction handlePublicKeyError(error: Error): ClerkWebAuthnError | ClerkRuntimeError | Error {\n  if (error.name === 'AbortError') {\n    return new ClerkWebAuthnError(error.message, { code: 'passkey_operation_aborted' });\n  }\n  if (error.name === 'SecurityError') {\n    return new ClerkWebAuthnError(error.message, {\n      code: 'passkey_invalid_rpID_or_domain',\n      docsUrl: 'https://clerk.com/docs/deployments/overview#authentication-across-subdomains',\n    });\n  }\n  return error;\n}\n\n/**\n * Map webauthn errors from `navigator.credentials.create()` to Clerk-js errors\n *\n * @param error\n */\nfunction handlePublicKeyCreateError(error: Error): ClerkWebAuthnError | ClerkRuntimeError | Error {\n  if (error.name === 'InvalidStateError') {\n    // Note: Firefox will throw 'NotAllowedError' when passkeys exists\n    return new ClerkWebAuthnError(error.message, { code: 'passkey_already_exists' });\n  }\n  if (error.name === 'NotAllowedError') {\n    return new ClerkWebAuthnError(error.message, { code: 'passkey_registration_cancelled' });\n  }\n  return handlePublicKeyError(error);\n}\n\n/**\n * Map webauthn errors from `navigator.credentials.get()` to Clerk-js errors\n *\n * @param error\n */\nfunction handlePublicKeyGetError(error: Error): ClerkWebAuthnError | ClerkRuntimeError | Error {\n  if (error.name === 'NotAllowedError') {\n    return new ClerkWebAuthnError(error.message, { code: 'passkey_retrieval_cancelled' });\n  }\n  return handlePublicKeyError(error);\n}\n\nfunction convertJSONToPublicKeyCreateOptions(jsonPublicKey: PublicKeyCredentialCreationOptionsJSON) {\n  const userIdBuffer = base64UrlToBuffer(jsonPublicKey.user.id);\n  const challengeBuffer = base64UrlToBuffer(jsonPublicKey.challenge);\n\n  const excludeCredentialsWithBuffer = (jsonPublicKey.excludeCredentials || []).map(cred => ({\n    ...cred,\n    id: base64UrlToBuffer(cred.id),\n  }));\n\n  return {\n    ...jsonPublicKey,\n    excludeCredentials: excludeCredentialsWithBuffer,\n    challenge: challengeBuffer,\n    user: {\n      ...jsonPublicKey.user,\n      id: userIdBuffer,\n    },\n  } as PublicKeyCredentialCreationOptionsWithoutExtensions;\n}\n\nfunction convertJSONToPublicKeyRequestOptions(jsonPublicKey: PublicKeyCredentialRequestOptionsJSON) {\n  const challengeBuffer = base64UrlToBuffer(jsonPublicKey.challenge);\n\n  const allowCredentialsWithBuffer = (jsonPublicKey.allowCredentials || []).map(cred => ({\n    ...cred,\n    id: base64UrlToBuffer(cred.id),\n  }));\n\n  return {\n    ...jsonPublicKey,\n    allowCredentials: allowCredentialsWithBuffer,\n    challenge: challengeBuffer,\n  } as PublicKeyCredentialRequestOptionsWithoutExtensions;\n}\n\nfunction __serializePublicKeyCredential<T extends Omit<PublicKeyCredential, 'getClientExtensionResults'>>(pkc: T) {\n  return {\n    type: pkc.type,\n    id: pkc.id,\n    rawId: bufferToBase64Url(pkc.rawId),\n    authenticatorAttachment: pkc.authenticatorAttachment,\n  };\n}\n\nfunction serializePublicKeyCredential(pkc: PublicKeyCredentialWithAuthenticatorAttestationResponse) {\n  const response = pkc.response;\n  return {\n    ...__serializePublicKeyCredential(pkc),\n    response: {\n      clientDataJSON: bufferToBase64Url(response.clientDataJSON),\n      attestationObject: bufferToBase64Url(response.attestationObject),\n      transports: response.getTransports(),\n    },\n  };\n}\n\nfunction serializePublicKeyCredentialAssertion(pkc: PublicKeyCredentialWithAuthenticatorAssertionResponse) {\n  const response = pkc.response;\n  return {\n    ...__serializePublicKeyCredential(pkc),\n    response: {\n      clientDataJSON: bufferToBase64Url(response.clientDataJSON),\n      authenticatorData: bufferToBase64Url(response.authenticatorData),\n      signature: bufferToBase64Url(response.signature),\n      userHandle: response.userHandle ? bufferToBase64Url(response.userHandle) : null,\n    },\n  };\n}\n\nconst bufferToBase64Url = Base64Converter.encode.bind(Base64Converter);\nconst base64UrlToBuffer = Base64Converter.decode.bind(Base64Converter);\n\nexport {\n  base64UrlToBuffer,\n  bufferToBase64Url,\n  handlePublicKeyCreateError,\n  webAuthnCreateCredential,\n  webAuthnGetCredential,\n  convertJSONToPublicKeyCreateOptions,\n  convertJSONToPublicKeyRequestOptions,\n  serializePublicKeyCredential,\n  serializePublicKeyCredentialAssertion,\n  __internal_WebAuthnAbortService,\n};\n"],"mappings":"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"}