From e960d1bace2985eb1efd608d0dce421a1893d7b8 Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 18 Dec 2025 14:11:22 +0100 Subject: [PATCH] fix: resolve infinite recursion in admin_users RLS policy The admin_users policy was checking if user is admin by querying the same table, causing infinite recursion. Changed to allow users to view their own admin record directly using auth.uid() = user_id. This fixes the error: 'infinite recursion detected in policy for relation admin_users' --- src/app/api/debug-admin/route.ts | 48 ++++++++++++++++++++++++++++++++ src/services/track-api-usage.ts | 10 +++++-- supa_schema.sql | 6 ++-- 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 src/app/api/debug-admin/route.ts diff --git a/src/app/api/debug-admin/route.ts b/src/app/api/debug-admin/route.ts new file mode 100644 index 0000000..419c38c --- /dev/null +++ b/src/app/api/debug-admin/route.ts @@ -0,0 +1,48 @@ +import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'; +import { cookies } from 'next/headers'; +import { NextResponse } from 'next/server'; + +export async function GET() { + const supabase = createServerComponentClient({ cookies }); + + // Get current user + const { data: { user }, error: userError } = await supabase.auth.getUser(); + + if (userError || !user) { + return NextResponse.json({ + success: false, + error: 'Not authenticated', + userError: userError?.message + }); + } + + // Check admin_users table + const { data: adminData, error: adminError } = await supabase + .from('admin_users') + .select('*') + .eq('user_id', user.id) + .single(); + + // Get all admin users (for debugging) + const { data: allAdmins, error: allAdminsError } = await supabase + .from('admin_users') + .select('*'); + + return NextResponse.json({ + success: true, + currentUser: { + id: user.id, + email: user.email + }, + adminCheck: { + data: adminData, + error: adminError?.message, + isAdmin: !!adminData + }, + allAdmins: { + data: allAdmins, + error: allAdminsError?.message, + count: allAdmins?.length || 0 + } + }); +} diff --git a/src/services/track-api-usage.ts b/src/services/track-api-usage.ts index 073e0ba..bab96bb 100644 --- a/src/services/track-api-usage.ts +++ b/src/services/track-api-usage.ts @@ -189,6 +189,7 @@ export async function getGlobalApiStats(): Promise { */ export async function checkIsAdmin(userId: string): Promise { try { + console.log('[checkIsAdmin] Checking admin status for user:', userId); const supabase = createServerComponentClient({ cookies }); const { data, error } = await supabase @@ -197,13 +198,18 @@ export async function checkIsAdmin(userId: string): Promise { .eq('user_id', userId) .single(); + console.log('[checkIsAdmin] Query result - data:', data, 'error:', error); + if (error) { + console.log('[checkIsAdmin] Error occurred:', error.message); return false; } - return !!data; + const isAdmin = !!data; + console.log('[checkIsAdmin] Final result:', isAdmin); + return isAdmin; } catch (err) { - console.error('Error checking admin status:', err); + console.error('[checkIsAdmin] Exception:', err); return false; } } diff --git a/supa_schema.sql b/supa_schema.sql index fe502a7..183e4d2 100644 --- a/supa_schema.sql +++ b/supa_schema.sql @@ -283,9 +283,9 @@ CREATE POLICY "Admins can view all credits" ON user_credits FOR SELECT USING ( EXISTS (SELECT 1 FROM admin_users WHERE user_id = auth.uid()) ); --- Policies for admin_users (only admins can view) -CREATE POLICY "Admins can view admin users" ON admin_users FOR SELECT USING ( - EXISTS (SELECT 1 FROM admin_users WHERE user_id = auth.uid()) +-- Policies for admin_users (users can see their own admin record) +CREATE POLICY "Users can view their own admin record" ON admin_users FOR SELECT USING ( + auth.uid() = user_id ); -- Note: To add robin as admin, run this after getting the user_id: