Skip to main content

max / makenotwork

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>
Author: Max Johnson <me@maxj.phd> · 2026-07-05 15:49 UTC
Commit: c70d53985a06f9c9dbeca5a0acc6d40624e5952f
Parent: 94ac0bd
2 files changed, +18 insertions, -2 deletions
@@ -157,6 +157,11 @@ pub const API_EXPORT_RATE_LIMIT_BURST: u32 = 3;
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,6 +469,8 @@ const _: () = assert!(LICENSE_KEY_RATE_LIMIT_BURST > 0);
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,9 +479,18 @@ pub fn api_routes() -> CsrfRouter<AppState> {
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)