tidy_browser/
firefox.rs

1use std::{collections::HashSet, fmt::Display, path::PathBuf};
2
3use decrypt_cookies::prelude::*;
4use snafu::ResultExt;
5use strum::IntoEnumIterator;
6use tokio::task;
7
8use crate::{
9    args::{FirefoxName, Value},
10    error::{self, Result},
11    utils::{self},
12};
13
14#[derive(Clone, Copy)]
15#[derive(Debug)]
16#[derive(Default)]
17#[derive(PartialEq, Eq, PartialOrd, Ord)]
18pub struct FirefoxBased;
19
20impl FirefoxBased {
21    pub async fn multi_data<H>(
22        names: impl Iterator<Item = FirefoxName>,
23        output_dir: PathBuf,
24        sep: String,
25        host: H,
26    ) -> Result<()>
27    where
28        H: Into<Option<String>>,
29    {
30        let host = host.into();
31        for task in names.map(|name| {
32            let host = host.clone();
33            let output_dir = output_dir.clone();
34            let sep = sep.clone();
35            let values = HashSet::from_iter(Value::iter());
36
37            tokio::task::spawn(async move {
38                Self::write_data(name, None, None, None, host, values, output_dir, sep).await
39            })
40        }) {
41            task.await
42                .context(error::TokioTaskSnafu)??;
43        }
44
45        Ok(())
46    }
47
48    #[expect(clippy::too_many_arguments, reason = "bin not lib")]
49    pub async fn write_data<B, P, PP, H, S>(
50        name: FirefoxName,
51        base: B,
52        profile: P,
53        profile_path: PP,
54        host: H,
55        values: HashSet<Value>,
56        mut output_dir: PathBuf,
57        sep: S,
58    ) -> Result<()>
59    where
60        B: Into<Option<PathBuf>>,
61        P: Into<Option<String>>,
62        PP: Into<Option<PathBuf>>,
63        H: Into<Option<String>>,
64        S: Display + Send + Clone + 'static,
65    {
66        let base: Option<PathBuf> = base.into();
67        let profile: Option<String> = profile.into();
68        let profile_path: Option<PathBuf> = profile_path.into();
69        let host: Option<String> = host.into();
70
71        macro_rules! firefoxes {
72            ($($browser:ident,) *) => {
73                match name {
74                    $(
75                        FirefoxName::$browser => {
76                            let firefox = if let Some(pp) = profile_path {
77                                FirefoxBuilder::<$browser>::with_profile_path(pp)
78                            }
79                            else {
80                                let mut builder = FirefoxBuilder::<$browser>::new();
81                                if let Some(base) = base {
82                                    builder.base(base);
83                                }
84                                if let Some(profile) = &profile {
85                                    builder.profile(profile);
86                                }
87                                builder
88                            }
89                            .build()
90                                .await
91                                .context(error::FirefoxBuilderSnafu)?;
92
93                            let task = if values.contains(&Value::Cookie) {
94                                let host = host.clone();
95                                let firefox = firefox.clone();
96                                let task = task::spawn(async move {
97                                    let cookies = if let Some(host) = host {
98                                        firefox.cookies_by_host(host).await
99                                    }
100                                    else {
101                                        firefox.cookies_all().await
102                                    }
103                                    .context(error::FirefoxSnafu)?;
104                                    Ok::<_, error::Error>(cookies)
105                                });
106                                Some(task)
107                            }
108                            else {
109                                None
110                            };
111
112                            if values.contains(&Value::Login) {
113                                // TODO:
114                            }
115                            (task, $browser::NAME)
116                        },
117                    )*
118                }
119            };
120        }
121
122        let (ff, name) = firefoxes![Firefox, Librewolf, Floorp,];
123
124        output_dir.push(name);
125        tokio::fs::create_dir_all(&output_dir)
126            .await
127            .context(error::IoSnafu { path: output_dir.clone() })?;
128
129        if let Some(ff) = ff {
130            let cookies = ff
131                .await
132                .context(error::TokioTaskSnafu)??;
133            let out_file = output_dir.join(crate::COOKIES_FILE);
134            let sep = sep.clone();
135
136            utils::write_cookies(out_file, cookies, sep)
137                .await
138                .context(error::TokioTaskSnafu)??;
139        }
140
141        Ok(())
142    }
143}