style consistency changes to add security key form

This commit is contained in:
miloschwartz 2025-07-14 15:43:33 -07:00
parent 0a97d91aed
commit 3505342a8d
No known key found for this signature in database
4 changed files with 645 additions and 329 deletions

View file

@ -1143,8 +1143,7 @@
"securityKeyNameRequired": "Name is required", "securityKeyNameRequired": "Name is required",
"securityKeyRemove": "Remove", "securityKeyRemove": "Remove",
"securityKeyLastUsed": "Last used: {date}", "securityKeyLastUsed": "Last used: {date}",
"securityKeyNameLabel": "Name", "securityKeyNameLabel": "Security Key Name",
"securityKeyNamePlaceholder": "Enter a name for this security key",
"securityKeyRegisterSuccess": "Security key registered successfully", "securityKeyRegisterSuccess": "Security key registered successfully",
"securityKeyRegisterError": "Failed to register security key", "securityKeyRegisterError": "Failed to register security key",
"securityKeyRemoveSuccess": "Security key removed successfully", "securityKeyRemoveSuccess": "Security key removed successfully",
@ -1152,7 +1151,7 @@
"securityKeyLoadError": "Failed to load security keys", "securityKeyLoadError": "Failed to load security keys",
"securityKeyLogin": "Sign in with security key", "securityKeyLogin": "Sign in with security key",
"securityKeyAuthError": "Failed to authenticate with security key", "securityKeyAuthError": "Failed to authenticate with security key",
"securityKeyRecommendation": "Tip: Register a backup security key on another device to ensure you always have access to your account.", "securityKeyRecommendation": "Register a backup security key on another device to ensure you always have access to your account.",
"registering": "Registering...", "registering": "Registering...",
"securityKeyPrompt": "Please verify your identity using your security key. Make sure your security key is connected and ready.", "securityKeyPrompt": "Please verify your identity using your security key. Make sure your security key is connected and ready.",
"securityKeyBrowserNotSupported": "Your browser doesn't support security keys. Please use a modern browser like Chrome, Firefox, or Safari.", "securityKeyBrowserNotSupported": "Your browser doesn't support security keys. Please use a modern browser like Chrome, Firefox, or Safari.",
@ -1163,5 +1162,16 @@
"twoFactorRequired": "Two-factor authentication is required to register a security key.", "twoFactorRequired": "Two-factor authentication is required to register a security key.",
"twoFactor": "Two-Factor Authentication", "twoFactor": "Two-Factor Authentication",
"adminEnabled2FaOnYourAccount": "Your administrator has enabled two-factor authentication for {email}. Please complete the setup process to continue.", "adminEnabled2FaOnYourAccount": "Your administrator has enabled two-factor authentication for {email}. Please complete the setup process to continue.",
"continueToApplication": "Continue to Application" "continueToApplication": "Continue to Application",
"securityKeyAdd": "Add Security Key",
"securityKeyRegisterTitle": "Register New Security Key",
"securityKeyRegisterDescription": "Connect your security key and enter a name to identify it",
"securityKeyTwoFactorRequired": "Two-Factor Authentication Required",
"securityKeyTwoFactorDescription": "Please enter your two-factor authentication code to register the security key",
"securityKeyTwoFactorRemoveDescription": "Please enter your two-factor authentication code to remove the security key",
"securityKeyTwoFactorCode": "Two-Factor Code",
"securityKeyRemoveTitle": "Remove Security Key",
"securityKeyRemoveDescription": "Enter your password to remove the security key \"{name}\"",
"securityKeyNoKeysRegistered": "No security keys registered",
"securityKeyNoKeysDescription": "Add a security key to enhance your account security"
} }

2
package-lock.json generated
View file

@ -33,9 +33,9 @@
"@radix-ui/react-toast": "1.2.14", "@radix-ui/react-toast": "1.2.14",
"@react-email/components": "0.3.1", "@react-email/components": "0.3.1",
"@react-email/render": "^1.1.2", "@react-email/render": "^1.1.2",
"@react-email/tailwind": "1.2.1",
"@simplewebauthn/browser": "^13.1.0", "@simplewebauthn/browser": "^13.1.0",
"@simplewebauthn/server": "^9.0.3", "@simplewebauthn/server": "^9.0.3",
"@react-email/tailwind": "1.2.1",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.10",
"@tanstack/react-table": "8.21.3", "@tanstack/react-table": "8.21.3",
"arctic": "^3.7.0", "arctic": "^3.7.0",

View file

@ -107,7 +107,8 @@ async function clearChallenge(sessionId: string) {
export const registerSecurityKeyBody = z.object({ export const registerSecurityKeyBody = z.object({
name: z.string().min(1), name: z.string().min(1),
password: z.string().min(1) password: z.string().min(1),
code: z.string().optional()
}).strict(); }).strict();
export const verifyRegistrationBody = z.object({ export const verifyRegistrationBody = z.object({
@ -143,7 +144,7 @@ export async function startRegistration(
); );
} }
const { name, password } = parsedBody.data; const { name, password, code } = parsedBody.data;
const user = req.user as User; const user = req.user as User;
// Only allow internal users to use security keys // Only allow internal users to use security keys
@ -163,6 +164,39 @@ export async function startRegistration(
return next(unauthorized()); return next(unauthorized());
} }
// If user has 2FA enabled, require and verify the code
if (user.twoFactorEnabled) {
if (!code) {
return response<{ codeRequested: boolean }>(res, {
data: { codeRequested: true },
success: true,
error: false,
message: "Two-factor authentication required",
status: HttpCode.ACCEPTED
});
}
const validOTP = await verifyTotpCode(
code,
user.twoFactorSecret!,
user.userId
);
if (!validOTP) {
if (config.getRawConfig().app.log_failed_attempts) {
logger.info(
`Two-factor code incorrect. Email: ${user.email}. IP: ${req.ip}.`
);
}
return next(
createHttpError(
HttpCode.UNAUTHORIZED,
"The two-factor code you entered is incorrect"
)
);
}
}
// Get existing security keys for user // Get existing security keys for user
const existingSecurityKeys = await db const existingSecurityKeys = await db
.select() .select()

File diff suppressed because it is too large Load diff