-- ============================================================================ -- PHASE 1: EMERGENCY RLS & SECURITY FIXES (SIMPLIFIED - CRITICAL ONLY) -- Only the most critical security fixes -- ============================================================================ -- ============================================================================ -- 1.1 FIX PROFILES TABLE RLS (CRITICAL ⚠️⚠️⚠️) -- ============================================================================ -- Drop existing policies DROP POLICY IF EXISTS "Users can view own profile" ON profiles; DROP POLICY IF EXISTS "Users can update own profile" ON profiles; DROP POLICY IF EXISTS "Public profiles viewable by everyone" ON profiles; DROP POLICY IF EXISTS "Moderators can view all profiles" ON profiles; DROP POLICY IF EXISTS "Users can view own full profile" ON profiles; DROP POLICY IF EXISTS "Public can view sanitized profiles" ON profiles; DROP POLICY IF EXISTS "Admins can update any profile" ON profiles; -- Ensure RLS is enabled ALTER TABLE profiles ENABLE ROW LEVEL SECURITY; -- Policy: Users see their own FULL profile CREATE POLICY "Users can view own full profile" ON profiles FOR SELECT TO authenticated USING (user_id = auth.uid()); -- Policy: Public sees SANITIZED profiles only CREATE POLICY "Public can view sanitized profiles" ON profiles FOR SELECT TO public USING (banned = false); -- Policy: Moderators can view ALL profiles CREATE POLICY "Moderators can view all profiles" ON profiles FOR SELECT TO authenticated USING ( has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role) ); -- Policy: Users can update their own profile (but not banned status) CREATE POLICY "Users can update own profile" ON profiles FOR UPDATE TO authenticated USING (user_id = auth.uid()) WITH CHECK ( user_id = auth.uid() AND banned = (SELECT banned FROM profiles WHERE user_id = auth.uid()) ); -- Policy: Admins can update any profile CREATE POLICY "Admins can update any profile" ON profiles FOR UPDATE TO authenticated USING ( has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role) ); -- ============================================================================ -- 1.2 FIX SUBMISSIONS RLS (CRITICAL ⚠️⚠️⚠️) -- ============================================================================ -- content_submissions DROP POLICY IF EXISTS "Users can view own submissions" ON content_submissions; DROP POLICY IF EXISTS "Authenticated users can create submissions" ON content_submissions; DROP POLICY IF EXISTS "Moderators can update any submission" ON content_submissions; DROP POLICY IF EXISTS "Users can update own pending submissions" ON content_submissions; CREATE POLICY "Users can view own submissions" ON content_submissions FOR SELECT TO authenticated USING ( user_id = auth.uid() OR has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role) ); CREATE POLICY "Authenticated users can create submissions" ON content_submissions FOR INSERT TO authenticated WITH CHECK ( user_id = auth.uid() AND NOT EXISTS ( SELECT 1 FROM profiles WHERE user_id = auth.uid() AND banned = true ) ); CREATE POLICY "Moderators can update any submission" ON content_submissions FOR UPDATE TO authenticated USING ( has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role) ); CREATE POLICY "Users can update own pending submissions" ON content_submissions FOR UPDATE TO authenticated USING (user_id = auth.uid() AND status = 'pending') WITH CHECK (user_id = auth.uid() AND status = 'pending'); -- submission_items DROP POLICY IF EXISTS "Users can view own submission items" ON submission_items; DROP POLICY IF EXISTS "Moderators can update submission items" ON submission_items; CREATE POLICY "Users can view own submission items" ON submission_items FOR SELECT TO authenticated USING ( EXISTS ( SELECT 1 FROM content_submissions cs WHERE cs.id = submission_items.submission_id AND ( cs.user_id = auth.uid() OR has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role) ) ) ); CREATE POLICY "Moderators can update submission items" ON submission_items FOR UPDATE TO authenticated USING ( has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role) ); -- park_submissions DROP POLICY IF EXISTS "Users can view own park submissions" ON park_submissions; CREATE POLICY "Users can view own park submissions" ON park_submissions FOR SELECT TO authenticated USING ( EXISTS ( SELECT 1 FROM content_submissions cs WHERE cs.id = park_submissions.submission_id AND (cs.user_id = auth.uid() OR has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role)) ) ); -- ride_submissions DROP POLICY IF EXISTS "Users can view own ride submissions" ON ride_submissions; CREATE POLICY "Users can view own ride submissions" ON ride_submissions FOR SELECT TO authenticated USING ( EXISTS ( SELECT 1 FROM content_submissions cs WHERE cs.id = ride_submissions.submission_id AND (cs.user_id = auth.uid() OR has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role)) ) ); -- company_submissions DROP POLICY IF EXISTS "Users can view own company submissions" ON company_submissions; CREATE POLICY "Users can view own company submissions" ON company_submissions FOR SELECT TO authenticated USING ( EXISTS ( SELECT 1 FROM content_submissions cs WHERE cs.id = company_submissions.submission_id AND (cs.user_id = auth.uid() OR has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role)) ) ); -- ride_model_submissions DROP POLICY IF EXISTS "Users can view own ride model submissions" ON ride_model_submissions; CREATE POLICY "Users can view own ride model submissions" ON ride_model_submissions FOR SELECT TO authenticated USING ( EXISTS ( SELECT 1 FROM content_submissions cs WHERE cs.id = ride_model_submissions.submission_id AND (cs.user_id = auth.uid() OR has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role)) ) ); -- photo_submissions DROP POLICY IF EXISTS "Users can view own photo submissions" ON photo_submissions; CREATE POLICY "Users can view own photo submissions" ON photo_submissions FOR SELECT TO authenticated USING ( EXISTS ( SELECT 1 FROM content_submissions cs WHERE cs.id = photo_submissions.submission_id AND (cs.user_id = auth.uid() OR has_role(auth.uid(), 'moderator'::app_role) OR has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role)) ) ); -- ============================================================================ -- 1.3 BAN PREVENTION DATABASE ENFORCEMENT (CRITICAL ⚠️⚠️) -- ============================================================================ CREATE OR REPLACE FUNCTION prevent_banned_user_submissions() RETURNS TRIGGER LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$ DECLARE v_is_banned BOOLEAN; BEGIN SELECT banned INTO v_is_banned FROM profiles WHERE user_id = NEW.user_id; IF v_is_banned = true THEN RAISE EXCEPTION 'Cannot create submission: User account is suspended' USING ERRCODE = '42501', HINT = 'Contact support for account status inquiries'; END IF; RETURN NEW; END; $$; DROP TRIGGER IF EXISTS check_banned_user_before_submission ON content_submissions; CREATE TRIGGER check_banned_user_before_submission BEFORE INSERT ON content_submissions FOR EACH ROW EXECUTE FUNCTION prevent_banned_user_submissions(); -- ============================================================================ -- VERIFICATION -- ============================================================================ DO $$ BEGIN RAISE NOTICE '✅ Phase 1 Emergency RLS & Security Fixes completed'; RAISE NOTICE ' ✓ Profiles RLS: Secured (own/public/moderator views)'; RAISE NOTICE ' ✓ Submissions RLS: Secured (users own, moderators all)'; RAISE NOTICE ' ✓ Ban enforcement: Database trigger active'; END $$;