decrypt_cookies/firefox/
mod.rs1pub mod builder;
2pub mod items;
3
4use std::{
5 fmt::Display,
6 future::Future,
7 marker::{PhantomData, Sync},
8};
9
10use chrono::Utc;
11use rayon::prelude::{IntoParallelIterator, ParallelIterator};
12use sea_orm::{prelude::ColumnTrait, sea_query::IntoCondition, DbErr};
13use snafu::{Location, ResultExt, Snafu};
14
15pub use self::items::cookie::{
16 entities::moz_cookies::{Column as MozCookiesCol, ColumnIter as MozCookiesColIter},
17 MozCookie,
18};
19use self::items::{cookie::dao::CookiesQuery, I64ToMozTime};
20use crate::browser::{cookies::LeetCodeCookies, FirefoxPath};
21
22#[derive(Debug)]
23#[derive(Snafu)]
24#[snafu(visibility(pub))]
25pub enum FirefoxError {
26 #[snafu(display("{source}\n@:{location}"))]
27 Db {
28 source: DbErr,
29 #[snafu(implicit)]
30 location: Location,
31 },
32}
33
34type Result<T> = std::result::Result<T, FirefoxError>;
35
36#[derive(Clone)]
37#[derive(Debug)]
38#[derive(Default)]
39pub struct FirefoxGetter<T> {
40 pub(crate) cookies_query: CookiesQuery,
41 pub(crate) __browser: PhantomData<T>,
42}
43
44#[derive(Clone)]
45#[derive(Debug)]
46#[derive(Default)]
47pub struct FirefoxCookieGetter<T> {
48 pub(crate) cookies_query: CookiesQuery,
49 pub(crate) __browser: PhantomData<T>,
50}
51
52macro_rules! impl_display {
53 ($($s:ident),* $(,)?) => {
54 $(
55 impl<B: FirefoxPath> Display for $s<B> {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 f.write_str(B::NAME)
58 }
59 }
60 )*
61 };
62}
63impl_display![FirefoxGetter, FirefoxCookieGetter,];
64
65impl<B> SealedCookies for FirefoxGetter<B> {
66 fn cookies_query(&self) -> &CookiesQuery {
67 &self.cookies_query
68 }
69}
70impl<B> SealedCookies for FirefoxCookieGetter<B> {
71 fn cookies_query(&self) -> &CookiesQuery {
72 &self.cookies_query
73 }
74}
75impl<B> GetCookies for FirefoxGetter<B> {}
76impl<B> GetCookies for FirefoxCookieGetter<B> {}
77
78trait SealedCookies {
79 fn cookies_query(&self) -> &CookiesQuery;
80}
81
82#[expect(private_bounds, reason = "impl details")]
83pub trait GetCookies: SealedCookies {
84 fn cookies_filter<F>(&self, filter: F) -> impl Future<Output = Result<Vec<MozCookie>>> + Send
104 where
105 F: IntoCondition + Send,
106 Self: Sync,
107 {
108 async {
109 let res = self
110 .cookies_query()
111 .query_cookie_filter(filter)
112 .await
113 .context(DbSnafu)?;
114 let res = res
115 .into_par_iter()
116 .map(MozCookie::from)
117 .collect();
118 Ok(res)
119 }
120 }
121
122 fn cookies_all(&self) -> impl Future<Output = Result<Vec<MozCookie>>> + Send
123 where
124 Self: Sync,
125 {
126 async {
127 let res = self
128 .cookies_query()
129 .query_all_cookie()
130 .await
131 .context(DbSnafu)?;
132 let res = res
133 .into_par_iter()
134 .map(MozCookie::from)
135 .collect();
136 Ok(res)
137 }
138 }
139
140 #[doc(alias = "cookies_by_domain", alias = "cookies_by_url")]
142 fn cookies_by_host<H>(&self, host: H) -> impl Future<Output = Result<Vec<MozCookie>>> + Send
143 where
144 Self: Sync,
145 H: AsRef<str> + Send + Sync,
146 {
147 async move {
148 let res = self
149 .cookies_query()
150 .query_cookie_by_host(host.as_ref())
151 .await
152 .context(DbSnafu)?;
153 let res = res
154 .into_par_iter()
155 .map(MozCookie::from)
156 .collect();
157 Ok(res)
158 }
159 }
160
161 fn get_session_csrf<H>(&self, host: H) -> impl Future<Output = Result<LeetCodeCookies>> + Send
163 where
164 Self: Sync,
165 H: AsRef<str> + Send + Sync,
166 {
167 async move {
168 let cookies = self
169 .cookies_query()
170 .query_cookie_filter(
171 MozCookiesCol::Host
172 .contains(host.as_ref())
173 .and(
174 MozCookiesCol::Name
175 .eq("csrftoken")
176 .or(MozCookiesCol::Name.eq("LEETCODE_SESSION")),
177 ),
178 )
179 .await
180 .context(DbSnafu)?;
181
182 let mut res = LeetCodeCookies::default();
183
184 for cookie in cookies {
185 if let Some(s) = cookie.name {
186 if s == "csrftoken" {
187 let expir = cookie
188 .expiry
189 .unwrap_or_default()
190 .secs_to_moz_utc();
191 if let Some(expir) = expir {
192 if Utc::now() > expir {
193 res.expiry = true;
194 break;
195 }
196 }
197
198 res.csrf = cookie.value.unwrap_or_default();
199 }
200 else if s == "LEETCODE_SESSION" {
201 let expir = cookie
202 .expiry
203 .unwrap_or_default()
204 .secs_to_moz_utc();
205 if let Some(expir) = expir {
206 if Utc::now() > expir {
207 res.expiry = true;
208 break;
209 }
210 }
211
212 res.session = cookie.value.unwrap_or_default();
213 }
214 }
215 }
216 Ok(res)
217 }
218 }
219}