feat: Implement comprehensive ban enforcement

This commit is contained in:
gpt-engineer-app[bot]
2025-10-30 01:47:51 +00:00
parent f95eaf9eb7
commit fe76c8c572
8 changed files with 452 additions and 0 deletions

View File

@@ -110,6 +110,19 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
const currentAal = await getSessionAal(session);
setAal(currentAal);
authLog('[Auth] Current AAL:', currentAal);
// Check if user is banned
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', session.user.id)
.maybeSingle();
if (profile?.banned) {
authWarn('[Auth] Banned user detected, signing out');
await supabase.auth.signOut();
return;
}
} else {
setAal(null);
}

82
src/hooks/useBanCheck.ts Normal file
View File

@@ -0,0 +1,82 @@
import { useEffect, useState } from 'react';
import { useAuth } from '@/hooks/useAuth';
import { supabase } from '@/integrations/supabase/client';
import { useNavigate } from 'react-router-dom';
import { toast } from '@/hooks/use-toast';
export function useBanCheck() {
const { user } = useAuth();
const navigate = useNavigate();
const [isBanned, setIsBanned] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!user) {
setIsBanned(false);
setLoading(false);
return;
}
const checkBan = async () => {
try {
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', user.id)
.single();
if (profile?.banned) {
setIsBanned(true);
toast({
title: 'Account Suspended',
description: 'Your account has been suspended. Contact support for assistance.',
variant: 'destructive',
duration: Infinity // Don't auto-dismiss
});
// Sign out banned user
await supabase.auth.signOut();
navigate('/');
}
} catch (error) {
console.error('Ban check error:', error);
} finally {
setLoading(false);
}
};
checkBan();
// Subscribe to profile changes (real-time ban detection)
const channel = supabase
.channel('ban-check')
.on(
'postgres_changes',
{
event: 'UPDATE',
schema: 'public',
table: 'profiles',
filter: `user_id=eq.${user.id}`
},
(payload) => {
if (payload.new && (payload.new as { banned: boolean }).banned) {
setIsBanned(true);
toast({
title: 'Account Suspended',
description: 'Your account has been suspended. Contact support for assistance.',
variant: 'destructive',
duration: Infinity
});
supabase.auth.signOut();
navigate('/');
}
}
)
.subscribe();
return () => {
supabase.removeChannel(channel);
};
}, [user, navigate]);
return { isBanned, loading };
}

View File

@@ -4099,6 +4099,7 @@ export type Database = {
}
is_moderator: { Args: { _user_id: string }; Returns: boolean }
is_superuser: { Args: { _user_id: string }; Returns: boolean }
is_user_banned: { Args: { _user_id: string }; Returns: boolean }
log_admin_action: {
Args: {
_action: string

View File

@@ -12,6 +12,17 @@ export async function submitCompanyCreation(
companyType: 'manufacturer' | 'designer' | 'operator' | 'property_owner',
userId: string
) {
// Check if user is banned
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', userId)
.single();
if (profile?.banned) {
throw new Error('Account suspended. Contact support for assistance.');
}
// Upload any pending local images first
let processedImages = data.images;
if (data.images?.uploaded && data.images.uploaded.length > 0) {
@@ -78,6 +89,17 @@ export async function submitCompanyUpdate(
data: CompanyFormData,
userId: string
) {
// Check if user is banned
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', userId)
.single();
if (profile?.banned) {
throw new Error('Account suspended. Contact support for assistance.');
}
// Fetch existing company data (all fields for original_data)
const { data: existingCompany, error: fetchError } = await supabase
.from('companies')

View File

@@ -177,6 +177,17 @@ export async function submitParkCreation(
data: ParkFormData,
userId: string
): Promise<{ submitted: boolean; submissionId: string }> {
// Check if user is banned
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', userId)
.single();
if (profile?.banned) {
throw new Error('Account suspended. Contact support for assistance.');
}
// Upload any pending local images first
let processedImages = data.images;
if (data.images?.uploaded && data.images.uploaded.length > 0) {
@@ -257,6 +268,17 @@ export async function submitParkUpdate(
data: ParkFormData,
userId: string
): Promise<{ submitted: boolean; submissionId: string }> {
// Check if user is banned
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', userId)
.single();
if (profile?.banned) {
throw new Error('Account suspended. Contact support for assistance.');
}
// Fetch existing park data first
const { data: existingPark, error: fetchError } = await supabase
.from('parks')
@@ -349,6 +371,17 @@ export async function submitRideCreation(
data: RideFormData,
userId: string
): Promise<{ submitted: boolean; submissionId: string }> {
// Check if user is banned
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', userId)
.single();
if (profile?.banned) {
throw new Error('Account suspended. Contact support for assistance.');
}
// Upload any pending local images first
let processedImages = data.images;
if (data.images?.uploaded && data.images.uploaded.length > 0) {
@@ -429,6 +462,17 @@ export async function submitRideUpdate(
data: RideFormData,
userId: string
): Promise<{ submitted: boolean; submissionId: string }> {
// Check if user is banned
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', userId)
.single();
if (profile?.banned) {
throw new Error('Account suspended. Contact support for assistance.');
}
// Fetch existing ride data first
const { data: existingRide, error: fetchError } = await supabase
.from('rides')
@@ -518,6 +562,17 @@ export async function submitRideModelCreation(
data: RideModelFormData,
userId: string
): Promise<{ submitted: boolean; submissionId: string }> {
// Check if user is banned
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', userId)
.single();
if (profile?.banned) {
throw new Error('Account suspended. Contact support for assistance.');
}
// Upload any pending local images first
let processedImages = data.images;
if (data.images?.uploaded && data.images.uploaded.length > 0) {
@@ -584,6 +639,17 @@ export async function submitRideModelUpdate(
data: RideModelFormData,
userId: string
): Promise<{ submitted: boolean; submissionId: string }> {
// Check if user is banned
const { data: profile } = await supabase
.from('profiles')
.select('banned')
.eq('user_id', userId)
.single();
if (profile?.banned) {
throw new Error('Account suspended. Contact support for assistance.');
}
// Fetch existing ride model
const { data: existingModel, error: fetchError } = await supabase
.from('ride_models')