@@ -4,70 +4,12 @@ use futures_util::StreamExt;
44use reqwest:: { self , Client } ;
55use serde_json:: json;
66use tauri:: { AppHandle , Emitter } ;
7- use url:: Url ;
87
8+ pub use vector_core:: net:: validate_url_not_private;
99pub use vector_core:: SiteMetadata ;
1010
1111use crate :: simd:: html_meta;
1212
13- /// Reject URLs that resolve to private/loopback/link-local addresses (SSRF protection).
14- /// Returns Ok(()) if the URL is safe to fetch, Err with reason otherwise.
15- pub fn validate_url_not_private ( url_str : & str ) -> Result < ( ) , & ' static str > {
16- let parsed = Url :: parse ( url_str) . map_err ( |_| "Invalid URL" ) ?;
17-
18- // Only allow http/https schemes
19- match parsed. scheme ( ) {
20- "http" | "https" => { }
21- _ => return Err ( "Only HTTP(S) URLs are allowed" ) ,
22- }
23-
24- // Check the host — reject IPs directly, resolve hostnames later (reqwest handles DNS)
25- match parsed. host ( ) {
26- Some ( url:: Host :: Ipv4 ( ip) ) => {
27- let o = ip. octets ( ) ;
28- if ip. is_loopback ( )
29- || ip. is_private ( )
30- || ip. is_link_local ( )
31- || ip. is_broadcast ( )
32- || ip. is_unspecified ( )
33- || ( o[ 0 ] == 100 && o[ 1 ] >= 64 && o[ 1 ] <= 127 ) // CGN (100.64.0.0/10)
34- {
35- return Err ( "Private/internal IP addresses are not allowed" ) ;
36- }
37- }
38- Some ( url:: Host :: Ipv6 ( ip) ) => {
39- if ip. is_loopback ( ) || ip. is_unspecified ( ) || is_ipv6_private ( & ip) {
40- return Err ( "Private/internal IP addresses are not allowed" ) ;
41- }
42- }
43- Some ( url:: Host :: Domain ( domain) ) => {
44- // Block localhost variants
45- if domain == "localhost"
46- || domain. ends_with ( ".local" )
47- || domain. ends_with ( ".internal" )
48- {
49- return Err ( "Local hostnames are not allowed" ) ;
50- }
51- }
52- None => return Err ( "URL has no host" ) ,
53- }
54-
55- Ok ( ( ) )
56- }
57-
58- fn is_ipv6_private ( ip : & std:: net:: Ipv6Addr ) -> bool {
59- // Check for IPv4-mapped addresses (::ffff:x.x.x.x)
60- if let Some ( ipv4) = ip. to_ipv4_mapped ( ) {
61- return ipv4. is_loopback ( ) || ipv4. is_private ( ) || ipv4. is_link_local ( ) ;
62- }
63- let segments = ip. segments ( ) ;
64- // Unique local (fc00::/7)
65- if segments[ 0 ] & 0xfe00 == 0xfc00 { return true ; }
66- // Link-local (fe80::/10)
67- if segments[ 0 ] & 0xffc0 == 0xfe80 { return true ; }
68- false
69- }
70-
7113/// Trait for reporting download progress
7214pub trait ProgressReporter {
7315 /// Report progress of a download
0 commit comments