diff --git a/supabase/migrations/20251107135746_11607f33-6a04-44ea-883a-57537ae6024f.sql b/supabase/migrations/20251107135746_11607f33-6a04-44ea-883a-57537ae6024f.sql new file mode 100644 index 00000000..37ae0199 --- /dev/null +++ b/supabase/migrations/20251107135746_11607f33-6a04-44ea-883a-57537ae6024f.sql @@ -0,0 +1,192 @@ +-- Phase 2: Fix Remaining RLS Security Issues (corrected) +-- Fix user_roles, reviews, reports, submission_items, and other tables + +-- ============================================================================ +-- 1. FIX user_roles TABLE - Remove public read access +-- ============================================================================ + +DROP POLICY IF EXISTS "Public read access to user_roles" ON user_roles; +DROP POLICY IF EXISTS "Anyone can view user roles" ON user_roles; +DROP POLICY IF EXISTS "Users can view their own roles" ON user_roles; +DROP POLICY IF EXISTS "Moderators can view all roles with MFA" ON user_roles; +DROP POLICY IF EXISTS "Superusers can manage roles with MFA" ON user_roles; + +CREATE POLICY "Users can view their own roles" +ON user_roles FOR SELECT TO authenticated +USING (user_id = auth.uid()); + +CREATE POLICY "Moderators can view all roles with MFA" +ON user_roles FOR SELECT TO authenticated +USING (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())); + +CREATE POLICY "Superusers can manage roles with MFA" +ON user_roles FOR ALL TO authenticated +USING (has_role(auth.uid(), 'superuser') AND has_aal2()) +WITH CHECK (has_role(auth.uid(), 'superuser') AND has_aal2()); + +-- ============================================================================ +-- 2. FIX reviews TABLE - Implement proper access control +-- ============================================================================ + +DROP POLICY IF EXISTS "Public read access to reviews" ON reviews; +DROP POLICY IF EXISTS "Anyone can view reviews" ON reviews; +DROP POLICY IF EXISTS "Public can insert reviews" ON reviews; +DROP POLICY IF EXISTS "Public can view approved reviews" ON reviews; +DROP POLICY IF EXISTS "Users can view their own reviews" ON reviews; +DROP POLICY IF EXISTS "Moderators can view all reviews with MFA" ON reviews; +DROP POLICY IF EXISTS "Authenticated users can insert reviews" ON reviews; +DROP POLICY IF EXISTS "Users can update their own pending reviews" ON reviews; +DROP POLICY IF EXISTS "Moderators can update any review with MFA" ON reviews; +DROP POLICY IF EXISTS "Moderators can delete reviews with MFA" ON reviews; + +CREATE POLICY "Public can view approved reviews" +ON reviews FOR SELECT TO authenticated +USING (moderation_status = 'approved'); + +CREATE POLICY "Users can view their own reviews" +ON reviews FOR SELECT TO authenticated +USING (user_id = auth.uid()); + +CREATE POLICY "Moderators can view all reviews with MFA" +ON reviews FOR SELECT TO authenticated +USING (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())); + +CREATE POLICY "Authenticated users can insert reviews" +ON reviews FOR INSERT TO authenticated +WITH CHECK (user_id = auth.uid() AND NOT is_user_banned(auth.uid())); + +CREATE POLICY "Users can update their own pending reviews" +ON reviews FOR UPDATE TO authenticated +USING (user_id = auth.uid() AND moderation_status = 'pending') +WITH CHECK (user_id = auth.uid() AND moderation_status = 'pending'); + +CREATE POLICY "Moderators can update any review with MFA" +ON reviews FOR UPDATE TO authenticated +USING (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())) +WITH CHECK (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())); + +CREATE POLICY "Moderators can delete reviews with MFA" +ON reviews FOR DELETE TO authenticated +USING (is_moderator(auth.uid()) AND has_aal2()); + +-- ============================================================================ +-- 3. FIX reports TABLE - Implement proper access control +-- ============================================================================ + +DROP POLICY IF EXISTS "Anyone can view reports" ON reports; +DROP POLICY IF EXISTS "Public read access to reports" ON reports; +DROP POLICY IF EXISTS "Users can view their own reports" ON reports; +DROP POLICY IF EXISTS "Moderators can view all reports with MFA" ON reports; +DROP POLICY IF EXISTS "Authenticated users can create reports" ON reports; +DROP POLICY IF EXISTS "Moderators can update reports with MFA" ON reports; +DROP POLICY IF EXISTS "Moderators can delete reports with MFA" ON reports; + +CREATE POLICY "Users can view their own reports" +ON reports FOR SELECT TO authenticated +USING (reporter_id = auth.uid()); + +CREATE POLICY "Moderators can view all reports with MFA" +ON reports FOR SELECT TO authenticated +USING (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())); + +CREATE POLICY "Authenticated users can create reports" +ON reports FOR INSERT TO authenticated +WITH CHECK (reporter_id = auth.uid() AND NOT is_user_banned(auth.uid())); + +CREATE POLICY "Moderators can update reports with MFA" +ON reports FOR UPDATE TO authenticated +USING (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())) +WITH CHECK (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())); + +CREATE POLICY "Moderators can delete reports with MFA" +ON reports FOR DELETE TO authenticated +USING (is_moderator(auth.uid()) AND has_aal2()); + +-- ============================================================================ +-- 4. FIX submission_items TABLE - Implement proper access control +-- ============================================================================ + +DROP POLICY IF EXISTS "Anyone can view submission items" ON submission_items; +DROP POLICY IF EXISTS "Public read access to submission_items" ON submission_items; +DROP POLICY IF EXISTS "Users can view items from their own submissions" ON submission_items; +DROP POLICY IF EXISTS "Moderators can view all submission items with MFA" ON submission_items; +DROP POLICY IF EXISTS "Moderators can manage submission items with MFA" ON submission_items; + +CREATE POLICY "Users can view items from their own submissions" +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() +)); + +CREATE POLICY "Moderators can view all submission items with MFA" +ON submission_items FOR SELECT TO authenticated +USING (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())); + +CREATE POLICY "Moderators can manage submission items with MFA" +ON submission_items FOR ALL TO authenticated +USING (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())) +WITH CHECK (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())); + +-- ============================================================================ +-- 5. FIX user_blocks TABLE - Ensure proper access control +-- ============================================================================ + +DROP POLICY IF EXISTS "Anyone can view blocks" ON user_blocks; +DROP POLICY IF EXISTS "Users can view their own blocks" ON user_blocks; +DROP POLICY IF EXISTS "Users can manage their own blocks" ON user_blocks; +DROP POLICY IF EXISTS "Moderators can view all blocks with MFA" ON user_blocks; + +CREATE POLICY "Users can view their own blocks" +ON user_blocks FOR SELECT TO authenticated +USING (blocker_id = auth.uid()); + +CREATE POLICY "Users can manage their own blocks" +ON user_blocks FOR ALL TO authenticated +USING (blocker_id = auth.uid()) +WITH CHECK (blocker_id = auth.uid()); + +CREATE POLICY "Moderators can view all blocks with MFA" +ON user_blocks FOR SELECT TO authenticated +USING (is_moderator(auth.uid()) AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2())); + +-- ============================================================================ +-- 6. FIX user_preferences TABLE - Ensure proper access control +-- ============================================================================ + +DROP POLICY IF EXISTS "Anyone can view preferences" ON user_preferences; +DROP POLICY IF EXISTS "Users can view their own preferences" ON user_preferences; +DROP POLICY IF EXISTS "Users can manage their own preferences" ON user_preferences; +DROP POLICY IF EXISTS "Moderators can view all preferences with MFA" ON user_preferences; + +CREATE POLICY "Users can view their own preferences" +ON user_preferences FOR SELECT TO authenticated +USING (user_id = auth.uid()); + +CREATE POLICY "Users can manage their own preferences" +ON user_preferences FOR ALL TO authenticated +USING (user_id = auth.uid()) +WITH CHECK (user_id = auth.uid()); + +CREATE POLICY "Moderators can view all preferences with MFA" +ON user_preferences FOR SELECT TO authenticated +USING (is_moderator(auth.uid()) AND has_aal2()); + +-- ============================================================================ +-- 7. AUDIT: Verify all critical tables have RLS enabled +-- ============================================================================ + +ALTER TABLE user_roles ENABLE ROW LEVEL SECURITY; +ALTER TABLE reviews ENABLE ROW LEVEL SECURITY; +ALTER TABLE reports ENABLE ROW LEVEL SECURITY; +ALTER TABLE submission_items ENABLE ROW LEVEL SECURITY; +ALTER TABLE user_blocks ENABLE ROW LEVEL SECURITY; +ALTER TABLE user_preferences ENABLE ROW LEVEL SECURITY; + +DO $$ +BEGIN + RAISE NOTICE '✅ Phase 2 Complete: Secured user_roles, reviews, reports, submission_items, user_blocks, user_preferences'; + RAISE NOTICE '🔒 All critical tables now have proper access control with MFA enforcement'; + RAISE NOTICE '🚫 Banned users blocked from creating reviews and reports'; +END $$; \ No newline at end of file