generalbots/src/security/request_limits.rs
Rodrigo Rodriguez e143968179 feat: Add JWT secret rotation and health verification
SEC-02: Implement credential rotation security improvements

- Add JWT secret rotation to rotate-secret command
- Generate 64-character HS512-compatible secrets
- Automatic .env backup with timestamp
- Atomic file updates via temp+rename pattern
- Add health verification for rotated credentials
- Route rotate-secret, rotate-secrets, vault commands in CLI
- Add verification attempts for database and JWT endpoints

Security improvements:
- JWT_SECRET now rotatable (previously impossible)
- Automatic rollback via backup files
- Health checks catch configuration errors
- Clear warnings about token invalidation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-19 19:42:41 +00:00

66 lines
1.8 KiB
Rust

use axum::{
body::Body,
extract::Request,
http::StatusCode,
middleware::Next,
response::{IntoResponse, Response},
};
pub const DEFAULT_MAX_REQUEST_SIZE: usize = 10 * 1024 * 1024;
pub const MAX_UPLOAD_SIZE: usize = 100 * 1024 * 1024;
pub async fn request_size_middleware(
req: Request<Body>,
next: Next,
) -> Response {
let content_length = req
.headers()
.get("content-length")
.and_then(|v| v.to_str().ok())
.and_then(|s| s.parse::<usize>().ok());
if let Some(len) = content_length {
if len > DEFAULT_MAX_REQUEST_SIZE {
return (
StatusCode::PAYLOAD_TOO_LARGE,
axum::Json(serde_json::json!({
"error": "request_too_large",
"message": format!("Request body {} bytes exceeds maximum {}", len, DEFAULT_MAX_REQUEST_SIZE),
"max_size": DEFAULT_MAX_REQUEST_SIZE
})),
)
.into_response();
}
}
next.run(req).await
}
pub async fn upload_size_middleware(
req: Request<Body>,
next: Next,
) -> Response {
let content_length = req
.headers()
.get("content-length")
.and_then(|v| v.to_str().ok())
.and_then(|s| s.parse::<usize>().ok());
if let Some(len) = content_length {
if len > MAX_UPLOAD_SIZE {
return (
StatusCode::PAYLOAD_TOO_LARGE,
axum::Json(serde_json::json!({
"error": "upload_too_large",
"message": format!("Upload {} bytes exceeds maximum {}", len, MAX_UPLOAD_SIZE),
"max_size": MAX_UPLOAD_SIZE
})),
)
.into_response();
}
}
next.run(req).await
}