fix(ws): allow APP_DOMAIN_URL and APP_STATIC_DOMAIN origins
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions

validate_origin() only allowed localhost origins by default, causing
production WebSocket connections to be rejected. Now it reads
APP_DOMAIN_URL and APP_STATIC_DOMAIN from env and automatically
adds their http/https/ws/wss variants to the allowed origins list.

Also add APP_DOMAIN_URL to the production configmap.
This commit is contained in:
ZhenYi 2026-04-16 18:51:52 +08:00
parent 89deebced6
commit 431f40063f
2 changed files with 50 additions and 12 deletions

View File

@ -11,6 +11,7 @@ data:
# App Info
APP_NAME: "gitdata"
APP_VERSION: "0.1.0"
APP_DOMAIN_URL: "https://gitdata.ai"
APP_STATIC_DOMAIN: "https://static.gitdata.ai"
APP_MEDIA_DOMAIN: "https://static.gitdata.ai"
APP_GIT_HTTP_DOMAIN: "https://git.gitdata.ai"

View File

@ -231,20 +231,57 @@ pub struct WsOutEvent {
pub(crate) fn validate_origin(req: &HttpRequest) -> bool {
static ALLOWED_ORIGINS: LazyLock<Vec<String>> = LazyLock::new(|| {
// Build default origins from localhost + APP_DOMAIN_URL
let domain = std::env::var("APP_DOMAIN_URL")
.unwrap_or_else(|_| "http://127.0.0.1".to_string());
// Normalize: strip trailing slash, derive https/wss variants
let domain = domain.trim_end_matches('/');
let https_domain = domain.replace("http://", "https://").replace("ws://", "wss://");
let ws_domain = domain.replace("https://", "ws://").replace("http://", "ws://");
let mut defaults = vec![
"http://localhost".to_string(),
"https://localhost".to_string(),
"http://127.0.0.1".to_string(),
"https://127.0.0.1".to_string(),
"ws://localhost".to_string(),
"wss://localhost".to_string(),
"ws://127.0.0.1".to_string(),
"wss://127.0.0.1".to_string(),
];
// Always include APP_DOMAIN_URL and APP_STATIC_DOMAIN origins
let mut add_origin = |origin: &str| {
let origin = origin.trim_end_matches('/');
let https_v = origin.replace("http://", "https://").replace("ws://", "wss://");
let ws_v = origin.replace("https://", "ws://").replace("http://", "ws://");
for v in [origin, &https_v, &ws_v] {
if !defaults.contains(&v.to_string()) && v != domain {
defaults.push(v.to_string());
}
}
};
if let Ok(static_domain) = std::env::var("APP_STATIC_DOMAIN") {
add_origin(&static_domain);
}
if !defaults.contains(&domain.to_string()) {
defaults.push(domain.to_string());
}
if !defaults.contains(&https_domain) && https_domain != domain {
defaults.push(https_domain.clone());
}
if !defaults.contains(&ws_domain) && ws_domain != domain && ws_domain != https_domain {
defaults.push(ws_domain);
}
std::env::var("WS_ALLOWED_ORIGINS")
.map(|v| v.split(',').map(|s| s.trim().to_string()).collect())
.unwrap_or_else(|_| {
vec![
"http://localhost".to_string(),
"https://localhost".to_string(),
"http://127.0.0.1".to_string(),
"https://127.0.0.1".to_string(),
"ws://localhost".to_string(),
"wss://localhost".to_string(),
"ws://127.0.0.1".to_string(),
"wss://127.0.0.1".to_string(),
]
.map(|v| {
let mut origins = defaults.clone();
origins.extend(v.split(',').map(|s| s.trim().to_string()));
origins
})
.unwrap_or_else(|_| defaults)
});
let Some(origin) = req.headers().get("origin") else {