From 973aae82fd63cca42e36fac90f08d06aa0730fac Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Wed, 10 Dec 2025 21:19:39 -0800 Subject: [PATCH] improve 2fa ux --- frontend/src/pages/settings/profile/index.tsx | 9 +++++++++ .../src/pages/settings/profile/passkey.tsx | 8 ++++---- frontend/src/pages/settings/profile/totp.tsx | 19 +++++++++++++++---- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/frontend/src/pages/settings/profile/index.tsx b/frontend/src/pages/settings/profile/index.tsx index 935280425..bb47bb365 100644 --- a/frontend/src/pages/settings/profile/index.tsx +++ b/frontend/src/pages/settings/profile/index.tsx @@ -138,6 +138,15 @@ const UserProfile = ({ user }: { user: Types.User }) => {
|
+
2FA:
+ {user.passkey?.created_at + ? "Passkey" + : user.totp?.confirmed_at + ? "TOTP" + : "None"} + +
|
+
Admin:
{user.admin ? "True" : "False"} diff --git a/frontend/src/pages/settings/profile/passkey.tsx b/frontend/src/pages/settings/profile/passkey.tsx index 14cd59ac0..9ec7e6e3e 100644 --- a/frontend/src/pages/settings/profile/passkey.tsx +++ b/frontend/src/pages/settings/profile/passkey.tsx @@ -1,7 +1,7 @@ import { ConfirmButton } from "@components/util"; import { useManageUser, useUserInvalidate } from "@lib/hooks"; import { Button } from "@ui/button"; -import { PlusCircle, Trash } from "lucide-react"; +import { Fingerprint, Trash } from "lucide-react"; import { Types } from "komodo_client"; import { base64urlToArrayBuffer, cn } from "@lib/utils"; import { useToast } from "@ui/use-toast"; @@ -15,7 +15,7 @@ export const EnrollPasskey = ({ user }: { user: Types.User }) => { { onSuccess: () => { userInvalidate(); - toast({ title: "Unenrolled in passkey authentication" }); + toast({ title: "Unenrolled in passkey 2FA" }); }, } ); @@ -66,11 +66,11 @@ export const EnrollPasskey = ({ user }: { user: Types.User }) => { variant="secondary" className={cn( "items-center gap-2", - !!user.passkey?.created_at && "hidden" + (user.totp?.confirmed_at || !!user.passkey?.created_at) && "hidden" )} onClick={() => begin_enrollment({})} > - Enroll Passkey 2FA + Enroll Passkey 2FA { const userInvalidate = useUserInvalidate(); + const { toast } = useToast(); const [open, setOpen] = useState(false); const [submitted, setSubmitted] = useState<{ uri: string; png: string }>(); const [confirm, setConfirm] = useState(""); @@ -34,7 +36,10 @@ export const EnrollTotp = ({ user }: { user: Types.User }) => { const { mutate: unenroll, isPending: unenroll_pending } = useManageUser( "UnenrollTotp", { - onSuccess: () => userInvalidate(), + onSuccess: () => { + userInvalidate(); + toast({ title: "Unenrolled in TOTP 2FA" }); + }, } ); const onOpenChange = (open: boolean) => { @@ -54,10 +59,11 @@ export const EnrollTotp = ({ user }: { user: Types.User }) => { variant="secondary" className={cn( "items-center gap-2", - !!user.totp?.confirmed_at && "hidden" + (user.passkey?.created_at || !!user.totp?.confirmed_at) && + "hidden" )} > - Enroll TOTP 2FA + Enroll TOTP 2FA @@ -86,6 +92,10 @@ export const EnrollTotp = ({ user }: { user: Types.User }) => { ) : submitted ? ( <>
+

+ Scan this QR code with your authenticator app, and enter the 6 + digit code below. +

{ className="w-72" value={confirm} onChange={(e) => setConfirm(e.target.value)} + autoFocus />