1use reqwest::header::{
2 HeaderMap, HeaderValue, ACCEPT, ACCEPT_ENCODING, ACCEPT_LANGUAGE, DNT,
3 UPGRADE_INSECURE_REQUESTS, USER_AGENT,
4};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8pub enum DeviceProfile {
9 #[default]
10 ChromeWindows,
11 ChromeLinux,
12 SafariMac,
13 SafariIos,
14 ChromeAndroid,
15}
16
17pub struct Fingerprint {
18 pub profile: DeviceProfile,
19 pub user_agent: &'static str,
20 pub platform: &'static str,
21 pub screen_width: u32,
22 pub screen_height: u32,
23 pub is_mobile: bool,
24}
25
26impl Fingerprint {
27 pub fn for_profile(profile: DeviceProfile) -> Self {
28 match profile {
29 DeviceProfile::ChromeWindows => Self {
30 profile,
31 user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
32 platform: "Win32",
33 screen_width: 1920,
34 screen_height: 1080,
35 is_mobile: false,
36 },
37 DeviceProfile::ChromeLinux => Self {
38 profile,
39 user_agent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
40 platform: "Linux x86_64",
41 screen_width: 1920,
42 screen_height: 1080,
43 is_mobile: false,
44 },
45 DeviceProfile::SafariMac => Self {
46 profile,
47 user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15",
48 platform: "MacIntel",
49 screen_width: 2560,
50 screen_height: 1440,
51 is_mobile: false,
52 },
53 DeviceProfile::SafariIos => Self {
54 profile,
55 user_agent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Mobile/15E148 Safari/604.1",
56 platform: "iPhone",
57 screen_width: 393,
58 screen_height: 852,
59 is_mobile: true,
60 },
61 DeviceProfile::ChromeAndroid => Self {
62 profile,
63 user_agent: "Mozilla/5.0 (Linux; Android 14; Pixel 8 Build/UD1A.230803.022) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.6943.122 Mobile Safari/537.36",
64 platform: "Linux armv8l",
65 screen_width: 412,
66 screen_height: 915,
67 is_mobile: true,
68 },
69 }
70 }
71
72 pub fn build_headers(&self) -> HeaderMap {
73 let mut headers = HeaderMap::new();
74
75 headers.insert(USER_AGENT, HeaderValue::from_static(self.user_agent));
76 headers.insert(
77 ACCEPT,
78 HeaderValue::from_static(
79 "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
80 ),
81 );
82 headers.insert(ACCEPT_LANGUAGE, HeaderValue::from_static("en-US,en;q=0.9"));
83 headers.insert(
84 ACCEPT_ENCODING,
85 HeaderValue::from_static("gzip, deflate, br"),
86 );
87 headers.insert(UPGRADE_INSECURE_REQUESTS, HeaderValue::from_static("1"));
88 headers.insert(DNT, HeaderValue::from_static("1"));
89
90 match self.profile {
91 DeviceProfile::ChromeWindows => {
92 headers.insert(
93 "sec-ch-ua",
94 HeaderValue::from_static(
95 "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
96 ),
97 );
98 headers.insert("sec-ch-ua-mobile", HeaderValue::from_static("?0"));
99 headers.insert(
100 "sec-ch-ua-platform",
101 HeaderValue::from_static("\"Windows\""),
102 );
103 headers.insert("sec-fetch-dest", HeaderValue::from_static("document"));
104 headers.insert("sec-fetch-mode", HeaderValue::from_static("navigate"));
105 headers.insert("sec-fetch-site", HeaderValue::from_static("none"));
106 headers.insert("sec-fetch-user", HeaderValue::from_static("?1"));
107 }
108 DeviceProfile::ChromeLinux => {
109 headers.insert(
110 "sec-ch-ua",
111 HeaderValue::from_static(
112 "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
113 ),
114 );
115 headers.insert("sec-ch-ua-mobile", HeaderValue::from_static("?0"));
116 headers.insert("sec-ch-ua-platform", HeaderValue::from_static("\"Linux\""));
117 headers.insert("sec-fetch-dest", HeaderValue::from_static("document"));
118 headers.insert("sec-fetch-mode", HeaderValue::from_static("navigate"));
119 headers.insert("sec-fetch-site", HeaderValue::from_static("none"));
120 headers.insert("sec-fetch-user", HeaderValue::from_static("?1"));
121 }
122 DeviceProfile::ChromeAndroid => {
123 headers.insert(
124 "sec-ch-ua",
125 HeaderValue::from_static(
126 "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
127 ),
128 );
129 headers.insert("sec-ch-ua-mobile", HeaderValue::from_static("?1"));
130 headers.insert(
131 "sec-ch-ua-platform",
132 HeaderValue::from_static("\"Android\""),
133 );
134 headers.insert("sec-fetch-dest", HeaderValue::from_static("document"));
135 headers.insert("sec-fetch-mode", HeaderValue::from_static("navigate"));
136 headers.insert("sec-fetch-site", HeaderValue::from_static("none"));
137 headers.insert("sec-fetch-user", HeaderValue::from_static("?1"));
138 }
139 DeviceProfile::SafariMac | DeviceProfile::SafariIos => {
140 }
142 }
143
144 headers
145 }
146}