UNPKG

@rize-labs/banana-passkey-manager

Version:

Passkey management module by Banana Team

146 lines 6.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.signMessageViaPassKeys = exports.checkAuth = exports.register = void 0; const base64url = require("./utils/base64url-arraybuffer"); const uuid_1 = require("uuid"); const axios_1 = require("axios"); const routes_1 = require("./constants/routes"); const ethers_1 = require("ethers"); const EllipticCurve__factory_1 = require("./typechain/factories/EllipticCurve__factory"); const index_1 = require("./constants/index"); const register = async () => { const uuid = (0, uuid_1.v4)(); const chanllenge = (0, uuid_1.v4)(); const isPlatformSupported = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); const authenticationSupport = isPlatformSupported ? "platform" : "cross-platform"; const publicKeyParams = { challenge: Uint8Array.from(chanllenge, (c) => c.charCodeAt(0)), rp: { name: "Banana Smart Wallet", }, user: { id: Uint8Array.from(uuid, (c) => c.charCodeAt(0)), name: "bananawallet", displayName: "Banana Smart Wallet", }, pubKeyCredParams: [{ type: "public-key", alg: -7 }], authenticatorSelection: { authenticatorAttachment: authenticationSupport, userVerification: "required", }, timeout: 60000, attestation: "none", }; let publicKeyCredential; try { publicKeyCredential = await navigator.credentials.create({ publicKey: publicKeyParams, }); } catch (err) { console.log("algo not supported, trying again", err); // @ts-ignore publicKeyParams.authenticatorSelection.authenticatorAttachment = "cross-platform"; publicKeyCredential = await navigator.credentials.create({ publicKey: publicKeyParams, }); } if (publicKeyCredential === null) { // alert('Failed to get credential') return Promise.reject(new Error("Failed to create credential")); } const response = await (0, axios_1.default)({ url: routes_1.REGISTRATION_LAMBDA_URL, method: "post", params: { aObject: JSON.stringify(Array.from(new Uint8Array(publicKeyCredential.response.attestationObject))), rawId: JSON.stringify( //@ts-ignore Array.from(new Uint8Array(publicKeyCredential?.rawId))), }, }); return { q0: response.data.message.q0hexString, q1: response.data.message.q1hexString, encodedId: response.data.message.encodedId, }; }; exports.register = register; const checkAuth = async (message, encodedId, eoaAddress) => { const { signature, messageSigned } = await (0, exports.signMessageViaPassKeys)({ message, encodedId, isMessageSignedNeeded: true }); const resp = await verifySignature(messageSigned, signature, eoaAddress); return resp; }; exports.checkAuth = checkAuth; const verifySignature = async (messageSigned, signature, eoaAddress) => { const rValue = ethers_1.ethers.BigNumber.from("0x" + signature.slice(2, 66)); const sValue = ethers_1.ethers.BigNumber.from("0x" + signature.slice(66, 132)); const ellipticCurve = EllipticCurve__factory_1.EllipticCurve__factory.connect(index_1.ELLIPTIC_CURVE_ADDRESS, new ethers_1.ethers.providers.JsonRpcProvider(index_1.JSON_RPC_PROVIDER)); const isVerified = await ellipticCurve.validateSignature(messageSigned, [rValue, sValue], eoaAddress); return isVerified; }; const signMessageViaPassKeys = async ({ message, encodedId, isMessageSignedNeeded }) => { const decodedId = base64url.decode(encodedId); const credential = await navigator.credentials.get({ publicKey: { allowCredentials: [ { id: decodedId, type: "public-key", }, ], challenge: Uint8Array.from(message, (c) => c.charCodeAt(0)).buffer, // Set the required authentication factors userVerification: "required", }, }); if (credential === null) { // alert('Failed to get credential') return Promise.reject(new Error("Failed to get credential")); } //@ts-ignore const response = credential.response; const clientDataJSON = Buffer.from(response.clientDataJSON); let signatureValid = false; let signature; while (!signatureValid) { signature = await (0, axios_1.default)({ url: routes_1.VERIFICATION_LAMBDA_URL, method: "post", params: { authDataRaw: JSON.stringify(Array.from(new Uint8Array(response.authenticatorData))), cData: JSON.stringify(Array.from(new Uint8Array(response.clientDataJSON))), signature: JSON.stringify(Array.from(new Uint8Array(response.signature))), }, }); if (signature.data.message.processStatus === "success") { signatureValid = true; } } const value = clientDataJSON.toString("hex").slice(72, 248); const clientDataJsonRequestId = ethers_1.ethers.utils.keccak256("0x" + value); //@ts-ignore const finalSignatureWithMessage = signature.data.message.finalSignature + clientDataJsonRequestId.slice(2); const abi = ethers_1.ethers.utils.defaultAbiCoder; const decoded = abi.decode(["uint256", "uint256", "uint256"], finalSignatureWithMessage); const signedMessage = decoded[2]; if (isMessageSignedNeeded) { const rHex = decoded[0].toHexString(); const sHex = decoded[1].toHexString(); const finalSignature = rHex + sHex.slice(2); return { //! signature signature: finalSignature, messageSigned: signedMessage }; } return { //! signature + message signature: finalSignatureWithMessage, }; }; exports.signMessageViaPassKeys = signMessageViaPassKeys; //# sourceMappingURL=WebAuthn.js.map