-- Fix all direct auth.mfa_factors queries by replacing with has_mfa_enabled() function -- This prevents "permission denied for table mfa_factors" errors for non-superuser roles -- ============================================================================ -- BLOG POSTS -- ============================================================================ DROP POLICY IF EXISTS "Admins can insert blog posts with MFA" ON public.blog_posts; DROP POLICY IF EXISTS "Admins can create blog posts with AAL2" ON public.blog_posts; CREATE POLICY "Admins can insert blog posts with MFA" ON public.blog_posts FOR INSERT TO authenticated WITH CHECK ( (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role)) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); DROP POLICY IF EXISTS "Admins can update blog posts with MFA" ON public.blog_posts; DROP POLICY IF EXISTS "Admins can update blog posts with AAL2" ON public.blog_posts; CREATE POLICY "Admins can update blog posts with MFA" ON public.blog_posts FOR UPDATE TO authenticated USING ( (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role)) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); DROP POLICY IF EXISTS "Admins can delete blog posts with MFA" ON public.blog_posts; DROP POLICY IF EXISTS "Admins can delete blog posts with AAL2" ON public.blog_posts; CREATE POLICY "Admins can delete blog posts with MFA" ON public.blog_posts FOR DELETE TO authenticated USING ( (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'superuser'::app_role)) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- ADMIN AUDIT LOG - Only fix the SELECT policy -- ============================================================================ -- Note: INSERT policy already uses has_aal2() correctly, no need to change -- We're only fixing policies that query auth.mfa_factors directly -- ============================================================================ -- COMPANY SUBMISSIONS -- ============================================================================ DROP POLICY IF EXISTS "Moderators can view all company submissions" ON public.company_submissions; CREATE POLICY "Moderators can view all company submissions" ON public.company_submissions FOR SELECT TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); DROP POLICY IF EXISTS "Moderators can update company submissions" ON public.company_submissions; CREATE POLICY "Moderators can update company submissions" ON public.company_submissions FOR UPDATE TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); DROP POLICY IF EXISTS "Moderators can delete company submissions" ON public.company_submissions; CREATE POLICY "Moderators can delete company submissions" ON public.company_submissions FOR DELETE TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- PARK SUBMISSIONS -- ============================================================================ DROP POLICY IF EXISTS "Moderators can view all park submissions" ON public.park_submissions; CREATE POLICY "Moderators can view all park submissions" ON public.park_submissions FOR SELECT TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); DROP POLICY IF EXISTS "Moderators can update park submissions" ON public.park_submissions; CREATE POLICY "Moderators can update park submissions" ON public.park_submissions FOR UPDATE TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); DROP POLICY IF EXISTS "Moderators can delete park submissions" ON public.park_submissions; CREATE POLICY "Moderators can delete park submissions" ON public.park_submissions FOR DELETE TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- PHOTO SUBMISSION ITEMS -- ============================================================================ DROP POLICY IF EXISTS "Moderators can manage photo submission items" ON public.photo_submission_items; CREATE POLICY "Moderators can manage photo submission items" ON public.photo_submission_items FOR ALL TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- PHOTO SUBMISSIONS -- ============================================================================ DROP POLICY IF EXISTS "Moderators can manage photo submissions" ON public.photo_submissions; CREATE POLICY "Moderators can manage photo submissions" ON public.photo_submissions FOR ALL TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- REPORTS -- ============================================================================ DROP POLICY IF EXISTS "Moderators can manage reports" ON public.reports; CREATE POLICY "Moderators can manage reports" ON public.reports FOR ALL TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- RIDE MODEL SUBMISSIONS -- ============================================================================ DROP POLICY IF EXISTS "Moderators can manage ride model submissions" ON public.ride_model_submissions; CREATE POLICY "Moderators can manage ride model submissions" ON public.ride_model_submissions FOR ALL TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- RIDE SUBMISSIONS -- ============================================================================ DROP POLICY IF EXISTS "Moderators can manage ride submissions" ON public.ride_submissions; CREATE POLICY "Moderators can manage ride submissions" ON public.ride_submissions FOR ALL TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- SUBMISSION ITEMS -- ============================================================================ DROP POLICY IF EXISTS "Moderators can view all submission items" ON public.submission_items; CREATE POLICY "Moderators can view all submission items" ON public.submission_items FOR SELECT TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); DROP POLICY IF EXISTS "Moderators can update submission items" ON public.submission_items; CREATE POLICY "Moderators can update submission items" ON public.submission_items FOR UPDATE TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- TIMELINE EVENT SUBMISSIONS -- ============================================================================ DROP POLICY IF EXISTS "Moderators can manage timeline event submissions" ON public.timeline_event_submissions; CREATE POLICY "Moderators can manage timeline event submissions" ON public.timeline_event_submissions FOR ALL TO authenticated USING ( is_moderator((SELECT auth.uid())) AND ((NOT has_mfa_enabled((SELECT auth.uid()))) OR has_aal2()) ); -- ============================================================================ -- VERIFICATION -- ============================================================================ COMMENT ON FUNCTION public.has_mfa_enabled IS 'Security definer function to safely check MFA enrollment without granting direct access to auth.mfa_factors table';