Files
thrilltrack-explorer/supabase/functions/validate-email/index.ts
gpt-engineer-app[bot] 2d65f13b85 Connect to Lovable Cloud
Add centralized errorFormatter to convert various error types into readable messages, and apply it across edge functions. Replace String(error) usage with formatEdgeError, update relevant imports, fix a throw to use toError, and enhance logger to log formatted errors. Includes new errorFormatter.ts and widespread updates to 18+ edge functions plus logger integration.
2025-11-10 18:09:15 +00:00

211 lines
6.7 KiB
TypeScript

import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
import { startRequest, endRequest, edgeLogger } from "../_shared/logger.ts";
import { formatEdgeError } from "../_shared/errorFormatter.ts";
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type, x-request-id',
};
// Comprehensive list of disposable email domains
const DISPOSABLE_DOMAINS = new Set([
// Popular disposable email services
'tempmail.com', 'temp-mail.org', 'temp-mail.io', 'temp-mail.de',
'10minutemail.com', '10minutemail.net', '10minemail.com',
'guerrillamail.com', 'guerrillamail.net', 'guerrillamailblock.com',
'mailinator.com', 'mailinator.net', 'mailinator2.com',
'throwaway.email', 'throwemail.com', 'throwawaymail.com',
'yopmail.com', 'yopmail.fr', 'yopmail.net',
'maildrop.cc', 'mailnesia.com', 'trashmail.com',
'fakeinbox.com', 'fakemail.net', 'fakemailgenerator.com',
'getnada.com', 'getairmail.com', 'dispostable.com',
'mintemail.com', 'mytemp.email', 'mohmal.com',
'sharklasers.com', 'grr.la', 'guerrillamail.biz',
'spam4.me', 'tempinbox.com', 'tempr.email',
'emailondeck.com', 'mailcatch.com', 'mailexpire.com',
'mailforspam.com', 'mailfreeonline.com', 'mailin8r.com',
'mailmoat.com', 'mailnull.com', 'mailsac.com',
'mailscrap.com', 'mailslite.com', 'mailtemp.info',
'mailtothis.com', 'mailzi.ru', 'mytrashmail.com',
'no-spam.ws', 'noclickemail.com', 'nodezine.com',
'nospam.ze.tc', 'nospamfor.us', 'nowmymail.com',
'objectmail.com', 'obobbo.com', 'oneoffemail.com',
'onewaymail.com', 'online.ms', 'oopi.org',
'ordinaryamerican.net', 'otherinbox.com', 'owlpic.com',
'pancakemail.com', 'pjjkp.com', 'plexolan.de',
'poofy.org', 'pookmail.com', 'privacy.net',
'proxymail.eu', 'prtnx.com', 'putthisinyourspamdatabase.com',
'quickinbox.com', 'rcpt.at', 'recode.me',
'recursor.net', 'regbypass.com', 'regspaces.tk',
'rklips.com', 'rmqkr.net', 'robertspcrepair.com',
'royal.net', 'ruffrey.com', 's0ny.net',
'safersignup.de', 'safetymail.info', 'safetypost.de',
'sandelf.de', 'saynotospams.com', 'schafmail.de',
'schrott-email.de', 'secretemail.de', 'secure-mail.biz',
'senseless-entertainment.com', 'services391.com', 'sharklasers.com',
'shiftmail.com', 'shippingterms.org', 'showslow.de',
'sibmail.com', 'sinnlos-mail.de', 'slapsfromlastnight.com',
'slaskpost.se', 'smashmail.de', 'smellfear.com',
'snakemail.com', 'sneakemail.com', 'sneakmail.de',
'snkmail.com', 'sofimail.com', 'solvemail.info',
'sogetthis.com', 'soodonims.com', 'spam.la',
'spam.su', 'spamail.de', 'spamarrest.com',
'spambob.com', 'spambog.com', 'spambog.de',
'spambox.us', 'spamcannon.com', 'spamcannon.net',
'spamcero.com', 'spamcon.org', 'spamcorptastic.com',
'spamcowboy.com', 'spamcowboy.net', 'spamcowboy.org',
'spamday.com', 'spamex.com', 'spamfree24.com',
'spamfree24.de', 'spamfree24.org', 'spamgourmet.com',
'spamherelots.com', 'spamhereplease.com', 'spamhole.com',
'spamify.com', 'spaminator.de', 'spamkill.info',
]);
interface ValidateEmailRequest {
email: string;
}
interface ValidationResult {
valid: boolean;
reason?: string;
suggestions?: string[];
}
const handler = async (req: Request): Promise<Response> => {
// Handle CORS preflight requests
if (req.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
const tracking = startRequest('validate-email');
try {
const { email }: ValidateEmailRequest = await req.json();
if (!email || typeof email !== 'string') {
endRequest(tracking, 400, 'Email address is required');
return new Response(
JSON.stringify({
valid: false,
reason: 'Email address is required',
requestId: tracking.requestId
} as ValidationResult),
{
status: 400,
headers: {
...corsHeaders,
'Content-Type': 'application/json',
'X-Request-ID': tracking.requestId
}
}
);
}
// Basic email format validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
endRequest(tracking, 400, 'Invalid email format');
return new Response(
JSON.stringify({
valid: false,
reason: 'Invalid email format',
requestId: tracking.requestId
} as ValidationResult),
{
status: 400,
headers: {
...corsHeaders,
'Content-Type': 'application/json',
'X-Request-ID': tracking.requestId
}
}
);
}
// Extract domain
const domain = email.split('@')[1].toLowerCase();
// Check if domain is disposable
if (DISPOSABLE_DOMAINS.has(domain)) {
edgeLogger.info('Blocked disposable email domain', {
domain,
requestId: tracking.requestId
});
endRequest(tracking, 400, 'Disposable email domain blocked');
return new Response(
JSON.stringify({
valid: false,
reason: 'Disposable email addresses are not allowed. Please use a permanent email address.',
suggestions: [
'Use a personal email (Gmail, Outlook, Yahoo, etc.)',
'Use your work or school email address',
'Use an email from your own domain'
],
requestId: tracking.requestId
} as ValidationResult),
{
status: 400,
headers: {
...corsHeaders,
'Content-Type': 'application/json',
'X-Request-ID': tracking.requestId
}
}
);
}
// Email is valid
edgeLogger.info('Email validated successfully', {
email,
requestId: tracking.requestId
});
endRequest(tracking, 200);
return new Response(
JSON.stringify({
valid: true,
requestId: tracking.requestId
} as ValidationResult),
{
status: 200,
headers: {
...corsHeaders,
'Content-Type': 'application/json',
'X-Request-ID': tracking.requestId
}
}
);
} catch (error) {
const errorMessage = formatEdgeError(error);
edgeLogger.error('Error in validate-email function', {
error: errorMessage,
requestId: tracking.requestId
});
endRequest(tracking, 500, error.message);
return new Response(
JSON.stringify({
valid: false,
reason: 'Internal server error during email validation',
requestId: tracking.requestId
} as ValidationResult),
{
status: 500,
headers: {
...corsHeaders,
'Content-Type': 'application/json',
'X-Request-ID': tracking.requestId
}
}
);
}
};
serve(handler);