rookie/common/
paths.rs

1use crate::{browser::mozilla::get_default_profile, config::Browser};
2use eyre::{anyhow, bail, Context, Result};
3use std::{env, path::PathBuf};
4
5fn expand_glob_paths(path: PathBuf) -> Result<Vec<PathBuf>> {
6  let mut paths: Vec<PathBuf> = vec![];
7  if let Some(path_str) = path.to_str() {
8    for entry in glob::glob(path_str)? {
9      if entry.is_ok() {
10        paths.push(entry?);
11      }
12    }
13  }
14  Ok(paths)
15}
16
17pub fn find_chrome_based_paths(config: &Browser) -> Result<(PathBuf, PathBuf)> {
18  for path in &config.paths {
19    // base paths
20    let channels = config.channels.clone().unwrap_or(vec!["".to_string()]);
21    for channel in channels {
22      // channels
23      let path = path.replace("{channel}", &channel);
24      let db_path = expand_path(path.as_str())?;
25      let glob_db_paths = expand_glob_paths(db_path)?;
26      for db_path in glob_db_paths {
27        // glob expanded paths
28        if db_path.exists() {
29          if let Some(parent) = db_path.parent() {
30            let key_path = ["../../Local State", "../Local State", "Local State"]
31              .iter()
32              .map(|p| parent.join(p))
33              .find(|p| p.exists())
34              .unwrap_or_else(|| parent.join("Local State"))
35              .canonicalize()
36              .context("canonicalize")?;
37            log::debug!(
38              "Found chrome path {}, {}",
39              db_path.display(),
40              key_path.display()
41            );
42            return Ok((key_path, db_path));
43          }
44        }
45      }
46    }
47  }
48  Err(anyhow!("can't find cookies file"))
49}
50
51pub fn find_mozilla_based_paths(config: &Browser) -> Result<PathBuf> {
52  for path in &config.paths {
53    // base paths
54    let channels = config.channels.clone().unwrap_or(vec!["".to_string()]);
55    for channel in channels {
56      // channels
57      let path = path.replace("{channel}", &channel);
58      let firefox_path = expand_path(path.as_str())?;
59      let glob_paths = expand_glob_paths(firefox_path)?;
60      for path in glob_paths {
61        // expanded glob paths
62        let profiles_path = path.join("profiles.ini");
63        let default_profile =
64          get_default_profile(profiles_path.as_path()).unwrap_or("".to_string());
65        let db_path = path.join(default_profile).join("cookies.sqlite");
66        if db_path.exists() {
67          log::debug!("Found mozilla path {}", db_path.display());
68          return Ok(db_path);
69        }
70      }
71    }
72  }
73
74  bail!("Can't find cookies file")
75}
76
77#[cfg(target_os = "macos")]
78pub fn find_safari_based_paths(config: &Browser) -> Result<PathBuf> {
79  for path in &config.paths {
80    // base paths
81    let channels = config.channels.clone().unwrap_or(vec!["".to_string()]);
82    for channel in channels {
83      // channels
84      let path = path.replace("{channel}", &channel);
85      let safari_path = expand_path(path.as_str())?;
86      let glob_paths = expand_glob_paths(safari_path)?;
87      for path in glob_paths {
88        // expanded glob paths
89        if path.exists() {
90          log::debug!("Found safari path {}", path.display());
91          return Ok(path);
92        }
93      }
94    }
95  }
96  bail!("Can't find cookies file")
97}
98
99#[cfg(target_os = "windows")]
100pub fn find_ie_based_paths(config: &Browser) -> Result<PathBuf> {
101  for path in &config.paths {
102    // base paths
103    let channels = config.channels.clone().unwrap_or(vec!["".to_string()]);
104    for channel in channels {
105      // channels
106
107      let path = path.replace("{channel}", &channel);
108      let path = expand_path(path.as_str())?;
109      let glob_paths = expand_glob_paths(path)?;
110      for path in glob_paths {
111        // expanded glob paths
112        if path.exists() {
113          log::debug!("Found IE path {}", path.display());
114          return Ok(path);
115        }
116      }
117    }
118  }
119
120  bail!("Can't find cookies file")
121}
122#[cfg(target_os = "windows")]
123pub fn expand_path(path: &str) -> Result<PathBuf> {
124  use regex::Regex;
125  // Define a regex pattern to match placeholders like %SOMETHING%
126  let re = Regex::new(r"%([^%]+)%")?;
127
128  // Clone the input path for modification
129  let mut expanded_path = path.to_owned();
130
131  // Iterate over all matches of the regex pattern in the input path
132  for capture in re.captures_iter(path) {
133    // Get the matched placeholder (e.g., "APPDATA" from "%APPDATA%")
134    let placeholder = &capture[1];
135
136    // Try to get the corresponding environment variable value
137    if let Ok(var_value) = env::var(placeholder) {
138      // Replace the placeholder with the environment variable value
139      expanded_path = expanded_path.replace(&capture[0], &var_value);
140    }
141  }
142
143  // Convert the expanded path to a PathBuf
144  let path_buf = PathBuf::from(expanded_path);
145
146  Ok(path_buf)
147}
148
149#[cfg(unix)]
150pub fn expand_path(path: &str) -> Result<PathBuf> {
151  // Get the value of the HOME environment variable
152  let home = env::var("HOME")?;
153
154  // Replace ~ or $HOME with the actual home directory path
155  let expanded_path = path.replace('~', &home).replace("$HOME", &home);
156
157  // Convert the expanded path to a PathBuf
158  Ok(PathBuf::from(expanded_path))
159}