/** * Error sanitization utility to prevent information disclosure * Prevents exposing database schema, RLS policies, and internal implementation details */ interface SanitizedError { error: string; code?: string; } const ERROR_PATTERNS: Record = { 'duplicate key': 'A record with this information already exists', 'foreign key': 'Invalid reference to related data', 'violates check': 'The provided data does not meet requirements', 'not-null': 'Required field is missing', 'violates row-level security': 'Access denied', 'permission denied': 'Access denied', 'authentication': 'Authentication failed', 'jwt': 'Authentication failed', 'unique constraint': 'This value is already in use', 'invalid input syntax': 'Invalid data format', 'value too long': 'Value exceeds maximum length', 'numeric field overflow': 'Number value is too large', }; /** * Sanitizes error messages to prevent information disclosure * Logs full error server-side for debugging */ export function sanitizeError(error: unknown, context?: string): SanitizedError { // Note: Error logging handled by edge function logger // Context and error are passed to edgeLogger.error() by caller // Handle non-Error objects if (!error || typeof error !== 'object') { return { error: 'An unexpected error occurred. Please try again.', code: 'UNKNOWN_ERROR' }; } const errorMessage = (error as Error).message || ''; const errorMessageLower = errorMessage.toLowerCase(); // Check for known patterns for (const [pattern, safeMessage] of Object.entries(ERROR_PATTERNS)) { if (errorMessageLower.includes(pattern.toLowerCase())) { return { error: safeMessage, code: pattern.toUpperCase().replace(/\s+/g, '_') }; } } // Rate limiting errors if (errorMessageLower.includes('rate limit') || errorMessageLower.includes('too many')) { return { error: 'Too many requests. Please try again later.', code: 'RATE_LIMITED' }; } // Network/timeout errors if (errorMessageLower.includes('timeout') || errorMessageLower.includes('network')) { return { error: 'Connection error. Please check your internet connection and try again.', code: 'NETWORK_ERROR' }; } // Default safe error return { error: 'An error occurred while processing your request. Please try again or contact support if the problem persists.', code: 'INTERNAL_ERROR' }; } /** * Creates a sanitized error response for edge functions */ export function createErrorResponse( error: unknown, status: number = 500, corsHeaders: Record = {}, context?: string ): Response { const sanitized = sanitizeError(error, context); return new Response( JSON.stringify(sanitized), { status, headers: { ...corsHeaders, 'Content-Type': 'application/json' } } ); }