decrypt_cookies/chromium/
mod.rs1pub mod builder;
2pub(crate) mod items;
3use std::marker::PhantomData;
4
5use chromium_crypto::Decrypter;
6use chrono::prelude::Utc;
7use items::cookie::cookie_entities::cookies;
8pub use items::{
9 cookie::{
10 cookie_entities::cookies::{
11 Column as ChromiumCookieCol, ColumnIter as ChromiumCookieColIter,
12 },
13 ChromiumCookie,
14 },
15 passwd::{
16 login_data_entities::logins::{Column as ChromiumLoginCol, Column as ChromiumLoginColIter},
17 LoginData,
18 },
19};
20use rayon::prelude::*;
21use sea_orm::{sea_query::IntoCondition, ColumnTrait, DbErr};
22use tokio::task::{self, JoinError};
23
24use crate::{
25 browser::cookies::LeetCodeCookies,
26 chromium::items::{
27 cookie::cookie_dao::CookiesQuery,
28 passwd::{login_data_dao::LoginDataQuery, login_data_entities::logins},
29 I64ToChromiumDateTime,
30 },
31};
32
33#[derive(Debug)]
34#[derive(thiserror::Error)]
35pub enum ChromiumError {
36 #[error(transparent)]
37 Task(#[from] JoinError),
38 #[error(transparent)]
39 Db(#[from] DbErr),
40 #[error(transparent)]
41 Decrypt(#[from] chromium_crypto::error::CryptoError),
42}
43
44type Result<T> = std::result::Result<T, ChromiumError>;
45
46#[derive(Clone)]
60#[derive(Debug)]
61#[derive(Default)]
62pub struct ChromiumGetter<T> {
63 pub(crate) cookies_query: CookiesQuery,
64 pub(crate) login_data_query: LoginDataQuery,
65 pub(crate) login_data_for_account_query: Option<LoginDataQuery>,
66 pub(crate) crypto: Decrypter,
67 pub(crate) __browser: PhantomData<T>,
68}
69
70impl<T: Send + Sync> ChromiumGetter<T> {
71 async fn par_decrypt_logins(&self, raw: Vec<logins::Model>) -> Result<Vec<LoginData>> {
72 let crypto = self.crypto.clone();
73
74 let login_data = task::spawn_blocking(move || {
75 raw.into_par_iter()
76 .map(|mut v| {
77 let res = v
78 .password_value
79 .as_mut()
80 .map_or_else(String::new, |passwd| {
81 crypto
82 .decrypt(passwd)
83 .unwrap_or_default()
84 });
85 let mut cookies = LoginData::from(v);
86 cookies.set_password_value(res);
87 cookies
88 })
89 .collect()
90 })
91 .await;
92 Ok(login_data?)
93 }
94 pub async fn logins_filter<F>(&self, filter: F) -> Result<Vec<LoginData>>
115 where
116 F: IntoCondition + Send + Clone,
117 {
118 let mut raw_login = self
119 .login_data_query
120 .query_login_dt_filter(filter.clone())
121 .await?;
122 if raw_login.is_empty() {
123 if let Some(query) = &self.login_data_for_account_query {
124 raw_login = query
125 .query_login_dt_filter(filter)
126 .await?;
127 }
128 }
129 self.par_decrypt_logins(raw_login)
130 .await
131 }
132 pub async fn logins_by_host<F>(&self, host: F) -> Result<Vec<LoginData>>
133 where
134 F: AsRef<str> + Send,
135 {
136 let mut raw_login = self
137 .login_data_query
138 .query_login_dt_filter(ChromiumLoginCol::OriginUrl.contains(host.as_ref()))
139 .await?;
140 if raw_login.is_empty() {
141 if let Some(query) = &self.login_data_for_account_query {
142 raw_login = query
143 .query_login_dt_filter(ChromiumLoginCol::OriginUrl.contains(host.as_ref()))
144 .await?;
145 }
146 }
147 self.par_decrypt_logins(raw_login)
148 .await
149 }
150 pub async fn all_logins(&self) -> Result<Vec<LoginData>> {
152 let mut raw_login = self
153 .login_data_query
154 .query_all_login_dt()
155 .await?;
156 if raw_login.is_empty() {
157 if let Some(query) = &self.login_data_for_account_query {
158 raw_login = query.query_all_login_dt().await?;
159 }
160 }
161 self.par_decrypt_logins(raw_login)
162 .await
163 }
164}
165
166impl<T: Send + Sync> ChromiumGetter<T> {
167 pub async fn cookies_filter<F>(&self, filter: F) -> Result<Vec<ChromiumCookie>>
188 where
189 F: IntoCondition + Send,
190 {
191 let raw_ck = self
192 .cookies_query
193 .cookie_filter(filter)
194 .await?;
195 self.par_decrypt_ck(raw_ck).await
196 }
197 pub async fn cookies_by_host<A: AsRef<str> + Send>(
199 &self,
200 host: A,
201 ) -> Result<Vec<ChromiumCookie>> {
202 let raw_ck = self
203 .cookies_query
204 .cookie_by_host(host.as_ref())
205 .await?;
206 self.par_decrypt_ck(raw_ck).await
207 }
208
209 pub async fn all_cookies(&self) -> Result<Vec<ChromiumCookie>> {
211 let raw_ck = self
212 .cookies_query
213 .all_cookie()
214 .await?;
215 self.par_decrypt_ck(raw_ck).await
216 }
217
218 async fn par_decrypt_ck(&self, raw: Vec<cookies::Model>) -> Result<Vec<ChromiumCookie>> {
221 let crypto = self.crypto.clone();
222
223 let decrypted_ck = task::spawn_blocking(move || {
224 raw.into_par_iter()
225 .map(|mut v| {
226 let res = crypto
227 .decrypt(&mut v.encrypted_value)
228 .unwrap_or_default();
229 let mut cookies = ChromiumCookie::from(v);
230 cookies.set_encrypted_value(res);
231 cookies
232 })
233 .collect()
234 })
235 .await?;
236 Ok(decrypted_ck)
237 }
238
239 pub async fn get_session_csrf<A: AsRef<str> + Send>(&self, host: A) -> Result<LeetCodeCookies> {
241 let cookies = self
242 .cookies_query
243 .cookie_filter(
244 ChromiumCookieCol::HostKey
245 .contains(host.as_ref())
246 .and(
247 ChromiumCookieCol::Name
248 .eq("csrftoken")
249 .or(ChromiumCookieCol::Name.eq("LEETCODE_SESSION")),
250 ),
251 )
252 .await?;
253
254 let mut csrf_token = LeetCodeCookies::default();
255 let mut hds = Vec::with_capacity(2);
256
257 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
258 enum CsrfSession {
259 Csrf,
260 Session,
261 }
262 for mut cookie in cookies {
263 if cookie.name == "csrftoken" {
264 let expir = cookie
265 .expires_utc
266 .micros_to_chromium_utc();
267 if let Some(expir) = expir {
268 if Utc::now() > expir {
269 csrf_token.expiry = true;
270 break;
271 }
272 }
273
274 let cy = self.crypto.clone();
275 let csrf_hd =
276 task::spawn_blocking(move || match cy.decrypt(&mut cookie.encrypted_value) {
277 Ok(it) => it,
278 Err(err) => {
279 tracing::warn!("decrypt csrf failed: {err}");
280 String::new()
281 },
282 });
283 hds.push((csrf_hd, CsrfSession::Csrf));
284 }
285 else if cookie.name == "LEETCODE_SESSION" {
286 let expir = cookie
287 .expires_utc
288 .micros_to_chromium_utc();
289 if let Some(expir) = expir {
290 if Utc::now() > expir {
291 csrf_token.expiry = true;
292 break;
293 }
294 }
295
296 let cy = self.crypto.clone();
297 let session_hd =
298 task::spawn_blocking(move || match cy.decrypt(&mut cookie.encrypted_value) {
299 Ok(it) => it,
300 Err(err) => {
301 tracing::warn!("decrypt session failed: {err}");
302 String::new()
303 },
304 });
305 hds.push((session_hd, CsrfSession::Session));
306 }
307 }
308 for (handle, flag) in hds {
309 let res = handle.await?;
310 match flag {
311 CsrfSession::Csrf => csrf_token.csrf = res,
312 CsrfSession::Session => csrf_token.session = res,
313 }
314 }
315 Ok(csrf_token)
316 }
317}
318
319impl<T> ChromiumGetter<T> {
320 pub fn decrypt(&self, ciphertext: &mut [u8]) -> Result<String> {
322 Ok(self.crypto.decrypt(ciphertext)?)
323 }
324}