coerceToArrayBuffer = function (thing, name) { if (typeof thing === "string") { // base64url to base64 thing = thing.replace(/-/g, "+").replace(/_/g, "/"); // base64 to Uint8Array const str = atob(thing); const bytes = new Uint8Array(str.length); for (let i = 0; i < str.length; i++) { bytes[i] = str.charCodeAt(i); } return bytes; } }; class Registration { constructor() { document.getElementById('start').addEventListener('click', this.registerAccount.bind(this)); } async registerAccount(event) { event.preventDefault(); const username = 'Foo! That Bar'; const login = btoa(username); const response = await fetch(`/buildCredentialOptions?login=${login}`, { method: 'GET', headers: { 'Accept': 'application/json' } }); const options = await response.json(); if (options.status !== "ok") { console.error("Error in buildCredentialOptions"); console.error(options.errorMessage); return; } else { console.log("Got options", options); } // Turn the challenge back into the accepted format of padded base64 options.challenge = coerceToArrayBuffer(options.challenge); // Turn ID into a UInt8Array Buffer for some reason options.user.id = coerceToArrayBuffer(options.user.id); options.excludeCredentials = options.excludeCredentials.map((c) => { c.id = coerceToArrayBuffer(c.id); return c; }); console.log("Options Formatted", options); // Create the Credential with navigator.credentials.create API let newCredential; try { newCredential = await navigator.credentials.create({ publicKey: options }); } catch (e) { console.error("credentials.create failed with exception", e); } console.log("PublicKeyCredential created", newCredential); // try { // register(newCredential); // } catch (e) { // console.error("Registering new credentials with the server failed with exception", e); // } } async register(newCredential) { // Move data into Arrays in case it is super long // TODO: check! let attestationObject = new Uint8Array(newCredential.response.attestationObject); let clientDataJSON = new Uint8Array(newCredential.response.clientDataJSON); let rawId = new Uint8Array(newCredential.rawId); const data = { id: newCredential.id, //rawId: coerceToBase64Url(rawId), type: newCredential.type, extensions: newCredential.getClientExtensionResults(), response: { AttestationObject: coerceToBase64Url(attestationObject), clientDataJSON: coerceToBase64Url(clientDataJSON), transports: newCredential.response.getTransports() } }; let response = await fetch(`/registerCredential?login=`, { method: 'POST', // or 'PUT' body: JSON.stringify(formData), // data can be `string` or {object}! headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }); const result = await response.json(); console.log("Credential Object", result); if (result.status !== "ok") { throw new Error(`Error creating credential: ${result.errorMessage}`); } } } window.registration = new Registration();