mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-24 22:06:38 +00:00
allow backup code input for totp
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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} />
|
||||||
|
|||||||
Reference in New Issue
Block a user