perf: improve compression reliability and deployment safety

This commit is contained in:
237899745
2026-07-25 10:29:49 +08:00
parent 06220ca921
commit 9d7668bdee
34 changed files with 1391 additions and 1042 deletions

View File

@@ -18,8 +18,14 @@ use uuid::Uuid;
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Principal {
Anonymous { session_id: String },
User { user_id: Uuid, role: String, email_verified: bool },
Anonymous {
session_id: String,
},
User {
user_id: Uuid,
role: String,
email_verified: bool,
},
ApiKey {
user_id: Uuid,
api_key_id: Uuid,
@@ -29,6 +35,14 @@ pub enum Principal {
}
pub fn client_ip(headers: &HeaderMap, connect_ip: IpAddr) -> IpAddr {
resolve_client_ip(headers, connect_ip, crate::config::trust_proxy_headers())
}
fn resolve_client_ip(headers: &HeaderMap, connect_ip: IpAddr, trust_proxy: bool) -> IpAddr {
if !trust_proxy {
return connect_ip;
}
if let Some(ip) = parse_forwarded_for(headers) {
return ip;
}
@@ -69,7 +83,13 @@ pub async fn authenticate(
return Err(AppError::new(ErrorCode::Unauthorized, "未登录"));
}
let (jar, session_id) = ensure_session_cookie(jar);
let cookie_secure = state
.config
.public_base_url
.trim()
.to_ascii_lowercase()
.starts_with("https://");
let (jar, session_id) = ensure_session_cookie(jar, cookie_secure);
Ok((jar, Principal::Anonymous { session_id }))
}
@@ -178,11 +198,12 @@ async fn try_api_key(
return Err(AppError::new(ErrorCode::Unauthorized, "API Key 无效"));
}
let _ = sqlx::query("UPDATE api_keys SET last_used_at = NOW(), last_used_ip = $2 WHERE id = $1")
.bind(row.id)
.bind(ip.to_string())
.execute(&state.db)
.await;
let _ =
sqlx::query("UPDATE api_keys SET last_used_at = NOW(), last_used_ip = $2 WHERE id = $1")
.bind(row.id)
.bind(ip.to_string())
.execute(&state.db)
.await;
Ok(Some(Principal::ApiKey {
user_id: row.user_id,
@@ -192,7 +213,7 @@ async fn try_api_key(
}))
}
pub fn ensure_session_cookie(jar: CookieJar) -> (CookieJar, String) {
pub fn ensure_session_cookie(jar: CookieJar, secure: bool) -> (CookieJar, String) {
if let Some(cookie) = jar.get("if_session") {
let session_id = cookie.value().trim().to_string();
if !session_id.is_empty() {
@@ -204,6 +225,7 @@ pub fn ensure_session_cookie(jar: CookieJar) -> (CookieJar, String) {
let cookie = Cookie::build(("if_session", session_id.clone()))
.path("/")
.http_only(true)
.secure(secure)
.same_site(SameSite::Lax)
.max_age(TimeDuration::days(7))
.build();
@@ -220,10 +242,37 @@ fn generate_session_id() -> String {
pub fn api_key_hash(full_key: &str, pepper: &str) -> Result<String, AppError> {
type HmacSha256 = Hmac<Sha256>;
let mut mac = HmacSha256::new_from_slice(pepper.as_bytes())
.map_err(|err| AppError::new(ErrorCode::Internal, "API Key pepper 错误").with_source(err))?;
let mut mac = HmacSha256::new_from_slice(pepper.as_bytes()).map_err(|err| {
AppError::new(ErrorCode::Internal, "API Key pepper 错误").with_source(err)
})?;
mac.update(full_key.as_bytes());
let result = mac.finalize().into_bytes();
Ok(hex::encode(result))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn untrusted_proxy_headers_cannot_override_peer_ip() {
let mut headers = HeaderMap::new();
headers.insert("x-forwarded-for", "203.0.113.9".parse().unwrap());
let peer = "192.0.2.10".parse().unwrap();
assert_eq!(resolve_client_ip(&headers, peer, false), peer);
}
#[test]
fn trusted_proxy_headers_use_forwarded_client_ip() {
let mut headers = HeaderMap::new();
headers.insert(
"x-forwarded-for",
"203.0.113.9, 192.0.2.20".parse().unwrap(),
);
let peer = "192.0.2.10".parse().unwrap();
assert_eq!(
resolve_client_ip(&headers, peer, true),
"203.0.113.9".parse::<IpAddr>().unwrap()
);
}
}