diff --git a/src/api/endpoints/web_index.rs b/src/api/endpoints/web_index.rs index 9a0186b6b..bd0e54026 100644 --- a/src/api/endpoints/web_index.rs +++ b/src/api/endpoints/web_index.rs @@ -90,7 +90,7 @@ async fn index( if let Some(web_ui_path) = &app_state.config.web_ui.as_ref().and_then(|c| c.path.as_ref()) { match tokio::fs::read_to_string(&path).await { Ok(content) => { - let mut new_content = CONSTANTS.base_href.replace_all(&content, |caps: ®ex::Captures| { + let mut new_content = CONSTANTS.re_base_href.replace_all(&content, |caps: ®ex::Captures| { format!(r#"{}="/{web_ui_path}/{}""#, &caps[1], &caps[2]) }).to_string(); diff --git a/src/api/model/download.rs b/src/api/model/download.rs index 44256f148..808884f64 100644 --- a/src/api/model/download.rs +++ b/src/api/model/download.rs @@ -52,7 +52,7 @@ fn get_download_directory(download_cfg: &VideoDownloadConfig, filestem: &str) -> } } } - let dir_name = CONSTANTS.remove_filename_ending.replace(stem, ""); + let dir_name = CONSTANTS.re_remove_filename_ending.replace(stem, ""); let file_dir: PathBuf = [download_cfg.directory.as_ref().unwrap(), dir_name.as_ref()].iter().collect(); file_dir } else { @@ -71,7 +71,7 @@ impl FileDownload { pub fn new(req_url: &str, req_filename: &str, download_cfg: &VideoDownloadConfig) -> Option { match reqwest::Url::parse(req_url) { Ok(url) => { - let tmp_filename = CONSTANTS.filename.replace_all(&deunicode(req_filename) + let tmp_filename = CONSTANTS.re_filename.replace_all(&deunicode(req_filename) .replace(' ', "_"), "") .replace("__", "_") .replace("_-_", "-"); diff --git a/src/foundation/filter.rs b/src/foundation/filter.rs index a226da2c1..8622db50e 100644 --- a/src/foundation/filter.rs +++ b/src/foundation/filter.rs @@ -475,7 +475,7 @@ fn build_dependency_graph( let mut graph = DirectedGraph::::new(); for template in templates { graph.add_node(&template.name); - CONSTANTS.template_var + CONSTANTS.re_template_var .captures_iter(&template.value) .filter(|caps| caps.len() > 1) .filter_map(|caps| caps.get(1)) @@ -712,7 +712,7 @@ mod tests { match get_filter(flt, None) { Ok(filter) => { - let result = CONSTANTS.space.replace_all(&flt, " "); + let result = CONSTANTS.re_whitespace.replace_all(&flt, " "); assert_eq!(format!("{filter}"), result.trim()); } Err(e) => { diff --git a/src/model/config.rs b/src/model/config.rs index efb02bd4a..fd5602801 100644 --- a/src/model/config.rs +++ b/src/model/config.rs @@ -861,7 +861,7 @@ impl EpgSmartMatchConfig { } self.t_normalize_regex = match self.normalize_regex.as_ref() { - None => Some(CONSTANTS.epg_normalize.clone()), + None => Some(CONSTANTS.re_epg_normalize.clone()), Some(regstr) => { let re = regex::Regex::new(regstr.as_str()); if re.is_err() { diff --git a/src/model/mapping.rs b/src/model/mapping.rs index 72f042933..491bc8fc8 100644 --- a/src/model/mapping.rs +++ b/src/model/mapping.rs @@ -284,7 +284,7 @@ impl MappingValueProcessor<'_> { let attributes = &mapper.attributes; for (key, value) in attributes { if value.contains('<') { // possible replacement - let replaced = CONSTANTS.template_attribute.replace_all(value, |captures: ®ex::Captures| { + let replaced = CONSTANTS.re_template_attribute.replace_all(value, |captures: ®ex::Captures| { let capture_name = &captures[1]; (*captured_names.get(&capture_name).unwrap_or(&&captures[0])).to_string() }); @@ -297,7 +297,7 @@ impl MappingValueProcessor<'_> { fn apply_tags(&mut self, value: &str, captures: &HashMap<&str, &str>) -> Option { let mut new_value = String::from(value); - let tag_captures = CONSTANTS.template_tag.captures_iter(value) + let tag_captures = CONSTANTS.re_template_tag.captures_iter(value) .filter(|caps| caps.len() > 1) .filter_map(|caps| caps.get(1)) .map(|caps| caps.as_str()) diff --git a/src/processing/parser/hls.rs b/src/processing/parser/hls.rs index 964547d60..8721489d6 100644 --- a/src/processing/parser/hls.rs +++ b/src/processing/parser/hls.rs @@ -1,9 +1,7 @@ use crate::model::api_proxy::ProxyUserCredentials; use crate::utils::crypto_utils::encrypt_text; use std::str; - -pub const HLS_PREFIX: &str = "hls"; - +use crate::utils::constants::{CONSTANTS, HLS_PREFIX}; pub struct RewriteHlsProps<'a> { pub secret: &'a [u8;16], @@ -31,7 +29,15 @@ fn rewrite_hls_url(input: &str, replacement: &str) -> String { } } -// TODO # line can have URI parts whcih shuld rewritten too +fn rewrite_uri_attrib(line: &str, props: &RewriteHlsProps) -> String { + if let Some(caps) = CONSTANTS.re_memory_usage.captures(line) { + let uri = &caps[1]; + if let Ok(encrypted_uri) = encrypt_text(props.secret, &rewrite_hls_url(&props.hls_url, uri)) { + return CONSTANTS.re_hls_uri.replace(line, format!(r#"URI="{encrypted_uri}""#)).to_string(); + } + } + line.to_string() +} pub fn rewrite_hls(user: &ProxyUserCredentials, props: &RewriteHlsProps) -> String { let username = &user.username; @@ -39,8 +45,7 @@ pub fn rewrite_hls(user: &ProxyUserCredentials, props: &RewriteHlsProps) -> Stri let mut result = Vec::new(); for line in props.content.lines() { if line.starts_with('#') { - - result.push(line.to_string()); + result.push(rewrite_uri_attrib(line, props)); } else if let Ok(token) = if line.starts_with("http") { encrypt_text(props.secret, line) } else { diff --git a/src/utils/constants.rs b/src/utils/constants.rs index 88562d2b7..ea6ae33c6 100644 --- a/src/utils/constants.rs +++ b/src/utils/constants.rs @@ -19,6 +19,8 @@ pub const ENCODING_DEFLATE: &str = "deflate"; pub const HLS_EXT: &str = ".m3u8"; pub const DASH_EXT: &str = ".mpd"; +pub const HLS_PREFIX: &str = "hls"; + pub const HLS_EXT_QUERY: &str = ".m3u8?"; pub const HLS_EXT_FRAGMENT: &str = ".m3u8#"; pub const DASH_EXT_QUERY: &str = ".mpd?"; @@ -39,21 +41,22 @@ pub struct KodiStyle { } pub struct Constants { - pub username: Regex, - pub password: Regex, - pub token: Regex, - pub stream_url: Regex, - pub url: Regex, - pub base_href: Regex, - pub env: Regex, - pub memory_usage: Regex, - pub epg_normalize: Regex, - pub template_var: Regex, - pub template_tag: Regex, - pub template_attribute: Regex, - pub filename: Regex, - pub remove_filename_ending: Regex, - pub space: Regex, + pub re_username: Regex, + pub re_password: Regex, + pub re_token: Regex, + pub re_stream_url: Regex, + pub re_url: Regex, + pub re_base_href: Regex, + pub re_env_var: Regex, + pub re_memory_usage: Regex, + pub re_epg_normalize: Regex, + pub re_template_var: Regex, + pub re_template_tag: Regex, + pub re_template_attribute: Regex, + pub re_filename: Regex, + pub re_remove_filename_ending: Regex, + pub re_whitespace: Regex, + pub re_hls_uri: Regex, pub sanitize: AtomicBool, pub kodi_style: KodiStyle, pub country_codes: HashSet<&'static str>, @@ -61,21 +64,22 @@ pub struct Constants { pub static CONSTANTS: LazyLock = LazyLock::new(|| Constants { - username: Regex::new(r"(username=)[^&]*").unwrap(), - password: Regex::new(r"(password=)[^&]*").unwrap(), - token: Regex::new(r"(token=)[^&]*").unwrap(), - stream_url: Regex::new(r"(.*://).*/(live|video|movie|series|m3u-stream|resource)/\w+/\w+").unwrap(), - url: Regex::new(r"(.*://).*?/(.*)").unwrap(), - base_href: Regex::new(r#"(href|src)="/([^"]*)""#).unwrap(), - env: Regex::new(r"\$\{env:(?P[a-zA-Z_][a-zA-Z0-9_]*)}").unwrap(), - memory_usage: Regex::new(r"VmRSS:\s+(\d+) kB").unwrap(), - epg_normalize: Regex::new(r"[^a-zA-Z0-9\-]").unwrap(), - template_var: Regex::new("!(.*?)!").unwrap(), - template_tag: Regex::new("").unwrap(), - template_attribute: Regex::new("<(.*?)>").unwrap(), - filename: Regex::new(r"[^A-Za-z0-9_.-]").unwrap(), - remove_filename_ending: Regex::new(r"[_.\s-]$").unwrap(), - space: Regex::new(r"\s+").unwrap(), + re_username: Regex::new(r"(username=)[^&]*").unwrap(), + re_password: Regex::new(r"(password=)[^&]*").unwrap(), + re_token: Regex::new(r"(token=)[^&]*").unwrap(), + re_stream_url: Regex::new(r"(.*://).*/(live|video|movie|series|m3u-stream|resource)/\w+/\w+").unwrap(), + re_url: Regex::new(r"(.*://).*?/(.*)").unwrap(), + re_base_href: Regex::new(r#"(href|src)="/([^"]*)""#).unwrap(), + re_env_var: Regex::new(r"\$\{env:(?P[a-zA-Z_][a-zA-Z0-9_]*)}").unwrap(), + re_memory_usage: Regex::new(r"VmRSS:\s+(\d+) kB").unwrap(), + re_epg_normalize: Regex::new(r"[^a-zA-Z0-9\-]").unwrap(), + re_template_var: Regex::new("!(.*?)!").unwrap(), + re_template_tag: Regex::new("").unwrap(), + re_template_attribute: Regex::new("<(.*?)>").unwrap(), + re_filename: Regex::new(r"[^A-Za-z0-9_.-]").unwrap(), + re_remove_filename_ending: Regex::new(r"[_.\s-]$").unwrap(), + re_whitespace: Regex::new(r"\s+").unwrap(), + re_hls_uri: Regex::new(r#"URI="([^"]+)""#).unwrap(), sanitize: AtomicBool::new(true), kodi_style: KodiStyle { diff --git a/src/utils/file/config_reader.rs b/src/utils/file/config_reader.rs index 389e92cf2..dbaf0cc8c 100644 --- a/src/utils/file/config_reader.rs +++ b/src/utils/file/config_reader.rs @@ -172,7 +172,7 @@ pub fn resolve_env_var(value: &str) -> String { if value.is_empty() { return String::new(); } - CONSTANTS.env.replace_all(value, |caps: ®ex::Captures| { + CONSTANTS.re_env_var.replace_all(value, |caps: ®ex::Captures| { let var_name = &caps["var"]; env::var(var_name).unwrap_or_else(|_| format!("${{env:{var_name}}}")) }).to_string() diff --git a/src/utils/network/request.rs b/src/utils/network/request.rs index 0c0954d9c..8e5d12a91 100644 --- a/src/utils/network/request.rs +++ b/src/utils/network/request.rs @@ -371,11 +371,11 @@ pub fn set_sanitize_sensitive_info(value: bool) { pub fn sanitize_sensitive_info(query: &str) -> String { if CONSTANTS.sanitize.load(Ordering::SeqCst) { // Replace with "***" - let masked_query = CONSTANTS.username.replace_all(query, "$1***"); - let masked_query = CONSTANTS.password.replace_all(&masked_query, "$1***"); - let masked_query = CONSTANTS.token.replace_all(&masked_query, "$1***"); - let masked_query = CONSTANTS.stream_url.replace_all(&masked_query, "$1***/$2/***"); - let masked_query = CONSTANTS.url.replace_all(&masked_query, "$1***/$2"); + 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() diff --git a/src/utils/sys_utils.rs b/src/utils/sys_utils.rs index e03461057..e42d4d173 100644 --- a/src/utils/sys_utils.rs +++ b/src/utils/sys_utils.rs @@ -20,7 +20,7 @@ fn get_memory_usage_linux() -> std::io::Result { let mut contents = String::new(); reader.read_to_string(&mut contents)?; - if let Some(captures) = CONSTANTS.memory_usage.captures(&contents) { + if let Some(captures) = CONSTANTS.re_memory_usage.captures(&contents) { let memory_kb: u64 = captures[1].parse().unwrap(); Ok(memory_kb * 1024) } else {