leetcode_api/leetcode/
headers.rs1use std::str::FromStr;
2
3use decrypt_cookies::{browser::cookies::LeetCodeCookies, prelude::*};
4use lcode_config::global::G_USER_CONFIG;
5use miette::{bail, IntoDiagnostic, Result};
6use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
7
8#[derive(Debug)]
12#[derive(Default)]
13#[derive(Clone)]
14#[derive(PartialEq, Eq)]
15pub struct Headers {
16 pub headers: HeaderMap,
17}
18
19impl Headers {
20 pub async fn build_default() -> Result<Self> {
21 let host = format!("{}.{}", "leetcode", G_USER_CONFIG.config.url_suffix);
22 Self::build(&host).await
23 }
24 pub async fn build(host: &str) -> Result<Self> {
25 let default_headers = HeaderMap::new();
26 let mut cookies = G_USER_CONFIG.cookies.clone();
27 if !cookies.is_completion() {
28 cookies = get_cookie_by_browser(&G_USER_CONFIG.config.browser, host)
29 .await
30 .unwrap_or_default();
31 }
32
33 if !cookies.is_completion() {
34 cookies = get_cookie(host)
35 .await
36 .unwrap_or_else(|err| {
37 tracing::warn!("{err}");
38 LeetCodeCookies::default()
39 });
40 }
41
42 let cookie = cookies.to_string();
43
44 let kv_vec: Vec<(&str, &str)> = vec![
45 ("cookie", &cookie),
46 ("x-csrftoken", &cookies.csrf),
47 ("origin", &G_USER_CONFIG.urls.origin),
48 ];
49 let default_headers = Self::mod_headers(default_headers, kv_vec)?;
50
51 Ok(Self { headers: default_headers })
52 }
53
54 pub fn mod_headers(mut headers: HeaderMap, kv_vec: Vec<(&str, &str)>) -> Result<HeaderMap> {
59 for (k, v) in kv_vec {
60 let name = HeaderName::from_str(k).into_diagnostic()?;
61 let value = HeaderValue::from_str(v).into_diagnostic()?;
62
63 headers.insert(name, value);
64 }
65 Ok(headers)
66 }
67}
68
69async fn get_cookie_by_browser(browser: &str, host: &str) -> Result<LeetCodeCookies> {
70 macro_rules! ff_ck {
71 ($ff:ident) => {
72 let Ok(builder) = FirefoxBuilder::<$ff>::new()
73 else {
74 bail!("failed")
75 };
76 let Ok(getter) = builder.build().await
77 else {
78 bail!("failed")
79 };
80 let Ok(ck) = getter.get_session_csrf(host).await
81 else {
82 bail!("failed")
83 };
84 if ck.is_completion() {
85 return Ok(ck);
86 }
87 bail!("failed")
88 };
89 }
90 macro_rules! ch_ck {
91 ($chromium:ident) => {
92 let Ok(getter) = ChromiumBuilder::<$chromium>::new()
93 .build()
94 .await
95 else {
96 bail!("failed")
97 };
98 let Ok(ck) = getter
99 .get_cookies_session_csrf(host)
100 .await
101 else {
102 bail!("failed")
103 };
104 if ck.is_completion() {
105 return Ok(ck);
106 }
107 bail!("failed")
108 };
109 }
110
111 match browser.to_lowercase().as_str() {
112 "firefox" => {
113 ff_ck!(Firefox);
114 },
115 "librewolf" => {
116 ff_ck!(Librewolf);
117 },
118 "chrome" => {
119 ch_ck!(Chrome);
120 },
121 "edge" => {
122 ch_ck!(Edge);
123 },
124 "chromium" => {
125 ch_ck!(Chromium);
126 },
127 "brave" => {
128 ch_ck!(Brave);
129 },
130 "vivaldi" => {
131 ch_ck!(Vivaldi);
132 },
133 "yandex" => {
134 ch_ck!(Yandex);
135 },
136 "opera" => {
137 ch_ck!(Opera);
138 },
139 #[cfg(not(target_os = "linux"))]
140 "operagx" => {
141 ch_ck!(OperaGX);
142 },
143 #[cfg(not(target_os = "linux"))]
144 "coccoc" => {
145 ch_ck!(CocCoc);
146 },
147 _ => {
148 bail!("failed")
149 },
150 }
151}
152
153async fn get_cookie(host: &str) -> Result<LeetCodeCookies> {
154 macro_rules! ffs {
155 ($($ff:ident), *,) => {
156 $(
157 'outer: {
158 let Ok(builder) = FirefoxBuilder::<$ff>::new()
159 else {
160 break 'outer;
161 };
162 let Ok(getter) = builder.build().await
163 else {
164 break 'outer;
165 };
166 let Ok(ck) = getter.get_session_csrf(host).await
167 else {
168 break 'outer;
169 };
170 if ck.is_completion() {
171 return Ok(ck);
172 }
173 }
174 )*
175 };
176 }
177 ffs!(Firefox, Librewolf,);
178
179 macro_rules! chromiums {
180 ($($chromium:ident), *,) => {
181 $(
182 'outer: {
183 let Ok(chromium) = ChromiumBuilder::<$chromium>::new()
184 .build()
185 .await
186 else {
187 break 'outer;
188 };
189 let Ok(ck) = chromium
190 .get_cookies_session_csrf(host)
191 .await
192 else {
193 break 'outer;
194 };
195 if ck.is_completion() {
196 return Ok(ck);
197 }
198 }
199 )*
200 };
201 }
202 chromiums!(Chrome, Edge, Chromium, Brave, Yandex, Vivaldi, Opera,);
203 #[cfg(not(target_os = "linux"))]
204 chromiums!(OperaGX, CocCoc,);
205
206 bail!("failed")
207}