diff --git a/src/lib.rs b/src/lib.rs index 01a0f4c..412e320 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,10 @@ pub mod file_types; pub mod template; -pub const ENV_VAR_PATTERN_START: &str = "${env:"; -pub const ENV_VAR_PATTERN_END: &str = "}"; +// It could be the case that the colon (:) in the start pattern has been escaped, as e.g. the product-config crate does +pub const ENV_VAR_START_PATTERNS: [&str; 2] = ["${env:", "${env\\:"]; +pub const ENV_VAR_END_PATTERN: &str = "}"; -pub const FILE_PATTERN_START: &str = "${file:UTF-8:"; -pub const FILE_PATTERN_END: &str = "}"; +// It could be the case that the colon (:) in the start pattern has been escaped, as e.g. the product-config crate does +pub const FILE_START_PATTERNS: [&str; 2] = ["${file:UTF-8:", "${file\\:UTF-8\\:"]; +pub const FILE_END_PATTERN: &str = "}"; diff --git a/src/template/mod.rs b/src/template/mod.rs index 9f89fa9..6425244 100644 --- a/src/template/mod.rs +++ b/src/template/mod.rs @@ -9,7 +9,7 @@ use snafu::{OptionExt, ResultExt, Snafu}; use crate::{ file_types::{FileType, KNOWN_FILE_TYPES}, - ENV_VAR_PATTERN_END, ENV_VAR_PATTERN_START, FILE_PATTERN_END, FILE_PATTERN_START, + ENV_VAR_END_PATTERN, ENV_VAR_START_PATTERNS, FILE_END_PATTERN, FILE_START_PATTERNS, }; pub mod cli_args; @@ -141,23 +141,31 @@ fn run_all_replacements_on_line( escape: bool, ) -> Result<()> { loop { + #[allow(clippy::type_complexity)] // It's only used in a single place + let mut replacements: Vec<(&str, &str, fn(&str) -> Result)> = Vec::new(); + + for start_pattern in ENV_VAR_START_PATTERNS { + replacements.push(( + start_pattern, + ENV_VAR_END_PATTERN, + replacement_action_for_env_var, + )); + } + for start_pattern in FILE_START_PATTERNS { + replacements.push((start_pattern, FILE_END_PATTERN, replacement_action_for_file)); + } + let mut changed = false; - changed |= replace_thingy_in_line( - line, - ENV_VAR_PATTERN_START, - ENV_VAR_PATTERN_END, - replacement_action_for_env_var, - file_type, - escape, - )?; - changed |= replace_thingy_in_line( - line, - FILE_PATTERN_START, - FILE_PATTERN_END, - replacement_action_for_file, - file_type, - escape, - )?; + for (start_pattern, end_pattern, replacement_action) in replacements { + changed |= replace_thingy_in_line( + line, + start_pattern, + end_pattern, + replacement_action, + file_type, + escape, + )?; + } if !changed { break; diff --git a/tests/resources/properties/security_escaped_command.properties.expected b/tests/resources/properties/security_escaped_command.properties.expected new file mode 100644 index 0000000..153bbf3 --- /dev/null +++ b/tests/resources/properties/security_escaped_command.properties.expected @@ -0,0 +1,3 @@ +# We must also recognize commands where the colon was escaped +test.from.env=foo +test.from.file=42 diff --git a/tests/resources/properties/security_escaped_command.properties.in b/tests/resources/properties/security_escaped_command.properties.in new file mode 100644 index 0000000..078eb87 --- /dev/null +++ b/tests/resources/properties/security_escaped_command.properties.in @@ -0,0 +1,3 @@ +# We must also recognize commands where the colon was escaped +test.from.env=${env\:ENV_TEST} +test.from.file=${file\:UTF-8\:${env\:${env\:FILE_TEST_42_FILE_ENV_NAME}}}