mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 07:51:13 -05:00
Fix remaining SECURITY DEFINER functions
Add `SET search_path = public` to all remaining SECURITY DEFINER functions to address security linter warnings.
This commit is contained in:
@@ -0,0 +1,269 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- 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 $$;
|
||||||
Reference in New Issue
Block a user