Compare commits
5 Commits
9bbbae8dd2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7248372cd8 | ||
|
|
1d2f4dfc9b | ||
|
|
03ce446b8a | ||
| 89ea8a48fc | |||
|
|
055d59f979 |
58
devices.html
58
devices.html
@@ -46,7 +46,6 @@
|
||||
<!--? Config: Mandatory theme config file contain global vars & default theme options, Set your preferred theme option in this file. -->
|
||||
<script src="files/config.js"></script>
|
||||
|
||||
<script src="files/jquery.js"></script>
|
||||
<script src="files/popper.js"></script>
|
||||
<script src="files/bootstrap.js"></script>
|
||||
<script src="files/perfect-scrollbar.js"></script>
|
||||
@@ -169,27 +168,25 @@
|
||||
window.location.href = "login.html";
|
||||
}
|
||||
}
|
||||
$('#user_id').html(user_id);
|
||||
document.getElementById('user_id').textContent = user_id;
|
||||
listDevices();
|
||||
}
|
||||
|
||||
async function setSessionStatus(){
|
||||
const sessionOk = await validSession();
|
||||
const sessionStatusEl = document.getElementById('session_status');
|
||||
if(sessionOk){
|
||||
$('#session_status').html(getI18NText(i18n_messages, 'msg_session_status_ok'))
|
||||
sessionStatusEl.textContent = getI18NText(i18n_messages, 'msg_session_status_ok');
|
||||
}else{
|
||||
$('#session_status').html(getI18NText(i18n_messages, 'msg_session_status_fail'))
|
||||
sessionStatusEl.textContent = getI18NText(i18n_messages, 'msg_session_status_fail');
|
||||
}
|
||||
}
|
||||
|
||||
async function addDevice(display_name){
|
||||
//You can change the display name or ask the user to input it, if the display_name is null.
|
||||
const result = await registerFido2(user_id, display_name?display_name:'dis_'+user_id);
|
||||
|
||||
if(result.status === 'ok'){
|
||||
//You can try to insert user_id into your user db now if this user_id does not exist in your db.
|
||||
|
||||
alert($('#msg_register_ok').html());
|
||||
alert(document.getElementById('msg_register_ok').textContent);
|
||||
listDevices();
|
||||
}else{
|
||||
errProcessFido2(result)
|
||||
@@ -213,17 +210,17 @@
|
||||
|
||||
async function listDevices(){
|
||||
const result = await listUserDevicesFido2()
|
||||
$("#devices_list").html("");
|
||||
const devicesListEl = document.getElementById('devices_list');
|
||||
devicesListEl.innerHTML = "";
|
||||
if("ok" === result.status){
|
||||
let lst_html = ""
|
||||
|
||||
for(let dev of result.devices){
|
||||
var dev_desc = dev.desc
|
||||
if(!dev_desc || 0 === dev_desc.length){
|
||||
let parser = new UAParser(dev.userAgent);
|
||||
|
||||
if(parser.getOS().name){
|
||||
dev_desc = parser.getDevice().model + ',' + parser.getOS().name + ',' + parser.getBrowser().name;
|
||||
const parser = new UAParser(dev.userAgent);
|
||||
const osName = parser.getOS().name;
|
||||
if(osName){
|
||||
dev_desc = parser.getDevice().model + ',' + osName + ',' + parser.getBrowser().name;
|
||||
}else{
|
||||
dev_desc = dev.userAgent;
|
||||
}
|
||||
@@ -231,14 +228,35 @@
|
||||
|
||||
var date = new Date(dev.registered_time);
|
||||
|
||||
lst_html += '<tr><td><strong>'+ dev_desc +'</strong></td><td>'+
|
||||
date.toLocaleString()+'</td><td>'+
|
||||
"<a style=\"padding-left: 0px;\" class=\"dropdown-item\" href=\"javascript:delDevice('"+dev.device_id+"');\">"+
|
||||
'<i class="bx bx-trash me-1"></i><span id="title_del"> '+ getI18NText(i18n_messages, 'title_del') +'</span></a></div></td></tr>'
|
||||
const row = document.createElement('tr');
|
||||
|
||||
const tdDevice = document.createElement('td');
|
||||
const strong = document.createElement('strong');
|
||||
strong.textContent = dev_desc;
|
||||
tdDevice.appendChild(strong);
|
||||
|
||||
const tdTime = document.createElement('td');
|
||||
tdTime.textContent = date.toLocaleString();
|
||||
|
||||
const tdAction = document.createElement('td');
|
||||
const link = document.createElement('a');
|
||||
link.className = 'dropdown-item';
|
||||
link.href = "javascript:delDevice('" + dev.device_id + "');";
|
||||
const icon = document.createElement('i');
|
||||
icon.className = 'bx bx-trash me-1';
|
||||
const span = document.createElement('span');
|
||||
span.textContent = ' ' + getI18NText(i18n_messages, 'title_del');
|
||||
link.appendChild(icon);
|
||||
link.appendChild(span);
|
||||
tdAction.appendChild(link);
|
||||
|
||||
row.appendChild(tdDevice);
|
||||
row.appendChild(tdTime);
|
||||
row.appendChild(tdAction);
|
||||
devicesListEl.appendChild(row);
|
||||
}
|
||||
$("#devices_list").html(lst_html);
|
||||
}else{
|
||||
const msg = getI18NErrorMessage(result.errorMessage); //fido2LibErrMsgLanguages.japanese
|
||||
const msg = getI18NErrorMessage(result.errorMessage);
|
||||
alert(msg?msg:result.errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* amiPro utils
|
||||
* amiPro utils - jQuery-free version
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function setI18NText(i18n_map){
|
||||
for (const key of i18n_map.keys()) {
|
||||
const elm = $("#"+key);
|
||||
const elm = document.getElementById(key);
|
||||
if(elm){
|
||||
const lang = window.navigator.language;
|
||||
var elem = i18n_map.get(key)
|
||||
@@ -17,7 +17,7 @@ function setI18NText(i18n_map){
|
||||
}
|
||||
if(!msg)msg = key+"-"+lang
|
||||
|
||||
$("#"+key).html(msg);
|
||||
elm.textContent = msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
/**
|
||||
*
|
||||
* @file dfido2-lib.js
|
||||
* @description FIDO2 library of amipro FIDO2 Server
|
||||
* @version 2025-12-12
|
||||
* @author Amipro Co., Ltd. (https://www.amipro.me/)
|
||||
* @license Copyright (c) Amipro Co., Ltd. All rights reserved.
|
||||
*/
|
||||
|
||||
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'
|
||||
|
||||
let configuredServerUrl = null;
|
||||
|
||||
/** ===APIs=== */
|
||||
|
||||
if(!localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL)){
|
||||
@@ -9,9 +20,25 @@ if(!localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL)){
|
||||
}
|
||||
|
||||
function setFidoServerURL(url){
|
||||
if (!url || !url.startsWith('https://')) {
|
||||
throw new Error('serverUrl must be a valid HTTPS URL');
|
||||
}
|
||||
configuredServerUrl = url;
|
||||
localStorage.setItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL, url);
|
||||
}
|
||||
|
||||
function getServerUrl() {
|
||||
if (configuredServerUrl) {
|
||||
return configuredServerUrl;
|
||||
}
|
||||
const stored = localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL);
|
||||
if (stored) {
|
||||
configuredServerUrl = stored;
|
||||
return stored;
|
||||
}
|
||||
return 'https://fido2.amipro.me';
|
||||
}
|
||||
|
||||
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)))
|
||||
@@ -67,7 +94,7 @@ async function listUserDevicesFido2(rpId = null) {
|
||||
req.rp = { id: rpId };
|
||||
}
|
||||
|
||||
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/usr/dvc/lst", {
|
||||
const response = await fetch(getServerUrl() + "/usr/dvc/lst", {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
headers: {
|
||||
@@ -104,7 +131,7 @@ async function delUserDeviceFido2(device_id, rpId = null) {
|
||||
req.rp = { id: rpId };
|
||||
}
|
||||
|
||||
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/usr/dvc/rm", {
|
||||
const response = await fetch(getServerUrl() + "/usr/dvc/rm", {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
headers: {
|
||||
@@ -154,7 +181,7 @@ async function validSession(rpId = null) {
|
||||
req.rp = { id: rpId };
|
||||
}
|
||||
|
||||
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/usr/validsession", {
|
||||
const response = await fetch(getServerUrl() + "/usr/validsession", {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
headers: {
|
||||
@@ -177,7 +204,7 @@ async function logoutFido2UserSession(){
|
||||
|
||||
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", {
|
||||
const response = await fetch(getServerUrl() + "/usr/delsession", {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
headers: {
|
||||
@@ -192,7 +219,7 @@ async function logoutFido2UserSession(){
|
||||
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", {
|
||||
const response = await fetch(getServerUrl() + "/reg/username", {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
headers: {
|
||||
@@ -223,16 +250,64 @@ function errMessageFido2(result){
|
||||
case fido2LibErrCodes.timeout:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr103:');
|
||||
break;
|
||||
case fido2LibErrCodes.invalid_state:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr105:');
|
||||
break;
|
||||
case fido2LibErrCodes.not_allowed:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr107:');
|
||||
break;
|
||||
case fido2LibErrCodes.abort:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr108:');
|
||||
break;
|
||||
case fido2LibErrCodes.not_supported:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr109:');
|
||||
break;
|
||||
case fido2LibErrCodes.security:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr110:');
|
||||
break;
|
||||
case fido2LibErrCodes.network:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr111:');
|
||||
break;
|
||||
case fido2LibErrCodes.constraint:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr112:');
|
||||
break;
|
||||
case fido2LibErrCodes.not_readable:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr113:');
|
||||
break;
|
||||
case fido2LibErrCodes.encoding:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr114:');
|
||||
break;
|
||||
case fido2LibErrCodes.data_error:
|
||||
rtn=getI18NErrorMessage('Fido2LibErr115:');
|
||||
break;
|
||||
default:
|
||||
rtn=result.errorMessage?result.errorMessage:getI18NErrorMessage('Fido2LibErr104:');
|
||||
}
|
||||
}else if(result.name && "InvalidStateError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr105:');
|
||||
}else if(result.name && "NotAllowedError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr107:');
|
||||
}else if(result.name && "AbortError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr108:');
|
||||
}else if(result.name && "NotSupportedError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr109:');
|
||||
}else if(result.name && "SecurityError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr110:');
|
||||
}else if(result.name && "NetworkError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr111:');
|
||||
}else if(result.name && "ConstraintError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr112:');
|
||||
}else if(result.name && "NotReadableError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr113:');
|
||||
}else if(result.name && "EncodingError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr114:');
|
||||
}else if(result.name && "DataError" === result.name){
|
||||
rtn=getI18NErrorMessage('Fido2LibErr115:');
|
||||
}else if(result.errorMessage){
|
||||
const msg = getI18NErrorMessage(result.errorMessage);
|
||||
rtn=msg?msg:result.errorMessage;
|
||||
}else{
|
||||
rtn=getI18NErrorMessage(i18n_messages, 'Fido2LibErr104:');
|
||||
rtn=getI18NErrorMessage('Fido2LibErr104:');
|
||||
}
|
||||
|
||||
return rtn;
|
||||
@@ -241,7 +316,17 @@ function errMessageFido2(result){
|
||||
const fido2LibErrCodes = {
|
||||
user_canceled : -101,
|
||||
timeout : -102,
|
||||
unknown : -999
|
||||
unknown : -999,
|
||||
invalid_state : -103,
|
||||
not_allowed : -104,
|
||||
abort : -105,
|
||||
not_supported : -106,
|
||||
security : -107,
|
||||
network : -108,
|
||||
constraint : -109,
|
||||
not_readable : -110,
|
||||
encoding : -111,
|
||||
data_error : -112
|
||||
}
|
||||
|
||||
const errMsgs = new Map();
|
||||
@@ -271,11 +356,23 @@ errMsgs.get(fido2LibErrMsgLanguages.english).set('SvrErr118:', 'Signature is not
|
||||
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.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr101:', 'Your browser does not support FIDO2/WebAuthn.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr102:', 'The operation was canceled by the user.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr103:', 'The operation timed out.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr104:', 'A system error occurred.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr105:', 'The authenticator contains credentials that are already registered with this website.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr106:', 'Another request is already in progress.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr107:', 'The operation was not allowed.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr108:', 'The operation was aborted.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr109:', 'This operation is not supported on your device.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr110:', 'A security error occurred.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr111:', 'A network error occurred.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr112:', 'The operation failed due to a constraint violation.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr113:', 'Could not read the credential.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr114:', 'The data format is invalid.');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr115:', 'A data error occurred.');
|
||||
|
||||
errMsgs.get(fido2LibErrMsgLanguages.english).set('Fido2LibErr106:', 'Another request is already in progress.');
|
||||
|
||||
errMsgs.set(fido2LibErrMsgLanguages.japanese, new Map());
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr101:', '登録されていないエンタープライズ認証デバイス aaguid!');
|
||||
@@ -297,11 +394,23 @@ errMsgs.get(fido2LibErrMsgLanguages.japanese).set('SvrErr118:', '署名は base6
|
||||
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.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr101:', 'お使いのブラウザは FIDO2/WebAuthn をサポートしていません。');
|
||||
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.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr106:', '別のリクエストがすでに進行中です。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr107:', '操作が許可されませんでした。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr108:', '操作が中止されました。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr109:', 'この機器ではこの操作はサポートされていません。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr110:', 'セキュリティエラーが発生しました。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr111:', 'ネットワークエラーが発生しました。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr112:', '制約違反のため操作に失敗しました。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr113:', '憑拠を読み取れませんでした。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr114:', 'データ形式が無効です。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr115:', 'データエラーが発生しました。');
|
||||
|
||||
errMsgs.get(fido2LibErrMsgLanguages.japanese).set('Fido2LibErr106:', '別のリクエストがすでに進行中です。');
|
||||
|
||||
errMsgs.set(fido2LibErrMsgLanguages.chinese_cn, new Map());
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr101:', '未注册的企业认证器 aaguid!');
|
||||
@@ -323,11 +432,23 @@ errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('SvrErr118:', '签名不是
|
||||
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('Fido2LibErr106:', '另一个请求正在进行中。');
|
||||
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr101:', '您的浏览器不支持FIDO2/WebAuthn。');
|
||||
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:', '无法再次注册相同的认证器。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr104:', '发生系统错误。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr105:', '您的认证器包含已在此网站注册的凭据。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr106:', '另一个请求正在进行中。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr107:', '操作不被允许。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr108:', '操作已中止。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr109:', '您的设备不支持此操作。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr110:', '发生安全错误。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr111:', '发生网络错误。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr112:', '由于约束冲突,操作失败。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr113:', '无法读取凭据。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr114:', '数据格式无效。');
|
||||
errMsgs.get(fido2LibErrMsgLanguages.chinese_cn).set('Fido2LibErr115:', '发生数据错误。');
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -410,7 +531,7 @@ async function doAttestation(username, displayName, rpId, userVerification = 'pr
|
||||
attestationOptions.rp = { id: rpId }
|
||||
}
|
||||
|
||||
const svrUrl = localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL)
|
||||
const svrUrl = getServerUrl()
|
||||
const response = await fetch(svrUrl + "/attestation/options", {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
@@ -445,7 +566,7 @@ async function doAttestation(username, displayName, rpId, userVerification = 'pr
|
||||
attResult.transports = res.response.getTransports();
|
||||
}
|
||||
|
||||
const result = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/attestation/result", {
|
||||
const result = await fetch(getServerUrl() + "/attestation/result", {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
headers: {
|
||||
@@ -471,6 +592,7 @@ async function doAttestation(username, displayName, rpId, userVerification = 'pr
|
||||
} 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){
|
||||
@@ -478,7 +600,27 @@ async function doAttestation(username, displayName, rpId, userVerification = 'pr
|
||||
}else{
|
||||
errRtn.errCode = fido2LibErrCodes.user_canceled
|
||||
}
|
||||
}else errRtn.errCode = fido2LibErrCodes.unknown
|
||||
} else if(err.name && 'InvalidStateError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.invalid_state
|
||||
} else if(err.name && 'AbortError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.abort
|
||||
} else if(err.name && 'NotSupportedError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.not_supported
|
||||
} else if(err.name && 'SecurityError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.security
|
||||
} else if(err.name && 'NetworkError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.network
|
||||
} else if(err.name && 'ConstraintError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.constraint
|
||||
} else if(err.name && 'NotReadableError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.not_readable
|
||||
} else if(err.name && 'EncodingError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.encoding
|
||||
} else if(err.name && 'DataError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.data_error
|
||||
} else {
|
||||
errRtn.errCode = fido2LibErrCodes.unknown
|
||||
}
|
||||
|
||||
return errRtn;
|
||||
} finally {
|
||||
@@ -524,7 +666,7 @@ async function doAssertion(username = null, rpId = null, userVerification = 'pre
|
||||
authnOptions.rp = { id: rpId };
|
||||
}
|
||||
|
||||
const response = await fetch(localStorage.getItem(DFIDO2_LIB_LOCALSTG_NAME_SVR_URL) + "/assertion/options", {
|
||||
const response = await fetch(getServerUrl() + "/assertion/options", {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
headers: {
|
||||
@@ -566,7 +708,7 @@ async function doAssertion(username = null, rpId = null, userVerification = 'pre
|
||||
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", {
|
||||
const res = await fetch(getServerUrl() + "/assertion/result", {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
headers: {
|
||||
@@ -589,6 +731,7 @@ async function doAssertion(username = null, rpId = null, userVerification = 'pre
|
||||
} 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){
|
||||
@@ -596,7 +739,27 @@ async function doAssertion(username = null, rpId = null, userVerification = 'pre
|
||||
}else{
|
||||
errRtn.errCode = fido2LibErrCodes.user_canceled
|
||||
}
|
||||
}else errRtn.errCode = fido2LibErrCodes.unknown
|
||||
} else if(err.name && 'InvalidStateError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.invalid_state
|
||||
} else if(err.name && 'AbortError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.abort
|
||||
} else if(err.name && 'NotSupportedError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.not_supported
|
||||
} else if(err.name && 'SecurityError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.security
|
||||
} else if(err.name && 'NetworkError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.network
|
||||
} else if(err.name && 'ConstraintError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.constraint
|
||||
} else if(err.name && 'NotReadableError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.not_readable
|
||||
} else if(err.name && 'EncodingError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.encoding
|
||||
} else if(err.name && 'DataError' === err.name){
|
||||
errRtn.errCode = fido2LibErrCodes.data_error
|
||||
} else {
|
||||
errRtn.errCode = fido2LibErrCodes.unknown
|
||||
}
|
||||
|
||||
return errRtn;
|
||||
} finally {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.fido2-sdk-logo {
|
||||
@@ -86,33 +87,9 @@
|
||||
border-radius: 6px;
|
||||
background-color: #e7f1ff;
|
||||
border-left: 4px solid #0d6efd;
|
||||
}
|
||||
}
|
||||
|
||||
.fido2-sdk-standalone {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.fido2-sdk-standalone .container {
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
.fido2-sdk-standalone .card {
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.fido2-sdk-standalone .card-header {
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
border-bottom: 2px solid #dee2e6;
|
||||
}
|
||||
|
||||
.fido2-sdk-standalone .card-body {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.fido2-sdk-table .text-danger {
|
||||
.fido2-sdk-table .text-danger {
|
||||
color: #dc3545 !important;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
@@ -138,10 +115,6 @@
|
||||
max-width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.fido2-sdk-standalone {
|
||||
padding: 20px 10px;
|
||||
}
|
||||
|
||||
.fido2-sdk-table th,
|
||||
.fido2-sdk-table td {
|
||||
padding: 8px 12px;
|
||||
@@ -156,6 +129,25 @@
|
||||
.fido2-sdk-logo {
|
||||
max-height: 30px;
|
||||
}
|
||||
|
||||
.fido2-sdk-status-badge {
|
||||
width: 100%;
|
||||
order: 3;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.fido2-sdk-header .btn-close {
|
||||
order: 2;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.fido2-sdk-header .modal-title {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.fido2-sdk-header .fido2-sdk-logo {
|
||||
order: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.fido2-sdk-loading {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,6 @@
|
||||
<!--? Config: Mandatory theme config file contain global vars & default theme options, Set your preferred theme option in this file. -->
|
||||
<script src="files/config.js"></script>
|
||||
|
||||
<script src="files/jquery.js"></script>
|
||||
<script src="files/popper.js"></script>
|
||||
<script src="files/bootstrap.js"></script>
|
||||
<script src="files/perfect-scrollbar.js"></script>
|
||||
@@ -167,13 +166,12 @@
|
||||
}
|
||||
|
||||
async function authenticate(){
|
||||
var uid = $('#uid').val()
|
||||
var uid = document.getElementById('uid').value
|
||||
if(uid && 0==uid.length)uid=null
|
||||
|
||||
const result = await authenticateFido2(uid)
|
||||
|
||||
if(result.status === 'ok'){
|
||||
//Set your logged in status and jump to user's top page.
|
||||
location.href = 'devices.html?uid='+result.username
|
||||
}else{
|
||||
errProcessFido2(result)
|
||||
@@ -181,9 +179,9 @@
|
||||
}
|
||||
|
||||
function checkInput(){
|
||||
const uid = $('#uid').val()
|
||||
const uid = document.getElementById('uid').value
|
||||
if(!uid || 0>=uid.length){
|
||||
alert($('#msg_uid_input').html())
|
||||
alert(document.getElementById('msg_uid_input').textContent)
|
||||
return false;
|
||||
}else return true;
|
||||
}
|
||||
|
||||
163
modal-demo.html
163
modal-demo.html
@@ -179,7 +179,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="files/jquery.js"></script>
|
||||
<script src="files/popper.js"></script>
|
||||
<script src="files/bootstrap.js"></script>
|
||||
<script src="files/dfido2-lib.js"></script>
|
||||
@@ -366,6 +365,36 @@
|
||||
lang_map.set("ja", "テーマの色とスタイルのカスタマイズ");
|
||||
i18n_messages.set("msg_feature_7", lang_map);
|
||||
|
||||
lang_map = new Map();
|
||||
lang_map.set("en-US", "Login Default");
|
||||
lang_map.set("zh-CN", "登录缺省");
|
||||
lang_map.set("ja", "ログイン デフォルト");
|
||||
i18n_messages.set("msg_code_login_default", lang_map);
|
||||
|
||||
lang_map = new Map();
|
||||
lang_map.set("en-US", "Login Custom");
|
||||
lang_map.set("zh-CN", "登录定制");
|
||||
lang_map.set("ja", "ログイン カスタム");
|
||||
i18n_messages.set("msg_code_login_custom", lang_map);
|
||||
|
||||
lang_map = new Map();
|
||||
lang_map.set("en-US", "Device Manager Default");
|
||||
lang_map.set("zh-CN", "设备管理缺省");
|
||||
lang_map.set("ja", "デバイス管理 デフォルト");
|
||||
i18n_messages.set("msg_code_device_default", lang_map);
|
||||
|
||||
lang_map = new Map();
|
||||
lang_map.set("en-US", "Device Manager Custom");
|
||||
lang_map.set("zh-CN", "设备管理定制");
|
||||
lang_map.set("ja", "デバイス管理 カスタム");
|
||||
i18n_messages.set("msg_code_device_custom", lang_map);
|
||||
|
||||
lang_map = new Map();
|
||||
lang_map.set("en-US", "JS Import Examples:");
|
||||
lang_map.set("zh-CN", "JS 引入示例:");
|
||||
lang_map.set("ja", "JS インポート例:");
|
||||
i18n_messages.set("msg_js_import_examples", lang_map);
|
||||
|
||||
lang_map = new Map();
|
||||
lang_map.set("en-US", "Multi-language support (English/Japanese/Chinese)");
|
||||
lang_map.set("zh-CN", "多语言支持(英/日/中)");
|
||||
@@ -510,41 +539,107 @@
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 id="msg_section_code_title">💻 Code Examples</h2>
|
||||
<p id="msg_code_simple">Simplest integration:</p>
|
||||
|
||||
<p id="msg_js_import_examples">JS Import Examples:</p>
|
||||
<div class="code-block">
|
||||
<code>Fido2UIManager.renderLogin({
|
||||
container: '#login-container',
|
||||
mode: 'modal',
|
||||
serverUrl: SERVER_URL
|
||||
<code><script src="files/popper.js"></script><br>
|
||||
<script src="files/bootstrap.js"></script><br>
|
||||
<script src="files/dfido2-lib.js"></script><br>
|
||||
<script src="files/fido2-ui-sdk.js"></script><br>
|
||||
<script src="files/amipro_utils.js"></script></code>
|
||||
</div>
|
||||
|
||||
<p id="msg_code_login_default">Login Default:</p>
|
||||
<div class="code-block">
|
||||
<code>// Login Default<br>
|
||||
Fido2UIManager.renderLogin({<br>
|
||||
container: '#login-container',<br>
|
||||
mode: 'modal',<br>
|
||||
serverUrl: SERVER_URL,<br>
|
||||
language: CURRENT_LANG<br>
|
||||
});</code>
|
||||
</div>
|
||||
|
||||
<p id="msg_code_theme">With theme customization:</p>
|
||||
<p id="msg_code_login_custom">Login Custom:</p>
|
||||
<div class="code-block">
|
||||
<code>Fido2UIManager.renderLogin({
|
||||
container: '#login-container',
|
||||
mode: 'modal',
|
||||
serverUrl: SERVER_URL,
|
||||
language: 'ja',
|
||||
theme: {
|
||||
primaryColor: '#ce59d9',
|
||||
backgroundColor: '#faf5ff'
|
||||
},
|
||||
features: {
|
||||
enablePasswordLogin: true,
|
||||
autoShowPassword: true
|
||||
}
|
||||
<code>// Login with Custom Theme<br>
|
||||
Fido2UIManager.renderLogin({<br>
|
||||
container: '#login-container',<br>
|
||||
mode: 'modal',<br>
|
||||
serverUrl: SERVER_URL,<br>
|
||||
language: 'ja',<br>
|
||||
theme: {<br>
|
||||
logo: 'files/favicon.ico',<br>
|
||||
primaryColor: '#ce59d9',<br>
|
||||
backgroundColor: '#faf5ff',<br>
|
||||
textColor: '#6b21a8',<br>
|
||||
borderRadius: '12px'<br>
|
||||
},<br>
|
||||
features: {<br>
|
||||
autoAuth: false,<br>
|
||||
enablePasswordLogin: true,<br>
|
||||
autoShowPassword: true,<br>
|
||||
maxPasswordAttempts: 3<br>
|
||||
},<br>
|
||||
callbacks: {<br>
|
||||
onFido2Success: function(username, session) {<br>
|
||||
// Handle login success<br>
|
||||
},<br>
|
||||
onFido2Error: function(error) {<br>
|
||||
// Handle error<br>
|
||||
}<br>
|
||||
}<br>
|
||||
});</code>
|
||||
</div>
|
||||
|
||||
<p id="msg_code_device">Device Manager:</p>
|
||||
<p id="msg_code_device_default">Device Manager Default:</p>
|
||||
<div class="code-block">
|
||||
<code>Fido2UIManager.renderDeviceManager({
|
||||
userId: currentUserId,
|
||||
container: '#device-container',
|
||||
mode: 'modal',
|
||||
serverUrl: SERVER_URL,
|
||||
language: 'ja'
|
||||
<code>// Device Manager Default<br>
|
||||
Fido2UIManager.renderDeviceManager({<br>
|
||||
userId: currentUserId,<br>
|
||||
container: '#device-container',<br>
|
||||
mode: 'modal',<br>
|
||||
serverUrl: SERVER_URL,<br>
|
||||
language: CURRENT_LANG<br>
|
||||
});</code>
|
||||
</div>
|
||||
|
||||
<p id="msg_code_device_custom">Device Manager Custom:</p>
|
||||
<div class="code-block">
|
||||
<code>// Device Manager with Custom Style<br>
|
||||
Fido2UIManager.renderDeviceManager({<br>
|
||||
userId: currentUserId,<br>
|
||||
container: '#device-container',<br>
|
||||
mode: 'modal',<br>
|
||||
serverUrl: SERVER_URL,<br>
|
||||
language: 'ja',<br>
|
||||
theme: {<br>
|
||||
logo: 'files/favicon.ico',<br>
|
||||
primaryColor: '#ce59d9',<br>
|
||||
backgroundColor: '#faf5ff',<br>
|
||||
textColor: '#6b21a8',<br>
|
||||
borderRadius: '12px'<br>
|
||||
},<br>
|
||||
features: {<br>
|
||||
showAddButton: true,<br>
|
||||
showDeleteButton: true,<br>
|
||||
showUserInfo: true,<br>
|
||||
showSessionStatus: true<br>
|
||||
},<br>
|
||||
callbacks: {<br>
|
||||
onInit: function(manager) {<br>
|
||||
// Manager initialized<br>
|
||||
},<br>
|
||||
onDeviceAdded: function(device) {<br>
|
||||
// Device added<br>
|
||||
},<br>
|
||||
onDeviceDeleted: function(deviceId) {<br>
|
||||
// Device deleted<br>
|
||||
},<br>
|
||||
onClose: function() {<br>
|
||||
// Manager closed<br>
|
||||
}<br>
|
||||
}<br>
|
||||
});</code>
|
||||
</div>
|
||||
</div>
|
||||
@@ -585,7 +680,7 @@
|
||||
return 'en-US';
|
||||
}
|
||||
|
||||
const CURRENT_LANG = getBrowserLanguage();//'https://fido2.amipro.me';
|
||||
const CURRENT_LANG = getBrowserLanguage();
|
||||
|
||||
function enableDeviceManagementButtons() {
|
||||
document.getElementById('btn-manage-devices').disabled = false;
|
||||
@@ -602,6 +697,7 @@
|
||||
}
|
||||
|
||||
function logout() {
|
||||
Fido2UIManager.logout();
|
||||
currentUserId = null;
|
||||
isLoggedIn = false;
|
||||
log('success', getI18NText(i18n_messages, 'msg_logout_success'));
|
||||
@@ -825,5 +921,16 @@
|
||||
https://amipro.me/fido2_top.html
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<!--
|
||||
CSP (Content Security Policy) 示例 - 生产环境部署建议添加:
|
||||
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self';
|
||||
script-src 'self' 'unsafe-inline';
|
||||
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
|
||||
font-src 'self' https://fonts.gstatic.com;
|
||||
connect-src 'self' https://your-server.com;">
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -151,7 +151,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="files/jquery.js"></script>
|
||||
<script src="files/popper.js"></script>
|
||||
<script src="files/bootstrap.js"></script>
|
||||
<script src="files/dfido2-lib.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user