1
1
import { json , redirect , type DataFunctionArgs } from '@remix-run/node'
2
- import { useFetcher , useLoaderData } from '@remix-run/react'
2
+ import { Link , useFetcher , useLoaderData } from '@remix-run/react'
3
+ import { Icon } from '~/components/ui/icon.tsx'
3
4
import { StatusButton } from '~/components/ui/status-button.tsx'
4
5
import { requireUserId } from '~/utils/auth.server.ts'
5
6
import { prisma } from '~/utils/db.server.ts'
6
7
import { generateTOTP } from '~/utils/totp.server.ts'
8
+ import { shouldRequestTwoFA } from '../resources+/login.tsx'
7
9
import { twoFAVerificationType } from './profile.two-factor.tsx'
8
10
import { verificationType as verifyVerificationType } from './profile.two-factor.verify.tsx'
9
11
@@ -13,63 +15,47 @@ export async function loader({ request }: DataFunctionArgs) {
13
15
where : { type : twoFAVerificationType , target : userId } ,
14
16
select : { id : true } ,
15
17
} )
16
- return json ( { is2FAEnabled : Boolean ( verification ) } )
18
+ const shouldReverify = await shouldRequestTwoFA ( request )
19
+ return json ( { is2FAEnabled : Boolean ( verification ) , shouldReverify } )
17
20
}
18
21
19
22
export async function action ( { request } : DataFunctionArgs ) {
20
- const form = await request . formData ( )
21
23
const userId = await requireUserId ( request )
22
- const intent = form . get ( 'intent' )
23
- switch ( intent ) {
24
- case 'enable' : {
25
- const { otp : _otp , ...config } = generateTOTP ( )
26
- // delete any existing entries
27
- await prisma . verification . deleteMany ( {
28
- where : { type : verifyVerificationType , target : userId } ,
29
- } )
30
- await prisma . verification . create ( {
31
- data : { ...config , type : verifyVerificationType , target : userId } ,
32
- } )
33
- return redirect ( '/settings/profile/two-factor/verify' )
34
- }
35
- case 'disable' : {
36
- await prisma . verification . deleteMany ( {
37
- where : { type : twoFAVerificationType , target : userId } ,
38
- } )
39
- break
40
- }
41
- default : {
42
- return json ( { status : 'error' , message : 'Invalid intent' } as const )
43
- }
44
- }
45
- return json ( { status : 'success' } as const )
24
+ const { otp : _otp , ...config } = generateTOTP ( )
25
+ // delete any existing entries
26
+ await prisma . verification . deleteMany ( {
27
+ where : { type : verifyVerificationType , target : userId } ,
28
+ } )
29
+ await prisma . verification . create ( {
30
+ data : { ...config , type : verifyVerificationType , target : userId } ,
31
+ } )
32
+ return redirect ( '/settings/profile/two-factor/verify' )
46
33
}
47
34
48
35
export default function TwoFactorRoute ( ) {
49
- const data = useLoaderData < typeof loader > ( ) || { }
36
+ const data = useLoaderData < typeof loader > ( )
50
37
const toggle2FAFetcher = useFetcher < typeof action > ( )
51
38
52
39
return (
53
40
< div className = "flex flex-col gap-4" >
54
41
{ data . is2FAEnabled ? (
55
42
< >
56
- < p className = "text-sm" > You have enabled two-factor authentication.</ p >
57
- < toggle2FAFetcher . Form method = "POST" preventScrollReset >
58
- < StatusButton
59
- variant = "secondary"
60
- type = "submit"
61
- name = "intent"
62
- value = "disable"
63
- status = { toggle2FAFetcher . state === 'loading' ? 'pending' : 'idle' }
64
- className = "mx-auto"
65
- >
66
- Disable 2FA
67
- </ StatusButton >
68
- </ toggle2FAFetcher . Form >
43
+ < p className = "text-lg" >
44
+ < Icon name = "check" >
45
+ You have enabled two-factor authentication.
46
+ </ Icon >
47
+ </ p >
48
+ < Link to = "disable" >
49
+ < Icon name = "lock-open-1" > Disable 2FA</ Icon >
50
+ </ Link >
69
51
</ >
70
52
) : (
71
53
< >
72
- < p > You have not enabled two-factor authentication yet.</ p >
54
+ < p >
55
+ < Icon name = "lock-open-1" >
56
+ You have not enabled two-factor authentication yet.
57
+ </ Icon >
58
+ </ p >
73
59
< p className = "text-sm" >
74
60
Two factor authentication adds an extra layer of security to your
75
61
account. You will need to enter a code from an authenticator app
0 commit comments