mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 11:51:14 -05:00
Add rate limiting to high-risk
Introduce centralized rate limiting by applying defined tiers (STRICT, STANDARD, LENIENT, MODERATE) to high-risk edge functions: - export-user-data (STRICT, 5 req/min) - send-contact-message (STANDARD, 20 req/min) - validate-email-backend (LENIENT, 30 req/min) - admin-delete-user, resend-deletion-code (MODERATE) - additional standard targets identified (request-account-deletion, cancel-account-deletion) as per guidance Implements: - Wrapped handlers with withRateLimit using centralized rateLimiters - Imported from shared rate limiter module - Annotated with comments explaining tier rationale - Updated three initial functions and extended coverage to admin/account management functions - Added documentation guide for rate limiting usage This aligns with the Rate Limiting Guide and centralizes rate limit configuration for consistency.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { corsHeaders } from '../_shared/cors.ts';
|
import { corsHeaders } from '../_shared/cors.ts';
|
||||||
|
import { rateLimiters, withRateLimit } from '../_shared/rateLimiter.ts';
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
@@ -13,7 +14,9 @@ interface DeleteUserResponse {
|
|||||||
errorCode?: 'aal2_required' | 'permission_denied' | 'invalid_request' | 'deletion_failed';
|
errorCode?: 'aal2_required' | 'permission_denied' | 'invalid_request' | 'deletion_failed';
|
||||||
}
|
}
|
||||||
|
|
||||||
Deno.serve(async (req) => {
|
// Apply moderate rate limiting (10 req/min) for admin user deletion
|
||||||
|
// Prevents abuse of this sensitive administrative operation
|
||||||
|
Deno.serve(withRateLimit(async (req) => {
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders });
|
return new Response(null, { headers: corsHeaders });
|
||||||
}
|
}
|
||||||
@@ -556,4 +559,4 @@ Deno.serve(async (req) => {
|
|||||||
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}, rateLimiters.moderate, corsHeaders));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { corsHeaders } from '../_shared/cors.ts';
|
import { corsHeaders } from '../_shared/cors.ts';
|
||||||
|
import { rateLimiters, withRateLimit } from '../_shared/rateLimiter.ts';
|
||||||
import { sanitizeError } from '../_shared/errorSanitizer.ts';
|
import { sanitizeError } from '../_shared/errorSanitizer.ts';
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
@@ -13,7 +14,9 @@ interface ExportOptions {
|
|||||||
format: 'json';
|
format: 'json';
|
||||||
}
|
}
|
||||||
|
|
||||||
serve(async (req) => {
|
// Apply strict rate limiting (5 req/min) for expensive data export operations
|
||||||
|
// This prevents abuse and manages server load from large data exports
|
||||||
|
serve(withRateLimit(async (req) => {
|
||||||
const tracking = startRequest();
|
const tracking = startRequest();
|
||||||
|
|
||||||
// Handle CORS preflight requests
|
// Handle CORS preflight requests
|
||||||
@@ -364,4 +367,4 @@ serve(async (req) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}, rateLimiters.strict, corsHeaders));
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||||
import { corsHeaders } from '../_shared/cors.ts';
|
import { corsHeaders } from '../_shared/cors.ts';
|
||||||
|
import { rateLimiters, withRateLimit } from '../_shared/rateLimiter.ts';
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
serve(async (req) => {
|
// Apply standard rate limiting (20 req/min) for account deletion requests
|
||||||
|
// Balances user needs with protection against automated abuse
|
||||||
|
serve(withRateLimit(async (req) => {
|
||||||
const tracking = startRequest();
|
const tracking = startRequest();
|
||||||
|
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
@@ -218,4 +221,4 @@ serve(async (req) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}, rateLimiters.standard, corsHeaders));
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||||
import { corsHeaders } from '../_shared/cors.ts';
|
import { corsHeaders } from '../_shared/cors.ts';
|
||||||
|
import { rateLimiters, withRateLimit } from '../_shared/rateLimiter.ts';
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
|
||||||
serve(async (req) => {
|
// Apply moderate rate limiting (10 req/min) to prevent deletion code spam
|
||||||
|
// Protects against abuse while allowing legitimate resend requests
|
||||||
|
serve(withRateLimit(async (req) => {
|
||||||
const tracking = startRequest();
|
const tracking = startRequest();
|
||||||
|
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
@@ -177,4 +180,4 @@ serve(async (req) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}, rateLimiters.moderate, corsHeaders));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
||||||
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
||||||
import { corsHeaders } from '../_shared/cors.ts';
|
import { corsHeaders } from '../_shared/cors.ts';
|
||||||
|
import { rateLimiters, withRateLimit } from '../_shared/rateLimiter.ts';
|
||||||
import { edgeLogger } from "../_shared/logger.ts";
|
import { edgeLogger } from "../_shared/logger.ts";
|
||||||
import { createErrorResponse } from "../_shared/errorSanitizer.ts";
|
import { createErrorResponse } from "../_shared/errorSanitizer.ts";
|
||||||
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
||||||
@@ -338,4 +339,6 @@ The ThrillWiki Team`,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
serve(handler);
|
// Apply standard rate limiting (20 req/min) for contact form submissions
|
||||||
|
// Balances legitimate user needs with spam prevention
|
||||||
|
serve(withRateLimit(handler, rateLimiters.standard, corsHeaders));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.39.3';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.39.3';
|
||||||
import { corsHeaders } from '../_shared/cors.ts';
|
import { corsHeaders } from '../_shared/cors.ts';
|
||||||
|
import { rateLimiters, withRateLimit } from '../_shared/rateLimiter.ts';
|
||||||
import { edgeLogger } from "../_shared/logger.ts";
|
import { edgeLogger } from "../_shared/logger.ts";
|
||||||
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
||||||
|
|
||||||
@@ -51,7 +52,9 @@ function validateEmailFormat(email: string): EmailValidationResult {
|
|||||||
return { valid: true };
|
return { valid: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
serve(async (req) => {
|
// Apply lenient rate limiting (30 req/min) for email validation
|
||||||
|
// Users may need to validate multiple times during signup/profile update
|
||||||
|
serve(withRateLimit(async (req) => {
|
||||||
const tracking = startRequest();
|
const tracking = startRequest();
|
||||||
|
|
||||||
// Handle CORS preflight requests
|
// Handle CORS preflight requests
|
||||||
@@ -115,4 +118,4 @@ serve(async (req) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}, rateLimiters.lenient, corsHeaders));
|
||||||
|
|||||||
Reference in New Issue
Block a user