Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 16x 16x 16x 50x 16x 14x 14x 12x 14x 14x 14x 66x 14x 3x 3x 1x 3x 3x 1x 1x 1x 2x 2x | /**
* Base64url encode/decode utilities for WebAuthn binary fields.
*/
export function base64urlEncode(buffer: ArrayBuffer): string {
const bytes = new Uint8Array(buffer)
let binary = ''
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i])
}
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
}
export function base64urlDecode(str: string): ArrayBuffer {
// Add padding
let base64 = str.replace(/-/g, '+').replace(/_/g, '/')
while (base64.length % 4 !== 0) {
base64 += '='
}
const binary = atob(base64)
const bytes = new Uint8Array(binary.length)
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i)
}
return bytes.buffer
}
/**
* Prepare PublicKeyCredentialCreationOptions from server JSON.
* Converts base64url strings to ArrayBuffers where the WebAuthn API expects them.
*/
export function prepareRegistrationOptions(
options: Record<string, unknown>
): PublicKeyCredentialCreationOptions {
const publicKey = (options.publicKey ?? options) as Record<string, unknown>
return {
...publicKey,
challenge: base64urlDecode(publicKey.challenge as string),
user: {
...(publicKey.user as Record<string, unknown>),
id: base64urlDecode((publicKey.user as Record<string, string>).id),
},
excludeCredentials: ((publicKey.excludeCredentials as Array<Record<string, unknown>>) ?? []).map(
(cred) => ({
...cred,
id: base64urlDecode(cred.id as string),
})
),
} as PublicKeyCredentialCreationOptions
}
/**
* Prepare PublicKeyCredentialRequestOptions from server JSON.
*/
export function prepareAuthenticationOptions(
options: Record<string, unknown>
): PublicKeyCredentialRequestOptions {
const publicKey = (options.publicKey ?? options) as Record<string, unknown>
return {
...publicKey,
challenge: base64urlDecode(publicKey.challenge as string),
allowCredentials: ((publicKey.allowCredentials as Array<Record<string, unknown>>) ?? []).map(
(cred) => ({
...cred,
id: base64urlDecode(cred.id as string),
})
),
} as PublicKeyCredentialRequestOptions
}
/**
* Serialize a registration credential response for sending to the server.
*/
export function serializeRegistrationCredential(
credential: PublicKeyCredential
): Record<string, unknown> {
const response = credential.response as AuthenticatorAttestationResponse
return {
id: credential.id,
rawId: base64urlEncode(credential.rawId),
type: credential.type,
response: {
attestationObject: base64urlEncode(response.attestationObject),
clientDataJSON: base64urlEncode(response.clientDataJSON),
},
authenticatorAttachment: (credential as unknown as Record<string, string>).authenticatorAttachment,
}
}
/**
* Serialize an authentication credential response for sending to the server.
*/
export function serializeAuthenticationCredential(
credential: PublicKeyCredential
): Record<string, unknown> {
const response = credential.response as AuthenticatorAssertionResponse
return {
id: credential.id,
rawId: base64urlEncode(credential.rawId),
type: credential.type,
response: {
authenticatorData: base64urlEncode(response.authenticatorData),
clientDataJSON: base64urlEncode(response.clientDataJSON),
signature: base64urlEncode(response.signature),
userHandle: response.userHandle ? base64urlEncode(response.userHandle) : null,
},
}
}
|