Skip to main content

seher/crypto/
mod.rs

1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum CryptoError {
5    #[error("Failed to decrypt: {0}")]
6    DecryptionFailed(String),
7
8    #[error("Unsupported encryption version: {0}")]
9    UnsupportedVersion(String),
10
11    #[cfg(target_os = "macos")]
12    #[error("Keychain error: {0}")]
13    KeychainError(String),
14
15    #[cfg(target_os = "linux")]
16    #[error("Secret service error: {0}")]
17    SecretServiceError(String),
18
19    #[cfg(target_os = "windows")]
20    #[error("DPAPI error: {0}")]
21    DpapiError(String),
22}
23
24pub type Result<T> = std::result::Result<T, CryptoError>;
25
26#[cfg(target_os = "macos")]
27pub mod macos;
28
29#[cfg(target_os = "linux")]
30pub mod linux;
31
32#[cfg(target_os = "windows")]
33pub mod windows;
34
35pub fn decrypt_cookie_value(encrypted_value: &[u8]) -> Result<String> {
36    if encrypted_value.is_empty() {
37        return Ok(String::new());
38    }
39
40    #[cfg(target_os = "macos")]
41    let value = macos::decrypt(encrypted_value)?;
42
43    #[cfg(target_os = "linux")]
44    let value = linux::decrypt(encrypted_value)?;
45
46    #[cfg(target_os = "windows")]
47    let value = windows::decrypt(encrypted_value)?;
48
49    #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
50    return Err(CryptoError::UnsupportedVersion(
51        "Unsupported OS".to_string(),
52    ));
53
54    Ok(strip_chrome_value_prefix(&value))
55}
56
57/// Strip Chrome's cookie value format prefix (Chrome 130+).
58///
59/// Chrome stores cookie values with a prefix indicating the format:
60/// - `[digit]t` prefix: plaintext value (e.g. "0tyes" → "yes")
61/// - `[digit]e`` prefix: encoded value (e.g. "1e`token" → "token")
62fn strip_chrome_value_prefix(value: &str) -> String {
63    let bytes = value.as_bytes();
64    if bytes.len() >= 2 && bytes[0].is_ascii_digit() {
65        if bytes[1] == b't' {
66            return value[2..].to_string();
67        }
68        if bytes[1] == b'e' && bytes.len() >= 3 && bytes[2] == b'`' {
69            return value[3..].to_string();
70        }
71    }
72    value.to_string()
73}