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:
@@ -34,6 +34,7 @@ export interface PendingTotp {
|
||||
passwordHash: string;
|
||||
masterKey: Uint8Array;
|
||||
kdfIterations: number;
|
||||
providerType: number;
|
||||
}
|
||||
|
||||
export interface PendingPasskeyPassword {
|
||||
@@ -70,10 +71,31 @@ export interface CompletedLogin {
|
||||
freshUserVerificationToken?: string | null;
|
||||
}
|
||||
|
||||
const TWO_FACTOR_PROVIDER_AUTHENTICATOR = 0;
|
||||
const TWO_FACTOR_PROVIDER_YUBIKEY = 3;
|
||||
|
||||
function readTokenUserVerificationToken(token: TokenSuccess): string | null {
|
||||
return String(token.UserVerificationToken || token.userVerificationToken || '').trim() || null;
|
||||
}
|
||||
|
||||
function resolvePendingTwoFactorProvider(providers: unknown): number {
|
||||
if (Array.isArray(providers)) {
|
||||
if (providers.some((provider: any) => Number(
|
||||
provider && typeof provider === 'object' ? provider.Type ?? provider.type : provider
|
||||
) === TWO_FACTOR_PROVIDER_YUBIKEY)) {
|
||||
return TWO_FACTOR_PROVIDER_YUBIKEY;
|
||||
}
|
||||
return TWO_FACTOR_PROVIDER_AUTHENTICATOR;
|
||||
}
|
||||
if (providers && typeof providers === 'object') {
|
||||
const record = providers as Record<string, unknown>;
|
||||
if (record[String(TWO_FACTOR_PROVIDER_YUBIKEY)] || record.YubiKey || record.Yubikey) {
|
||||
return TWO_FACTOR_PROVIDER_YUBIKEY;
|
||||
}
|
||||
}
|
||||
return TWO_FACTOR_PROVIDER_AUTHENTICATOR;
|
||||
}
|
||||
|
||||
export type PasswordLoginResult =
|
||||
| { kind: 'success'; login: CompletedLogin }
|
||||
| { kind: 'totp'; pendingTotp: PendingTotp }
|
||||
@@ -425,6 +447,7 @@ export async function performPasswordLogin(
|
||||
passwordHash: derived.hash,
|
||||
masterKey: derived.masterKey,
|
||||
kdfIterations: derived.kdfIterations,
|
||||
providerType: resolvePendingTwoFactorProvider(tokenError.TwoFactorProviders),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -498,6 +521,7 @@ export async function performTotpLogin(
|
||||
): Promise<CompletedLogin> {
|
||||
const token = await loginWithPassword(pendingTotp.email, pendingTotp.passwordHash, {
|
||||
totpCode: totpCode.trim(),
|
||||
twoFactorProvider: pendingTotp.providerType,
|
||||
rememberDevice,
|
||||
});
|
||||
if ('access_token' in token && token.access_token) {
|
||||
@@ -615,6 +639,7 @@ export async function performUnlock(
|
||||
passwordHash: derived.hash,
|
||||
masterKey: derived.masterKey,
|
||||
kdfIterations: derived.kdfIterations,
|
||||
providerType: resolvePendingTwoFactorProvider(tokenError.TwoFactorProviders),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user