{"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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"}