use ntex::http::header::CONTENT_TYPE; use ntex::{ http::Response, web::{self, HttpRequest, error}, }; use std::process::Command; use url::Url; use crate::util::requester::Requester; fn is_allowed_thumb_url(url: &str) -> bool { let Some(url) = Url::parse(url).ok() else { return false; }; if url.scheme() != "https" { return false; } let Some(host) = url.host_str() else { return false; }; matches!(host, "www.porndish.com" | "porndish.com") && url.path().starts_with("/wp-content/uploads/") } pub async fn get_image( req: HttpRequest, _requester: web::types::State, ) -> Result { let endpoint = req.match_info().query("endpoint").to_string(); let image_url = if endpoint.starts_with("http://") || endpoint.starts_with("https://") { endpoint } else { format!("https://{}", endpoint.trim_start_matches('/')) }; if !is_allowed_thumb_url(&image_url) { return Ok(web::HttpResponse::BadRequest().finish()); } let output = tokio::task::spawn_blocking(move || { Command::new("python3") .arg("-c") .arg( r#" import sys from curl_cffi import requests url = sys.argv[1] response = requests.get( url, impersonate="chrome", timeout=30, allow_redirects=True, headers={"Referer": "https://www.porndish.com/"}, ) if response.status_code >= 400: sys.stderr.write(f"status={response.status_code}\n") sys.exit(1) sys.stderr.write(response.headers.get("content-type", "application/octet-stream")) sys.stdout.buffer.write(response.content) "#, ) .arg(image_url) .output() }) .await .map_err(error::ErrorBadGateway)? .map_err(error::ErrorBadGateway)?; if !output.status.success() { return Ok(web::HttpResponse::NotFound().finish()); } let content_type = String::from_utf8_lossy(&output.stderr).trim().to_string(); let mut resp = Response::build(ntex::http::StatusCode::OK); if !content_type.is_empty() { resp.set_header(CONTENT_TYPE, content_type); } Ok(resp.body(output.stdout)) }