use std::net::IpAddr;
use std::sync::{OnceLock, RwLock};
pub const COOKIE: &str = "rws_me";
pub const PATH: &str = "/_rws/me";
fn networks() -> &'static RwLock<Vec<String>> {
static NETWORKS: OnceLock<RwLock<Vec<String>>> = OnceLock::new();
NETWORKS.get_or_init(|| RwLock::new(super::config::owner_networks()))
}
pub fn set_networks(entries: &[String]) {
*networks().write().unwrap_or_else(|e| e.into_inner()) = entries.to_vec();
}
pub fn in_networks(ip: IpAddr) -> bool {
let networks = networks().read().unwrap_or_else(|e| e.into_inner());
if networks.is_empty() {
return false;
}
let ip = ip.to_canonical().to_string();
networks.iter().any(|entry| crate::ip_filter::matches(entry, &ip))
}
fn hex(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{b:02x}")).collect()
}
pub fn key() -> &'static str {
static KEY: OnceLock<String> = OnceLock::new();
KEY.get_or_init(|| {
#[cfg(not(target_arch = "wasm32"))]
if let Ok(token) = crate::admin::AdminConfig::from_env().token() {
return hex(&crate::core::sha256::hmac_sha256(token.as_bytes(), b"rws-traffic-owner")[..16]);
}
use std::hash::{BuildHasher, Hasher};
let mut out = String::new();
for i in 0..2u8 {
let mut h = std::collections::hash_map::RandomState::new().build_hasher();
h.write_u8(i);
out.push_str(&format!("{:016x}", h.finish()));
}
out
})
}
pub fn key_matches(value: &str) -> bool {
crate::core::constant_time_eq(value.trim().as_bytes(), key().as_bytes())
}
pub fn has_cookie(headers: &[crate::header::Header]) -> bool {
headers.iter().filter(|h| h.name.eq_ignore_ascii_case("cookie")).any(|h| {
h.value.split(';').any(|pair| match pair.trim().split_once('=') {
Some((name, value)) => name.trim() == COOKIE && key_matches(value),
None => false,
})
})
}
pub fn is_admin_call(headers: &[crate::header::Header], status: i16) -> bool {
(200..300).contains(&status) && headers.iter().any(|h| h.name.eq_ignore_ascii_case("x-rws-admin"))
}