Files
sample-site/files/dfido2-lib.js
2025-10-06 21:22:13 +09:00

617 lines
26 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION = 'fido2_user_session'
const DFIDO2_LIB_LOCALSTG_NAME_REGISTERED = 'dfido2_lib_registered'
const DFIDO2_LIB_LOCALSTG_NAME_SVR_URL = 'dfido2_lib_svr_url'
/** ===APIs=== */
if(!localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL)){
localStorage.setItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL, 'https://fido2.amipro.me')
}
function setFidoServerURL(url){
localStorage.setItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL, url);
}
function canTryAutoAuthentication(){
//const session_text = localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION)
//alert('canTryAuth:'+session_text+"|"+(null != localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_REGISTERED)))
return null != localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_REGISTERED)
}
/**
*
* @param {String} userId
* @param {String} rpId
*/
async function authenticateFido2(userId = null, rpId = null) {
var result
result = await doAssertion(userId, rpId);
if(result.status === 'ok'){
sessionStorage.setItem(DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION,
JSON.stringify({session:result.session, uid:result.username}))
localStorage.setItem(DFIDO2_LIB_LOCALSTG_NAME_REGISTERED, new Date());
}
return result
}
/**
*
* @param {String} userId
* @param {String} rpId
*/
async function registerFido2(userId, userDisplay, rpId = null) {
if (isWebAuthnSupported()) {
const result = await doAttestation(userId, userDisplay, rpId);
if(result.status === 'ok'){
localStorage.setItem(DFIDO2_LIB_LOCALSTG_NAME_REGISTERED, new Date());
sessionStorage.setItem(DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION, JSON.stringify({session:result.session, uid:result.username}))
}
return result
}else return {status:'failed', errorMessage: getI18NErrorMessage('Fido2LibErr101:')}
}
/**
*
* @param {String} rpId
* @returns
*/
async function listUserDevicesFido2(rpId = null) {
try {
const session_text = sessionStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION)
if(!session_text) return {status:'ok', devices:[]}
const session_data = JSON.parse(session_text)
let req = {session: session_data.session}
if (rpId && 0 < rpId.length) {
req.rp = { id: rpId };
}
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/usr/dvc/lst", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(req)
});
const resp = await response.json();
if ('ok' === resp.status && resp.session === session_data.session) {
return {status:'ok', devices:resp.devices}
} else {
return {status:'failed', errorMessage: resp.errorMessage}
}
} catch (err) {
console.log(err)
let msg = err.message ? err.message : err;
//console.error("Assertion err: ", err);
var errRtn = {status:'failed', errorMessage: msg};
if(err.name) errRtn.name = err.name
return errRtn;
}
}
async function delUserDeviceFido2(device_id, rpId = null) {
try {
const session_text = sessionStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION)
const session_data = JSON.parse(session_text)
let req = {session: session_data.session, device_id: device_id}
if (rpId && 0 < rpId.length) {
req.rp = { id: rpId };
}
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/usr/dvc/rm", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(req)
});
const resp = await response.json();
return resp
} catch (err) {
console.log(err)
let msg = err.message ? err.message : err;
//console.error("Assertion err: ", err);
var errRtn = {status:'failed', errorMessage: msg};
if(err.name) errRtn.name = err.name
return errRtn;
}
}
function getSessionId() {
var rtn = null
try {
const session_text = sessionStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION)
if(session_text){
const session_data = JSON.parse(session_text)
rtn = session_data.session
}
return rtn
} catch (err) {
console.log(err)
return null;
}
}
async function validSession(rpId = null) {
try {
const session_text = sessionStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION)
if(!session_text) return false
const session_data = JSON.parse(session_text)
let req = {session: session_data.session}
if (rpId && 0 < rpId.length) {
req.rp = { id: rpId };
}
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/usr/validsession", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(req)
});
const resp = await response.json();
return resp.status === 'ok'
} catch (err) {
console.log(err)
return false;
}
}
async function logoutFido2UserSession(){
const session_text = sessionStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION)
if(!session_text) return
const session_data = JSON.parse(session_text)
let req = {session: session_data['session'], username: session_data['uid']}
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/usr/delsession", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(req)
});
sessionStorage.removeItem(DFIDO2_LIB_LOCALSTG_NAME_USER_SESSION);
}
async function getRegistrationUser(reg_session_id){
try {
let req = {session_id: reg_session_id}
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/reg/username", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(req)
});
const resp = await response.json();
return resp.username
} catch (err) {
console.log(err)
return false;
}
}
function errProcessFido2(result){
alert(errMessageFido2(result));
}
function errMessageFido2(result){
var rtn
if(result.errCode && fido2LibErrCodes.unknown != result.errCode ){
switch (result.errCode){
case fido2LibErrCodes.user_canceled:
rtn=getI18NErrorMessage('Fido2LibErr102:');
break;
case fido2LibErrCodes.timeout:
rtn=getI18NErrorMessage('Fido2LibErr103:');
break;
default:
rtn=result.errorMessage?result.errorMessage:getI18NErrorMessage('Fido2LibErr104:');
}
}else if(result.name && "InvalidStateError" === result.name){
rtn=getI18NErrorMessage('Fido2LibErr105:');
}else if(result.errorMessage){
const msg = getI18NErrorMessage(result.errorMessage);
rtn=msg?msg:result.errorMessage;
}else{
rtn=getI18NErrorMessage(i18n_messages, 'Fido2LibErr104:');
}
return rtn;
}
const fido2LibErrCodes = {
user_canceled : -101,
timeout : -102,
unknown : -999
}
const errMsgs = new Map();
const fido2LibErrMsgLanguages = {
english: 'en-US',
japanese: 'ja',
chinese_cn: 'zh-CN',
//chinese_tw: 'zh-TW',
}
errMsgs.set(fido2LibErrMsgLanguages.english, new Map());
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr101:', 'Unregistered enterprise authenticator aaguid!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr102:', 'Unable to authenticate with a unique device binding key from another device!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr103:', 'Unable to verify signature!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr104:', 'Key not found!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr105:', 'Username does not exist!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr106:', 'Unique Device ID is null!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr107:', '/attestation/result request body has no ID field!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr108:', 'ID field is not Base64Url encoded in /attestation/result request body!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr109:', '/attestation/result request body has no TYPE field!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr110:', 'TYPE field is not a DOMString in /attestation/result request body!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr111:', 'The TYPE field is not a public key in the /attestation/result request body!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr112:', 'ID field is not a DOMString in /attestation/result request body!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr115:', 'authenticatorData not found!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr116:', 'authenticatorData is not base64 URL encoded!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr117:', 'Signature not found!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr118:', 'Signature is not base64 URL encoded!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr119:', 'No user session!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr120:', 'User has reached the device limit!');
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr101:', 'Your browser does not support FIDO2.');
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr102:', 'The user canceled.');
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr103:', 'The process timeout.');
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr104:', 'System error.');
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr105:', 'The same authenticator cannot be registered again.');
errMsgs.set(fido2LibErrMsgLanguages.japanese, new Map());
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr101:', '登録されていないエンタープライズ認証デバイス aaguid!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr102:', '別のデバイスからの一意のデバイス バインド キーで認証できません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr103:', '署名を認証できません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr104:', 'キーが見つかりません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr105:', 'ユーザー名は存在しません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr106:', '固有のデバイス ID が null です!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr107:', '/attestation/result request の本文に ID フィールドがありません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr108:', 'ID フィールドは、/attestation/result リクエストの本文でエンコードされた Base64Url ではありません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr109:', '/attestation/result リクエストのボディに TYPE フィールドがありません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr110:', 'TYPE フィールドは、/attestation/result リクエストの本文の DOMString ではありません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr111:', 'TYPE フィールドは、/attestation/result リクエストの本文の公開鍵ではありません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr112:', 'ID フィールドは、/attestation/result リクエストの本文の DOMString ではありません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr115:', 'authenticatorData が見つかりません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr116:', 'authenticatorData は base64 URL エンコードされていません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr117:', '署名が見つかりません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr118:', '署名は base64 URL エンコードされていません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr119:', 'ユーザーセッションがありません!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr120:', 'ユーザーはデバイスの制限数に達しました!');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr101:', 'お使いのブラウザは FIDO2 をサポートしていません。');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr102:', 'ユーザーがキャンセルしました。');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr103:', 'プロセスがタイムアウトしました。');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr104:', 'システムエラー。');
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr105:', '同じ認証デバイスを再登録することはできません。');
errMsgs.set(fido2LibErrMsgLanguages.chinese_cn, new Map());
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr101:', '未注册的企业认证器 aaguid!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr102:', '无法使用来自其他设备的唯一设备绑定密钥进行身份验证!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr103:', '无法验证签名!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr104:', '认证Key未找到!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr105:', '用户名不存在!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr106:', 'Unique Device ID 为 null!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr107:', '/attestation/result请求体没有ID字段');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr108:', 'ID字段不是/attestation/result请求体中编码的Base64Url');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr109:', '/attestation/result请求体没有TYPE字段');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr110:', '/attestation/result 请求正文中的 TYPE 字段不是 DOMString!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr111:', 'TYPE字段不是/attestation/result请求体中的公钥');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr112:', 'ID 字段不是 /attestation/result 请求体中的 DOMString');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr115:', 'authenticatorData 未找到!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr116:', 'authenticatorData 不是 base64 URL 编码!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr117:', '未找到签名!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr118:', '签名不是 base64 URL 编码!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr119:', '未建立用户会话!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr120:', '用户已达到设备限制数!');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr101:', '您的浏览器不支持FIDO2.');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr102:', '用户取消了操作。');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr103:', '操作超时。');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr104:', '系统错误。');
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr105:', '无法再次注册相同的认证器。');
/**
*
* @param {String} errorMessage
* @param {errMsgLanguages} language
*/
function getI18NErrorMessage(errorMessage, language = null){
var lang = language ? language : window.navigator.language
var msgs = errMsgs.get(lang)
if(!msgs)msgs = errMsgs.get(fido2LibErrMsgLanguages.english)
if(errorMessage){
const msgHeader = 0<errorMessage.indexOf(':')?errorMessage.substring(0, errorMessage.indexOf(':')):errorMessage
const msg = msgs.get(msgHeader+":")
return msg?msgHeader+":"+msg:errorMessage;
} else return errorMessage;
}
/** ===utils=== */
function isWebAuthnSupported() {
if (window.PublicKeyCredential) {
return true;
} else {
return false;
}
}
function makePublicKey(attOptsResp) {
if (attOptsResp.excludeCredentials) {
attOptsResp.excludeCredentials = attOptsResp.excludeCredentials.map(
function (cred) {
cred.id = _base64ToArrayBuffer(_fromBase64URL(cred.id));
cred.transports = ["internal", "usb", "ble", "nfc"];
return cred;
}
);
//console.log("Attestation Options:");
//console.log(attOptsResp);
}
const keys = {
publicKey: {
attestation: attOptsResp.attestation,
authenticatorSelection: attOptsResp.authenticatorSelection,
excludeCredentials: attOptsResp.excludeCredentials,
rp: attOptsResp.rp,
user: {
id: _stringToArrayBuffer(attOptsResp.user.id), //_base64ToArrayBuffer(_fromBase64URL(attOptsResp.user.id)),
name: attOptsResp.user.name,
displayName: attOptsResp.user.displayName,
},
pubKeyCredParams: attOptsResp.pubKeyCredParams,
timeout: attOptsResp.timeout,
challenge: _base64ToArrayBuffer(_fromBase64URL(attOptsResp.challenge)),
}
}
return keys;
}
async function doAttestation(username, displayName, rpId, userVerification = 'preferred') {
var process_time_limit = Number.MAX_SAFE_INTEGER
try {
const attestationOptions = {
username: username,
displayName: encodeURIComponent(displayName),
authenticatorSelection: {
//authenticatorAttachment: "platform",
userVerification: userVerification,
requireResidentKey: false,
},
//attestation: "none",
};
if (rpId && 0 < rpId.length) {
attestationOptions.rp = { id: rpId }
}
const svrUrl = localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL)
const response = await fetch(svrUrl + "/attestation/options", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(attestationOptions),
});
const resp = await response.json();
if (resp.status === "failed") {
return {status:'failed', errorMessage: resp.errorMessage}
} else {
process_time_limit = (new Date()).getTime() + resp.timeout;
const res = await navigator.credentials.create(makePublicKey(resp));
if (res) {
let attResult = {
id: res.id,
rawId: _toBase64URL(btoa(_bufferToString(res.rawId)))
,
type: "public-key",
response: {
clientDataJSON: _toBase64URL(btoa(_bufferToString(res.response.clientDataJSON)))
,
attestationObject: _toBase64URL(btoa(_bufferToString(res.response.attestationObject)))
,
},
};
const result = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/attestation/result", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(attResult),
});
const respResult = await result.json();
if (respResult) {
if (respResult.status === "ok") {
return respResult
} else {
return {status:'failed', errorMessage: respResult.errorMessage}
}
} else {
return {status:'failed', errorMessage: 'Fido2LibErr999:Svr result error'}
}
} else {
return {status:'failed', errorMessage: 'Fido2LibErr999:Undefined Result'};
}
}
} catch (err) {
var errRtn = {status:'failed', errorMessage: err.message};
if(err.name) errRtn.name = err.name
if(err.name && 'NotAllowedError' === err.name){
const nowtm = (new Date()).getTime()
if(nowtm > process_time_limit){
errRtn.errCode = fido2LibErrCodes.timeout
}else{
errRtn.errCode = fido2LibErrCodes.user_canceled
}
}else errRtn.errCode = fido2LibErrCodes.unknown
return errRtn;
}
}
async function doAssertion(username = null, rpId = null, userVerification = 'preferred') {
var process_time_limit = Number.MAX_SAFE_INTEGER
try {
let authnOptions;
/*if (!username) {
authnOptions = {
authenticatorSelection: {
//authenticatorAttachment: "platform",
userVerification: "discouraged"
}
};
} else {
authnOptions = {
username: username,
authenticatorSelection: {
//authenticatorAttachment: "platform",
userVerification: "preferred"
}
};
}*/
authnOptions = {
username: username,
authenticatorSelection: {
//authenticatorAttachment: "platform",
userVerification: userVerification
}
};
if (rpId && 0 < rpId.length) {
authnOptions.rp = { id: rpId };
}
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/assertion/options", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(authnOptions)
});
const resp = await response.json();
if ('ok' === resp.status) {
process_time_limit = (new Date()).getTime() + resp.timeout;
resp.allowCredentials = resp.allowCredentials || [];
let mappedAllowCreds = resp.allowCredentials.map(x => {
return {
id: _base64ToArrayBuffer(_fromBase64URL(x.id)),
type: x.type,
transports: x.transports // can set like ['internal', 'usb'] to override server settings
};
});
const cred = await navigator.credentials.get({
publicKey: {
challenge: _base64ToArrayBuffer(_fromBase64URL(resp.challenge)),
timeout: resp.timeout,
rpId: resp.rpId,
userVerification: resp.userVerification,
allowCredentials: mappedAllowCreds
}
});
if (cred) {
let authRequest = {
id: cred.id,
rawId: Array.from(new Uint8Array(cred.rawId)),
type: cred.type,
response: {
authenticatorData: _toBase64URL(btoa(_bufferToString(cred.response.authenticatorData))),
clientDataJSON: _toBase64URL(btoa(_bufferToString(cred.response.clientDataJSON))),
signature: _toBase64URL(btoa(_bufferToString(cred.response.signature))),
userHandle: _toBase64URL(btoa(_bufferToString(cred.response.userHandle))) //_toBase64URL(btoa(_bufferToString(cred.response.userHandle)))
}
};
const res = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/assertion/result", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(authRequest)
});
const result = await res.json();
if (result.status === 'ok') {
return result
} else {
return {status:'failed', errorMessage: result.errorMessage}
}
} else {
return {status:'failed', errorMessage: 'Fido2LibErr999:Undefined Result'};
}
} else {
return {status:'failed', errorMessage: resp.errorMessage}
}
} catch (err) {
var errRtn = {status:'failed', errorMessage: err.message};
if(err.name) errRtn.name = err.name
if(err.name && 'NotAllowedError' === err.name){
const nowtm = (new Date()).getTime()
if(nowtm > process_time_limit){
errRtn.errCode = fido2LibErrCodes.timeout
}else{
errRtn.errCode = fido2LibErrCodes.user_canceled
}
}else errRtn.errCode = fido2LibErrCodes.unknown
return errRtn;
}
}
function _toBase64URL(s) {
return (s = (s = (s = s.split("=")[0]).replace(/\+/g, "-")).replace(/\//g, "_"));
}
function _base64ToArrayBuffer(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes;
}
function _stringToArrayBuffer(src) {
return (new Uint8Array([].map.call(src, function (c) {
return c.charCodeAt(0)
}))).buffer;
}
function _fromBase64URL(s) {
var chk = (s = s.replace(/-/g, "+").replace(/_/g, "/")).length % 4;
if (chk) {
if (1 === chk) throw new Error("Base64url string is wrong.");
s += new Array(5 - chk).join("=");
}
return s;
}
function _bufferToString(s) {
return new Uint8Array(s).reduce((s, e) => s + String.fromCodePoint(e), "");
}