diff --git a/src/utils/constants.rs b/src/utils/constants.rs index fccc2cd8e..7ced5f32b 100644 --- a/src/utils/constants.rs +++ b/src/utils/constants.rs @@ -69,9 +69,9 @@ pub struct KodiStyle { } pub struct Constants { - pub re_username: Regex, - pub re_password: Regex, - pub re_token: Regex, + pub re_credentials: Regex, + pub re_ipv4: Regex, + pub re_ipv6: Regex, pub re_stream_url: Regex, pub re_url: Regex, pub re_base_href: Regex, @@ -93,9 +93,9 @@ pub struct Constants { pub static CONSTANTS: LazyLock = LazyLock::new(|| Constants { - re_username: Regex::new(r"(username=)[^&]*").unwrap(), - re_password: Regex::new(r"(password=)[^&]*").unwrap(), - re_token: Regex::new(r"(token=)[^&]*").unwrap(), + re_credentials: Regex::new(r"((username|password|token)=)[^&]*").unwrap(), + re_ipv4: Regex::new(r"\b((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\b").unwrap(), + re_ipv6: Regex::new(r"\b([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|\b::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}\b|\b([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}\b|\b::ffff:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b").unwrap(), re_stream_url: Regex::new(r"(?i)^(?Phttps?://)[^/]+/(?Plive|video|movie|series|m3u-stream|resource)/[^/]+/[^/]+/").unwrap(), re_url: Regex::new(r"(.*://).*?/(.*)").unwrap(), re_base_href: Regex::new(r#"(href|src)="/([^"]*)""#).unwrap(), diff --git a/src/utils/network/epg.rs b/src/utils/network/epg.rs index b49566f02..672ae6c2c 100644 --- a/src/utils/network/epg.rs +++ b/src/utils/network/epg.rs @@ -15,7 +15,7 @@ async fn download_epg_file(url: &str, client: &Arc, input: &Con let persist_file_path = prepare_file_path(input.persist.as_deref(), working_dir, "") .map(|path| add_prefix_to_filename(&path, format!("{file_prefix}_epg_").as_str(), Some("xml"))); - request::get_input_text_content_as_file(Arc::clone(client), input, working_dir, url, persist_file_path).await + request::get_input_epg_content_as_file(Arc::clone(client), input, working_dir, url, persist_file_path).await } pub async fn get_xmltv(client: Arc, _cfg: &Config, input: &ConfigInput, working_dir: &str) -> (Option, Vec) { diff --git a/src/utils/network/request.rs b/src/utils/network/request.rs index 19d0bb7c8..3a141a594 100644 --- a/src/utils/network/request.rs +++ b/src/utils/network/request.rs @@ -29,10 +29,10 @@ pub const fn bytes_to_megabytes(bytes: u64) -> u64 { bytes / 1_048_576 } -pub async fn get_input_text_content_as_file(client: Arc, input: &ConfigInput, working_dir: &str, url_str: &str, persist_filepath: Option) -> Result { +pub async fn get_input_epg_content_as_file(client: Arc, input: &ConfigInput, working_dir: &str, url_str: &str, persist_filepath: Option) -> Result { debug_if_enabled!("getting input text content working_dir: {}, url: {}", working_dir, sanitize_sensitive_info(url_str)); if url_str.parse::().is_ok() { - match download_text_content_as_file(client, input, url_str, working_dir, persist_filepath).await { + match download_epg_content_as_file(client, input, url_str, working_dir, persist_filepath).await { Ok(content) => Ok(content), Err(e) => { error!("cant download input url: {} => {}", sanitize_sensitive_info(url_str), sanitize_sensitive_info(e.to_string().as_str())); @@ -298,7 +298,7 @@ async fn get_remote_content(client: Arc, input: &ConfigInput, u } } -pub async fn download_text_content_as_file(client: Arc, input: &ConfigInput, url_str: &str, working_dir: &str, persist_filepath: Option) -> Result { +async fn download_epg_content_as_file(client: Arc, input: &ConfigInput, url_str: &str, working_dir: &str, persist_filepath: Option) -> Result { if let Ok(url) = url_str.parse::() { if url.scheme() == "file" { url.to_file_path().map_or_else(|()| Err(Error::new(ErrorKind::Unsupported, format!("Unknown file {}", sanitize_sensitive_info(url_str)))), |file_path| if file_path.exists() { @@ -371,19 +371,26 @@ pub fn set_sanitize_sensitive_info(value: bool) { CONSTANTS.sanitize.store(value, Ordering::SeqCst); } pub fn sanitize_sensitive_info(query: &str) -> String { - if CONSTANTS.sanitize.load(Ordering::SeqCst) { - // Replace with "***" - let masked_query = CONSTANTS.re_username.replace_all(query, "$1***"); - let masked_query = CONSTANTS.re_password.replace_all(&masked_query, "$1***"); - let masked_query = CONSTANTS.re_token.replace_all(&masked_query, "$1***"); - let masked_query = CONSTANTS.re_stream_url.replace_all(&masked_query, "$1***/$2/***"); - let masked_query = CONSTANTS.re_url.replace_all(&masked_query, "$1***/$2"); - masked_query.to_string() - } else { - query.to_string() + if !CONSTANTS.sanitize.load(Ordering::SeqCst) { + return query.to_string(); } + + let mut result = query.to_owned(); + + for (re, replacement) in &[ + (&CONSTANTS.re_credentials, "$1***"), + (&CONSTANTS.re_ipv4, "$1***"), + (&CONSTANTS.re_ipv6, "$1***"), + (&CONSTANTS.re_stream_url, "$1***/$2/***"), + (&CONSTANTS.re_url, "$1***/$2"), + ] { + result = re.replace_all(&result, *replacement).into_owned(); + } + + result } + pub fn extract_extension_from_url(url: &str) -> Option<&str> { if let Some(protocol_pos) = url.find("://") { if let Some(last_slash_pos) = url[protocol_pos + 3..].rfind('/') {