Skip to main content

leyline/core/device/
check.rs

1use crate::core::error::Result;
2use crate::core::{Session, SessionIdentity};
3
4use super::secret::ProxyKey;
5use super::{Device, config};
6
7impl Device {
8    pub fn check(&self, session: &Session) -> Result<()> {
9        let id = session.identity();
10        let mut differences = match self.profile_id.as_deref() {
11            Some(expected) => profile_difference(expected, &id),
12            None => self.identity_differences(&id),
13        };
14        let profile_changed = !differences.is_empty();
15        differences.extend(self.setting_differences(session, &id));
16        differences.extend(self.strict_gaps());
17        if differences.is_empty() {
18            return Ok(());
19        }
20        let err = config(format!(
21            "the session differs from the device: {}",
22            differences.join("; ")
23        ));
24        Err(if profile_changed {
25            err.with_source(crate::core::error::ProfileChanged)
26        } else {
27            err
28        })
29    }
30
31    fn identity_differences(&self, id: &SessionIdentity) -> Vec<String> {
32        let mut differences = Vec::new();
33        if self.identity != id.to_identity() {
34            differences.push(format!(
35                "identity {:?} (device {:?})",
36                id.to_identity(),
37                self.identity
38            ));
39        }
40        if self.platform != id.platform() {
41            differences.push(format!(
42                "platform {:?} (device {:?})",
43                id.platform(),
44                self.platform
45            ));
46        }
47        if self.brand != id.brand() {
48            differences.push(format!("brand {:?} (device {:?})", id.brand(), self.brand));
49        }
50        if let Some(expected) = self.user_agent.as_deref()
51            && expected != id.user_agent()
52        {
53            differences.push(format!(
54                "user_agent {:?} (device {expected:?})",
55                id.user_agent()
56            ));
57        }
58        differences
59    }
60
61    fn strict_gaps(&self) -> Vec<String> {
62        let mut gaps = Vec::new();
63        if !self.strict {
64            return gaps;
65        }
66        if self.profile_id.is_none() {
67            gaps.push("strict device has no profile_id".to_owned());
68        }
69        if self.proxy.is_none() && !self.env_proxy {
70            gaps.push("strict device has no proxy and env_proxy is false".to_owned());
71        }
72        gaps
73    }
74
75    fn setting_differences(&self, session: &Session, id: &SessionIdentity) -> Vec<String> {
76        let mut differences = Vec::new();
77        if self.languages.as_deref() != id.languages() {
78            differences.push(format!(
79                "languages {:?} (device {:?})",
80                id.languages(),
81                self.languages
82            ));
83        }
84        let proxy = session.proxy_url();
85        if !self.env_proxy
86            && self.proxy.as_ref().map(ProxyKey::of) != proxy.as_ref().map(ProxyKey::of)
87        {
88            differences.push(format!("proxy {proxy:?} (device {:?})", self.proxy));
89        }
90        differences
91    }
92}
93
94fn profile_difference(expected: &str, id: &SessionIdentity) -> Vec<String> {
95    match id.profile_id() {
96        Some(actual) if actual == expected => Vec::new(),
97        actual => vec![format!("profile_id {actual:?} (device {expected:?})")],
98    }
99}