/** * AAL2 Error Detection Utilities * * Detects when operations fail due to AAL2/MFA requirements * and provides user-friendly error messages */ import { PostgrestError } from '@supabase/supabase-js'; /** * Check if an error is due to AAL2/RLS policy failure */ export function isAAL2PolicyError(error: unknown): boolean { if (!error) return false; // Handle Supabase PostgrestError if (isPostgrestError(error)) { const code = error.code; const message = error.message?.toLowerCase() || ''; const details = error.details?.toLowerCase() || ''; // Check for RLS policy violations if (code === 'PGRST301' || code === '42501') { return true; } // Check for permission denied messages if ( message.includes('permission denied') || message.includes('row-level security') || message.includes('policy') || details.includes('policy') ) { return true; } } // Handle generic errors with 403 status if (hasStatusCode(error) && error.status === 403) { return true; } // Handle error messages if (error instanceof Error) { const message = error.message.toLowerCase(); return ( message.includes('row-level security') || message.includes('permission denied') || message.includes('policy') || message.includes('403') ); } return false; } /** * Get user-friendly error message for AAL2 errors */ export function getAAL2ErrorMessage(error: unknown): string { // Default message const defaultMessage = 'This action requires additional security verification'; if (!error) return defaultMessage; // Check if error mentions specific operations if (error instanceof Error) { const message = error.message.toLowerCase(); if (message.includes('delete') || message.includes('remove')) { return 'Deleting this data requires additional security verification'; } if (message.includes('update') || message.includes('modify')) { return 'Modifying this data requires additional security verification'; } if (message.includes('insert') || message.includes('create')) { return 'Creating this data requires additional security verification'; } } return defaultMessage; } /** * Type guard for PostgrestError */ function isPostgrestError(error: unknown): error is PostgrestError { return ( typeof error === 'object' && error !== null && 'code' in error && 'message' in error ); } /** * Type guard for errors with status code */ function hasStatusCode(error: unknown): error is { status: number } { return ( typeof error === 'object' && error !== null && 'status' in error && typeof (error as any).status === 'number' ); } /** * Create a user-cancellation error */ export class MFACancelledError extends Error { constructor() { super('MFA verification was cancelled by user'); this.name = 'MFACancelledError'; } } /** * Check if error is a user cancellation */ export function isMFACancelledError(error: unknown): boolean { return error instanceof MFACancelledError; }