diff --git a/supabase/functions/process-selective-approval/index.ts b/supabase/functions/process-selective-approval/index.ts index c9b838e8..1ee2e77c 100644 --- a/supabase/functions/process-selective-approval/index.ts +++ b/supabase/functions/process-selective-approval/index.ts @@ -122,13 +122,22 @@ serve(async (req) => { ); // Check if user has moderator permissions using service role to bypass RLS + console.log('🔍 [ROLE CHECK] Fetching roles for user:', authenticatedUserId); + const { data: roles, error: rolesError } = await supabase .from('user_roles') .select('role') .eq('user_id', authenticatedUserId); + console.log('🔍 [ROLE CHECK] Query result:', { + roles, + error: rolesError, + rolesCount: roles?.length, + userId: authenticatedUserId + }); + if (rolesError) { - console.error('Failed to fetch user roles:', rolesError); + console.error('❌ [ROLE CHECK] Failed:', rolesError); return new Response( JSON.stringify({ error: 'Failed to verify user permissions.' }), { status: 403, headers: { ...corsHeaders, 'Content-Type': 'application/json' } } @@ -140,34 +149,39 @@ serve(async (req) => { userRoles.includes('admin') || userRoles.includes('superuser'); + console.log('🔍 [ROLE CHECK] Result:', { + userRoles, + isModerator, + userId: authenticatedUserId + }); + if (!isModerator) { + console.error('❌ [ROLE CHECK] Insufficient permissions'); return new Response( JSON.stringify({ error: 'Insufficient permissions. Moderator role required.' }), { status: 403, headers: { ...corsHeaders, 'Content-Type': 'application/json' } } ); } + console.log('✅ [ROLE CHECK] User is moderator'); + // Phase 2: AAL2 Enforcement - Check if user has MFA enrolled and requires AAL2 - const { data: { session } } = await supabaseAuth.auth.getSession(); - if (!session) { - return new Response( - JSON.stringify({ error: 'No active session found.' }), - { status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } } - ); - } + // Parse JWT directly from Authorization header to get AAL level + const jwt = authHeader.replace('Bearer ', ''); + const payload = JSON.parse(atob(jwt.split('.')[1])); + const aal = payload.aal || 'aal1'; + + console.log('🔍 [AAL CHECK] Session AAL level:', { aal, userId: authenticatedUserId }); // Check if user has MFA enrolled const { data: factorsData } = await supabaseAuth.auth.mfa.listFactors(); const hasMFA = factorsData?.totp?.some(f => f.status === 'verified') || false; - // Parse JWT to get AAL level - const jwt = session.access_token; - const payload = JSON.parse(atob(jwt.split('.')[1])); - const aal = payload.aal || 'aal1'; + console.log('🔍 [MFA CHECK] MFA status:', { hasMFA, userId: authenticatedUserId }); // Enforce AAL2 if MFA is enrolled if (hasMFA && aal !== 'aal2') { - console.error('AAL2 required but session is at AAL1', { userId: authenticatedUserId }); + console.error('❌ [AAL CHECK] AAL2 required but session is at AAL1', { userId: authenticatedUserId }); return new Response( JSON.stringify({ error: 'MFA verification required', @@ -178,7 +192,7 @@ serve(async (req) => { ); } - console.log('AAL2 check passed', { userId: authenticatedUserId, hasMFA, aal }); + console.log('✅ [AAL CHECK] AAL2 check passed', { userId: authenticatedUserId, hasMFA, aal }); const { itemIds, submissionId }: ApprovalRequest = await req.json();