Block 2FA setup in demo mode at all entry points

The dashboard had a 'Set up 2FA' banner link to /security/totp that
bypassed the settings button guard entirely. Three fixes:
- Dashboard: hide the 2FA nudge banner completely in demo mode
- TwoFactorSetupPage: redirect to /settings on mount if isDemo, and
  disable the setup query so no API call fires even briefly
- This covers both the UI entry point and direct URL navigation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
megaproxy 2026-04-23 23:46:27 +00:00
parent bc1ed8372d
commit b30e8e577b
2 changed files with 12 additions and 3 deletions

View file

@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
@ -7,6 +7,7 @@ import { getTotpSetup, enableTotp } from "@/api/auth";
import { useAuthStore } from "@/store/authStore";
import { useQuery, useMutation } from "@tanstack/react-query";
import { ShieldCheck, Copy, CheckCircle, Loader2 } from "lucide-react";
import { useDemoMode } from "@/hooks/useDemoMode";
const schema = z.object({ code: z.string().length(6, "6-digit code required") });
type Form = z.infer<typeof schema>;
@ -14,6 +15,11 @@ type Form = z.infer<typeof schema>;
export default function TwoFactorSetupPage() {
const navigate = useNavigate();
const { setTotpEnabled } = useAuthStore();
const isDemo = useDemoMode();
useEffect(() => {
if (isDemo) navigate("/settings", { replace: true });
}, [isDemo, navigate]);
const [copied, setCopied] = useState(false);
const [secret, setSecret] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
@ -25,6 +31,7 @@ export default function TwoFactorSetupPage() {
setSecret(res.secret);
return res;
},
enabled: !isDemo,
});
const { register, handleSubmit, formState } = useForm<Form>({