(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);
|