mirror of
https://github.com/documenso/documenso.git
synced 2025-11-18 02:32:00 +10:00
fix: migrate 2fa to custom auth
This commit is contained in:
@ -9,7 +9,7 @@ import { useForm } from 'react-hook-form';
|
||||
import { useRevalidator } from 'react-router';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Dialog,
|
||||
@ -47,8 +47,6 @@ export const DisableAuthenticatorAppDialog = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [twoFactorDisableMethod, setTwoFactorDisableMethod] = useState<'totp' | 'backup'>('totp');
|
||||
|
||||
const { mutateAsync: disable2FA } = trpc.twoFactorAuthentication.disable.useMutation();
|
||||
|
||||
const disable2FAForm = useForm<TDisable2FAForm>({
|
||||
defaultValues: {
|
||||
totpCode: '',
|
||||
@ -81,7 +79,7 @@ export const DisableAuthenticatorAppDialog = () => {
|
||||
|
||||
const onDisable2FAFormSubmit = async ({ totpCode, backupCode }: TDisable2FAForm) => {
|
||||
try {
|
||||
await disable2FA({ totpCode, backupCode });
|
||||
await authClient.twoFactor.disable({ totpCode, backupCode });
|
||||
|
||||
toast({
|
||||
title: _(msg`Two-factor authentication disabled`),
|
||||
|
||||
@ -9,8 +9,8 @@ import { useRevalidator } from 'react-router';
|
||||
import { renderSVG } from 'uqr';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { downloadFile } from '@documenso/lib/client-only/download-file';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Dialog,
|
||||
@ -52,24 +52,8 @@ export const EnableAuthenticatorAppDialog = ({ onSuccess }: EnableAuthenticatorA
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [recoveryCodes, setRecoveryCodes] = useState<string[] | null>(null);
|
||||
|
||||
const { mutateAsync: enable2FA } = trpc.twoFactorAuthentication.enable.useMutation();
|
||||
|
||||
const {
|
||||
mutateAsync: setup2FA,
|
||||
data: setup2FAData,
|
||||
isPending: isSettingUp2FA,
|
||||
} = trpc.twoFactorAuthentication.setup.useMutation({
|
||||
onError: () => {
|
||||
toast({
|
||||
title: _(msg`Unable to setup two-factor authentication`),
|
||||
description: _(
|
||||
msg`We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again.`,
|
||||
),
|
||||
variant: 'destructive',
|
||||
});
|
||||
},
|
||||
});
|
||||
const [isSettingUp2FA, setIsSettingUp2FA] = useState(false);
|
||||
const [setup2FAData, setSetup2FAData] = useState<{ uri: string; secret: string } | null>(null);
|
||||
|
||||
const enable2FAForm = useForm<TEnable2FAForm>({
|
||||
defaultValues: {
|
||||
@ -80,9 +64,34 @@ export const EnableAuthenticatorAppDialog = ({ onSuccess }: EnableAuthenticatorA
|
||||
|
||||
const { isSubmitting: isEnabling2FA } = enable2FAForm.formState;
|
||||
|
||||
const setup2FA = async () => {
|
||||
if (isSettingUp2FA) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSettingUp2FA(true);
|
||||
setSetup2FAData(null);
|
||||
|
||||
try {
|
||||
const data = await authClient.twoFactor.setup();
|
||||
|
||||
setSetup2FAData(data);
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: _(msg`Unable to setup two-factor authentication`),
|
||||
description: _(
|
||||
msg`We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again.`,
|
||||
),
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
|
||||
setIsSettingUp2FA(false);
|
||||
};
|
||||
|
||||
const onEnable2FAFormSubmit = async ({ token }: TEnable2FAForm) => {
|
||||
try {
|
||||
const data = await enable2FA({ code: token });
|
||||
const data = await authClient.twoFactor.enable({ code: token });
|
||||
|
||||
setRecoveryCodes(data.recoveryCodes);
|
||||
onSuccess?.();
|
||||
|
||||
@ -6,9 +6,9 @@ import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { downloadFile } from '@documenso/lib/client-only/download-file';
|
||||
import { AppError } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { Alert, AlertDescription } from '@documenso/ui/primitives/alert';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
@ -41,20 +41,32 @@ export type TViewRecoveryCodesForm = z.infer<typeof ZViewRecoveryCodesForm>;
|
||||
export const ViewRecoveryCodesDialog = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const {
|
||||
data: recoveryCodes,
|
||||
mutate,
|
||||
isPending,
|
||||
error,
|
||||
} = trpc.twoFactorAuthentication.viewRecoveryCodes.useMutation();
|
||||
const [recoveryCodes, setRecoveryCodes] = useState<string[] | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const viewRecoveryCodesForm = useForm<TViewRecoveryCodesForm>({
|
||||
const form = useForm<TViewRecoveryCodesForm>({
|
||||
defaultValues: {
|
||||
token: '',
|
||||
},
|
||||
resolver: zodResolver(ZViewRecoveryCodesForm),
|
||||
});
|
||||
|
||||
const onFormSubmit = async ({ token }: TViewRecoveryCodesForm) => {
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const data = await authClient.twoFactor.viewRecoveryCodes({
|
||||
token,
|
||||
});
|
||||
|
||||
setRecoveryCodes(data.backupCodes);
|
||||
} catch (err) {
|
||||
const error = AppError.parseError(err);
|
||||
|
||||
setError(error.code);
|
||||
}
|
||||
};
|
||||
|
||||
const downloadRecoveryCodes = () => {
|
||||
if (recoveryCodes) {
|
||||
const blob = new Blob([recoveryCodes.join('\n')], {
|
||||
@ -106,8 +118,8 @@ export const ViewRecoveryCodesDialog = () => {
|
||||
</DialogFooter>
|
||||
</div>
|
||||
) : (
|
||||
<Form {...viewRecoveryCodesForm}>
|
||||
<form onSubmit={viewRecoveryCodesForm.handleSubmit((value) => mutate(value))}>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<DialogHeader className="mb-4">
|
||||
<DialogTitle>
|
||||
<Trans>View Recovery Codes</Trans>
|
||||
@ -118,10 +130,10 @@ export const ViewRecoveryCodesDialog = () => {
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<fieldset className="flex flex-col space-y-4" disabled={isPending}>
|
||||
<fieldset className="flex flex-col space-y-4" disabled={form.formState.isSubmitting}>
|
||||
<FormField
|
||||
name="token"
|
||||
control={viewRecoveryCodesForm.control}
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
@ -161,7 +173,7 @@ export const ViewRecoveryCodesDialog = () => {
|
||||
</Button>
|
||||
</DialogClose>
|
||||
|
||||
<Button type="submit" loading={isPending}>
|
||||
<Button type="submit" loading={form.formState.isSubmitting}>
|
||||
<Trans>View</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
|
||||
Reference in New Issue
Block a user