mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 16:31:13 -05:00
Fix: Implement MFA security fix
This commit is contained in:
@@ -8,8 +8,9 @@ import { Label } from '@/components/ui/label';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Zap, Mail, Lock, User, AlertCircle, Eye, EyeOff } from 'lucide-react';
|
||||
import { Zap, Mail, Lock, User, AlertCircle, Eye, EyeOff, Shield } from 'lucide-react';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
@@ -228,9 +229,43 @@ export default function Auth() {
|
||||
});
|
||||
};
|
||||
|
||||
const handleMfaCancel = () => {
|
||||
const handleMfaCancel = async () => {
|
||||
try {
|
||||
// CRITICAL SECURITY: Log cancellation attempt
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (session) {
|
||||
try {
|
||||
const { data: aalData } = await supabase.auth.mfa.getAuthenticatorAssuranceLevel();
|
||||
await supabase.rpc('log_admin_action', {
|
||||
_admin_user_id: session.user.id,
|
||||
_action: 'mfa_verification_cancelled',
|
||||
_target_user_id: session.user.id,
|
||||
_details: {
|
||||
timestamp: new Date().toISOString(),
|
||||
reason: 'user_cancelled_mfa_prompt',
|
||||
aal_before_cancel: aalData?.currentLevel || 'aal1'
|
||||
}
|
||||
});
|
||||
} catch (logError) {
|
||||
console.error('Failed to log MFA cancellation:', logError);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error during MFA cancellation:', error);
|
||||
}
|
||||
|
||||
// CRITICAL SECURITY: User cannot bypass MFA if enrolled
|
||||
// Cancelling MFA prompt MUST sign the user out
|
||||
await supabase.auth.signOut();
|
||||
|
||||
setMfaFactorId(null);
|
||||
setSignInCaptchaKey(prev => prev + 1);
|
||||
|
||||
toast({
|
||||
title: "Sign in cancelled",
|
||||
description: "Two-factor authentication is required for your account. Please sign in again and complete MFA verification.",
|
||||
variant: "destructive"
|
||||
});
|
||||
};
|
||||
const handleSignUp = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -427,11 +462,33 @@ export default function Auth() {
|
||||
)}
|
||||
|
||||
{mfaFactorId ? (
|
||||
<MFAChallenge
|
||||
factorId={mfaFactorId}
|
||||
onSuccess={handleMfaSuccess}
|
||||
onCancel={handleMfaCancel}
|
||||
/>
|
||||
<Dialog open={!!mfaFactorId} onOpenChange={(isOpen) => {
|
||||
if (!isOpen) {
|
||||
handleMfaCancel();
|
||||
}
|
||||
}}>
|
||||
<DialogContent
|
||||
className="sm:max-w-md"
|
||||
onInteractOutside={(e) => e.preventDefault()}
|
||||
onEscapeKeyDown={(e) => e.preventDefault()}
|
||||
>
|
||||
<DialogHeader>
|
||||
<div className="flex items-center gap-2 justify-center mb-2">
|
||||
<Shield className="h-6 w-6 text-primary" />
|
||||
<DialogTitle>Two-Factor Authentication Required</DialogTitle>
|
||||
</div>
|
||||
<DialogDescription className="text-center">
|
||||
Your account security settings require MFA verification to continue.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<MFAChallenge
|
||||
factorId={mfaFactorId}
|
||||
onSuccess={handleMfaSuccess}
|
||||
onCancel={handleMfaCancel}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
) : (
|
||||
<>
|
||||
<form onSubmit={handleSignIn} className="space-y-4">
|
||||
|
||||
Reference in New Issue
Block a user