mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-08-05 06:50:10 +00:00
feat: Add YubiKey OTP support and management features
- Implemented YubiKey OTP settings management in useAccountSecurityActions hook. - Added API functions for retrieving, saving, and bootstrapping YubiKey OTP credentials. - Enhanced authentication flow to support multiple two-factor providers, including YubiKey. - Updated localization files to include new YubiKey-related strings in English, Spanish, Russian, and Chinese. - Introduced new styles for YubiKey management UI components. - Created utility functions for YubiKey OTP validation and credential handling.
This commit is contained in:
@@ -4,7 +4,7 @@ type SafeBind = (stmt: D1PreparedStatement, ...values: any[]) => D1PreparedState
|
||||
const USER_SELECT_COLUMNS =
|
||||
'id, email, name, master_password_hint, master_password_hash, key, private_key, public_key, ' +
|
||||
'kdf_type, kdf_iterations, kdf_memory, kdf_parallelism, security_stamp, role, status, verify_devices, ' +
|
||||
'totp_secret, totp_recovery_code, api_key, created_at, updated_at';
|
||||
'totp_secret, totp_recovery_code, yubikey_key1, yubikey_key2, yubikey_key3, yubikey_key4, yubikey_key5, yubikey_nfc, api_key, created_at, updated_at';
|
||||
|
||||
function mapUserRow(row: any): User {
|
||||
return {
|
||||
@@ -26,6 +26,12 @@ function mapUserRow(row: any): User {
|
||||
verifyDevices: row.verify_devices == null ? true : !!row.verify_devices,
|
||||
totpSecret: row.totp_secret ?? null,
|
||||
totpRecoveryCode: row.totp_recovery_code ?? null,
|
||||
yubikeyKey1: row.yubikey_key1 ?? null,
|
||||
yubikeyKey2: row.yubikey_key2 ?? null,
|
||||
yubikeyKey3: row.yubikey_key3 ?? null,
|
||||
yubikeyKey4: row.yubikey_key4 ?? null,
|
||||
yubikeyKey5: row.yubikey_key5 ?? null,
|
||||
yubikeyNfc: !!row.yubikey_nfc,
|
||||
apiKey: row.api_key ?? null,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at,
|
||||
@@ -65,11 +71,11 @@ export async function getAllUsers(db: D1Database): Promise<User[]> {
|
||||
export async function saveUser(db: D1Database, safeBind: SafeBind, user: User): Promise<void> {
|
||||
const email = user.email.toLowerCase();
|
||||
const stmt = db.prepare(
|
||||
'INSERT INTO users(id, email, name, master_password_hint, master_password_hash, key, private_key, public_key, kdf_type, kdf_iterations, kdf_memory, kdf_parallelism, security_stamp, role, status, verify_devices, totp_secret, totp_recovery_code, api_key, created_at, updated_at) ' +
|
||||
'VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ' +
|
||||
'INSERT INTO users(id, email, name, master_password_hint, master_password_hash, key, private_key, public_key, kdf_type, kdf_iterations, kdf_memory, kdf_parallelism, security_stamp, role, status, verify_devices, totp_secret, totp_recovery_code, yubikey_key1, yubikey_key2, yubikey_key3, yubikey_key4, yubikey_key5, yubikey_nfc, api_key, created_at, updated_at) ' +
|
||||
'VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ' +
|
||||
'ON CONFLICT(id) DO UPDATE SET ' +
|
||||
'email=excluded.email, name=excluded.name, master_password_hint=excluded.master_password_hint, master_password_hash=excluded.master_password_hash, key=excluded.key, private_key=excluded.private_key, public_key=excluded.public_key, ' +
|
||||
'kdf_type=excluded.kdf_type, kdf_iterations=excluded.kdf_iterations, kdf_memory=excluded.kdf_memory, kdf_parallelism=excluded.kdf_parallelism, security_stamp=excluded.security_stamp, role=excluded.role, status=excluded.status, verify_devices=excluded.verify_devices, totp_secret=excluded.totp_secret, totp_recovery_code=excluded.totp_recovery_code, api_key=excluded.api_key, updated_at=excluded.updated_at'
|
||||
'kdf_type=excluded.kdf_type, kdf_iterations=excluded.kdf_iterations, kdf_memory=excluded.kdf_memory, kdf_parallelism=excluded.kdf_parallelism, security_stamp=excluded.security_stamp, role=excluded.role, status=excluded.status, verify_devices=excluded.verify_devices, totp_secret=excluded.totp_secret, totp_recovery_code=excluded.totp_recovery_code, yubikey_key1=excluded.yubikey_key1, yubikey_key2=excluded.yubikey_key2, yubikey_key3=excluded.yubikey_key3, yubikey_key4=excluded.yubikey_key4, yubikey_key5=excluded.yubikey_key5, yubikey_nfc=excluded.yubikey_nfc, api_key=excluded.api_key, updated_at=excluded.updated_at'
|
||||
);
|
||||
await safeBind(
|
||||
stmt,
|
||||
@@ -91,6 +97,12 @@ export async function saveUser(db: D1Database, safeBind: SafeBind, user: User):
|
||||
user.verifyDevices ? 1 : 0,
|
||||
user.totpSecret,
|
||||
user.totpRecoveryCode,
|
||||
user.yubikeyKey1,
|
||||
user.yubikeyKey2,
|
||||
user.yubikeyKey3,
|
||||
user.yubikeyKey4,
|
||||
user.yubikeyKey5,
|
||||
user.yubikeyNfc ? 1 : 0,
|
||||
user.apiKey,
|
||||
user.createdAt,
|
||||
user.updatedAt
|
||||
@@ -104,8 +116,8 @@ export async function createUser(db: D1Database, safeBind: SafeBind, user: User)
|
||||
export async function createFirstUser(db: D1Database, safeBind: SafeBind, user: User): Promise<boolean> {
|
||||
const email = user.email.toLowerCase();
|
||||
const stmt = db.prepare(
|
||||
'INSERT INTO users(id, email, name, master_password_hint, master_password_hash, key, private_key, public_key, kdf_type, kdf_iterations, kdf_memory, kdf_parallelism, security_stamp, role, status, verify_devices, totp_secret, totp_recovery_code, api_key, created_at, updated_at) ' +
|
||||
'SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ' +
|
||||
'INSERT INTO users(id, email, name, master_password_hint, master_password_hash, key, private_key, public_key, kdf_type, kdf_iterations, kdf_memory, kdf_parallelism, security_stamp, role, status, verify_devices, totp_secret, totp_recovery_code, yubikey_key1, yubikey_key2, yubikey_key3, yubikey_key4, yubikey_key5, yubikey_nfc, api_key, created_at, updated_at) ' +
|
||||
'SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ' +
|
||||
'WHERE NOT EXISTS (SELECT 1 FROM users LIMIT 1)'
|
||||
);
|
||||
const result = await safeBind(
|
||||
@@ -128,6 +140,12 @@ export async function createFirstUser(db: D1Database, safeBind: SafeBind, user:
|
||||
user.verifyDevices ? 1 : 0,
|
||||
user.totpSecret,
|
||||
user.totpRecoveryCode,
|
||||
user.yubikeyKey1,
|
||||
user.yubikeyKey2,
|
||||
user.yubikeyKey3,
|
||||
user.yubikeyKey4,
|
||||
user.yubikeyKey5,
|
||||
user.yubikeyNfc ? 1 : 0,
|
||||
user.apiKey,
|
||||
user.createdAt,
|
||||
user.updatedAt
|
||||
|
||||
Reference in New Issue
Block a user