Skip to main content

seher/browser/
types.rs

1use std::path::PathBuf;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum BrowserType {
5    Chrome,
6    Edge,
7    Brave,
8    Chromium,
9    Vivaldi,
10    Comet,
11    Dia,
12    Atlas,
13    Firefox,
14    Safari,
15}
16
17impl BrowserType {
18    #[must_use]
19    pub fn name(&self) -> &str {
20        match self {
21            BrowserType::Chrome => "Chrome",
22            BrowserType::Edge => "Edge",
23            BrowserType::Brave => "Brave",
24            BrowserType::Chromium => "Chromium",
25            BrowserType::Vivaldi => "Vivaldi",
26            BrowserType::Comet => "Comet",
27            BrowserType::Dia => "Dia",
28            BrowserType::Atlas => "Atlas",
29            BrowserType::Firefox => "Firefox",
30            BrowserType::Safari => "Safari",
31        }
32    }
33
34    #[must_use]
35    pub fn is_chromium_based(&self) -> bool {
36        matches!(
37            self,
38            BrowserType::Chrome
39                | BrowserType::Edge
40                | BrowserType::Brave
41                | BrowserType::Chromium
42                | BrowserType::Vivaldi
43                | BrowserType::Comet
44                | BrowserType::Dia
45                | BrowserType::Atlas
46        )
47    }
48}
49
50impl std::str::FromStr for BrowserType {
51    type Err = String;
52    fn from_str(s: &str) -> Result<Self, Self::Err> {
53        match s.to_lowercase().as_str() {
54            "chrome" => Ok(BrowserType::Chrome),
55            "edge" => Ok(BrowserType::Edge),
56            "brave" => Ok(BrowserType::Brave),
57            "chromium" => Ok(BrowserType::Chromium),
58            "vivaldi" => Ok(BrowserType::Vivaldi),
59            "comet" => Ok(BrowserType::Comet),
60            "dia" => Ok(BrowserType::Dia),
61            "atlas" => Ok(BrowserType::Atlas),
62            "firefox" => Ok(BrowserType::Firefox),
63            "safari" => Ok(BrowserType::Safari),
64            other => Err(format!("Unknown browser: {other}")),
65        }
66    }
67}
68
69#[derive(Debug, Clone)]
70pub struct Profile {
71    pub name: String,
72    pub path: PathBuf,
73    pub browser_type: BrowserType,
74}
75
76impl Profile {
77    #[must_use]
78    pub fn new(name: String, path: PathBuf, browser_type: BrowserType) -> Self {
79        Self {
80            name,
81            path,
82            browser_type,
83        }
84    }
85
86    #[must_use]
87    pub fn cookies_path(&self) -> PathBuf {
88        match self.browser_type {
89            BrowserType::Firefox => self.path.join("cookies.sqlite"),
90            BrowserType::Safari => self.path.clone(),
91            _ => self.path.join("Cookies"),
92        }
93    }
94
95    #[must_use]
96    pub fn local_state_path(&self) -> PathBuf {
97        self.path
98            .parent()
99            .map_or_else(|| PathBuf::from("Local State"), |p| p.join("Local State"))
100    }
101}
102
103#[derive(Debug, Clone)]
104pub struct Cookie {
105    pub name: String,
106    pub value: String,
107    pub domain: String,
108    pub path: String,
109    pub expires_utc: i64,
110    pub is_secure: bool,
111    pub is_httponly: bool,
112    pub same_site: i32,
113}
114
115impl Cookie {
116    #[must_use]
117    pub fn is_expired(&self) -> bool {
118        use std::time::{SystemTime, UNIX_EPOCH};
119        let now = SystemTime::now()
120            .duration_since(UNIX_EPOCH)
121            .unwrap_or_default()
122            .as_secs()
123            .cast_signed();
124
125        // Chrome uses microseconds since Windows epoch (1601-01-01)
126        // Convert to Unix timestamp
127        let unix_timestamp = (self.expires_utc / 1_000_000) - 11_644_473_600;
128        unix_timestamp > 0 && unix_timestamp < now
129    }
130}