mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 06:40:50 +00:00
Rate-limit the AI-consent endpoints per user
POST /api/consent/ai, POST /api/consent/ai/web, and GET/DELETE /api/consent/ai/latest had no rate limit, so a scripted loop or a stolen session could pin the receipts table. Add a shared per-user bucket (20/min, keyed by user id) mirroring the coach-chat ceiling, checked right after requireAuth, returning 429 with the X-RateLimit headers attached. The web heal endpoint runs on every AI-settings mount, so the bucket is generous enough to never throttle normal use.
This commit is contained in:
1 parent
6a173a89dd
commit
cc34cbd03d
7 files changed
+343
-67
No files matched your search
@@ -87,6 +87,25 @@ export async function checkAnalyticsReadRateLimit(
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* v1.16.16 — per-user ceiling for the AI-consent surfaces
|
||||
* (`POST /api/consent/ai`, `POST /api/consent/ai/web`,
|
||||
* `GET/DELETE /api/consent/ai/latest`). The web client calls the heal
|
||||
* endpoint on every AI-settings mount and the iOS toggle hits grant/revoke
|
||||
* per flip, so the bucket is generous — 20/min only caps a scripted loop or
|
||||
* a stolen session pinning the receipts table, mirroring the coach-chat
|
||||
* ceiling. One shared bucket keyed by `userId` (not per-route) keeps the cap
|
||||
* meaningful when a loop rotates across the four endpoints.
|
||||
*/
|
||||
const CONSENT_LIMIT = 20;
|
||||
const CONSENT_WINDOW_MS = 60 * 1000;
|
||||
|
||||
export async function checkConsentRateLimit(
|
||||
userId: string,
|
||||
): Promise<RateLimitResult> {
|
||||
return checkRateLimit(`consent:${userId}`, CONSENT_LIMIT, CONSENT_WINDOW_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* v1.4.43 W13 M-4 — anonymous/trust-violation bucket key shared by every
|
||||
* caller of `checkAuthSurfaceRateLimit`. When `TRUST_PROXY_HOPS` and the
|
||||
|
||||
Reference in new issue
Block a user