Skip to main content

modo/auth/session/
device.rs

1//! User-agent parsing helpers for device classification.
2
3/// Derive a human-readable device name from the `User-Agent` string.
4///
5/// Returns a string such as `"Chrome on macOS"` or `"Safari on iPhone"`.
6pub fn parse_device_name(user_agent: &str) -> String {
7    let browser = parse_browser(user_agent);
8    let os = parse_os(user_agent);
9    format!("{browser} on {os}")
10}
11
12/// Classify the device type from the `User-Agent` string.
13///
14/// Returns one of `"tablet"`, `"mobile"`, or `"desktop"`.
15pub fn parse_device_type(user_agent: &str) -> String {
16    let ua = user_agent.to_lowercase();
17    if ua.contains("tablet") || ua.contains("ipad") {
18        "tablet".to_string()
19    } else if ua.contains("mobile")
20        || ua.contains("iphone")
21        || (ua.contains("android") && !ua.contains("tablet"))
22    {
23        "mobile".to_string()
24    } else {
25        "desktop".to_string()
26    }
27}
28
29fn parse_browser(ua: &str) -> &str {
30    if ua.contains("OPR/") || ua.contains("Opera") {
31        "Opera"
32    } else if ua.contains("Edg/") {
33        "Edge"
34    } else if ua.contains("Firefox/") {
35        "Firefox"
36    } else if ua.contains("Chromium/") {
37        "Chromium"
38    } else if ua.contains("Chrome/") {
39        "Chrome"
40    } else if ua.contains("Safari/") {
41        "Safari"
42    } else {
43        "Unknown"
44    }
45}
46
47fn parse_os(ua: &str) -> &str {
48    if ua.contains("iPhone") {
49        "iPhone"
50    } else if ua.contains("iPad") {
51        "iPad"
52    } else if ua.contains("HarmonyOS") {
53        "HarmonyOS"
54    } else if ua.contains("Android") {
55        "Android"
56    } else if ua.contains("CrOS") {
57        "ChromeOS"
58    } else if ua.contains("Mac OS X") || ua.contains("Macintosh") || ua.contains("OS X") {
59        "macOS"
60    } else if ua.contains("Windows") {
61        "Windows"
62    } else if ua.contains("FreeBSD") {
63        "FreeBSD"
64    } else if ua.contains("OpenBSD") {
65        "OpenBSD"
66    } else if ua.contains("Linux") {
67        "Linux"
68    } else {
69        "Unknown"
70    }
71}