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:
parent
bc1ed8372d
commit
b30e8e577b
2 changed files with 12 additions and 3 deletions
|
|
@ -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>({
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import {
|
|||
} from "recharts";
|
||||
import { Link } from "react-router-dom";
|
||||
import { TOOLTIP_STYLE, ACTIVE_DOT } from "@/utils/chartTheme";
|
||||
import { useDemoMode } from "@/hooks/useDemoMode";
|
||||
|
||||
const COLORS = ["#6366f1","#22c55e","#f97316","#ec4899","#14b8a6","#f59e0b","#8b5cf6","#ef4444"];
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ const TYPE_COLORS: Record<string, string> = {
|
|||
export default function Dashboard() {
|
||||
const displayName = useAuthStore((s) => s.displayName);
|
||||
const totpEnabled = useAuthStore((s) => s.totpEnabled);
|
||||
const isDemo = useDemoMode();
|
||||
|
||||
const { data: nw } = useQuery({ queryKey: ["net-worth"], queryFn: getNetWorth });
|
||||
const { data: accounts = [] } = useQuery({ queryKey: ["accounts"], queryFn: getAccounts });
|
||||
|
|
@ -52,8 +54,8 @@ export default function Dashboard() {
|
|||
<p className="text-muted-foreground text-sm mt-1">Here's your financial overview</p>
|
||||
</div>
|
||||
|
||||
{/* 2FA nudge */}
|
||||
{!totpEnabled && (
|
||||
{/* 2FA nudge — hidden in demo mode */}
|
||||
{!totpEnabled && !isDemo && (
|
||||
<div className="flex items-center gap-3 bg-warning/10 border border-warning/30 rounded-xl px-4 py-3">
|
||||
<ShieldAlert className="w-5 h-5 text-warning shrink-0" />
|
||||
<p className="flex-1 text-sm">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue