feat: rate limiting + E2E crypto lifecycle test
Rate limiting (closes the last security gap #3): - New RateLimiter: in-memory fixed-window IP-based limiter (std::sync::Mutex HashMap, no new deps). Configurable via RATE_LIMIT_MAX (default 100) + RATE_LIMIT_WINDOW_SECS (default 60) env vars. - general_rate_limit_middleware now reads ClientIp from request extensions and rejects with 429 + Retry-After header when over the limit. Wired via from_fn_with_state in app.rs. Lived on AppState as Arc<RateLimiter>. - Deleted the dead auth_rate_limit_middleware (never wired). - 3 unit tests (allows up to N, independent IPs, window reset). E2E crypto lifecycle test: - Full zero-knowledge round-trip against jsdom's real Web Crypto: setup → encrypt → verify ciphertext → unlock with password → decrypt → recover via phrase → rewrap under new password → decrypt. Plus wrong-password/wrong-phrase failures and cross-user key isolation. - Fixed wrapDek/unwrapDek: base64-encode raw DEK bytes (was using TextDecoder which produced non-base64), and make unwrapped DEK extractable (needed for rewrapDek to export). Verified: backend 24 tests 0 warnings; frontend 24 tests, build clean.
This commit is contained in:
parent
dcd86524d7
commit
b55b7c34f8
9 changed files with 262 additions and 23 deletions
|
|
@ -92,7 +92,7 @@ pub fn build_app(state: AppState) -> Router {
|
|||
|
||||
public_routes
|
||||
.merge(protected_routes)
|
||||
.with_state(state)
|
||||
.with_state(state.clone())
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
// Resolve the client IP once and stash it for handlers/middleware
|
||||
|
|
@ -104,8 +104,9 @@ pub fn build_app(state: AppState) -> Router {
|
|||
.layer(axum::middleware::from_fn(
|
||||
middleware::security_headers_middleware,
|
||||
))
|
||||
// General rate limiting (currently a stub)
|
||||
.layer(axum::middleware::from_fn(
|
||||
// IP-based rate limiting (reads ClientIp from extensions).
|
||||
.layer(axum::middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
middleware::general_rate_limit_middleware,
|
||||
))
|
||||
.layer(TraceLayer::new_for_http())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue