diff --git a/src/lib/cycle/feed/__tests__/serve.test.ts b/src/lib/cycle/feed/__tests__/serve.test.ts index 4aa12ccc8..a822043cc 100644 --- a/src/lib/cycle/feed/__tests__/serve.test.ts +++ b/src/lib/cycle/feed/__tests__/serve.test.ts @@ -145,7 +145,7 @@ describe("serveCycleFeed", () => { expect(limits.surface).toHaveBeenCalledWith( expect.anything(), "cycle-feed", - 120, + 600, 3_600_000, ); }); @@ -156,7 +156,7 @@ describe("serveCycleFeed", () => { expect(res.status).toBe(429); expect(limits.token).toHaveBeenCalledWith( `cycle-feed:${hashToken(TOKEN)}`, - 30, + 120, 3_600_000, ); expect(built.build).not.toHaveBeenCalled(); diff --git a/src/lib/cycle/feed/serve.ts b/src/lib/cycle/feed/serve.ts index 73295d05a..c953d44f5 100644 --- a/src/lib/cycle/feed/serve.ts +++ b/src/lib/cycle/feed/serve.ts @@ -56,12 +56,18 @@ import { parseFeedTokenSegment } from "./token"; /** * Per source address, across every feed. Generous because the big calendar - * providers poll from a pool of addresses that churns; the per-token bucket - * below is the one that bounds a single link. + * providers poll from a pool of addresses that churns, and a household behind + * one address may hold several links on several devices; the per-token bucket + * below is the one that bounds a single link. The token is a random secret + * checked by its HMAC, so guessing links is not what these limits stop. */ -const SURFACE_LIMIT_PER_HOUR = 120; -/** Per link. A provider polling every few minutes still fits. */ -const TOKEN_LIMIT_PER_HOUR = 30; +const SURFACE_LIMIT_PER_HOUR = 600; +/** + * Per link. One link subscribed on a phone, a tablet and a computer, each + * refreshing every five minutes, is 36 fetches an hour; 120 leaves room for + * a fourth device and for retries. + */ +const TOKEN_LIMIT_PER_HOUR = 120; const HOUR_MS = 60 * 60 * 1000; /** The longest User-Agent kept for the status read. */ diff --git a/tests/integration/cycle-calendar-feed.test.ts b/tests/integration/cycle-calendar-feed.test.ts index b615b2755..adc7bcf04 100644 --- a/tests/integration/cycle-calendar-feed.test.ts +++ b/tests/integration/cycle-calendar-feed.test.ts @@ -510,7 +510,7 @@ describe("fetching the feed", () => { it("throttles a well-formed unknown token through the anonymous limit", async () => { let throttled = false; - for (let i = 0; i < 130 && !throttled; i++) { + for (let i = 0; i < 610 && !throttled; i++) { const res = await fetchFeed(`hlf_${"1".repeat(48)}.ics`); if (res.status === 429) throttled = true; else expect(res.status).toBe(404);