UNPKG

@adorsys-gis/web-auth-prf

Version:

A WebAuthn library implementing password-based key derivation functions (PRF) for secure authentication and encryption

182 lines (181 loc) 7.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.saveMessage = saveMessage; exports.handleRegister = handleRegister; exports.handleAuthenticate = handleAuthenticate; exports.handleLogout = handleLogout; exports.main = main; const webAuthnService_1 = require("./webAuthnService"); const keyDerivationService_1 = require("./keyDerivationService"); const localDBService_1 = require("./localDBService"); const domainNameId = window.location.hostname; // Convert ArrayBuffer to Base64 and vice versa. function arrayBufferToBase64(buffer) { const binary = String.fromCharCode(...new Uint8Array(buffer)); return window.btoa(binary); } function base64ToUint8Array(base64) { const binary = atob(base64); const len = binary.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binary.charCodeAt(i); } return bytes; } // Load messages from localStorage and display them function loadMessages(decryptedMessages = []) { const messageList = document.querySelector("#messageList"); messageList.innerHTML = decryptedMessages .map((msg) => `<li>${msg}</li>`) .join(""); } // Save a message to localStorage async function saveMessage() { const input = document.querySelector("#messageInput"); const message = input.value.trim(); if (message) { const messages = JSON.parse(localStorage.getItem("messages") || "[]"); const keyService = new keyDerivationService_1.KeyDerivationService(); const storedSaltBase64 = localStorage.getItem("registrationSalt"); const storedSalt = storedSaltBase64 ? base64ToUint8Array(storedSaltBase64) : new Uint8Array(); const encryptionKey = { key: await keyService.deriveKey(new Uint8Array(32), new Uint8Array(storedSalt)), }; const localDB = new localDBService_1.LocalDBService(); const encryptedMessage = await localDB.encryptData(message, encryptionKey); messages.push(arrayBufferToBase64(encryptedMessage)); localStorage.setItem("messages", JSON.stringify(messages)); input.value = ""; loadMessages(); } } // Register function async function handleRegister() { const webAuthnService = new webAuthnService_1.WebAuthnService(); const regOptions = { challenge: crypto.getRandomValues(new Uint8Array(32)).buffer, rp: { name: "Localhost, Inc", id: domainNameId }, user: { id: crypto.getRandomValues(new Uint8Array(16)), name: "", displayName: "", }, pubKeyCredParams: [ { type: "public-key", alg: -7 }, // ES256 { type: "public-key", alg: -257 }, // RS256 ], timeout: 60000, authenticatorSelection: { authenticatorAttachment: "platform", residentKey: "required", userVerification: "required", }, extensions: { prf: { eval: { first: new Uint8Array(32).fill(1) } }, }, }; try { const registration = await webAuthnService.register(regOptions); // Convert credentialId to Base64 and store in local storage. const credentialIdBase64 = arrayBufferToBase64(registration.credentialId); localStorage.setItem("credentialId", credentialIdBase64); } catch (error) { console.error("Error in process:", error.message); document.getElementById("error").textContent = error.message; } } // Authenticate function async function handleAuthenticate() { const webAuthnService = new webAuthnService_1.WebAuthnService(); const keyService = new keyDerivationService_1.KeyDerivationService(); const localDB = new localDBService_1.LocalDBService(); // Retrieve the credentialId from local storage. const storedCredentialIdBase64 = localStorage.getItem("credentialId"); if (!storedCredentialIdBase64) { console.error("No stored credentialId found."); document.getElementById("error").textContent = "No stored credentialId found."; return []; } const storedCredentialId = base64ToUint8Array(storedCredentialIdBase64); // Retrieve the salt from local storage. const storedSaltBase64 = localStorage.getItem("registrationSalt"); if (!storedSaltBase64) { console.error("No stored salt found."); document.getElementById("error").textContent = "No stored salt found."; return []; } const storedSalt = base64ToUint8Array(storedSaltBase64); const authOptions = { challenge: crypto.getRandomValues(new Uint8Array(32)).buffer, allowCredentials: [ { type: "public-key", id: storedCredentialId, }, ], timeout: 60000, rpId: domainNameId, extensions: { prf: { eval: { first: new Uint8Array(32).fill(1) } }, }, }; try { const assertion = await webAuthnService.authenticate(authOptions); console.log("PRF output received:", assertion.prfResult); // Derive the encryption key using prfResult and stored salt const encryptionKey = { key: await keyService.deriveKey(new Uint8Array(32), new Uint8Array(storedSalt)), }; const messages = JSON.parse(localStorage.getItem("messages") || "[]"); const decryptedMessages = await Promise.all(messages.map(async (msg) => { const encryptedData = new Uint8Array(base64ToUint8Array(msg)); try { console.log("Attempting to decrypt message:", msg); const decryptedMessage = await localDB.decryptData(encryptedData.buffer, encryptionKey); return decryptedMessage; } catch (error) { console.error("Decryption failed for message:", msg, error); return "Decryption failed"; } })); const messageList = document.querySelector("#messageList"); messageList.innerHTML = decryptedMessages .map((msg) => `<li>${msg}</li>`) .join(""); // Pass decrypted messages to loadMessages loadMessages(decryptedMessages); return decryptedMessages; } catch (error) { console.error("Error in process:", error.message); document.getElementById("error").textContent = error.message; return []; } } // Logout function function handleLogout() { // localStorage.removeItem("credentialId"); // localStorage.removeItem("registrationSalt"); // localStorage.removeItem("messages"); console.log("User logged out. Credential and messages removed."); document.getElementById("error").textContent = "Logged out successfully."; } // Main function to set up event listeners async function main() { document .getElementById("registerBtn") ?.addEventListener("click", handleRegister); document .getElementById("authenticateBtn") ?.addEventListener("click", handleAuthenticate); document.getElementById("logoutBtn")?.addEventListener("click", handleLogout); document .getElementById("saveMessageBtn") ?.addEventListener("click", saveMessage); }