mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-29 20:17:09 +00:00
fix: pass capture cookies and headers securely to metadata fetcher
- Pass captured cookies and headers from UI state into the backend `fetch_metadata` command. - Implement secure domain-matching redirect policy in the backend to prevent leaking cookies, headers, and Basic Auth credentials to third-party domains upon redirect. - Ensure metadata fetches correctly identify authenticated files (e.g. from Gofile) without being redirected to login/error pages.
This commit is contained in:
+46
-6
@@ -876,8 +876,11 @@ async fn fetch_metadata(
|
|||||||
user_agent: Option<String>,
|
user_agent: Option<String>,
|
||||||
username: Option<String>,
|
username: Option<String>,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
|
headers: Option<String>,
|
||||||
|
cookies: Option<String>,
|
||||||
) -> Result<MetadataResponse, String> {
|
) -> Result<MetadataResponse, String> {
|
||||||
let mut current_url = url.clone();
|
let mut current_url = url.clone();
|
||||||
|
let original_host = reqwest::Url::parse(&url).ok().and_then(|u| u.host_str().map(|s| s.to_string()));
|
||||||
let mut redirects = 0;
|
let mut redirects = 0;
|
||||||
let res;
|
let res;
|
||||||
|
|
||||||
@@ -904,21 +907,58 @@ async fn fetch_metadata(
|
|||||||
builder = builder.resolve(&host, addr);
|
builder = builder.resolve(&host, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let current_host = reqwest::Url::parse(¤t_url).ok().and_then(|u| u.host_str().map(|s| s.to_string()));
|
||||||
|
let mut should_send_auth = redirects == 0;
|
||||||
|
if !should_send_auth {
|
||||||
|
if let (Some(orig), Some(curr)) = (&original_host, ¤t_host) {
|
||||||
|
if curr == orig || curr.ends_with(&format!(".{}", orig)) {
|
||||||
|
should_send_auth = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut header_map = reqwest::header::HeaderMap::new();
|
||||||
|
if should_send_auth {
|
||||||
|
if let Some(ref h_str) = headers {
|
||||||
|
for line in h_str.lines() {
|
||||||
|
if let Some((k, v)) = line.split_once(':') {
|
||||||
|
if let Ok(name) = reqwest::header::HeaderName::from_bytes(k.trim().as_bytes()) {
|
||||||
|
if let Ok(value) = reqwest::header::HeaderValue::from_str(v.trim()) {
|
||||||
|
header_map.insert(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ref c_str) = cookies {
|
||||||
|
if !c_str.trim().is_empty() {
|
||||||
|
if let Ok(value) = reqwest::header::HeaderValue::from_str(c_str.trim()) {
|
||||||
|
header_map.insert(reqwest::header::COOKIE, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder = builder.default_headers(header_map);
|
||||||
|
|
||||||
let client = builder.build().map_err(|e| e.to_string())?;
|
let client = builder.build().map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
let mut head_req = client.head(¤t_url);
|
let mut head_req = client.head(¤t_url);
|
||||||
if let Some(ref user) = username {
|
if should_send_auth {
|
||||||
if !user.is_empty() {
|
if let Some(ref user) = username {
|
||||||
head_req = head_req.basic_auth(user, password.as_deref());
|
if !user.is_empty() {
|
||||||
|
head_req = head_req.basic_auth(user, password.as_deref());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut current_res = head_req.send().await.map_err(|e| e.to_string())?;
|
let mut current_res = head_req.send().await.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
if !current_res.status().is_success() && !current_res.status().is_redirection() {
|
if !current_res.status().is_success() && !current_res.status().is_redirection() {
|
||||||
let mut get_req = client.get(¤t_url);
|
let mut get_req = client.get(¤t_url);
|
||||||
if let Some(ref user) = username {
|
if should_send_auth {
|
||||||
if !user.is_empty() {
|
if let Some(ref user) = username {
|
||||||
get_req = get_req.basic_auth(user, password.as_deref());
|
if !user.is_empty() {
|
||||||
|
get_req = get_req.basic_auth(user, password.as_deref());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_res = get_req.send().await.map_err(|e| e.to_string())?;
|
current_res = get_req.send().await.map_err(|e| e.to_string())?;
|
||||||
|
|||||||
@@ -247,7 +247,9 @@ export const AddDownloadsModal = () => {
|
|||||||
url: row.sourceUrl,
|
url: row.sourceUrl,
|
||||||
userAgent: settingsStore.customUserAgent || null,
|
userAgent: settingsStore.customUserAgent || null,
|
||||||
username: useAuth ? username.trim() || null : login?.username || null,
|
username: useAuth ? username.trim() || null : login?.username || null,
|
||||||
password: useAuth ? password || null : keychainPassword
|
password: useAuth ? password || null : keychainPassword,
|
||||||
|
headers: headers?.trim() || null,
|
||||||
|
cookies: cookies?.trim() || null
|
||||||
});
|
});
|
||||||
setParsedItems(current => updateRowIfCurrent(
|
setParsedItems(current => updateRowIfCurrent(
|
||||||
current,
|
current,
|
||||||
@@ -291,7 +293,7 @@ export const AddDownloadsModal = () => {
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
}, [parsedItems, pendingAddFilename, password, useAuth, username]);
|
}, [parsedItems, pendingAddFilename, password, useAuth, username, headers, cookies]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (parsedItems.length === 0) {
|
if (parsedItems.length === 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user