main
tag: launch-2026-06-01
tag: magicmirror-v0.1.1
tag: magicmirror-v0.3.0
tag: mnw-cli-v0.1.2
tag: mnw-cli-v0.1.3
tag: mnw-cli-v0.1.4
tag: pom-v0.4.1
tag: pom-v0.4.2
tag: pom-v0.4.3
tag: pom-v0.4.4
tag: pom-v0.4.5
tag: wam-v0.3.0
tag: wam-v0.3.1
Files
Commits
Tags
Notes
Issues
server: attach per-IP rate limit to guest download route
download_routes now attaches a lenient GovernorLayer (GUEST_DOWNLOAD_RATE_LIMIT_PER_SEC=2 / _BURST=60, >0 compile assert); the misleading 'more lenient rate limit' comment that claimed a layer that wasn't wired is replaced with an accurate one.
Co-Authored-By
Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2 files changed,
+18 insertions,
-2 deletions
157
157
// Guest checkout (public, no auth): burst 10, then 1/sec
158
158
pub const GUEST_CHECKOUT_RATE_LIMIT_PER_SEC: u64 = 1;
159
159
pub const GUEST_CHECKOUT_RATE_LIMIT_BURST: u32 = 10;
160
+
// Guest download (public, no auth, token-gated): deliberately lenient — a buyer
161
+
// may pull several files in a row — but still a per-IP ceiling so the endpoint
162
+
// can't be hammered anonymously. Burst 60, then 2/sec.
163
+
pub const GUEST_DOWNLOAD_RATE_LIMIT_PER_SEC: u64 = 2;
164
+
pub const GUEST_DOWNLOAD_RATE_LIMIT_BURST: u32 = 60;
160
165
// License key validation (public): burst 20, then 5/sec
161
166
pub const LICENSE_KEY_RATE_LIMIT_MS: u64 = 200;
162
167
pub const LICENSE_KEY_RATE_LIMIT_BURST: u32 = 20;
464
469
const _: () = assert!(UPLOAD_RATE_LIMIT_BURST > 0);
465
470
const _: () = assert!(OAUTH_RATE_LIMIT_BURST > 0);
466
471
const _: () = assert!(OAUTH_TOKEN_RATE_LIMIT_BURST > 0);
472
+
const _: () = assert!(GUEST_CHECKOUT_RATE_LIMIT_BURST > 0);
473
+
const _: () = assert!(GUEST_DOWNLOAD_RATE_LIMIT_BURST > 0);
467
474
468
475
// Rate-limit burst ordering: read > write > auth
469
476
const _: () = assert!(API_READ_RATE_LIMIT_BURST > API_WRITE_RATE_LIMIT_BURST);
479
479
config: guest_checkout_rate_limit,
480
480
});
481
481
482
-
// Guest download route — separate, more lenient rate limit
482
+
// Guest download route — separate, more lenient per-IP rate limit. Unauth'd
483
+
// and token-gated; the throttle is defense-in-depth against anonymous flooding
484
+
// (token entropy already makes enumeration impractical).
485
+
let download_rate_limit = crate::helpers::rate_limiter_per_sec(
486
+
constants::GUEST_DOWNLOAD_RATE_LIMIT_PER_SEC,
487
+
constants::GUEST_DOWNLOAD_RATE_LIMIT_BURST,
488
+
);
483
489
let download_routes = CsrfRouter::new()
484
-
.route_get("/download/{token}", get(guest_checkout::guest_download));
490
+
.route_get("/download/{token}", get(guest_checkout::guest_download))
491
+
.route_layer(GovernorLayer {
492
+
config: download_rate_limit,
493
+
});
485
494
486
495
write_routes
487
496
.merge(totp_sensitive_routes)