ox
Version:
Ethereum Standard Library
105 lines • 3.29 kB
JavaScript
import * as Base64 from '../../core/Base64.js';
/** @internal */
export const base64UrlOptions = { url: true, pad: false };
/** @internal */
export const responseKeys = [
'attestationObject',
'authenticatorData',
'clientDataJSON',
'signature',
'userHandle',
];
/** @internal */
export function bytesToArrayBuffer(bytes) {
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
}
/** @internal */
export function bufferSourceToBytes(source) {
if (source instanceof Uint8Array)
return source;
if (source instanceof ArrayBuffer)
return new Uint8Array(source);
return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
}
/**
* Parses the fixed 37-byte header of authenticator data into rpIdHash, flags
* and signature counter. Variable-length tail (attested credential data,
* extensions) is the caller's responsibility.
*
* @internal
*/
export function parseAuthenticatorData(authenticatorData) {
if (authenticatorData.length < 37)
return undefined;
const flags = authenticatorData[32];
return {
bytes: authenticatorData,
rpIdHash: authenticatorData.subarray(0, 32),
flags,
up: (flags & 0x01) === 0x01,
uv: (flags & 0x04) === 0x04,
be: (flags & 0x08) === 0x08,
bs: (flags & 0x10) === 0x10,
at: (flags & 0x40) === 0x40,
ed: (flags & 0x80) === 0x80,
signCount: ((authenticatorData[33] << 24) |
(authenticatorData[34] << 16) |
(authenticatorData[35] << 8) |
authenticatorData[36]) >>>
0,
};
}
/**
* Serializes the response fields of a WebAuthn `AuthenticatorResponse`-like
* object into a base64url-encoded record. Falls back to getter methods
* (e.g. `getAuthenticatorData()`) for browsers and passkey providers that
* expose response fields only via getters.
*
* @internal
*/
export function serializeResponseFields(response) {
const out = {};
for (const key of responseKeys) {
let value = response[key];
// Some providers expose response fields only via getter methods
// (e.g. `getAuthenticatorData()`).
if (!(value instanceof ArrayBuffer)) {
const getter = `get${key[0].toUpperCase()}${key.slice(1)}`;
const fn = response[getter];
if (typeof fn === 'function')
value = fn.call(response);
}
if (value instanceof ArrayBuffer)
out[key] = Base64.fromBytes(new Uint8Array(value), base64UrlOptions);
}
return out;
}
/** @internal */
export function serializeExtensions(extensions) {
const { prf, ...rest } = extensions;
return {
...rest,
...(prf && {
prf: {
eval: {
first: Base64.fromBytes(prf.eval.first, base64UrlOptions),
},
},
}),
};
}
/** @internal */
export function deserializeExtensions(extensions) {
const { prf, ...rest } = extensions;
return {
...rest,
...(prf && {
prf: {
eval: {
first: Base64.toBytes(prf.eval.first),
},
},
}),
};
}
//# sourceMappingURL=utils.js.map