import { base64url } from "rfc4648"; export async function registerByWebAuthn(input) { // Check if WebAuthn is supported by this browser if (!window.PublicKeyCredential) { returnFailure(input.errmsg); return; } const publicKey = { challenge: base64url.parse(input.challenge, {loose: true}), rp: {id: input.rpId, name: input.rpEntityName}, user: { id: base64url.parse(input.userid, {loose: true}), name: input.username, displayName: input.username }, pubKeyCredParams: getPubKeyCredParams(input.signatureAlgorithms), }; if (input.attestationConveyancePreference !== 'not specified') { publicKey.attestation = input.attestationConveyancePreference; } const authenticatorSelection = {}; let isAuthenticatorSelectionSpecified = false; if (input.authenticatorAttachment !== 'not specified') { authenticatorSelection.authenticatorAttachment = input.authenticatorAttachment; isAuthenticatorSelectionSpecified = true; } if (input.requireResidentKey !== 'not specified') { if (input.requireResidentKey === 'Yes') { authenticatorSelection.requireResidentKey = true; } else { authenticatorSelection.requireResidentKey = false; } isAuthenticatorSelectionSpecified = true; } if (input.userVerificationRequirement !== 'not specified') { authenticatorSelection.userVerification = input.userVerificationRequirement; isAuthenticatorSelectionSpecified = true; } if (isAuthenticatorSelectionSpecified) { publicKey.authenticatorSelection = authenticatorSelection; } if (input.createTimeout !== 0) { publicKey.timeout = input.createTimeout * 1000; } const excludeCredentials = getExcludeCredentials(input.excludeCredentialIds); if (excludeCredentials.length > 0) { publicKey.excludeCredentials = excludeCredentials; } try { const result = await doRegister(publicKey); returnSuccess(result, input.initLabel, input.initLabelPrompt); } catch (error) { returnFailure(error); } } function doRegister(publicKey) { return navigator.credentials.create({publicKey}); } function getPubKeyCredParams(signatureAlgorithmsList) { const pubKeyCredParams = []; if (signatureAlgorithmsList.length === 0) { pubKeyCredParams.push({type: "public-key", alg: -7}); return pubKeyCredParams; } for (const entry of signatureAlgorithmsList) { pubKeyCredParams.push({ type: "public-key", alg: entry }); } return pubKeyCredParams; } function getExcludeCredentials(excludeCredentialIds) { const excludeCredentials = []; if (excludeCredentialIds === "") { return excludeCredentials; } for (const entry of excludeCredentialIds.split(',')) { excludeCredentials.push({ type: "public-key", id: base64url.parse(entry, {loose: true}) }); } return excludeCredentials; } function getTransportsAsString(transportsList) { if (!Array.isArray(transportsList)) { return ""; } return transportsList.join(); } function returnSuccess(result, initLabel, initLabelPrompt) { document.getElementById("clientDataJSON").value = base64url.stringify(new Uint8Array(result.response.clientDataJSON), {pad: false}); document.getElementById("attestationObject").value = base64url.stringify(new Uint8Array(result.response.attestationObject), {pad: false}); document.getElementById("publicKeyCredentialId").value = base64url.stringify(new Uint8Array(result.rawId), {pad: false}); if (typeof result.response.getTransports === "function") { const transports = result.response.getTransports(); if (transports) { document.getElementById("transports").value = getTransportsAsString(transports); } } else { console.log("Your browser is not able to recognize supported transport media for the authenticator."); } let labelResult = window.prompt(initLabelPrompt, initLabel); if (labelResult === null) { labelResult = initLabel; } document.getElementById("authenticatorLabel").value = labelResult; document.getElementById("register").submit(); } function returnFailure(err) { document.getElementById("error").value = err; document.getElementById("register").submit(); }