1use once_cell::sync::Lazy;
6use parking_lot::RwLock;
7use url::Url;
8
9#[derive(Debug)]
19#[non_exhaustive]
20pub struct Settings {
21 pub default_user_agent: Option<String>,
22 pub addn_allowed_insecure_url: Option<Url>,
23}
24
25pub static GLOBAL_SETTINGS: Lazy<RwLock<Settings>> = Lazy::new(|| {
27 RwLock::new(Settings {
28 default_user_agent: None,
29 addn_allowed_insecure_url: None,
30 })
31});
32
33#[uniffi::export]
35pub fn allow_android_emulator_loopback() {
36 let url = url::Url::parse("http://10.0.2.2").unwrap();
37 let mut settings = GLOBAL_SETTINGS.write();
38 settings.addn_allowed_insecure_url = Some(url);
39}
40
41#[uniffi::export]
46pub fn set_global_default_user_agent(user_agent: String) {
47 let mut settings = GLOBAL_SETTINGS.write();
48 settings.default_user_agent = Some(user_agent);
49}
50
51pub fn validate_request(request: &crate::Request) -> Result<(), crate::ViaductError> {
53 if request.url.scheme() != "https"
54 && match request.url.host() {
55 Some(url::Host::Domain(d)) => d != "localhost",
56 Some(url::Host::Ipv4(addr)) => !addr.is_loopback(),
57 Some(url::Host::Ipv6(addr)) => !addr.is_loopback(),
58 None => true,
59 }
60 && {
61 let settings = GLOBAL_SETTINGS.read();
62 settings
63 .addn_allowed_insecure_url
64 .as_ref()
65 .map(|url| url.host() != request.url.host() || url.scheme() != request.url.scheme())
66 .unwrap_or(true)
67 }
68 {
69 return Err(crate::ViaductError::NonTlsUrl);
70 }
71 Ok(())
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_validate_request() {
80 let _https_request = crate::Request::new(
81 crate::Method::Get,
82 url::Url::parse("https://www.example.com").unwrap(),
83 );
84 assert!(validate_request(&_https_request).is_ok());
85
86 let _http_request = crate::Request::new(
87 crate::Method::Get,
88 url::Url::parse("http://www.example.com").unwrap(),
89 );
90 assert!(validate_request(&_http_request).is_err());
91
92 let _localhost_https_request = crate::Request::new(
93 crate::Method::Get,
94 url::Url::parse("https://127.0.0.1/index.html").unwrap(),
95 );
96 assert!(validate_request(&_localhost_https_request).is_ok());
97
98 let _localhost_https_request_2 = crate::Request::new(
99 crate::Method::Get,
100 url::Url::parse("https://localhost:4242/").unwrap(),
101 );
102 assert!(validate_request(&_localhost_https_request_2).is_ok());
103
104 let _localhost_http_request = crate::Request::new(
105 crate::Method::Get,
106 url::Url::parse("http://localhost:4242/").unwrap(),
107 );
108 assert!(validate_request(&_localhost_http_request).is_ok());
109
110 let localhost_request = crate::Request::new(
111 crate::Method::Get,
112 url::Url::parse("localhost:4242/").unwrap(),
113 );
114 assert!(validate_request(&localhost_request).is_err());
115
116 let localhost_request_shorthand_ipv6 =
117 crate::Request::new(crate::Method::Get, url::Url::parse("http://[::1]").unwrap());
118 assert!(validate_request(&localhost_request_shorthand_ipv6).is_ok());
119
120 let localhost_request_ipv6 = crate::Request::new(
121 crate::Method::Get,
122 url::Url::parse("http://[0:0:0:0:0:0:0:1]").unwrap(),
123 );
124 assert!(validate_request(&localhost_request_ipv6).is_ok());
125 }
126
127 #[test]
128 fn test_validate_request_addn_allowed_insecure_url() {
129 let request_root = crate::Request::new(
130 crate::Method::Get,
131 url::Url::parse("http://anything").unwrap(),
132 );
133 let request = crate::Request::new(
134 crate::Method::Get,
135 url::Url::parse("http://anything/path").unwrap(),
136 );
137 let request_ftp = crate::Request::new(
139 crate::Method::Get,
140 url::Url::parse("ftp://anything/path").unwrap(),
141 );
142 assert!(validate_request(&request_root).is_err());
143 assert!(validate_request(&request).is_err());
144 {
145 let mut settings = GLOBAL_SETTINGS.write();
146 settings.addn_allowed_insecure_url =
147 Some(url::Url::parse("http://something-else").unwrap());
148 }
149 assert!(validate_request(&request_root).is_err());
150 assert!(validate_request(&request).is_err());
151
152 {
153 let mut settings = GLOBAL_SETTINGS.write();
154 settings.addn_allowed_insecure_url = Some(url::Url::parse("http://anything").unwrap());
155 }
156 assert!(validate_request(&request_root).is_ok());
157 assert!(validate_request(&request).is_ok());
158 assert!(validate_request(&request_ftp).is_err());
159 }
160}