max / makenotwork
- Co-Authored-By
- Claude Opus 4.8 (1M context) <noreply@anthropic.com>
16 files changed,
+140 insertions,
-135 deletions
| @@ -1214,15 +1214,16 @@ | |||
| 1214 | 1214 | ||
| 1215 | 1215 | [[package]] | |
| 1216 | 1216 | name = "axum-extra" | |
| 1217 | - | version = "0.10.3" | |
| 1217 | + | version = "0.12.6" | |
| 1218 | 1218 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1219 | - | checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" | |
| 1219 | + | checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970" | |
| 1220 | 1220 | dependencies = [ | |
| 1221 | 1221 | "axum", | |
| 1222 | 1222 | "axum-core", | |
| 1223 | 1223 | "bytes", | |
| 1224 | 1224 | "cookie", | |
| 1225 | 1225 | "form_urlencoded", | |
| 1226 | + | "futures-core", | |
| 1226 | 1227 | "futures-util", | |
| 1227 | 1228 | "headers", | |
| 1228 | 1229 | "http 1.4.2", | |
| @@ -1230,7 +1231,6 @@ | |||
| 1230 | 1231 | "http-body-util", | |
| 1231 | 1232 | "mime", | |
| 1232 | 1233 | "pin-project-lite", | |
| 1233 | - | "rustversion", | |
| 1234 | 1234 | "serde_core", | |
| 1235 | 1235 | "serde_html_form", | |
| 1236 | 1236 | "serde_path_to_error", | |
| @@ -3233,9 +3233,9 @@ | |||
| 3233 | 3233 | ||
| 3234 | 3234 | [[package]] | |
| 3235 | 3235 | name = "governor" | |
| 3236 | - | version = "0.8.1" | |
| 3236 | + | version = "0.10.4" | |
| 3237 | 3237 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3238 | - | checksum = "be93b4ec2e4710b04d9264c0c7350cdd62a8c20e5e4ac732552ebb8f0debe8eb" | |
| 3238 | + | checksum = "9efcab3c1958580ff1f25a2a41be1668f7603d849bb63af523b208a3cc1223b8" | |
| 3239 | 3239 | dependencies = [ | |
| 3240 | 3240 | "cfg-if", | |
| 3241 | 3241 | "dashmap", | |
| @@ -3243,7 +3243,7 @@ | |||
| 3243 | 3243 | "futures-timer", | |
| 3244 | 3244 | "futures-util", | |
| 3245 | 3245 | "getrandom 0.3.4", | |
| 3246 | - | "no-std-compat", | |
| 3246 | + | "hashbrown 0.16.1", | |
| 3247 | 3247 | "nonzero_ext", | |
| 3248 | 3248 | "parking_lot", | |
| 3249 | 3249 | "portable-atomic", | |
| @@ -3558,6 +3558,19 @@ | |||
| 3558 | 3558 | "webpki-roots", | |
| 3559 | 3559 | ] | |
| 3560 | 3560 | ||
| 3561 | + | [[package]] | |
| 3562 | + | name = "hyper-timeout" | |
| 3563 | + | version = "0.5.2" | |
| 3564 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3565 | + | checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" | |
| 3566 | + | dependencies = [ | |
| 3567 | + | "hyper", | |
| 3568 | + | "hyper-util", | |
| 3569 | + | "pin-project-lite", | |
| 3570 | + | "tokio", | |
| 3571 | + | "tower-service", | |
| 3572 | + | ] | |
| 3573 | + | ||
| 3561 | 3574 | [[package]] | |
| 3562 | 3575 | name = "hyper-tls" | |
| 3563 | 3576 | version = "0.6.0" | |
| @@ -4368,7 +4381,7 @@ | |||
| 4368 | 4381 | "toml 1.1.3+spec-1.1.0", | |
| 4369 | 4382 | "totp-rs", | |
| 4370 | 4383 | "tower", | |
| 4371 | - | "tower-http", | |
| 4384 | + | "tower-http 0.7.0", | |
| 4372 | 4385 | "tower-sessions", | |
| 4373 | 4386 | "tower-sessions-sqlx-store", | |
| 4374 | 4387 | "tower_governor", | |
| @@ -4647,12 +4660,6 @@ | |||
| 4647 | 4660 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 4648 | 4661 | checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" | |
| 4649 | 4662 | ||
| 4650 | - | [[package]] | |
| 4651 | - | name = "no-std-compat" | |
| 4652 | - | version = "0.4.1" | |
| 4653 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 4654 | - | checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" | |
| 4655 | - | ||
| 4656 | 4663 | [[package]] | |
| 4657 | 4664 | name = "nom" | |
| 4658 | 4665 | version = "7.1.3" | |
| @@ -5967,7 +5974,7 @@ | |||
| 5967 | 5974 | "tokio", | |
| 5968 | 5975 | "tokio-rustls", | |
| 5969 | 5976 | "tower", | |
| 5970 | - | "tower-http", | |
| 5977 | + | "tower-http 0.6.11", | |
| 5971 | 5978 | "tower-service", | |
| 5972 | 5979 | "url", | |
| 5973 | 5980 | "wasm-bindgen", | |
| @@ -6011,7 +6018,7 @@ | |||
| 6011 | 6018 | "tokio", | |
| 6012 | 6019 | "tokio-rustls", | |
| 6013 | 6020 | "tower", | |
| 6014 | - | "tower-http", | |
| 6021 | + | "tower-http 0.6.11", | |
| 6015 | 6022 | "tower-service", | |
| 6016 | 6023 | "url", | |
| 6017 | 6024 | "wasm-bindgen", | |
| @@ -7555,6 +7562,35 @@ | |||
| 7555 | 7562 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 7556 | 7563 | checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" | |
| 7557 | 7564 | ||
| 7565 | + | [[package]] | |
| 7566 | + | name = "tonic" | |
| 7567 | + | version = "0.14.6" | |
| 7568 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 7569 | + | checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" | |
| 7570 | + | dependencies = [ | |
| 7571 | + | "async-trait", | |
| 7572 | + | "axum", | |
| 7573 | + | "base64 0.22.1", | |
| 7574 | + | "bytes", | |
| 7575 | + | "h2", | |
| 7576 | + | "http 1.4.2", | |
| 7577 | + | "http-body 1.0.1", | |
| 7578 | + | "http-body-util", | |
| 7579 | + | "hyper", | |
| 7580 | + | "hyper-timeout", | |
| 7581 | + | "hyper-util", | |
| 7582 | + | "percent-encoding", | |
| 7583 | + | "pin-project", | |
| 7584 | + | "socket2", | |
| 7585 | + | "sync_wrapper", | |
| 7586 | + | "tokio", | |
| 7587 | + | "tokio-stream", | |
| 7588 | + | "tower", | |
| 7589 | + | "tower-layer", | |
| 7590 | + | "tower-service", | |
| 7591 | + | "tracing", | |
| 7592 | + | ] | |
| 7593 | + | ||
| 7558 | 7594 | [[package]] | |
| 7559 | 7595 | name = "totp-rs" | |
| 7560 | 7596 | version = "5.7.2" | |
| @@ -7579,9 +7615,12 @@ | |||
| 7579 | 7615 | dependencies = [ | |
| 7580 | 7616 | "futures-core", | |
| 7581 | 7617 | "futures-util", | |
| 7618 | + | "indexmap", | |
| 7582 | 7619 | "pin-project-lite", | |
| 7620 | + | "slab", | |
| 7583 | 7621 | "sync_wrapper", | |
| 7584 | 7622 | "tokio", | |
| 7623 | + | "tokio-util", | |
| 7585 | 7624 | "tower-layer", | |
| 7586 | 7625 | "tower-service", | |
| 7587 | 7626 | "tracing", | |
| @@ -7608,6 +7647,24 @@ | |||
| 7608 | 7647 | version = "0.6.11" | |
| 7609 | 7648 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 7610 | 7649 | checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" | |
| 7650 | + | dependencies = [ | |
| 7651 | + | "bitflags 2.13.0", | |
| 7652 | + | "bytes", | |
| 7653 | + | "futures-util", | |
| 7654 | + | "http 1.4.2", | |
| 7655 | + | "http-body 1.0.1", | |
| 7656 | + | "pin-project-lite", | |
| 7657 | + | "tower", | |
| 7658 | + | "tower-layer", | |
| 7659 | + | "tower-service", | |
| 7660 | + | "url", | |
| 7661 | + | ] | |
| 7662 | + | ||
| 7663 | + | [[package]] | |
| 7664 | + | name = "tower-http" | |
| 7665 | + | version = "0.7.0" | |
| 7666 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 7667 | + | checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233" | |
| 7611 | 7668 | dependencies = [ | |
| 7612 | 7669 | "bitflags 2.13.0", | |
| 7613 | 7670 | "bytes", | |
| @@ -7624,11 +7681,9 @@ | |||
| 7624 | 7681 | "pin-project-lite", | |
| 7625 | 7682 | "tokio", | |
| 7626 | 7683 | "tokio-util", | |
| 7627 | - | "tower", | |
| 7628 | 7684 | "tower-layer", | |
| 7629 | 7685 | "tower-service", | |
| 7630 | 7686 | "tracing", | |
| 7631 | - | "url", | |
| 7632 | 7687 | "uuid", | |
| 7633 | 7688 | ] | |
| 7634 | 7689 | ||
| @@ -7711,9 +7766,9 @@ | |||
| 7711 | 7766 | ||
| 7712 | 7767 | [[package]] | |
| 7713 | 7768 | name = "tower_governor" | |
| 7714 | - | version = "0.6.0" | |
| 7769 | + | version = "0.8.0" | |
| 7715 | 7770 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 7716 | - | checksum = "57a2ccff6830fa835371af7541e561a90e4c07b84f72991ebac4b3cb6790dc0d" | |
| 7771 | + | checksum = "44de9b94d849d3c46e06a883d72d408c2de6403367b39df2b1c9d9e7b6736fe6" | |
| 7717 | 7772 | dependencies = [ | |
| 7718 | 7773 | "axum", | |
| 7719 | 7774 | "forwarded-header-value", | |
| @@ -7721,6 +7776,7 @@ | |||
| 7721 | 7776 | "http 1.4.2", | |
| 7722 | 7777 | "pin-project", | |
| 7723 | 7778 | "thiserror 2.0.18", | |
| 7779 | + | "tonic", | |
| 7724 | 7780 | "tower", | |
| 7725 | 7781 | "tracing", | |
| 7726 | 7782 | ] |
| @@ -16,7 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | 17 | # Web framework | |
| 18 | 18 | axum = { version = "0.8.8", features = ["macros"] } | |
| 19 | - | axum-extra = { version = "0.10.3", features = ["cookie", "form", "query", "typed-header"] } | |
| 19 | + | axum-extra = { version = "0.12.6", features = ["cookie", "form", "query", "typed-header"] } | |
| 20 | 20 | ||
| 21 | 21 | # OpenAPI spec generation | |
| 22 | 22 | utoipa = { version = "5", features = ["axum_extras", "chrono", "uuid"] } | |
| @@ -29,7 +29,7 @@ | |||
| 29 | 29 | tokio-stream = { version = "0.1", features = ["sync"] } | |
| 30 | 30 | tokio-util = { version = "0.7", features = ["io"] } | |
| 31 | 31 | tower = "0.5.3" | |
| 32 | - | tower-http = { version = "0.6.8", features = ["trace", "fs", "limit", "request-id", "propagate-header", "set-header"] } | |
| 32 | + | tower-http = { version = "0.7.0", features = ["trace", "fs", "limit", "request-id", "propagate-header", "set-header"] } | |
| 33 | 33 | tracing = "0.1.44" | |
| 34 | 34 | tracing-subscriber = { version = "0.3.22", features = ["env-filter", "json"] } | |
| 35 | 35 | ||
| @@ -53,8 +53,8 @@ | |||
| 53 | 53 | dashmap = "6" | |
| 54 | 54 | ||
| 55 | 55 | # Rate Limiting | |
| 56 | - | tower_governor = "0.6.0" | |
| 57 | - | governor = "0.8.1" | |
| 56 | + | tower_governor = "0.8.0" | |
| 57 | + | governor = "0.10.4" | |
| 58 | 58 | ||
| 59 | 59 | # JWT (SyncKit) | |
| 60 | 60 | jsonwebtoken = "9.3.1" |
| @@ -681,7 +681,7 @@ | |||
| 681 | 681 | "tokio", | |
| 682 | 682 | "tokio-stream", | |
| 683 | 683 | "tower", | |
| 684 | - | "tower-http", | |
| 684 | + | "tower-http 0.7.0", | |
| 685 | 685 | "tracing", | |
| 686 | 686 | "tracing-subscriber", | |
| 687 | 687 | "uuid", | |
| @@ -959,7 +959,7 @@ | |||
| 959 | 959 | "tokio", | |
| 960 | 960 | "tokio-rustls", | |
| 961 | 961 | "tower", | |
| 962 | - | "tower-http", | |
| 962 | + | "tower-http 0.6.11", | |
| 963 | 963 | "tower-service", | |
| 964 | 964 | "url", | |
| 965 | 965 | "wasm-bindgen", | |
| @@ -1459,10 +1459,26 @@ | |||
| 1459 | 1459 | "tower", | |
| 1460 | 1460 | "tower-layer", | |
| 1461 | 1461 | "tower-service", | |
| 1462 | - | "tracing", | |
| 1463 | 1462 | "url", | |
| 1464 | 1463 | ] | |
| 1465 | 1464 | ||
| 1465 | + | [[package]] | |
| 1466 | + | name = "tower-http" | |
| 1467 | + | version = "0.7.0" | |
| 1468 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1469 | + | checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233" | |
| 1470 | + | dependencies = [ | |
| 1471 | + | "bitflags", | |
| 1472 | + | "bytes", | |
| 1473 | + | "http", | |
| 1474 | + | "http-body", | |
| 1475 | + | "percent-encoding", | |
| 1476 | + | "pin-project-lite", | |
| 1477 | + | "tower-layer", | |
| 1478 | + | "tower-service", | |
| 1479 | + | "tracing", | |
| 1480 | + | ] | |
| 1481 | + | ||
| 1466 | 1482 | [[package]] | |
| 1467 | 1483 | name = "tower-layer" | |
| 1468 | 1484 | version = "0.3.3" |
| @@ -23,7 +23,7 @@ | |||
| 23 | 23 | ||
| 24 | 24 | axum = { version = "0.8", optional = true } | |
| 25 | 25 | tower = { version = "0.5", optional = true } | |
| 26 | - | tower-http = { version = "0.6", optional = true, features = ["trace"] } | |
| 26 | + | tower-http = { version = "0.7", optional = true, features = ["trace"] } | |
| 27 | 27 | ||
| 28 | 28 | reqwest = { version = "0.13", optional = true, features = ["json"] } | |
| 29 | 29 |
| @@ -53,17 +53,17 @@ | |||
| 53 | 53 | .route("/login", with_csrf_manual( | |
| 54 | 54 | "POST validates via validate_token_consuming (defense-in-depth on top of SameSite=Lax)", | |
| 55 | 55 | get(crate::routes::pages::public::landing::login_page) | |
| 56 | - | .post(login_handler.layer(GovernorLayer { config: auth_rate_limit.clone() })), | |
| 56 | + | .post(login_handler.layer(GovernorLayer::new(auth_rate_limit.clone()))), | |
| 57 | 57 | )) | |
| 58 | 58 | .route("/auth/passkey/start", with_csrf_skip( | |
| 59 | 59 | "pre-auth WebAuthn challenge", | |
| 60 | 60 | post(passkey_auth_start) | |
| 61 | - | .layer(GovernorLayer { config: auth_rate_limit.clone() }), | |
| 61 | + | .layer(GovernorLayer::new(auth_rate_limit.clone())), | |
| 62 | 62 | )) | |
| 63 | 63 | .route("/auth/passkey/finish", with_csrf_skip( | |
| 64 | 64 | "pre-auth WebAuthn assertion", | |
| 65 | 65 | post(passkey_auth_finish) | |
| 66 | - | .layer(GovernorLayer { config: auth_rate_limit }), | |
| 66 | + | .layer(GovernorLayer::new(auth_rate_limit)), | |
| 67 | 67 | )) | |
| 68 | 68 | // Routes without auth rate limiting | |
| 69 | 69 | .route("/logout", post_csrf(logout_handler)) | |
| @@ -71,9 +71,7 @@ | |||
| 71 | 71 | // Username validation with its own rate limit | |
| 72 | 72 | .route( | |
| 73 | 73 | "/api/validate/username", | |
| 74 | - | with_csrf(post(validate_username).layer(GovernorLayer { | |
| 75 | - | config: validate_rate_limit, | |
| 76 | - | })), | |
| 74 | + | with_csrf(post(validate_username).layer(GovernorLayer::new(validate_rate_limit))), | |
| 77 | 75 | ) | |
| 78 | 76 | } | |
| 79 | 77 |
| @@ -546,9 +546,7 @@ | |||
| 546 | 546 | "/api/sync/builds/apps/{app_id}/builds/{build_id}/cancel", | |
| 547 | 547 | post_csrf_skip(SYNC_SKIP, cancel_build), | |
| 548 | 548 | ) | |
| 549 | - | .route_layer(GovernorLayer { | |
| 550 | - | config: write_rate_limit, | |
| 551 | - | }); | |
| 549 | + | .route_layer(GovernorLayer::new(write_rate_limit)); | |
| 552 | 550 | ||
| 553 | 551 | let trigger_rate_limit = crate::helpers::rate_limiter_per_sec( | |
| 554 | 552 | constants::BUILD_TRIGGER_RATE_LIMIT_PER_SEC, | |
| @@ -560,9 +558,7 @@ | |||
| 560 | 558 | "/api/internal/builds/trigger", | |
| 561 | 559 | post_csrf_skip("internal CI hook: HMAC bearer auth", hook_trigger), | |
| 562 | 560 | ) | |
| 563 | - | .route_layer(GovernorLayer { | |
| 564 | - | config: trigger_rate_limit, | |
| 565 | - | }); | |
| 561 | + | .route_layer(GovernorLayer::new(trigger_rate_limit)); | |
| 566 | 562 | ||
| 567 | 563 | mgmt_routes.merge(internal_routes) | |
| 568 | 564 | } |
| @@ -1078,18 +1078,14 @@ | |||
| 1078 | 1078 | let authorize_routes = CsrfRouter::new() | |
| 1079 | 1079 | .route_get("/oauth/authorize", get(authorize_get)) | |
| 1080 | 1080 | .route("/oauth/authorize", post_csrf_manual("OAuth authorize validates the consent form _csrf in-handler via validate_token_consuming", authorize_post)) | |
| 1081 | - | .route_layer(GovernorLayer { | |
| 1082 | - | config: authorize_rate_limit, | |
| 1083 | - | }); | |
| 1081 | + | .route_layer(GovernorLayer::new(authorize_rate_limit)); | |
| 1084 | 1082 | ||
| 1085 | 1083 | let token_routes = CsrfRouter::new() | |
| 1086 | 1084 | .route( | |
| 1087 | 1085 | "/oauth/token", | |
| 1088 | 1086 | post_csrf_skip("pre-auth OAuth token exchange", token_exchange), | |
| 1089 | 1087 | ) | |
| 1090 | - | .route_layer(GovernorLayer { | |
| 1091 | - | config: token_rate_limit, | |
| 1092 | - | }); | |
| 1088 | + | .route_layer(GovernorLayer::new(token_rate_limit)); | |
| 1093 | 1089 | ||
| 1094 | 1090 | // userinfo is DB-amplifying (user + creator-tier lookup) and discovery is a | |
| 1095 | 1091 | // public read; govern both so every public OAuth route carries a rate limit | |
| @@ -1104,9 +1100,7 @@ | |||
| 1104 | 1100 | "/.well-known/oauth-authorization-server", | |
| 1105 | 1101 | get(discovery_metadata), | |
| 1106 | 1102 | ) | |
| 1107 | - | .route_layer(GovernorLayer { | |
| 1108 | - | config: read_rate_limit, | |
| 1109 | - | }); | |
| 1103 | + | .route_layer(GovernorLayer::new(read_rate_limit)); | |
| 1110 | 1104 | ||
| 1111 | 1105 | authorize_routes.merge(token_routes).merge(read_routes) | |
| 1112 | 1106 | } |
| @@ -611,9 +611,7 @@ | |||
| 611 | 611 | "/api/v1/sync/ota/apps/{app_id}/releases/{release_id}/artifacts/confirm", | |
| 612 | 612 | post_csrf_skip(OTA_SKIP, confirm_artifact), | |
| 613 | 613 | ) | |
| 614 | - | .route_layer(GovernorLayer { | |
| 615 | - | config: write_rate_limit, | |
| 616 | - | }); | |
| 614 | + | .route_layer(GovernorLayer::new(write_rate_limit)); | |
| 617 | 615 | ||
| 618 | 616 | let read_rate_limit = crate::helpers::rate_limiter_ms( | |
| 619 | 617 | constants::OTA_READ_RATE_LIMIT_MS, | |
| @@ -637,9 +635,7 @@ | |||
| 637 | 635 | "/api/v1/sync/ota/{slug}/download/{release_id}/{target}/{arch}", | |
| 638 | 636 | get(artifact_download), | |
| 639 | 637 | ) | |
| 640 | - | .route_layer(GovernorLayer { | |
| 641 | - | config: read_rate_limit, | |
| 642 | - | }); | |
| 638 | + | .route_layer(GovernorLayer::new(read_rate_limit)); | |
| 643 | 639 | ||
| 644 | 640 | mgmt_routes.merge(public_routes) | |
| 645 | 641 | } |
| @@ -548,9 +548,7 @@ | |||
| 548 | 548 | "/api/email-signup", | |
| 549 | 549 | post_csrf_skip("pre-auth landing signup, no session", email_signup), | |
| 550 | 550 | ) | |
| 551 | - | .route_layer(GovernorLayer { | |
| 552 | - | config: write_rate_limit, | |
| 553 | - | }); | |
| 551 | + | .route_layer(GovernorLayer::new(write_rate_limit)); | |
| 554 | 552 | ||
| 555 | 553 | // Password/code-verifying TOTP mutations — strict auth-strength rate limit | |
| 556 | 554 | // (matching login), not the looser API-write limit, so confirm-code and | |
| @@ -566,9 +564,7 @@ | |||
| 566 | 564 | "/api/users/me/totp/backup-codes", | |
| 567 | 565 | post_csrf(totp::regenerate_backup_codes), | |
| 568 | 566 | ) | |
| 569 | - | .route_layer(GovernorLayer { | |
| 570 | - | config: totp_sensitive_rate_limit, | |
| 571 | - | }); | |
| 567 | + | .route_layer(GovernorLayer::new(totp_sensitive_rate_limit)); | |
| 572 | 568 | ||
| 573 | 569 | // Export routes — stricter rate limit | |
| 574 | 570 | let export_routes = CsrfRouter::new() | |
| @@ -589,9 +585,7 @@ | |||
| 589 | 585 | ) | |
| 590 | 586 | .route("/api/export/content", post_csrf(exports::export_content)) | |
| 591 | 587 | .route("/api/export/contacts", post_csrf(exports::export_contacts)) | |
| 592 | - | .route_layer(GovernorLayer { | |
| 593 | - | config: export_rate_limit, | |
| 594 | - | }); | |
| 588 | + | .route_layer(GovernorLayer::new(export_rate_limit)); | |
| 595 | 589 | ||
| 596 | 590 | let key_rate_limit = crate::helpers::rate_limiter_ms( | |
| 597 | 591 | constants::LICENSE_KEY_RATE_LIMIT_MS, | |
| @@ -639,9 +633,7 @@ | |||
| 639 | 633 | "/api/v1/license/deactivate", | |
| 640 | 634 | post_csrf_skip(LICENSE_BEARER_SKIP, license_keys::license_deactivate), | |
| 641 | 635 | ) | |
| 642 | - | .route_layer(GovernorLayer { | |
| 643 | - | config: key_rate_limit, | |
| 644 | - | }); | |
| 636 | + | .route_layer(GovernorLayer::new(key_rate_limit)); | |
| 645 | 637 | ||
| 646 | 638 | let read_rate_limit = crate::helpers::rate_limiter_ms( | |
| 647 | 639 | constants::API_READ_RATE_LIMIT_MS, | |
| @@ -706,9 +698,7 @@ | |||
| 706 | 698 | "/api/v1/items/{id}/license.txt", | |
| 707 | 699 | get(license_keys::license_text), | |
| 708 | 700 | ) | |
| 709 | - | .route_layer(GovernorLayer { | |
| 710 | - | config: read_rate_limit, | |
| 711 | - | }); | |
| 701 | + | .route_layer(GovernorLayer::new(read_rate_limit)); | |
| 712 | 702 | ||
| 713 | 703 | let validate_rate_limit = crate::helpers::rate_limiter_per_sec( | |
| 714 | 704 | constants::VALIDATE_RATE_LIMIT_PER_SEC, | |
| @@ -728,9 +718,7 @@ | |||
| 728 | 718 | "/api/validate/blog-slug", | |
| 729 | 719 | post_csrf(validate::validate_blog_slug), | |
| 730 | 720 | ) | |
| 731 | - | .route_layer(GovernorLayer { | |
| 732 | - | config: validate_rate_limit, | |
| 733 | - | }); | |
| 721 | + | .route_layer(GovernorLayer::new(validate_rate_limit)); | |
| 734 | 722 | ||
| 735 | 723 | // Import route needs a higher body limit (base64-encoded CSV up to 10 MB | |
| 736 | 724 | // ≈ 14 MB encoded). The global 1 MB RequestBodyLimitLayer would reject it, | |
| @@ -738,12 +726,10 @@ | |||
| 738 | 726 | let import_routes = CsrfRouter::new() | |
| 739 | 727 | .route("/api/users/me/import", post_csrf(imports::start_import)) | |
| 740 | 728 | .layer(axum::extract::DefaultBodyLimit::max(15 * 1024 * 1024)) | |
| 741 | - | .route_layer(GovernorLayer { | |
| 742 | - | config: crate::helpers::rate_limiter_ms( | |
| 743 | - | constants::API_WRITE_RATE_LIMIT_MS, | |
| 744 | - | constants::API_WRITE_RATE_LIMIT_BURST, | |
| 745 | - | ), | |
| 746 | - | }); | |
| 729 | + | .route_layer(GovernorLayer::new(crate::helpers::rate_limiter_ms( | |
| 730 | + | constants::API_WRITE_RATE_LIMIT_MS, | |
| 731 | + | constants::API_WRITE_RATE_LIMIT_BURST, | |
| 732 | + | ))); | |
| 747 | 733 | ||
| 748 | 734 | // Guest checkout routes — public, no auth, CORS-enabled, stricter rate limit | |
| 749 | 735 | let guest_checkout_rate_limit = crate::helpers::rate_limiter_per_sec( | |
| @@ -767,9 +753,7 @@ | |||
| 767 | 753 | "/api/purchases/claim", | |
| 768 | 754 | post_csrf(guest_checkout::claim_purchase), | |
| 769 | 755 | ) | |
| 770 | - | .route_layer(GovernorLayer { | |
| 771 | - | config: guest_checkout_rate_limit, | |
| 772 | - | }); | |
| 756 | + | .route_layer(GovernorLayer::new(guest_checkout_rate_limit)); | |
| 773 | 757 | ||
| 774 | 758 | // Guest download route — separate, more lenient per-IP rate limit. Unauth'd | |
| 775 | 759 | // and token-gated; the throttle is defense-in-depth against anonymous flooding | |
| @@ -780,9 +764,7 @@ | |||
| 780 | 764 | ); | |
| 781 | 765 | let download_routes = CsrfRouter::new() | |
| 782 | 766 | .route_get("/download/{token}", get(guest_checkout::guest_download)) | |
| 783 | - | .route_layer(GovernorLayer { | |
| 784 | - | config: download_rate_limit, | |
| 785 | - | }); | |
| 767 | + | .route_layer(GovernorLayer::new(download_rate_limit)); | |
| 786 | 768 | ||
| 787 | 769 | write_routes | |
| 788 | 770 | .merge(totp_sensitive_routes) |
| @@ -74,9 +74,7 @@ | |||
| 74 | 74 | post(raw::smart_http_receive_pack) | |
| 75 | 75 | .layer(DefaultBodyLimit::max(constants::GIT_RECEIVE_PACK_MAX_BYTES)), | |
| 76 | 76 | ) | |
| 77 | - | .route_layer(GovernorLayer { | |
| 78 | - | config: browse_rate_limit, | |
| 79 | - | }) | |
| 77 | + | .route_layer(GovernorLayer::new(browse_rate_limit)) | |
| 80 | 78 | } | |
| 81 | 79 | ||
| 82 | 80 | // ============================================================================ |