diff --git a/supabase/migrations/20251107140327_78c055b6-9c85-482b-b972-edb4332dde1e.sql b/supabase/migrations/20251107140327_78c055b6-9c85-482b-b972-edb4332dde1e.sql new file mode 100644 index 00000000..01b03db1 --- /dev/null +++ b/supabase/migrations/20251107140327_78c055b6-9c85-482b-b972-edb4332dde1e.sql @@ -0,0 +1,226 @@ +-- Phase 3: Fix Submission Tables RLS Policies +-- Secure contact_submissions, park_submissions, company_submissions, photo_submissions + +-- ============================================================================ +-- 1. FIX contact_submissions TABLE +-- ============================================================================ + +-- Drop any overly permissive policies +DROP POLICY IF EXISTS "Public read access to contact_submissions" ON contact_submissions; +DROP POLICY IF EXISTS "Anyone can view contact submissions" ON contact_submissions; +DROP POLICY IF EXISTS "Public can insert contact submissions" ON contact_submissions; + +-- Keep existing good policies, add missing ones if needed +-- Note: Existing policies already restrict to user's own submissions and moderators + +-- Verify no direct INSERT is possible without proper validation +CREATE POLICY "Authenticated users insert own contact submissions" +ON contact_submissions +FOR INSERT +TO authenticated +WITH CHECK ( + user_id = auth.uid() OR user_id IS NULL +); + +-- ============================================================================ +-- 2. FIX park_submissions TABLE +-- ============================================================================ + +-- Drop any overly permissive policies +DROP POLICY IF EXISTS "Public read access to park_submissions" ON park_submissions; +DROP POLICY IF EXISTS "Anyone can view park submissions" ON park_submissions; + +-- Drop and recreate with proper restrictions +DROP POLICY IF EXISTS "Users can view own park submissions" ON park_submissions; +DROP POLICY IF EXISTS "Moderators can view all park submissions" ON park_submissions; +DROP POLICY IF EXISTS "Moderators can update park submissions" ON park_submissions; +DROP POLICY IF EXISTS "Moderators can delete park submissions" ON park_submissions; + +-- Users can only view their own 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() + ) +); + +-- Moderators can view all park submissions with MFA +CREATE POLICY "Moderators can view all park submissions" +ON park_submissions +FOR SELECT +TO authenticated +USING ( + is_moderator(auth.uid()) + AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2()) +); + +-- Moderators can update park submissions with MFA +CREATE POLICY "Moderators can update park submissions" +ON park_submissions +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()) +); + +-- Moderators can delete park submissions with MFA +CREATE POLICY "Moderators can delete park submissions" +ON park_submissions +FOR DELETE +TO authenticated +USING ( + is_moderator(auth.uid()) + AND has_aal2() +); + +-- ============================================================================ +-- 3. FIX company_submissions TABLE +-- ============================================================================ + +-- Drop any overly permissive policies +DROP POLICY IF EXISTS "Public read access to company_submissions" ON company_submissions; +DROP POLICY IF EXISTS "Anyone can view company submissions" ON company_submissions; + +-- Drop and recreate with proper restrictions +DROP POLICY IF EXISTS "Users can view own company submissions" ON company_submissions; +DROP POLICY IF EXISTS "Users can view their own company submissions" ON company_submissions; +DROP POLICY IF EXISTS "Moderators can view all company submissions" ON company_submissions; +DROP POLICY IF EXISTS "Moderators can update company submissions" ON company_submissions; +DROP POLICY IF EXISTS "Moderators can delete company submissions" ON company_submissions; + +-- Users can only view their own 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() + ) +); + +-- Moderators can view all company submissions with MFA +CREATE POLICY "Moderators can view all company submissions" +ON company_submissions +FOR SELECT +TO authenticated +USING ( + is_moderator(auth.uid()) + AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2()) +); + +-- Moderators can update company submissions with MFA +CREATE POLICY "Moderators can update company submissions" +ON company_submissions +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()) +); + +-- Moderators can delete company submissions with MFA +CREATE POLICY "Moderators can delete company submissions" +ON company_submissions +FOR DELETE +TO authenticated +USING ( + is_moderator(auth.uid()) + AND has_aal2() +); + +-- ============================================================================ +-- 4. FIX photo_submissions TABLE +-- ============================================================================ + +-- Drop any overly permissive policies +DROP POLICY IF EXISTS "Public read access to photo_submissions" ON photo_submissions; +DROP POLICY IF EXISTS "Anyone can view photo submissions" ON photo_submissions; + +-- Drop and recreate with proper restrictions +DROP POLICY IF EXISTS "Users can view own photo submissions" ON photo_submissions; +DROP POLICY IF EXISTS "Moderators can view all photo submissions" ON photo_submissions; +DROP POLICY IF EXISTS "Moderators can update photo submissions" ON photo_submissions; +DROP POLICY IF EXISTS "Moderators can delete photo submissions" ON photo_submissions; + +-- Users can only view their own 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() + ) +); + +-- Moderators can view all photo submissions with MFA +CREATE POLICY "Moderators can view all photo submissions" +ON photo_submissions +FOR SELECT +TO authenticated +USING ( + is_moderator(auth.uid()) + AND ((NOT has_mfa_enabled(auth.uid())) OR has_aal2()) +); + +-- Moderators can update photo submissions with MFA +CREATE POLICY "Moderators can update photo submissions" +ON photo_submissions +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()) +); + +-- Moderators can delete photo submissions with MFA +CREATE POLICY "Moderators can delete photo submissions" +ON photo_submissions +FOR DELETE +TO authenticated +USING ( + is_moderator(auth.uid()) + AND has_aal2() +); + +-- ============================================================================ +-- 5. AUDIT: Verify RLS is enabled on all submission tables +-- ============================================================================ + +ALTER TABLE contact_submissions ENABLE ROW LEVEL SECURITY; +ALTER TABLE park_submissions ENABLE ROW LEVEL SECURITY; +ALTER TABLE company_submissions ENABLE ROW LEVEL SECURITY; +ALTER TABLE photo_submissions ENABLE ROW LEVEL SECURITY; + +DO $$ +BEGIN + RAISE NOTICE '✅ Phase 3 Complete: Secured 4 submission tables'; + RAISE NOTICE '🔒 contact_submissions: Protected user emails and messages'; + RAISE NOTICE '🔒 park_submissions: Business contact info restricted'; + RAISE NOTICE '🔒 company_submissions: Company data restricted to submitters'; + RAISE NOTICE '🔒 photo_submissions: Photo metadata properly scoped'; + RAISE NOTICE '🛡️ All submission data now requires authentication + proper authorization'; +END $$; \ No newline at end of file