Files
sample-site/modal-demo.html
2026-01-18 21:48:19 +09:00

937 lines
34 KiB
HTML
Raw Permalink 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.

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FIDO2 UI SDK - Modal Demo</title>
<link rel="stylesheet" href="files/core.css">
<link rel="stylesheet" href="files/theme-default.css">
<link rel="stylesheet" href="files/demo.css">
<link rel="stylesheet" href="files/boxicons.css">
<link rel="stylesheet" href="files/fido2-ui-sdk.css">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
margin: 0;
padding: 40px 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.demo-header {
background: rgba(255, 255, 255, 0.95);
border-radius: 12px;
padding: 40px;
margin-bottom: 30px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
}
.demo-header h1 {
color: #333;
margin: 0 0 10px;
font-size: 32px;
}
.demo-header p {
color: #666;
margin: 0 0 20px;
font-size: 16px;
}
.demo-section {
background: rgba(255, 255, 255, 0.95);
border-radius: 12px;
padding: 30px;
margin-bottom: 30px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
}
.demo-section h2 {
color: #333;
margin: 0 0 20px;
font-size: 24px;
}
.demo-section p {
color: #666;
margin-bottom: 20px;
}
.demo-btn {
padding: 12px 32px;
font-size: 16px;
font-weight: 500;
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
margin-right: 12px;
margin-bottom: 12px;
}
.demo-btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.demo-btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.demo-btn-secondary {
background: #f8f9fa;
color: #333;
border: 1px solid #dee2e6;
}
.demo-btn-secondary:hover {
background: #e9ecef;
}
.demo-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none !important;
box-shadow: none !important;
}
.code-block {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
overflow-x: auto;
}
.code-block code {
font-family: 'Courier New', monospace;
font-size: 14px;
line-height: 1.6;
color: #333;
}
.feature-list {
list-style: none;
padding: 0;
margin: 0;
}
.feature-list li {
padding: 12px 0;
border-bottom: 1px solid #e9ecef;
color: #666;
}
.feature-list li:last-child {
border-bottom: none;
}
.feature-list i {
color: #28a745;
margin-right: 10px;
}
#log-container {
background: #1e1e1e;
color: #d4d4d4;
border-radius: 8px;
padding: 20px;
max-height: 300px;
overflow-y: auto;
font-family: 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
}
.log-entry {
padding: 4px 0;
border-bottom: 1px solid #333;
}
.log-entry:last-child {
border-bottom: none;
}
.log-time {
color: #569cd6;
margin-right: 8px;
}
.log-type-info {
color: #4ec9b0;
}
.log-type-success {
color: #6a9955;
}
.log-type-error {
color: #f48771;
}
</style>
<script src="files/popper.js"></script>
<script src="files/bootstrap.js"></script>
<script src="files/dfido2-lib.js"></script>
<script src="files/fido2-ui-sdk.js"></script>
<script src="files/amipro_utils.js"></script>
<script>
const i18n_messages = new Map();
var lang_map = new Map();
lang_map.set("en-US", "🔐 FIDO2 UI SDK - Modal Demo");
lang_map.set("zh-CN", "🔐 FIDO2 UI SDK - 模态框演示");
lang_map.set("ja", "🔐 FIDO2 UI SDK - モーダル デモ");
i18n_messages.set("msg_title", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Demonstrate how to use FIDO2 UI SDK to manage devices in a popup window");
lang_map.set("zh-CN", "演示如何使用 FIDO2 UI SDK 在弹出窗口中管理设备");
lang_map.set("ja", "FIDO2 UI SDK を使用してポップアップ ウィンドウでデバイスを管理する方法をデモします");
i18n_messages.set("msg_subtitle", lang_map);
lang_map = new Map();
lang_map.set("en-US", "👤 Step1: Login");
lang_map.set("zh-CN", "👤 步骤1登录");
lang_map.set("ja", "👤 ステップ1ログイン");
i18n_messages.set("msg_section_login_title", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Click the button below to open the login modal:");
lang_map.set("zh-CN", "点击下面的按钮打开登录模态框:");
lang_map.set("ja", "以下のボタンを押してログインモーダルを開いてください:");
i18n_messages.set("msg_login_desc", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Login");
lang_map.set("zh-CN", "登录");
lang_map.set("ja", "ログイン");
i18n_messages.set("msg_btn_passkey_login", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Custom Style");
lang_map.set("zh-CN", "自定义样式");
lang_map.set("ja", "カスタム スタイル");
i18n_messages.set("msg_btn_password_login", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Logout");
lang_map.set("zh-CN", "退出登录");
lang_map.set("ja", "ログアウト");
i18n_messages.set("msg_btn_logout", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Logged out successfully");
lang_map.set("zh-CN", "退出登录成功");
lang_map.set("ja", "ログアウトしました");
i18n_messages.set("msg_logout_success", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Please login first to access device management");
lang_map.set("zh-CN", "请先登录以访问设备管理");
lang_map.set("ja", "デバイス管理にアクセスするにはまずログインしてください");
i18n_messages.set("msg_login_required", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Login successful");
lang_map.set("zh-CN", "登录成功");
lang_map.set("ja", "ログイン成功");
i18n_messages.set("msg_login_success", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Opening login modal...");
lang_map.set("zh-CN", "打开登录模态框...");
lang_map.set("ja", "ログインモーダルを開いています...");
i18n_messages.set("msg_log_open_login", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Opening password login modal...");
lang_map.set("zh-CN", "打开密码登录模态框...");
lang_map.set("ja", "パスワードログイン模ーダルを開いています...");
i18n_messages.set("msg_log_open_password_login", lang_map);
lang_map = new Map();
lang_map.set("en-US", "📌 Step2: Device Management");
lang_map.set("zh-CN", "📌  步骤2设备管理");
lang_map.set("ja", "📌 ステップ2: デバイス管理");
i18n_messages.set("msg_section_quick_title", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Login first by Step1, then manage your FIDO2 devices");
lang_map.set("zh-CN", "先在步骤1登录再管理您的FIDO2设备");
lang_map.set("ja", "まずステップでログインして、FIDO2デバイスを管理します");
i18n_messages.set("msg_quick_desc", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Manage Devices");
lang_map.set("zh-CN", "管理设备");
lang_map.set("ja", "デバイス管理");
i18n_messages.set("msg_btn_manage", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Custom Style");
lang_map.set("zh-CN", "自定义样式");
lang_map.set("ja", "カスタム スタイル");
i18n_messages.set("msg_btn_custom", lang_map);
lang_map = new Map();
lang_map.set("en-US", "💻 Code Examples");
lang_map.set("zh-CN", "💻 代码示例");
lang_map.set("ja", "💻 コード例");
i18n_messages.set("msg_section_code_title", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Simplest integration:");
lang_map.set("zh-CN", "最简单的集成方式:");
lang_map.set("ja", "最も簡単な統合:");
i18n_messages.set("msg_code_simple", lang_map);
lang_map = new Map();
lang_map.set("en-US", "With theme customization:");
lang_map.set("zh-CN", "带主题定制:");
lang_map.set("ja", "テーマのカスタマイズあり:");
i18n_messages.set("msg_code_theme", lang_map);
lang_map = new Map();
lang_map.set("en-US", "✨ Features");
lang_map.set("zh-CN", "✨ 功能特性");
lang_map.set("ja", "✨ 機能");
i18n_messages.set("msg_section_features_title", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Popup mode, stay on current page");
lang_map.set("zh-CN", "弹出窗口模式,不离开当前页面");
lang_map.set("ja", "ポップアップ モードで現在のページに留まる");
i18n_messages.set("msg_feature_1", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Auto FIDO2/Passkey authentication");
lang_map.set("zh-CN", "自动 FIDO2/Passkey 认证");
lang_map.set("ja", "自動 FIDO2/Passkey 認証");
i18n_messages.set("msg_feature_2", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Password login fallback option");
lang_map.set("zh-CN", "密码登录回退选项");
lang_map.set("ja", "パスワード ログイン フォールバック");
i18n_messages.set("msg_feature_3", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Add/delete FIDO2 devices support");
lang_map.set("zh-CN", "支持添加/删除 FIDO2 设备");
lang_map.set("ja", "FIDO2 デバイスの追加/削除サポート");
i18n_messages.set("msg_feature_4", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Real-time device list display");
lang_map.set("zh-CN", "实时显示设备列表");
lang_map.set("ja", "リアルタイム デバイスリスト表示");
i18n_messages.set("msg_feature_5", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Session status monitoring");
lang_map.set("zh-CN", "会话状态监控");
lang_map.set("ja", "セッション ステータス監視");
i18n_messages.set("msg_feature_6", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Theme color and style customization");
lang_map.set("zh-CN", "主题色和样式定制");
lang_map.set("ja", "テーマの色とスタイルのカスタマイズ");
i18n_messages.set("msg_feature_7", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Multi-language support (English/Japanese/Chinese)");
lang_map.set("zh-CN", "多语言支持(英/日/中)");
lang_map.set("ja", "多言語対応(英/日/中)");
i18n_messages.set("msg_feature_8", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Event callback system");
lang_map.set("zh-CN", "事件回调系统");
lang_map.set("ja", "イベント コールバック システム");
i18n_messages.set("msg_feature_9", lang_map);
lang_map.set("zh-CN", "主题色和样式定制");
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", "多语言支持(英/日/中)");
lang_map.set("ja", "多言語対応(英/日/中)");
i18n_messages.set("msg_feature_8", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Event callback system");
lang_map.set("zh-CN", "事件回调系统");
lang_map.set("ja", "イベント コールバック システム");
i18n_messages.set("msg_feature_9", lang_map);
lang_map.set("zh-CN", "多语言支持(英/日/中)");
lang_map.set("ja", "多言語対応(英/日/中)");
i18n_messages.set("msg_feature_8", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Event callback system");
lang_map.set("zh-CN", "事件回调系统");
lang_map.set("ja", "イベント コールバック システム");
i18n_messages.set("msg_feature_9", lang_map);
lang_map = new Map();
lang_map.set("en-US", "📊 Event Log");
lang_map.set("zh-CN", "📊 事件日志");
lang_map.set("ja", "📊 イベント ログ");
i18n_messages.set("msg_section_log_title", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Clear Log");
lang_map.set("zh-CN", "清空日志");
lang_map.set("ja", "ログをクリア");
i18n_messages.set("msg_btn_clear", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Opening default device manager...");
lang_map.set("zh-CN", "打开默认设备管理器...");
lang_map.set("ja", "デフォルト デバイス マネージャーを開いています...");
i18n_messages.set("msg_log_open_default", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Opening custom style device manager...");
lang_map.set("zh-CN", "打开自定义样式设备管理器...");
lang_map.set("ja", "カスタム スタイル デバイス マネージャーを開いています...");
i18n_messages.set("msg_log_open_custom", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Device manager initialized successfully");
lang_map.set("zh-CN", "设备管理器初始化完成");
lang_map.set("ja", "デバイス マネージャーの初期化が完了しました");
i18n_messages.set("msg_log_init", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Custom style device manager initialized successfully");
lang_map.set("zh-CN", "自定义样式设备管理器初始化完成");
lang_map.set("ja", "カスタム スタイル デバイス マネージャーの初期化が完了しました");
i18n_messages.set("msg_log_init_custom", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Device added successfully");
lang_map.set("zh-CN", "设备添加成功");
lang_map.set("ja", "デバイスの追加が完了しました");
i18n_messages.set("msg_log_device_added", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Device deleted successfully");
lang_map.set("zh-CN", "设备删除成功");
lang_map.set("ja", "デバイスの削除が完了しました");
i18n_messages.set("msg_log_device_deleted", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Device list loaded, total");
lang_map.set("zh-CN", "设备列表加载完成,共");
lang_map.set("ja", "デバイスリストが読み込まれました。合計");
i18n_messages.set("msg_log_devices_loaded", lang_map);
lang_map = new Map();
lang_map.set("en-US", "devices");
lang_map.set("zh-CN", "个设备");
lang_map.set("ja", "デバイス");
i18n_messages.set("msg_log_devices_suffix", lang_map);
lang_map = new Map();
lang_map.set("en-US", "An error occurred");
lang_map.set("zh-CN", "发生错误");
lang_map.set("ja", "エラーが発生しました");
i18n_messages.set("msg_log_error", lang_map);
lang_map = new Map();
lang_map.set("en-US", "Device manager closed");
lang_map.set("zh-CN", "设备管理器已关闭");
lang_map.set("ja", "デバイス マネージャーが閉じられました");
i18n_messages.set("msg_log_closed", lang_map);
window.onload = function() {
if (window.location.hostname === '127.0.0.1') {
alert('本地测试请使用 localhost');
}
setI18NText(i18n_messages);
};
</script>
</head>
<body>
<div class="container">
<div class="demo-header">
<h1 id="msg_title">🔐 FIDO2 UI SDK - Modal Demo</h1>
<p id="msg_subtitle">Demonstrate how to use FIDO2 UI SDK to manage devices in a popup window</p>
</div>
<div class="demo-section">
<h2 id="msg_section_login_title">👤 Step1: Login</h2>
<p id="msg_login_desc">Click the button below to open the login modal:</p>
<button class="demo-btn demo-btn-primary" onclick="openPasskeyLogin()">
<i class="bx bx-key"></i> <span id="msg_btn_passkey_login">Passkey Login</span>
</button>
<button class="demo-btn demo-btn-secondary" onclick="openPasswordLogin()">
<i class="bx bx-palette"></i> <span id="msg_btn_password_login">Custom Style</span>
</button>
<button class="demo-btn demo-btn-secondary" id="btn-logout" onclick="logout()" disabled>
<i class="bx bx-log-out"></i> <span id="msg_btn_logout">Logout</span>
</button>
</div>
<div class="demo-section">
<h2 id="msg_section_quick_title">📌 Step2: Device Management</h2>
<p id="msg_quick_desc">Step1: Login first, then manage your FIDO2 devices</p>
<button class="demo-btn demo-btn-primary" id="btn-manage-devices" onclick="openDeviceManager()" disabled>
<i class="bx bx-device"></i> <span id="msg_btn_manage">Manage Devices</span>
</button>
<button class="demo-btn demo-btn-secondary" id="btn-custom-style" onclick="openCustomDeviceManager()" disabled>
<i class="bx bx-palette"></i> <span id="msg_btn_custom">Custom Style</span>
</button>
<p id="msg_login_required" style="color: #999; margin-top: 10px;">Please login first to access device management</p>
</div>
<div class="demo-section">
<h2 id="msg_section_log_title">📊 Event Log</h2>
<div id="log-container"></div>
<button class="demo-btn demo-btn-secondary" onclick="clearLog()" style="margin-top: 15px;">
<span id="msg_btn_clear">Clear Log</span>
</button>
</div>
<div class="demo-section">
<h2 id="msg_section_code_title">💻 Code Examples</h2>
<p id="msg_js_import_examples">JS Import Examples:</p>
<div class="code-block">
<code>&lt;script src="files/popper.js"&gt;&lt;/script&gt;<br>
&lt;script src="files/bootstrap.js"&gt;&lt;/script&gt;<br>
&lt;script src="files/dfido2-lib.js"&gt;&lt;/script&gt;<br>
&lt;script src="files/fido2-ui-sdk.js"&gt;&lt;/script&gt;<br>
&lt;script src="files/amipro_utils.js"&gt;&lt;/script&gt;</code>
</div>
<p id="msg_code_login_default">Login Default:</p>
<div class="code-block">
<code>// Login Default<br>
Fido2UIManager.renderLogin({<br>
&nbsp;&nbsp;container: '#login-container',<br>
&nbsp;&nbsp;mode: 'modal',<br>
&nbsp;&nbsp;serverUrl: SERVER_URL,<br>
&nbsp;&nbsp;language: CURRENT_LANG<br>
});</code>
</div>
<p id="msg_code_login_custom">Login Custom:</p>
<div class="code-block">
<code>// Login with Custom Theme<br>
Fido2UIManager.renderLogin({<br>
&nbsp;&nbsp;container: '#login-container',<br>
&nbsp;&nbsp;mode: 'modal',<br>
&nbsp;&nbsp;serverUrl: SERVER_URL,<br>
&nbsp;&nbsp;language: 'ja',<br>
&nbsp;&nbsp;theme: {<br>
&nbsp;&nbsp;&nbsp;&nbsp;logo: 'files/favicon.ico',<br>
&nbsp;&nbsp;&nbsp;&nbsp;primaryColor: '#ce59d9',<br>
&nbsp;&nbsp;&nbsp;&nbsp;backgroundColor: '#faf5ff',<br>
&nbsp;&nbsp;&nbsp;&nbsp;textColor: '#6b21a8',<br>
&nbsp;&nbsp;&nbsp;&nbsp;borderRadius: '12px'<br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;features: {<br>
&nbsp;&nbsp;&nbsp;&nbsp;autoAuth: false,<br>
&nbsp;&nbsp;&nbsp;&nbsp;enablePasswordLogin: true,<br>
&nbsp;&nbsp;&nbsp;&nbsp;autoShowPassword: true,<br>
&nbsp;&nbsp;&nbsp;&nbsp;maxPasswordAttempts: 3<br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;callbacks: {<br>
&nbsp;&nbsp;&nbsp;&nbsp;onFido2Success: function(username, session) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Handle login success<br>
&nbsp;&nbsp;&nbsp;&nbsp;},<br>
&nbsp;&nbsp;&nbsp;&nbsp;onFido2Error: function(error) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Handle error<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;}<br>
});</code>
</div>
<p id="msg_code_device_default">Device Manager Default:</p>
<div class="code-block">
<code>// Device Manager Default<br>
Fido2UIManager.renderDeviceManager({<br>
&nbsp;&nbsp;userId: currentUserId,<br>
&nbsp;&nbsp;container: '#device-container',<br>
&nbsp;&nbsp;mode: 'modal',<br>
&nbsp;&nbsp;serverUrl: SERVER_URL,<br>
&nbsp;&nbsp;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>
&nbsp;&nbsp;userId: currentUserId,<br>
&nbsp;&nbsp;container: '#device-container',<br>
&nbsp;&nbsp;mode: 'modal',<br>
&nbsp;&nbsp;serverUrl: SERVER_URL,<br>
&nbsp;&nbsp;language: 'ja',<br>
&nbsp;&nbsp;theme: {<br>
&nbsp;&nbsp;&nbsp;&nbsp;logo: 'files/favicon.ico',<br>
&nbsp;&nbsp;&nbsp;&nbsp;primaryColor: '#ce59d9',<br>
&nbsp;&nbsp;&nbsp;&nbsp;backgroundColor: '#faf5ff',<br>
&nbsp;&nbsp;&nbsp;&nbsp;textColor: '#6b21a8',<br>
&nbsp;&nbsp;&nbsp;&nbsp;borderRadius: '12px'<br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;features: {<br>
&nbsp;&nbsp;&nbsp;&nbsp;showAddButton: true,<br>
&nbsp;&nbsp;&nbsp;&nbsp;showDeleteButton: true,<br>
&nbsp;&nbsp;&nbsp;&nbsp;showUserInfo: true,<br>
&nbsp;&nbsp;&nbsp;&nbsp;showSessionStatus: true<br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;callbacks: {<br>
&nbsp;&nbsp;&nbsp;&nbsp;onInit: function(manager) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Manager initialized<br>
&nbsp;&nbsp;&nbsp;&nbsp;},<br>
&nbsp;&nbsp;&nbsp;&nbsp;onDeviceAdded: function(device) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Device added<br>
&nbsp;&nbsp;&nbsp;&nbsp;},<br>
&nbsp;&nbsp;&nbsp;&nbsp;onDeviceDeleted: function(deviceId) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Device deleted<br>
&nbsp;&nbsp;&nbsp;&nbsp;},<br>
&nbsp;&nbsp;&nbsp;&nbsp;onClose: function() {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Manager closed<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;}<br>
});</code>
</div>
</div>
<div class="demo-section">
<h2 id="msg_section_features_title">✨ Features</h2>
<ul class="feature-list">
<li><i class="bx bx-check-circle"></i> <span id="msg_feature_1">Popup mode, stay on current page</span></li>
<li><i class="bx bx-check-circle"></i> <span id="msg_feature_2">Auto FIDO2/Passkey authentication</span></li>
<li><i class="bx bx-check-circle"></i> <span id="msg_feature_3">Password login fallback option</span></li>
<li><i class="bx bx-check-circle"></i> <span id="msg_feature_4">Add/delete FIDO2 devices support</span></li>
<li><i class="bx bx-check-circle"></i> <span id="msg_feature_5">Real-time device list display</span></li>
<li><i class="bx bx-check-circle"></i> <span id="msg_feature_6">Session status monitoring</span></li>
<li><i class="bx bx-check-circle"></i> <span id="msg_feature_7">Theme color and style customization</span></li>
<li><i class="bx bx-check-circle"></i> <span id="msg_feature_8">Multi-language support (English/Japanese/Chinese)</span></li>
<li><i class="bx bx-check-circle"></i> <span id="msg_feature_9">Event callback system</span></li>
</ul>
</div>
</div>
<div id="login-container"></div>
<div id="device-container"></div>
<script>
const SERVER_URL = 'https://local.dqj-macpro.com';//'https://fido2.amipro.me';
let currentUserId = null;
let isLoggedIn = false;
let loginManager = null;
function getBrowserLanguage() {
const lang = window.navigator.language || window.navigator.userLanguage;
const supportedLangs = ['en-US', 'zh-CN', 'ja'];
if (supportedLangs.includes(lang)) {
return lang;
}
return 'en-US';
}
const CURRENT_LANG = getBrowserLanguage();
function enableDeviceManagementButtons() {
document.getElementById('btn-manage-devices').disabled = false;
document.getElementById('btn-custom-style').disabled = false;
document.getElementById('msg_login_required').style.display = 'none';
document.getElementById('btn-logout').disabled = false;
}
function disableDeviceManagementButtons() {
document.getElementById('btn-manage-devices').disabled = true;
document.getElementById('btn-custom-style').disabled = true;
document.getElementById('msg_login_required').style.display = 'block';
document.getElementById('btn-logout').disabled = true;
}
function logout() {
Fido2UIManager.logout();
currentUserId = null;
isLoggedIn = false;
log('success', getI18NText(i18n_messages, 'msg_logout_success'));
disableDeviceManagementButtons();
}
function openPasskeyLogin() {
clearLog();
log('info', getI18NText(i18n_messages, 'msg_log_open_login'));
if (loginManager) {
loginManager.destroy();
}
loginManager = Fido2UIManager.renderLogin({
container: '#login-container',
mode: 'modal',
serverUrl: SERVER_URL,
language: CURRENT_LANG,
features: {
autoAuth: true,
enablePasswordLogin: true,
autoShowPassword: false,
maxPasswordAttempts: 3,
showRemainingAttempts: true,
},
callbacks: {
onFido2Success: function(username, session) {
log('success', getI18NText(i18n_messages, 'msg_login_success') + ': ' + username);
currentUserId = username;
isLoggedIn = true;
enableDeviceManagementButtons();
openDeviceManager();
},
onFido2Error: function(error) {
log('error', getI18NText(i18n_messages, 'msg_log_error') + ': ' + error.message);
},
onPasswordLogin: function(userId, password) {
return new Promise(function(resolve) {
log('info', 'Password login for user: ' + userId);
currentUserId = userId;
isLoggedIn = true;
enableDeviceManagementButtons();
resolve(true);
});
},
onPasswordExhausted: function(userId, attemptCount, maxAttempts) {
log('error', getI18NText(i18n_messages, 'msg_log_error') + ': ' + getI18NText(i18n_messages, 'msg_password_exhausted'));
},
onLoginClosed: function() {
log('info', getI18NText(i18n_messages, 'msg_log_closed'));
}
}
});
}
function openPasswordLogin() {
clearLog();
log('info', getI18NText(i18n_messages, 'msg_log_open_password_login'));
if (loginManager) {
loginManager.destroy();
}
loginManager = Fido2UIManager.renderLogin({
container: '#login-container',
mode: 'modal',
serverUrl: SERVER_URL,
language: CURRENT_LANG,
theme: {
logo: 'files/favicon.ico',
primaryColor: '#ce59d9',
backgroundColor: '#faf5ff',
textColor: '#6b21a8',
borderRadius: '12px'
},
features: {
autoAuth: false,
enablePasswordLogin: true,
autoShowPassword: true,
maxPasswordAttempts: 3,
showRemainingAttempts: true,
},
callbacks: {
onFido2Success: function(username, session) {
log('success', getI18NText(i18n_messages, 'msg_login_success') + ': ' + username);
currentUserId = username;
isLoggedIn = true;
enableDeviceManagementButtons();
},
onFido2Error: function(error) {
log('error', getI18NText(i18n_messages, 'msg_log_error') + ': ' + error.message);
},
onPasswordLogin: function(userId, password) {
return new Promise(function(resolve) {
log('info', 'Password login for user: ' + userId);
currentUserId = userId;
isLoggedIn = true;
enableDeviceManagementButtons();
resolve(true);
});
},
onPasswordExhausted: function(userId, attemptCount, maxAttempts) {
log('error', getI18NText(i18n_messages, 'msg_log_error') + ': ' + getI18NText(i18n_messages, 'msg_password_exhausted'));
},
onLoginClosed: function() {
log('info', getI18NText(i18n_messages, 'msg_log_closed'));
}
}
});
}
function openDeviceManager() {
if (!isLoggedIn) {
log('info', getI18NText(i18n_messages, 'msg_login_required'));
return;
}
clearLog();
log('info', getI18NText(i18n_messages, 'msg_log_open_default'));
Fido2UIManager.renderDeviceManager({
userId: currentUserId,
container: '#device-container',
mode: 'modal',
serverUrl: SERVER_URL,
language: CURRENT_LANG,
callbacks: {
onInit: function(manager) {
log('success', getI18NText(i18n_messages, 'msg_log_init'));
},
onDeviceAdded: function(device) {
log('success', getI18NText(i18n_messages, 'msg_log_device_added') + ': ' + JSON.stringify(device));
},
onDeviceDeleted: function(deviceId) {
log('success', getI18NText(i18n_messages, 'msg_log_device_deleted') + ': ' + deviceId);
},
onDeviceListLoaded: function(devices) {
log('info', getI18NText(i18n_messages, 'msg_log_devices_loaded') + ' ' + devices.length + ' ' + getI18NText(i18n_messages, 'msg_log_devices_suffix'));
},
onError: function(error) {
log('error', getI18NText(i18n_messages, 'msg_log_error') + ': ' + error.message);
},
onClose: function() {
log('info', getI18NText(i18n_messages, 'msg_log_closed'));
}
}
});
}
function openCustomDeviceManager() {
if (!isLoggedIn) {
log('info', getI18NText(i18n_messages, 'msg_login_required'));
return;
}
clearLog();
log('info', getI18NText(i18n_messages, 'msg_log_open_custom'));
Fido2UIManager.renderDeviceManager({
userId: currentUserId,
container: '#device-container',
mode: 'modal',
serverUrl: SERVER_URL,
language: CURRENT_LANG,
theme: {
logo: 'files/favicon.ico',
primaryColor: '#ce59d9',
backgroundColor: '#faf5ff',
textColor: '#6b21a8',
borderRadius: '12px'
},
features: {
showAddButton: true,
showDeleteButton: true,
showUserInfo: true,
showSessionStatus: true
},
callbacks: {
onInit: function(manager) {
log('success', getI18NText(i18n_messages, 'msg_log_init_custom'));
},
onDeviceAdded: function(device) {
log('success', getI18NText(i18n_messages, 'msg_log_device_added') + ': ' + JSON.stringify(device));
},
onDeviceDeleted: function(deviceId) {
log('success', getI18NText(i18n_messages, 'msg_log_device_deleted') + ': ' + deviceId);
},
onDeviceListLoaded: function(devices) {
log('info', getI18NText(i18n_messages, 'msg_log_devices_loaded') + ' ' + devices.length + ' ' + getI18NText(i18n_messages, 'msg_log_devices_suffix'));
},
onError: function(error) {
log('error', getI18NText(i18n_messages, 'msg_log_error') + ': ' + error.message);
},
onClose: function() {
log('info', getI18NText(i18n_messages, 'msg_log_closed'));
}
}
});
}
function log(type, message) {
const container = document.getElementById('log-container');
const entry = document.createElement('div');
entry.className = 'log-entry';
const time = new Date().toLocaleTimeString('zh-CN');
const typeClass = 'log-type-' + type;
entry.innerHTML = `<span class="log-time">[${time}]</span><span class="${typeClass}">[${type.toUpperCase()}]</span> ${message}`;
container.appendChild(entry);
container.scrollTop = container.scrollHeight;
}
function clearLog() {
document.getElementById('log-container').innerHTML = '';
}
</script>
<p style="text-align: center; margin-top: 20px;">
<a href="https://amipro.me/fido2_top.html" target="_blank" style="display: inline-block; padding: 12px 24px; background: #667eea; color: white; text-decoration: none; border-radius: 8px; font-weight: bold;">
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>