fix(gateway): harden client identity and bound key stores
This commit is contained in:
parent
b1c04d8f88
commit
c507856710
2 changed files with 267 additions and 48 deletions
|
|
@ -479,9 +479,22 @@ pub struct GatewayConfig {
|
|||
#[serde(default = "default_webhook_rate_limit")]
|
||||
pub webhook_rate_limit_per_minute: u32,
|
||||
|
||||
/// Trust proxy-forwarded client IP headers (`X-Forwarded-For`, `X-Real-IP`).
|
||||
/// Disabled by default; enable only behind a trusted reverse proxy.
|
||||
#[serde(default)]
|
||||
pub trust_forwarded_headers: bool,
|
||||
|
||||
/// Maximum distinct client keys tracked by gateway rate limiter maps.
|
||||
#[serde(default = "default_gateway_rate_limit_max_keys")]
|
||||
pub rate_limit_max_keys: usize,
|
||||
|
||||
/// TTL for webhook idempotency keys.
|
||||
#[serde(default = "default_idempotency_ttl_secs")]
|
||||
pub idempotency_ttl_secs: u64,
|
||||
|
||||
/// Maximum distinct idempotency keys retained in memory.
|
||||
#[serde(default = "default_gateway_idempotency_max_keys")]
|
||||
pub idempotency_max_keys: usize,
|
||||
}
|
||||
|
||||
fn default_gateway_port() -> u16 {
|
||||
|
|
@ -504,6 +517,14 @@ fn default_idempotency_ttl_secs() -> u64 {
|
|||
300
|
||||
}
|
||||
|
||||
fn default_gateway_rate_limit_max_keys() -> usize {
|
||||
10_000
|
||||
}
|
||||
|
||||
fn default_gateway_idempotency_max_keys() -> usize {
|
||||
10_000
|
||||
}
|
||||
|
||||
fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
|
@ -518,7 +539,10 @@ impl Default for GatewayConfig {
|
|||
paired_tokens: Vec::new(),
|
||||
pair_rate_limit_per_minute: default_pair_rate_limit(),
|
||||
webhook_rate_limit_per_minute: default_webhook_rate_limit(),
|
||||
trust_forwarded_headers: false,
|
||||
rate_limit_max_keys: default_gateway_rate_limit_max_keys(),
|
||||
idempotency_ttl_secs: default_idempotency_ttl_secs(),
|
||||
idempotency_max_keys: default_gateway_idempotency_max_keys(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2946,7 +2970,10 @@ channel_id = "C123"
|
|||
);
|
||||
assert_eq!(g.pair_rate_limit_per_minute, 10);
|
||||
assert_eq!(g.webhook_rate_limit_per_minute, 60);
|
||||
assert!(!g.trust_forwarded_headers);
|
||||
assert_eq!(g.rate_limit_max_keys, 10_000);
|
||||
assert_eq!(g.idempotency_ttl_secs, 300);
|
||||
assert_eq!(g.idempotency_max_keys, 10_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2974,7 +3001,10 @@ channel_id = "C123"
|
|||
paired_tokens: vec!["zc_test_token".into()],
|
||||
pair_rate_limit_per_minute: 12,
|
||||
webhook_rate_limit_per_minute: 80,
|
||||
trust_forwarded_headers: true,
|
||||
rate_limit_max_keys: 2048,
|
||||
idempotency_ttl_secs: 600,
|
||||
idempotency_max_keys: 4096,
|
||||
};
|
||||
let toml_str = toml::to_string(&g).unwrap();
|
||||
let parsed: GatewayConfig = toml::from_str(&toml_str).unwrap();
|
||||
|
|
@ -2983,7 +3013,10 @@ channel_id = "C123"
|
|||
assert_eq!(parsed.paired_tokens, vec!["zc_test_token"]);
|
||||
assert_eq!(parsed.pair_rate_limit_per_minute, 12);
|
||||
assert_eq!(parsed.webhook_rate_limit_per_minute, 80);
|
||||
assert!(parsed.trust_forwarded_headers);
|
||||
assert_eq!(parsed.rate_limit_max_keys, 2048);
|
||||
assert_eq!(parsed.idempotency_ttl_secs, 600);
|
||||
assert_eq!(parsed.idempotency_max_keys, 4096);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -3622,6 +3655,9 @@ default_model = "legacy-model"
|
|||
assert!(g.require_pairing);
|
||||
assert!(!g.allow_public_bind);
|
||||
assert!(g.paired_tokens.is_empty());
|
||||
assert!(!g.trust_forwarded_headers);
|
||||
assert_eq!(g.rate_limit_max_keys, 10_000);
|
||||
assert_eq!(g.idempotency_max_keys, 10_000);
|
||||
}
|
||||
|
||||
// ── Peripherals config ───────────────────────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue