mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-07-23 13:31:00 +02:00
fix: rate-limit visitors by real IP regardless of Cloudflare proxy hops (#750)
Since the night of 2026-07-16 production keyed the rate limiter on Cloudflare edge IPs instead of visitor IPs: every visitor routed through the same edge shared one 175-req/15min bucket, causing widespread 429s (confirmed by probing: sequential requests alternated 200/429 across fresh and exhausted buckets). Root cause: 'trust proxy' used a fixed hop count (TRUST_PROXY=1), which silently breaks whenever the proxy chain gains or loses an X-Forwarded-For entry (e.g. a Cloudflare-side change). - TRUST_PROXY now accepts a comma-separated subnet list; the new default 'loopback,uniquelocal,cloudflare' expands Cloudflare's published IP ranges so Express skips trusted proxies no matter how many entries they add. Plain numbers keep the legacy hop-count behavior. - If resolution still stops at a Cloudflare address (visitor missing from X-Forwarded-For entirely), the limiter key falls back to cf-connecting-ip — safe because request.ip can only be a Cloudflare address when the whole chain to it is trusted. - CIDR matching uses Node's built-in net.BlockList (no new dependency). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+13
-6
@@ -38,7 +38,7 @@ describe("Config environment variable parsing", function () {
|
||||
MAX_REPO_SIZE: 60000,
|
||||
ENABLE_DOWNLOAD: true,
|
||||
RATE_LIMIT: 350,
|
||||
TRUST_PROXY: 1,
|
||||
TRUST_PROXY: "loopback,uniquelocal,cloudflare",
|
||||
SESSION_SECRET: "SESSION_SECRET",
|
||||
CLIENT_ID: "CLIENT_ID",
|
||||
APP_HOSTNAME: "anonymous.4open.science",
|
||||
@@ -80,14 +80,14 @@ describe("Config environment variable parsing", function () {
|
||||
});
|
||||
|
||||
it("handles zero correctly", function () {
|
||||
const config = parseConfigFromEnv(defaults, { TRUST_PROXY: "0" });
|
||||
expect(config.TRUST_PROXY).to.equal(0);
|
||||
expect(config.TRUST_PROXY).to.be.a("number");
|
||||
const config = parseConfigFromEnv(defaults, { RATE_LIMIT: "0" });
|
||||
expect(config.RATE_LIMIT).to.equal(0);
|
||||
expect(config.RATE_LIMIT).to.be.a("number");
|
||||
});
|
||||
|
||||
it("handles negative numbers", function () {
|
||||
const config = parseConfigFromEnv(defaults, { TRUST_PROXY: "-1" });
|
||||
expect(config.TRUST_PROXY).to.equal(-1);
|
||||
const config = parseConfigFromEnv(defaults, { RATE_LIMIT: "-1" });
|
||||
expect(config.RATE_LIMIT).to.equal(-1);
|
||||
});
|
||||
|
||||
it("correctly compares parsed numbers (no string comparison bug)", function () {
|
||||
@@ -163,6 +163,13 @@ describe("Config environment variable parsing", function () {
|
||||
const config = parseConfigFromEnv(defaults, { STORAGE: "s3" });
|
||||
expect(config.STORAGE).to.equal("s3");
|
||||
});
|
||||
|
||||
it("keeps TRUST_PROXY as a string (legacy hop counts included)", function () {
|
||||
// resolveTrustProxy() interprets the string later; a numeric env value
|
||||
// like "2" must survive as-is.
|
||||
const config = parseConfigFromEnv(defaults, { TRUST_PROXY: "2" });
|
||||
expect(config.TRUST_PROXY).to.equal("2");
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user