(function (window) { "use strict"; function base64UrlToArrayBuffer(base64Url) { var value = String(base64Url || "").replace(/-/g, "+").replace(/_/g, "/"); var padding = value.length % 4; if (padding) { value += new Array(5 - padding).join("="); } var binary = window.atob(value); var bytes = new Uint8Array(binary.length); for (var i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return bytes.buffer; } function arrayBufferToBase64Url(buffer) { var bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer || []); var binary = ""; for (var i = 0; i < bytes.length; i++) { binary += String.fromCharCode(bytes[i]); } return window.btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, ""); } function normalizeArray(value) { return Array.isArray(value) ? value : []; } function toCreationOptions(payload) { var publicKey = { challenge: base64UrlToArrayBuffer(payload.challenge), rp: { id: payload.rpId, name: payload.rpName || "WCS" }, user: { id: base64UrlToArrayBuffer(payload.userId), name: payload.userName, displayName: payload.userDisplayName || payload.userName }, pubKeyCredParams: normalizeArray(payload.pubKeyCredParams), timeout: Number(payload.timeout || 60000), attestation: payload.attestation || "none", authenticatorSelection: payload.authenticatorSelection || { residentKey: "preferred", userVerification: "required" } }; var excludeCredentials = normalizeArray(payload.excludeCredentials).map(function (item) { return { type: item.type || "public-key", id: base64UrlToArrayBuffer(item.id), transports: normalizeArray(item.transports) }; }); if (excludeCredentials.length) { publicKey.excludeCredentials = excludeCredentials; } return { publicKey: publicKey }; } function toRequestOptions(payload) { var publicKey = { challenge: base64UrlToArrayBuffer(payload.challenge), rpId: payload.rpId, timeout: Number(payload.timeout || 60000), userVerification: payload.userVerification || "required" }; var allowCredentials = normalizeArray(payload.allowCredentials).map(function (item) { return { type: item.type || "public-key", id: base64UrlToArrayBuffer(item.id), transports: normalizeArray(item.transports) }; }); if (allowCredentials.length) { publicKey.allowCredentials = allowCredentials; } return { publicKey: publicKey }; } function ensureSupported() { if (!window.isSecureContext) { throw new Error("secure-context"); } if (!window.PublicKeyCredential || !window.navigator || !window.navigator.credentials) { throw new Error("not-supported"); } } async function register(payload) { ensureSupported(); var credential = await window.navigator.credentials.create(toCreationOptions(payload)); if (!credential || !credential.response) { throw new Error("create-empty"); } var response = credential.response; if (typeof response.getPublicKey !== "function" || typeof response.getAuthenticatorData !== "function") { throw new Error("extension-unsupported"); } var publicKey = response.getPublicKey(); var authenticatorData = response.getAuthenticatorData(); if (!publicKey || !authenticatorData) { throw new Error("public-key-missing"); } return { credentialId: arrayBufferToBase64Url(credential.rawId), clientDataJSON: arrayBufferToBase64Url(response.clientDataJSON), authenticatorData: arrayBufferToBase64Url(authenticatorData), publicKey: arrayBufferToBase64Url(publicKey), publicKeyAlgorithm: response.getPublicKeyAlgorithm(), transports: JSON.stringify(typeof response.getTransports === "function" ? response.getTransports() || [] : []) }; } async function authenticate(payload) { ensureSupported(); var credential = await window.navigator.credentials.get(toRequestOptions(payload)); if (!credential || !credential.response) { throw new Error("get-empty"); } var response = credential.response; return { credentialId: arrayBufferToBase64Url(credential.rawId), clientDataJSON: arrayBufferToBase64Url(response.clientDataJSON), authenticatorData: arrayBufferToBase64Url(response.authenticatorData), signature: arrayBufferToBase64Url(response.signature), userHandle: response.userHandle ? arrayBufferToBase64Url(response.userHandle) : "" }; } window.WCS_WEBAUTHN = { isSupported: function () { return !!(window.isSecureContext && window.PublicKeyCredential && window.navigator && window.navigator.credentials); }, register: register, authenticate: authenticate }; })(window);