This commit is contained in:
Alexey
2026-08-23 10:56:00 +03:00
parent 596149cab8
commit 840b6f563a
31 changed files with 232 additions and 346 deletions
+11 -21
View File
@@ -2,15 +2,13 @@ use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use base64::Engine as _;
use hyper::header;
use hyper::Request;
use hyper::header;
use ipnetwork::IpNetwork;
use sha2::{Digest, Sha256};
use subtle::ConstantTimeEq;
use crate::config::{
WebClientIpSource, WebRuntimeProfile, WebRuntimeVhost,
};
use crate::config::{WebClientIpSource, WebRuntimeProfile, WebRuntimeVhost};
use crate::web::manager::TokenHash;
/// Parses one lowercase canonical Host value restricted to the public HTTPS port.
@@ -26,8 +24,7 @@ pub(super) fn canonical_request_host<B>(request: &Request<B>) -> Option<&str> {
return None;
}
let host = value.strip_suffix(":443").unwrap_or(value);
if authority.host() != host || host.bytes().any(|byte| byte.is_ascii_uppercase())
{
if authority.host() != host || host.bytes().any(|byte| byte.is_ascii_uppercase()) {
return None;
}
Some(host)
@@ -74,14 +71,14 @@ pub(super) fn bridge_candidate(query: Option<&str>) -> ([u8; 32], bool) {
return (candidate, false);
}
let mut decoded = [0u8; 32];
let Ok(decoded_len) = base64::engine::general_purpose::URL_SAFE_NO_PAD
.decode_slice(value, &mut decoded)
let Ok(decoded_len) =
base64::engine::general_purpose::URL_SAFE_NO_PAD.decode_slice(value, &mut decoded)
else {
return (candidate, false);
};
let mut canonical = [0u8; 43];
let Ok(encoded_len) = base64::engine::general_purpose::URL_SAFE_NO_PAD
.encode_slice(decoded, &mut canonical)
let Ok(encoded_len) =
base64::engine::general_purpose::URL_SAFE_NO_PAD.encode_slice(decoded, &mut canonical)
else {
return (candidate, false);
};
@@ -114,8 +111,7 @@ pub(super) fn bearer_token_hash<B>(request: &Request<B>) -> Option<TokenHash> {
let values = request.headers().get_all(header::AUTHORIZATION);
let mut values = values.iter();
let value = values.next()?.to_str().ok()?;
if values.next().is_some() || !value.starts_with("Bearer ") || value.matches(' ').count() != 1
{
if values.next().is_some() || !value.starts_with("Bearer ") || value.matches(' ').count() != 1 {
return None;
}
let token = value.strip_prefix("Bearer ")?;
@@ -133,7 +129,7 @@ pub(super) fn bearer_token_hash<B>(request: &Request<B>) -> Option<TokenHash> {
(decoded_len == decoded.len()
&& encoded_len == canonical.len()
&& bool::from(canonical.ct_eq(token.as_bytes())))
.then(|| Sha256::digest(decoded).into())
.then(|| Sha256::digest(decoded).into())
}
/// Checks the exact carrier media type without accepting duplicate headers.
@@ -146,10 +142,7 @@ pub(super) fn binary_content_type<B>(request: &Request<B>) -> bool {
}
/// Parses one canonical unsigned decimal carrier sequence header.
pub(super) fn canonical_u64_header<B>(
request: &Request<B>,
name: &'static str,
) -> Option<u64> {
pub(super) fn canonical_u64_header<B>(request: &Request<B>, name: &'static str) -> Option<u64> {
let values = request.headers().get_all(name);
let mut values = values.iter();
let value = values.next()?.to_str().ok()?;
@@ -183,10 +176,7 @@ mod tests {
.header("x-forwarded-for", "192.0.2.10")
.body(())
.unwrap();
assert_eq!(
canonical_request_host(&request),
Some("proxy.example.com")
);
assert_eq!(canonical_request_host(&request), Some("proxy.example.com"));
let trusted: [IpNetwork; 1] = ["127.0.0.1/32".parse().unwrap()];
assert_eq!(
client_ip(