63 lines
2.0 KiB
TypeScript
63 lines
2.0 KiB
TypeScript
|
export function buildDataString(assertedCredential: PublicKeyCredential) {
|
||
|
const response = assertedCredential.response as AuthenticatorAssertionResponse;
|
||
|
|
||
|
const authData = new Uint8Array(response.authenticatorData);
|
||
|
const clientDataJSON = new Uint8Array(response.clientDataJSON);
|
||
|
const rawId = new Uint8Array(assertedCredential.rawId);
|
||
|
const sig = new Uint8Array(response.signature);
|
||
|
|
||
|
const data = {
|
||
|
id: assertedCredential.id,
|
||
|
rawId: coerceToBase64Url(rawId),
|
||
|
type: assertedCredential.type,
|
||
|
extensions: assertedCredential.getClientExtensionResults(),
|
||
|
response: {
|
||
|
authenticatorData: coerceToBase64Url(authData),
|
||
|
clientDataJson: coerceToBase64Url(clientDataJSON),
|
||
|
signature: coerceToBase64Url(sig),
|
||
|
},
|
||
|
};
|
||
|
|
||
|
return JSON.stringify(data);
|
||
|
}
|
||
|
|
||
|
export function b64Decode(str: string) {
|
||
|
return decodeURIComponent(Array.prototype.map.call(atob(str), (c: string) => {
|
||
|
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||
|
}).join(''));
|
||
|
}
|
||
|
|
||
|
// From https://github.com/abergs/fido2-net-lib/blob/b487a1d47373ea18cd752b4988f7262035b7b54e/Demo/wwwroot/js/helpers.js#L34
|
||
|
// License: https://github.com/abergs/fido2-net-lib/blob/master/LICENSE.txt
|
||
|
function coerceToBase64Url(thing: any) {
|
||
|
// Array or ArrayBuffer to Uint8Array
|
||
|
if (Array.isArray(thing)) {
|
||
|
thing = Uint8Array.from(thing);
|
||
|
}
|
||
|
|
||
|
if (thing instanceof ArrayBuffer) {
|
||
|
thing = new Uint8Array(thing);
|
||
|
}
|
||
|
|
||
|
// Uint8Array to base64
|
||
|
if (thing instanceof Uint8Array) {
|
||
|
let str = '';
|
||
|
const len = thing.byteLength;
|
||
|
|
||
|
for (let i = 0; i < len; i++) {
|
||
|
str += String.fromCharCode(thing[i]);
|
||
|
}
|
||
|
thing = window.btoa(str);
|
||
|
}
|
||
|
|
||
|
if (typeof thing !== 'string') {
|
||
|
throw new Error('could not coerce to string');
|
||
|
}
|
||
|
|
||
|
// base64 to base64url
|
||
|
// NOTE: "=" at the end of challenge is optional, strip it off here
|
||
|
thing = thing.replace(/\+/g, '-').replace(/\//g, '_').replace(/=*$/g, '');
|
||
|
|
||
|
return thing;
|
||
|
}
|