Skip to main content

hns_browser_loopback_proxy/chromium/
endpoint.rs

1use crate::{ProxyAuthorization, ProxyInstanceId};
2use std::fmt;
3use std::net::{IpAddr, Ipv4Addr, SocketAddr};
4use std::sync::Arc;
5
6pub struct ProxyEndpoint {
7    instance: ProxyInstanceId,
8    address: SocketAddr,
9    authorization: Arc<ProxyAuthorization>,
10}
11
12impl ProxyEndpoint {
13    pub(crate) fn new(
14        instance: ProxyInstanceId,
15        address: SocketAddr,
16        authorization: Arc<ProxyAuthorization>,
17    ) -> Self {
18        Self {
19            instance,
20            address,
21            authorization,
22        }
23    }
24
25    pub fn instance(&self) -> &ProxyInstanceId {
26        &self.instance
27    }
28
29    pub fn address(&self) -> SocketAddr {
30        self.address
31    }
32
33    pub fn port(&self) -> u16 {
34        self.address.port()
35    }
36
37    pub fn realm(&self) -> &str {
38        self.authorization.realm()
39    }
40
41    pub fn username(&self) -> &str {
42        self.authorization.username()
43    }
44
45    pub fn password(&self) -> &str {
46        self.authorization.password()
47    }
48
49    pub fn authorization_header_value(&self) -> String {
50        self.authorization.authorization_header_value()
51    }
52
53    pub fn matches_challenge(&self, host: &str, port: u16, realm: &str) -> bool {
54        self.address.ip() == IpAddr::V4(Ipv4Addr::LOCALHOST)
55            && port == self.port()
56            && self.authorization.matches_challenge(host, realm)
57    }
58}
59
60impl fmt::Debug for ProxyEndpoint {
61    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
62        formatter
63            .debug_struct("ProxyEndpoint")
64            .field("instance", &self.instance)
65            .field("address", &self.address)
66            .field("realm", &"[REDACTED]")
67            .field("username", &"[REDACTED]")
68            .field("password", &"[REDACTED]")
69            .finish()
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use crate::ProxySessionId;
77
78    #[test]
79    fn endpoint_exposes_capability_only_through_explicit_accessors() {
80        let authorization = Arc::new(ProxyAuthorization::generate().unwrap());
81        let endpoint = ProxyEndpoint::new(
82            ProxyInstanceId::new(ProxySessionId::generate().unwrap(), 4),
83            "127.0.0.1:43123".parse().unwrap(),
84            Arc::clone(&authorization),
85        );
86        let debug = format!("{endpoint:?}");
87
88        assert!(!debug.contains(endpoint.realm()));
89        assert!(!debug.contains(endpoint.username()));
90        assert!(!debug.contains(endpoint.password()));
91        assert!(authorization.verify_header_value(&endpoint.authorization_header_value()));
92        assert!(endpoint.matches_challenge("127.0.0.1", 43123, endpoint.realm()));
93        assert!(!endpoint.matches_challenge("127.0.0.1", 43124, endpoint.realm()));
94    }
95}