feat: Implement secure MFA removal

This commit is contained in:
gpt-engineer-app[bot]
2025-10-01 15:06:17 +00:00
parent d6efa2d39f
commit 05ef5acee9
2 changed files with 265 additions and 54 deletions

View File

@@ -5,11 +5,11 @@ import { Label } from '@/components/ui/label';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Badge } from '@/components/ui/badge';
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog';
import { useToast } from '@/hooks/use-toast';
import { useAuth } from '@/hooks/useAuth';
import { supabase } from '@/integrations/supabase/client';
import { Smartphone, Shield, Copy, Eye, EyeOff, Trash2, AlertCircle } from 'lucide-react';
import { Smartphone, Shield, Copy, Eye, EyeOff, Trash2 } from 'lucide-react';
import { MFARemovalDialog } from './MFARemovalDialog';
interface TOTPFactor {
id: string;
@@ -30,6 +30,7 @@ export function TOTPSetup() {
const [factorId, setFactorId] = useState('');
const [verificationCode, setVerificationCode] = useState('');
const [showSecret, setShowSecret] = useState(false);
const [showRemovalDialog, setShowRemovalDialog] = useState(false);
useEffect(() => {
fetchTOTPFactors();
@@ -133,30 +134,8 @@ export function TOTPSetup() {
}
};
const unenrollFactor = async (factorId: string) => {
setLoading(true);
try {
const { error } = await supabase.auth.mfa.unenroll({
factorId
});
if (error) throw error;
toast({
title: 'TOTP Disabled',
description: 'Two-factor authentication has been disabled for your account.'
});
fetchTOTPFactors();
} catch (error: any) {
toast({
title: 'Error',
description: error.message || 'Failed to disable TOTP',
variant: 'destructive'
});
} finally {
setLoading(false);
}
const handleRemovalSuccess = async () => {
await fetchTOTPFactors();
};
const copySecret = () => {
@@ -281,36 +260,23 @@ export function TOTPSetup() {
<Badge variant="secondary" className="bg-green-50 dark:bg-green-950 text-green-700 dark:text-green-300">
Active
</Badge>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="outline" size="sm">
<Trash2 className="w-4 h-4 mr-2" />
Disable
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle className="flex items-center gap-2">
<AlertCircle className="w-5 h-5 text-destructive" />
Disable Two-Factor Authentication
</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to disable two-factor authentication? This will make your account less secure.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={() => unenrollFactor(activeFactor.id)}
className="bg-destructive hover:bg-destructive/90"
>
Disable TOTP
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<Button
variant="outline"
size="sm"
onClick={() => setShowRemovalDialog(true)}
>
<Trash2 className="w-4 h-4 mr-2" />
Disable
</Button>
</div>
</div>
<MFARemovalDialog
open={showRemovalDialog}
onOpenChange={setShowRemovalDialog}
factorId={activeFactor.id}
onSuccess={handleRemovalSuccess}
/>
</div>
) : (
<div className="flex items-center justify-between p-4 border rounded-lg">