feat(24-01): apply tiered rate limits to public GET endpoints
- Import createRateLimit in server index - Create browseTier (120 req/min) for list/search endpoints - Create detailTier (60 req/min) for individual resource endpoints - Apply browseTier to /api/global-items and /api/tags GET routes - Apply detailTier to /api/global-items/:id, /api/setups/:id/public, /api/users/:id/profile GET routes - Rate limits placed before auth middleware per D-07, D-08
This commit is contained in:
@@ -10,6 +10,7 @@ import { db as prodDb } from "../db/index.ts";
|
||||
import { seedDefaults } from "../db/seed.ts";
|
||||
import { mcpRoutes } from "./mcp/index.ts";
|
||||
import { requireAuth } from "./middleware/auth.ts";
|
||||
import { createRateLimit } from "./middleware/rateLimit.ts";
|
||||
import { authRoutes } from "./routes/auth.ts";
|
||||
import { categoryRoutes } from "./routes/categories.ts";
|
||||
import { globalItemRoutes } from "./routes/global-items.ts";
|
||||
@@ -117,6 +118,35 @@ app.use("/api/*", async (c, next) => {
|
||||
return next();
|
||||
});
|
||||
|
||||
// Rate limiting for public endpoints (per D-07, D-08)
|
||||
const browseTier = createRateLimit(120, 60_000);
|
||||
const detailTier = createRateLimit(60, 60_000);
|
||||
|
||||
// Browse endpoints — higher limit for list/search
|
||||
app.use("/api/global-items", async (c, next) => {
|
||||
if (c.req.method === "GET" && !c.req.path.match(/^\/api\/global-items\/\d+$/))
|
||||
return browseTier(c, next);
|
||||
return next();
|
||||
});
|
||||
app.use("/api/tags", async (c, next) => {
|
||||
if (c.req.method === "GET") return browseTier(c, next);
|
||||
return next();
|
||||
});
|
||||
|
||||
// Detail endpoints — moderate limit for individual resources
|
||||
app.use("/api/global-items/:id", async (c, next) => {
|
||||
if (c.req.method === "GET") return detailTier(c, next);
|
||||
return next();
|
||||
});
|
||||
app.use("/api/setups/:id/public", async (c, next) => {
|
||||
if (c.req.method === "GET") return detailTier(c, next);
|
||||
return next();
|
||||
});
|
||||
app.use("/api/users/:id/profile", async (c, next) => {
|
||||
if (c.req.method === "GET") return detailTier(c, next);
|
||||
return next();
|
||||
});
|
||||
|
||||
// Auth middleware for all data routes (userId must be available for per-user scoping)
|
||||
app.use("/api/*", async (c, next) => {
|
||||
// Skip auth routes — they handle their own auth
|
||||
|
||||
Reference in New Issue
Block a user