import { corsHeaders } from '../_shared/cors.ts'; import { rateLimiters, withRateLimit } from '../_shared/rateLimiter.ts'; import { createEdgeFunction } from '../_shared/edgeFunctionWrapper.ts'; import { validateString } from '../_shared/typeValidation.ts'; // Common disposable email domains (subset for performance) const DISPOSABLE_DOMAINS = new Set([ 'tempmail.com', 'guerrillamail.com', '10minutemail.com', 'mailinator.com', 'throwaway.email', 'temp-mail.org', 'fakeinbox.com', 'maildrop.cc', 'yopmail.com', 'sharklasers.com', 'guerrillamailblock.com' ]); interface EmailValidationResult { valid: boolean; reason?: string; suggestions?: string[]; } function validateEmailFormat(email: string): EmailValidationResult { // Basic format validation const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { return { valid: false, reason: 'Invalid email format' }; } // Extract domain const domain = email.split('@')[1].toLowerCase(); // Check against disposable domains if (DISPOSABLE_DOMAINS.has(domain)) { return { valid: false, reason: 'Disposable email addresses are not allowed. Please use a permanent email address.', suggestions: ['gmail.com', 'outlook.com', 'yahoo.com', 'protonmail.com'] }; } // Check for suspicious patterns if (domain.includes('temp') || domain.includes('disposable') || domain.includes('trash')) { return { valid: false, reason: 'This email domain appears to be temporary. Please use a permanent email address.', }; } return { valid: true }; } // Apply lenient rate limiting (30 req/min) for email validation const handler = createEdgeFunction( { name: 'validate-email-backend', requireAuth: false, corsHeaders: corsHeaders }, async (req, context) => { const { email } = await req.json(); validateString(email, 'email', { requestId: context.requestId }); context.span.setAttribute('action', 'validate_email'); // Validate email const result = validateEmailFormat(email.toLowerCase().trim()); return new Response( JSON.stringify(result), { status: 200, headers: { 'Content-Type': 'application/json' } } ); } ); export default withRateLimit(handler, rateLimiters.lenient, corsHeaders);