1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use std::{env, path::PathBuf, error::Error};
use crate::{mozilla::get_default_profile, BrowserConfig};
use glob;


fn expand_glob_paths(path: PathBuf) -> Result<Vec<PathBuf>, Box<dyn Error>> {
    let mut data_paths: Vec<PathBuf> = vec![];
    if let Some(path_str) = path.to_str() {
        for entry in glob::glob(path_str)? {
            if entry.is_ok() {
                data_paths.push(entry?);
            }
        }
    } 
    Ok(data_paths)
}

#[cfg(target_os = "windows")]
pub fn expand_path(path: &str) -> Result<PathBuf, Box<dyn std::error::Error>> {
    use regex::Regex;
    // Define a regex pattern to match placeholders like %SOMETHING%
    let re = Regex::new(r"%([^%]+)%")?;

    // Clone the input path for modification
    let mut expanded_path = path.to_owned();

    // Iterate over all matches of the regex pattern in the input path
    for capture in re.captures_iter(&path) {
        // Get the matched placeholder (e.g., "APPDATA" from "%APPDATA%")
        let placeholder = &capture[1];

        // Try to get the corresponding environment variable value
        if let Ok(var_value) = env::var(placeholder) {
            // Replace the placeholder with the environment variable value
            expanded_path = expanded_path.replace(&capture[0], &var_value);
        }
    }

    // Convert the expanded path to a PathBuf
    let path_buf = PathBuf::from(expanded_path);

    Ok(path_buf)
}

#[cfg(unix)]
pub fn expand_path(path: &str) -> Result<PathBuf, Box<dyn std::error::Error>> {
        // Get the value of the HOME environment variable
    let home = env::var("HOME")?;

    // Replace ~ or $HOME with the actual home directory path
    let expanded_path = path
        .replace("~", &home)
        .replace("$HOME", &home);

    // Convert the expanded path to a PathBuf
    Ok(PathBuf::from(expanded_path))
}


pub fn find_chrome_based_paths(browser_config: &BrowserConfig) -> Result<(PathBuf, PathBuf), Box<dyn std::error::Error>> {
    for path in browser_config.data_paths { // base paths
        let channels: &[&str] = &browser_config.channels.as_deref().unwrap_or(&[""]);
        for channel in channels { // channels
            let path = path.replace("{channel}", channel);
            let db_path = expand_path(path.as_str())?;
            let glob_db_paths = expand_glob_paths(db_path)?;
            for db_path in glob_db_paths { // glob expanded paths
                if db_path.exists() {
                    if let Some(parent) = db_path.parent() {
                    let key_path = ["../../Local State", "../Local State", "Local State"]
                        .iter()
                        .map(|p| parent.join(p))
                        .find(|p| p.exists())
                        .unwrap_or_else(|| parent.join("Local State"));
                    return Ok((key_path, db_path));
                }
            }
            }
            
        }
    }
    Err(("can't find any cookies file").into())
}



pub fn find_mozilla_based_paths(browser_config: &BrowserConfig) -> Result<PathBuf, Box<dyn std::error::Error>> {
    for path in browser_config.data_paths { // base paths
        let channels: &[&str] = &browser_config.channels.as_deref().unwrap_or(&[""]);
        for channel in channels { // channels
            let path = path.replace("{channel}", &channel);
            let firefox_path = expand_path(path.as_str())?;
            let glob_paths = expand_glob_paths(firefox_path)?;
            for path in glob_paths { // expanded glob paths
                let profiles_path = path.join("profiles.ini");
                let default_profile = get_default_profile(profiles_path.as_path()).unwrap_or("".to_string());
                let db_path = path.join(default_profile).join("cookies.sqlite");    
                if db_path.exists() {
                    return Ok(db_path);
                }
            }
        }
    }
    

    Err(("cant find any brave cookies file").into())
}


#[cfg(target_os = "macos")]
pub fn find_safari_based_paths(browser_config: &BrowserConfig) -> Result<PathBuf, Box<dyn std::error::Error>> {
    for path in browser_config.data_paths { // base paths
        let channels: &[&str] = &browser_config.channels.as_deref().unwrap_or(&[""]);
        for channel in channels { // channels
            let path = path.replace("{channel}", &channel);
            let safari_path = expand_path(path.as_str())?;
            let glob_paths = expand_glob_paths(safari_path)?;
            for path in glob_paths { // expanded glob paths
                if path.exists() {
                    return Ok(path);
                }
            }
        }
    }
    

    Err(("cant find any brave cookies file").into())
}

#[cfg(target_os = "windows")]
pub fn find_ie_based_paths(browser_config: &BrowserConfig) -> Result<PathBuf, Box<dyn std::error::Error>> {
    for path in browser_config.data_paths { // base paths
        let channels: &[&str] = &browser_config.channels.as_deref().unwrap_or(&[""]);
        for channel in channels { // channels
            
            let path = path.replace("{channel}", &channel);
            let path = expand_path(path.as_str())?;
            let glob_paths = expand_glob_paths(path)?;
            for path in glob_paths { // expanded glob paths
                if path.exists() {
                    return Ok(path);
                }
            }
        }
    }
    

    Err(("cant find any IE cookies file").into())
}