leyline/core/device/
check.rs1use 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}