From 259a07686d7eb174307814d4f750b0777026f935 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 20 Mar 2026 21:05:18 +0000 Subject: [PATCH] noodlemagazine fix --- src/providers/noodlemagazine.rs | 37 +++++++++++++++++++++++++++++---- src/proxies/noodlemagazine.rs | 35 ++++++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/src/providers/noodlemagazine.rs b/src/providers/noodlemagazine.rs index dd02f6e..ac3802e 100644 --- a/src/providers/noodlemagazine.rs +++ b/src/providers/noodlemagazine.rs @@ -10,6 +10,7 @@ use crate::videos::{ServerOptions, VideoFormat, VideoItem}; use async_trait::async_trait; use error_chain::error_chain; use htmlentity::entity::{ICodedDataTrait, decode}; +use std::net::IpAddr; use url::Url; use std::vec; use titlecase::Titlecase; @@ -197,6 +198,31 @@ impl NoodlemagazineProvider { .any(|ext| path.ends_with(ext)) } + fn is_disallowed_thumb_host(host: &str) -> bool { + if host.eq_ignore_ascii_case("localhost") { + return true; + } + + match host.parse::() { + Ok(IpAddr::V4(ip)) => { + ip.is_private() + || ip.is_loopback() + || ip.is_link_local() + || ip.is_broadcast() + || ip.is_documentation() + || ip.is_unspecified() + } + Ok(IpAddr::V6(ip)) => { + ip.is_loopback() + || ip.is_unspecified() + || ip.is_multicast() + || ip.is_unique_local() + || ip.is_unicast_link_local() + } + Err(_) => false, + } + } + fn is_allowed_thumb_url(&self, url: &str) -> bool { let Some(url) = Url::parse(url).ok() else { return false; @@ -207,9 +233,8 @@ impl NoodlemagazineProvider { let Some(host) = url.host_str() else { return false; }; - let is_noodlemagazine_host = host == "noodlemagazine.com" || host.ends_with(".noodlemagazine.com"); - is_noodlemagazine_host && Self::has_allowed_image_extension(url.path()) + !Self::is_disallowed_thumb_host(host) && Self::has_allowed_image_extension(url.path()) } fn proxied_thumb(&self, options: &ServerOptions, thumb: &str) -> String { @@ -395,7 +420,7 @@ mod tests { } #[test] - fn drops_non_noodlemagazine_or_non_image_thumbs() { + fn keeps_https_cdn_thumbs_but_drops_non_images() { let provider = NoodlemagazineProvider::new(); let options = options(); let html = r#" @@ -422,6 +447,10 @@ mod tests { let items = provider.get_video_items_from_html(html.to_string(), &options); assert_eq!(items.len(), 2); - assert!(items.iter().all(|item| item.thumb.is_empty())); + assert_eq!( + items[0].thumb, + "https://example.com/proxy/noodlemagazine-thumb/cdn.example/thumb.jpg" + ); + assert!(items[1].thumb.is_empty()); } } diff --git a/src/proxies/noodlemagazine.rs b/src/proxies/noodlemagazine.rs index 60364f2..6be39f6 100644 --- a/src/proxies/noodlemagazine.rs +++ b/src/proxies/noodlemagazine.rs @@ -4,6 +4,7 @@ use ntex::{ web::{self, HttpRequest, error}, }; use serde_json::Value; +use std::net::IpAddr; use url::Url; use wreq::Version; @@ -110,6 +111,31 @@ impl NoodlemagazineProxy { .any(|ext| path.ends_with(ext)) } + fn is_disallowed_thumb_host(host: &str) -> bool { + if host.eq_ignore_ascii_case("localhost") { + return true; + } + + match host.parse::() { + Ok(IpAddr::V4(ip)) => { + ip.is_private() + || ip.is_loopback() + || ip.is_link_local() + || ip.is_broadcast() + || ip.is_documentation() + || ip.is_unspecified() + } + Ok(IpAddr::V6(ip)) => { + ip.is_loopback() + || ip.is_unspecified() + || ip.is_multicast() + || ip.is_unique_local() + || ip.is_unicast_link_local() + } + Err(_) => false, + } + } + fn is_allowed_thumb_url(url: &str) -> bool { let Some(url) = Url::parse(url).ok() else { return false; @@ -121,8 +147,7 @@ impl NoodlemagazineProxy { return false; }; - (host == "noodlemagazine.com" || host.ends_with(".noodlemagazine.com")) - && Self::has_allowed_image_extension(url.path()) + !Self::is_disallowed_thumb_host(host) && Self::has_allowed_image_extension(url.path()) } fn is_binary_image_content_type(content_type: &str) -> bool { @@ -388,18 +413,18 @@ mod tests { } #[test] - fn allows_only_noodlemagazine_image_thumbs() { + fn allows_https_image_thumbs_but_rejects_local_or_non_images() { assert!(NoodlemagazineProxy::is_allowed_thumb_url( "https://noodlemagazine.com/thumbs/example.webp" )); assert!(NoodlemagazineProxy::is_allowed_thumb_url( - "https://img.noodlemagazine.com/previews/example.jpg" + "https://cdn.example/previews/example.jpg" )); assert!(!NoodlemagazineProxy::is_allowed_thumb_url( "https://noodlemagazine.com/watch/-123_456" )); assert!(!NoodlemagazineProxy::is_allowed_thumb_url( - "https://cdn.example/thumb.jpg" + "https://localhost/thumb.jpg" )); }