2021-03-16 17:44:31 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-04-23 21:07:15 +02:00
|
|
|
export function parseWebauthnJson(jsonString: string) {
|
|
|
|
const json = JSON.parse(jsonString);
|
|
|
|
|
|
|
|
const challenge = json.challenge.replace(/-/g, "+").replace(/_/g, "/");
|
|
|
|
json.challenge = Uint8Array.from(atob(challenge), (c) => c.charCodeAt(0));
|
|
|
|
|
|
|
|
json.allowCredentials.forEach((listItem: any) => {
|
|
|
|
const fixedId = listItem.id.replace(/\_/g, "/").replace(/\-/g, "+");
|
|
|
|
listItem.id = Uint8Array.from(atob(fixedId), (c) => c.charCodeAt(0));
|
|
|
|
});
|
|
|
|
|
|
|
|
return json;
|
|
|
|
}
|
|
|
|
|
2021-03-16 17:44:31 +01:00
|
|
|
// 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);
|
2021-12-17 15:57:11 +01:00
|
|
|
}
|
2021-03-16 17:44:31 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|