1use crate::error::IdentityError;
16use crate::identity::{Browser, Gpu, Identity, NavigatorPlatform, Os, PlatformInfo, ScreenResolution};
17
18fn win_platform(ver: &str) -> PlatformInfo {
23 PlatformInfo {
24 bitness: Some("64".into()),
25 architecture: Some("x86".into()),
26 navigator_platform: NavigatorPlatform::Win32,
27 version: ver.into(),
28 }
29}
30
31fn mac_platform(ver: &str) -> PlatformInfo {
32 PlatformInfo {
33 bitness: Some("64".into()),
34 architecture: Some("arm".into()),
35 navigator_platform: NavigatorPlatform::MacIntel,
36 version: ver.into(),
37 }
38}
39
40fn lin_platform(ver: &str) -> PlatformInfo {
41 PlatformInfo {
42 bitness: Some("64".into()),
43 architecture: Some("x86".into()),
44 navigator_platform: NavigatorPlatform::LinuxX86_64,
45 version: ver.into(),
46 }
47}
48
49fn screen(lw: u16, lh: u16, ow: u16, oh: u16, dpr: f32) -> ScreenResolution {
50 ScreenResolution {
51 logical_width: lw,
52 logical_height: lh,
53 original_width: ow,
54 original_height: oh,
55 density_pixel_ratio: dpr,
56 }
57}
58
59fn nvidia_gpu(model: &str) -> Gpu {
60 Gpu {
61 vendor: "NVIDIA Corporation".into(),
62 webgl_renderer: format!("ANGLE (NVIDIA {} Direct3D11 vs_5_0 ps_5_0)", model),
63 webgl_vendor: "Google Inc. (NVIDIA)".into(),
64 }
65}
66
67fn intel_gpu(model: &str) -> Gpu {
68 Gpu {
69 vendor: "Intel Inc.".into(),
70 webgl_renderer: format!("ANGLE (Intel, {} Direct3D11 vs_5_0 ps_5_0)", model),
71 webgl_vendor: "Google Inc. (Intel)".into(),
72 }
73}
74
75fn apple_gpu(model: &str) -> Gpu {
76 Gpu {
77 vendor: "Apple".into(),
78 webgl_renderer: model.into(),
79 webgl_vendor: "Apple".into(),
80 }
81}
82
83fn amd_gpu(model: &str) -> Gpu {
84 Gpu {
85 vendor: "Advanced Micro Devices, Inc.".into(),
86 webgl_renderer: format!("ANGLE (AMD, {} Direct3D11 vs_5_0 ps_5_0)", model),
87 webgl_vendor: "Google Inc. (AMD)".into(),
88 }
89}
90
91fn all() -> [Identity; 10] {
96 [
97 Identity {
99 id: Some(1),
100 device_model: None,
101 has_battery: false,
102 has_mouse: true,
103 has_touch: false,
104 os: Os::Windows,
105 os_version: "15.0.0".into(),
106 platform: win_platform("15.0.0"),
107 browser: Browser::Chrome,
108 browser_version: vec![124, 0, 6367, 78],
109 screen: screen(1920, 1080, 1920, 1080, 1.0),
110 hardware_concurrency: 16,
111 memory: 16,
112 gpu: nvidia_gpu("GeForce RTX 3080"),
113 language: vec!["en-US".into(), "en".into()],
114 history_count: Some(12),
115 proxy: None,
116 timezone: None
117 },
118 Identity {
120 id: Some(2),
121 device_model: None,
122 has_battery: false,
123 has_mouse: true,
124 has_touch: false,
125 os: Os::Windows,
126 os_version: "10.0.0".into(),
127 platform: win_platform("10.0.0"),
128 browser: Browser::Edge,
129 browser_version: vec![123, 0, 2420, 65],
130 screen: screen(1366, 768, 1366, 768, 1.0),
131 hardware_concurrency: 8,
132 memory: 8,
133 gpu: intel_gpu("Intel(R) UHD Graphics 630"),
134 language: vec!["en-US".into(), "en".into()],
135 history_count: Some(5),
136 proxy: None,
137 timezone: None
138 },
139 Identity {
141 id: Some(3),
142 device_model: None,
143 has_battery: true,
144 has_mouse: true,
145 has_touch: false,
146 os: Os::Macintosh,
147 os_version: "13.4.1".into(),
148 platform: mac_platform("13.4.1"),
149 browser: Browser::Safari,
150 browser_version: vec![17, 0, 0, 0],
151 screen: screen(2560, 1600, 2560, 1600, 2.0),
152 hardware_concurrency: 10,
153 memory: 16,
154 gpu: apple_gpu("Apple M2"),
155 language: vec!["en-GB".into(), "en".into()],
156 history_count: Some(20),
157 proxy: None,
158 timezone: None
159 },
160 Identity {
162 id: Some(4),
163 device_model: None,
164 has_battery: true,
165 has_mouse: true,
166 has_touch: false,
167 os: Os::Macintosh,
168 os_version: "12.6.0".into(),
169 platform: mac_platform("12.6.0"),
170 browser: Browser::Chrome,
171 browser_version: vec![124, 0, 6367, 82],
172 screen: screen(1440, 900, 2880, 1800, 2.0),
173 hardware_concurrency: 8,
174 memory: 8,
175 gpu: apple_gpu("Apple M1"),
176 language: vec!["en-US".into(), "en".into()],
177 history_count: Some(7),
178 proxy: None,
179 timezone: None
180 },
181 Identity {
183 id: Some(5),
184 device_model: None,
185 has_battery: false,
186 has_mouse: true,
187 has_touch: false,
188 os: Os::Linux,
189 os_version: "22.04".into(),
190 platform: lin_platform("22.04"),
191 browser: Browser::Chrome,
192 browser_version: vec![124, 0, 6367, 79],
193 screen: screen(1920, 1080, 1920, 1080, 1.0),
194 hardware_concurrency: 12,
195 memory: 16,
196 gpu: nvidia_gpu("GeForce GTX 1650"),
197 language: vec!["en-US".into(), "en".into()],
198 history_count: Some(3),
199 proxy: None,
200 timezone: None
201 },
202 Identity {
204 id: Some(6),
205 device_model: Some("Pixel 7".into()),
206 has_battery: true,
207 has_mouse: false,
208 has_touch: true,
209 os: Os::Android,
210 os_version: "13".into(),
211 platform: PlatformInfo {
212 bitness: None,
213 architecture: None,
214 navigator_platform: NavigatorPlatform::LinuxArmV81,
215 version: "13".into(),
216 },
217 browser: Browser::Chrome,
218 browser_version: vec![124, 0, 6367, 82],
219 screen: screen(412, 915, 1080, 2400, 2.625),
220 hardware_concurrency: 8,
221 memory: 8,
222 gpu: Gpu {
223 vendor: "Qualcomm".into(),
224 webgl_renderer: "Adreno (TM) 730".into(),
225 webgl_vendor: "Qualcomm".into(),
226 },
227 language: vec!["en-US".into(), "en".into()],
228 history_count: Some(2),
229 proxy: None,
230 timezone: None
231 },
232 Identity {
234 id: Some(7),
235 device_model: Some("iPhone 15".into()),
236 has_battery: true,
237 has_mouse: false,
238 has_touch: true,
239 os: Os::Ios,
240 os_version: "17.0".into(),
241 platform: PlatformInfo {
242 bitness: None,
243 architecture: None,
244 navigator_platform: NavigatorPlatform::IPhone,
245 version: "17.0".into(),
246 },
247 browser: Browser::Safari,
248 browser_version: vec![17, 0, 0, 0],
249 screen: screen(393, 852, 1179, 2556, 3.0),
250 hardware_concurrency: 6,
251 memory: 6,
252 gpu: apple_gpu("Apple A16 GPU"),
253 language: vec!["en-US".into(), "en".into()],
254 history_count: Some(4),
255 proxy: None,
256 timezone: None
257 },
258 Identity {
260 id: Some(8),
261 device_model: None,
262 has_battery: true,
263 has_mouse: true,
264 has_touch: true,
265 os: Os::Windows,
266 os_version: "11.0.0".into(),
267 platform: win_platform("11.0.0"),
268 browser: Browser::Chrome,
269 browser_version: vec![123, 0, 6312, 122],
270 screen: screen(1920, 1200, 1920, 1200, 1.0),
271 hardware_concurrency: 8,
272 memory: 16,
273 gpu: amd_gpu("AMD Radeon RX 6600"),
274 language: vec!["fr-FR".into(), "fr".into(), "en".into()],
275 history_count: Some(9),
276 proxy: None,
277 timezone: None
278 },
279 Identity {
281 id: Some(9),
282 device_model: None,
283 has_battery: true,
284 has_mouse: true,
285 has_touch: false,
286 os: Os::Macintosh,
287 os_version: "14.2.1".into(),
288 platform: mac_platform("14.2.1"),
289 browser: Browser::Chrome,
290 browser_version: vec![124, 0, 6367, 91],
291 screen: screen(1512, 982, 3024, 1964, 2.0),
292 hardware_concurrency: 12,
293 memory: 36,
294 gpu: apple_gpu("Apple M3 Pro"),
295 language: vec!["de-DE".into(), "de".into(), "en".into()],
296 history_count: Some(15),
297 proxy: None,
298 timezone: None
299 },
300 Identity {
302 id: Some(10),
303 device_model: Some("SM-S911B".into()),
304 has_battery: true,
305 has_mouse: false,
306 has_touch: true,
307 os: Os::Android,
308 os_version: "14".into(),
309 platform: PlatformInfo {
310 bitness: None,
311 architecture: None,
312 navigator_platform: NavigatorPlatform::LinuxArmV81,
313 version: "14".into(),
314 },
315 browser: Browser::Chrome,
316 browser_version: vec![124, 0, 6367, 82],
317 screen: screen(360, 780, 1080, 2340, 3.0),
318 hardware_concurrency: 8,
319 memory: 8,
320 gpu: Gpu {
321 vendor: "Samsung".into(),
322 webgl_renderer: "Xclipse 920".into(),
323 webgl_vendor: "Samsung".into(),
324 },
325 language: vec!["en-US".into(), "en".into()],
326 history_count: Some(6),
327 proxy: None,
328 timezone: None
329 },
330 ]
331}
332
333pub fn presets() -> Vec<Identity> {
339 all().to_vec()
340}
341
342pub fn get_by_id(id: u64) -> Result<Identity, IdentityError> {
347 all()
348 .into_iter()
349 .find(|p| p.id == Some(id))
350 .ok_or(IdentityError::NotFound(id))
351}
352
353pub fn random() -> Identity {
358 let idx = entropy_index(all().len());
359 all().into_iter().nth(idx).expect("preset index in bounds")
360}
361
362fn entropy_index(len: usize) -> usize {
367 use std::time::{SystemTime, UNIX_EPOCH};
368 let nanos = SystemTime::now()
369 .duration_since(UNIX_EPOCH)
370 .map(|d| d.subsec_nanos())
371 .unwrap_or(42);
372 (nanos as usize) % len
373}