Przeglądaj źródła

allow backup code input for totp

Milo Schwartz 6 miesięcy temu
rodzic
commit
4b34353354

+ 3 - 1
server/auth/2fa.ts

@@ -11,7 +11,9 @@ export async function verifyTotpCode(
     secret: string,
     secret: string,
     userId: string
     userId: string
 ): Promise<boolean> {
 ): Promise<boolean> {
-    if (code.length !== 6) {
+    // if code is digits only, it's totp
+    const isTotp = /^\d+$/.test(code);
+    if (!isTotp) {
         const validBackupCode = await verifyBackUpCode(code, userId);
         const validBackupCode = await verifyBackUpCode(code, userId);
         return validBackupCode;
         return validBackupCode;
     } else {
     } else {

+ 1 - 1
server/routers/auth/verifyTotp.ts

@@ -118,7 +118,7 @@ export async function verifyTotp(
 async function generateBackupCodes(): Promise<string[]> {
 async function generateBackupCodes(): Promise<string[]> {
     const codes = [];
     const codes = [];
     for (let i = 0; i < 10; i++) {
     for (let i = 0; i < 10; i++) {
-        const code = generateRandomString(8, alphabet("0-9", "A-Z", "a-z"));
+        const code = generateRandomString(6, alphabet("0-9", "A-Z", "a-z"));
         codes.push(code);
         codes.push(code);
     }
     }
     return codes;
     return codes;

+ 2 - 0
src/app/auth/reset-password/ResetPasswordForm.tsx

@@ -45,6 +45,7 @@ import { createApiClient } from "@app/api";
 import { useEnvContext } from "@app/hooks/useEnvContext";
 import { useEnvContext } from "@app/hooks/useEnvContext";
 import { passwordSchema } from "@server/auth/passwordSchema";
 import { passwordSchema } from "@server/auth/passwordSchema";
 import { get } from "http";
 import { get } from "http";
+import { REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp";
 
 
 const requestSchema = z.object({
 const requestSchema = z.object({
     email: z.string().email()
     email: z.string().email()
@@ -354,6 +355,7 @@ export default function ResetPasswordForm({
                                                         <InputOTP
                                                         <InputOTP
                                                             maxLength={6}
                                                             maxLength={6}
                                                             {...field}
                                                             {...field}
+                                                            pattern={REGEXP_ONLY_DIGITS_AND_CHARS}
                                                         >
                                                         >
                                                             <InputOTPGroup>
                                                             <InputOTPGroup>
                                                                 <InputOTPSlot
                                                                 <InputOTPSlot

+ 4 - 3
src/components/LoginForm.tsx

@@ -36,6 +36,7 @@ import {
     InputOTPSlot
     InputOTPSlot
 } from "./ui/input-otp";
 } from "./ui/input-otp";
 import Link from "next/link";
 import Link from "next/link";
+import { REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp";
 
 
 type LoginFormProps = {
 type LoginFormProps = {
     redirect?: string;
     redirect?: string;
@@ -61,7 +62,7 @@ export default function LoginForm({ redirect, onLogin }: LoginFormProps) {
     const [error, setError] = useState<string | null>(null);
     const [error, setError] = useState<string | null>(null);
     const [loading, setLoading] = useState(false);
     const [loading, setLoading] = useState(false);
 
 
-    const [mfaRequested, setMfaRequested] = useState(false);
+    const [mfaRequested, setMfaRequested] = useState(true);
 
 
     const form = useForm<z.infer<typeof formSchema>>({
     const form = useForm<z.infer<typeof formSchema>>({
         resolver: zodResolver(formSchema),
         resolver: zodResolver(formSchema),
@@ -129,7 +130,7 @@ export default function LoginForm({ redirect, onLogin }: LoginFormProps) {
     }
     }
 
 
     return (
     return (
-        <div>
+        <div className="space-y-8">
             {!mfaRequested && (
             {!mfaRequested && (
                 <Form {...form}>
                 <Form {...form}>
                     <form
                     <form
@@ -213,7 +214,7 @@ export default function LoginForm({ redirect, onLogin }: LoginFormProps) {
                                     <FormLabel>Authenticator Code</FormLabel>
                                     <FormLabel>Authenticator Code</FormLabel>
                                     <FormControl>
                                     <FormControl>
                                         <div className="flex justify-center">
                                         <div className="flex justify-center">
-                                            <InputOTP maxLength={6} {...field}>
+                                            <InputOTP maxLength={6} {...field} pattern={REGEXP_ONLY_DIGITS_AND_CHARS}>
                                                 <InputOTPGroup>
                                                 <InputOTPGroup>
                                                     <InputOTPSlot index={0} />
                                                     <InputOTPSlot index={0} />
                                                     <InputOTPSlot index={1} />
                                                     <InputOTPSlot index={1} />