mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 10:31:12 -05:00
feat: Implement comprehensive ban enforcement
This commit is contained in:
@@ -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
82
src/hooks/useBanCheck.ts
Normal 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 };
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user