atd_server_http/
origin.rs1use axum::http::HeaderMap;
18
19pub fn origin_allowed(headers: &HeaderMap, extras: &[String]) -> bool {
23 let origin = match headers.get("origin").and_then(|v| v.to_str().ok()) {
24 Some(s) => s,
25 None => return true,
30 };
31 if is_default_loopback_origin(origin) {
32 return true;
33 }
34 extras.iter().any(|p| origin == p)
35}
36
37pub fn is_default_loopback_origin(origin: &str) -> bool {
40 origin.starts_with("http://127.0.0.1")
41 || origin.starts_with("http://localhost")
42 || origin.starts_with("https://127.0.0.1")
43 || origin.starts_with("https://localhost")
44 || origin == "tauri://localhost"
45 || origin.starts_with("tauri://")
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use axum::http::HeaderValue;
52
53 fn headers_with_origin(origin: &str) -> HeaderMap {
54 let mut h = HeaderMap::new();
55 h.insert("origin", HeaderValue::from_str(origin).unwrap());
56 h
57 }
58
59 #[test]
60 fn default_allows_loopback_http() {
61 assert!(origin_allowed(
62 &headers_with_origin("http://127.0.0.1:5173"),
63 &[]
64 ));
65 assert!(origin_allowed(
66 &headers_with_origin("http://localhost:1420"),
67 &[]
68 ));
69 }
70
71 #[test]
72 fn default_allows_loopback_https_and_tauri() {
73 assert!(origin_allowed(
74 &headers_with_origin("https://127.0.0.1"),
75 &[]
76 ));
77 assert!(origin_allowed(
78 &headers_with_origin("https://localhost:8443"),
79 &[]
80 ));
81 assert!(origin_allowed(
82 &headers_with_origin("tauri://localhost"),
83 &[]
84 ));
85 assert!(origin_allowed(&headers_with_origin("tauri://custom"), &[]));
86 }
87
88 #[test]
89 fn default_rejects_remote_origin() {
90 assert!(!origin_allowed(
91 &headers_with_origin("https://evil.example"),
92 &[]
93 ));
94 assert!(!origin_allowed(
95 &headers_with_origin("http://attacker.test:8080"),
96 &[]
97 ));
98 }
99
100 #[test]
101 fn extras_admits_exact_match_only() {
102 let extras = vec!["https://celia.health".to_string()];
103 assert!(origin_allowed(
104 &headers_with_origin("https://celia.health"),
105 &extras
106 ));
107 assert!(!origin_allowed(
109 &headers_with_origin("https://celia.health.evil.example"),
110 &extras
111 ));
112 assert!(origin_allowed(
114 &headers_with_origin("http://127.0.0.1:5173"),
115 &extras
116 ));
117 }
118
119 #[test]
120 fn missing_origin_header_is_allowed() {
121 let headers = HeaderMap::new();
124 assert!(origin_allowed(&headers, &[]));
125 }
126}