From 4878f6ddd1b3fa17ee6681e0a56f6825eade03cd Mon Sep 17 00:00:00 2001 From: oluceps Date: Mon, 11 Nov 2024 01:48:51 +0800 Subject: [PATCH 1/6] + cover more cases in template --- src/cmd/deploy.rs | 1 - src/helper/template.rs | 59 ++++++++++++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/cmd/deploy.rs b/src/cmd/deploy.rs index 189a1c4..3346b9a 100644 --- a/src/cmd/deploy.rs +++ b/src/cmd/deploy.rs @@ -257,7 +257,6 @@ impl Profile { format!("{{{{ {} }}}}", hex::encode(k.as_slice())).as_str(), String::from_utf8_lossy(v).to_string().as_str(), ); - trace!("processed template: {}", template); }); deploy_to_fs( diff --git a/src/helper/template.rs b/src/helper/template.rs index 62e8cba..d39a7de 100644 --- a/src/helper/template.rs +++ b/src/helper/template.rs @@ -1,7 +1,8 @@ use crate::profile::Template; use eyre::Result; use nom::{ - bytes::complete::{is_not, tag, take_while_m_n}, + bytes::complete::{tag, take_while_m_n}, + combinator::verify, error::Error, sequence::delimited, IResult, @@ -15,15 +16,17 @@ fn parse_braced_hash(input: &str) -> IResult<&str, &str, Error<&str>> { )(input) } -fn pars<'a>(text: &'a str, res: &mut Vec<&'a str>) { - if let Ok((brace_start_then, _)) = is_not::<&str, &str, Error<&str>>("{")(text) { - if let Ok((remain, hashes)) = parse_braced_hash(brace_start_then) { - res.push(hashes); - if !remain.is_empty() { - pars(remain, res); - } - }; - }; +pub fn extract_all_hashes<'a>(input: &'a str, res: &mut Vec<&'a str>) { + if let Ok((o, b)) = verify(parse_braced_hash, |_: &str| true)(input) { + res.push(b); + extract_all_hashes(o, res) + } else if input.len() < 66 { + // less than expected `{{ hash }}` length + return; + } else { + let this = &input[1..]; + extract_all_hashes(this, res) + } } impl Template { @@ -33,7 +36,7 @@ impl Template { let mut res = vec![]; let text = format!(" {}", text); // hack - pars(text.as_str(), &mut res); + extract_all_hashes(text.as_str(), &mut res); Ok(res .into_iter() .map(|s| decode(s).expect("hex decode")) @@ -41,8 +44,6 @@ impl Template { } } -// pub struct Template - #[cfg(test)] mod tests { use super::*; @@ -96,6 +97,38 @@ mod tests { ) } #[test] + fn parse_template_normal() { + let str = "{{ cd789434d890685da841b8db8a02b0173b90eac3774109ba9bca1b81440a2a93 }}"; + + let t = Template { + content: String::from(str), + ..Template::default() + }; + let l = t.parse_hash_str_list().unwrap(); + assert_eq!( + hex!("cd789434d890685da841b8db8a02b0173b90eac3774109ba9bca1b81440a2a93"), + l.first().unwrap().as_slice() + ) + } + #[test] + fn parse_template_mix() { + let str = "{{ cd789434d890685da841b8db8a02b0173b90eac3774109ba9bca1b81440a2a93 }} {{ {{ c4e0ae1067d1ee736e051d7927d783bb70b032bf116f618454bf47122956d5ce }}"; + + let t = Template { + content: String::from(str), + ..Template::default() + }; + let l = t.parse_hash_str_list().unwrap(); + assert_eq!( + hex!("cd789434d890685da841b8db8a02b0173b90eac3774109ba9bca1b81440a2a93"), + l.first().unwrap().as_slice() + ); + assert_eq!( + hex!("c4e0ae1067d1ee736e051d7927d783bb70b032bf116f618454bf47122956d5ce"), + l.get(1).unwrap().as_slice() + ); + } + #[test] fn parse_template_with_heading_white() { let str = " {{ cd789434d890685da841b8db8a02b0173b90eac3774109ba9bca1b81440a2a93 }}"; From 28aa9fe196ac0c9d60b094bdd15f2c1e54386e4c Mon Sep 17 00:00:00 2001 From: oluceps Date: Mon, 11 Nov 2024 02:06:13 +0800 Subject: [PATCH 2/6] + option trim for template This commit adds option to control if all secret contents inserting to the template needs trim. Will remove leading and trailing whitespace of the content to insert while enable. Default enabled. --- module/template.nix | 4 ++++ src/cmd/deploy.rs | 15 +++++++++++++-- src/profile.rs | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/module/template.nix b/module/template.nix index 8d1a823..6cf35a5 100644 --- a/module/template.nix +++ b/module/template.nix @@ -29,6 +29,10 @@ let Content of the template ''; }; + trim = (mkEnableOption { }) // { + default = true; + description = "remove trailing and leading whitespace of the secret content to insert"; + }; name = mkOption { type = types.str; default = submod.config._module.args.name; diff --git a/src/cmd/deploy.rs b/src/cmd/deploy.rs index 3346b9a..536a48b 100644 --- a/src/cmd/deploy.rs +++ b/src/cmd/deploy.rs @@ -247,15 +247,26 @@ impl Profile { let mut template = t.content.clone(); let hashstrs_of_it = t.parse_hash_str_list().expect("parse template"); + let trim_the_insertial = t.trim; + hashstr_ctx_map .iter() .filter(|(k, _)| hashstrs_of_it.contains(k)) .for_each(|(k, v)| { - // render + // render and insert trace!("template before process: {}", template); + + let raw_composed_insertial = String::from_utf8_lossy(v).to_string(); + + let insertial = if trim_the_insertial { + raw_composed_insertial.trim() + } else { + raw_composed_insertial.as_str() + }; + template = template.replace( format!("{{{{ {} }}}}", hex::encode(k.as_slice())).as_str(), - String::from_utf8_lossy(v).to_string().as_str(), + insertial, ); }); diff --git a/src/profile.rs b/src/profile.rs index 0807340..dc1b5a2 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -28,6 +28,7 @@ pub struct Secret { pub struct Template { pub name: String, pub content: String, + pub trim: bool, pub group: String, pub mode: String, pub owner: String, From b73eed44d281e4b4ff308f062aeb3958e6a4e49d Mon Sep 17 00:00:00 2001 From: oluceps Date: Mon, 11 Nov 2024 02:11:15 +0800 Subject: [PATCH 3/6] + parser fit multibytes input --- src/helper/template.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/helper/template.rs b/src/helper/template.rs index d39a7de..871cdae 100644 --- a/src/helper/template.rs +++ b/src/helper/template.rs @@ -24,7 +24,13 @@ pub fn extract_all_hashes<'a>(input: &'a str, res: &mut Vec<&'a str>) { // less than expected `{{ hash }}` length return; } else { - let this = &input[1..]; + let this = { + // handle multibytes + let res = input.char_indices().nth(1).map_or("", |(i, _)| &input[i..]); + // skip to next `{` + res.find('{').map_or("", |index| &res[index..]) + }; + extract_all_hashes(this, res) } } From 4c50426d4c28d9149d312d695f2a2e271e44145d Mon Sep 17 00:00:00 2001 From: oluceps Date: Mon, 11 Nov 2024 02:33:47 +0800 Subject: [PATCH 4/6] + doc add state about trim template insertion --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 45b1148..948e7f3 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,9 @@ Adding nixosModule config: name = "template.txt"; # to be notice that the source secret file may have trailing `\n` content = "this is a template for testing ${config.vaultix.placeholder.example}"; + # removing trailing and leading whitespace by default + trim = true; + # ... }; } }; From 041467fe102ad722e27c5c6945ef4aec565285e7 Mon Sep 17 00:00:00 2001 From: oluceps Date: Mon, 11 Nov 2024 02:35:00 +0800 Subject: [PATCH 5/6] - remove parser hack --- src/helper/template.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/helper/template.rs b/src/helper/template.rs index 871cdae..1d8e76f 100644 --- a/src/helper/template.rs +++ b/src/helper/template.rs @@ -41,7 +41,6 @@ impl Template { let text = &self.content; let mut res = vec![]; - let text = format!(" {}", text); // hack extract_all_hashes(text.as_str(), &mut res); Ok(res .into_iter() From 2b2983c3216666c8aa6edd2b2cd7a36e5c185b06 Mon Sep 17 00:00:00 2001 From: oluceps Date: Mon, 11 Nov 2024 02:48:29 +0800 Subject: [PATCH 6/6] ~ typos --- src/helper/template.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper/template.rs b/src/helper/template.rs index 1d8e76f..6d4889e 100644 --- a/src/helper/template.rs +++ b/src/helper/template.rs @@ -58,7 +58,7 @@ mod tests { #[test] fn parse_template_single() { let str = - "here has {{ dcd789434d890685da841b8db8a02b0173b90eac3774109ba9bca1b81440aa93 }} whch should be replaced"; + "here has {{ dcd789434d890685da841b8db8a02b0173b90eac3774109ba9bca1b81440aa93 }} which should be replaced"; let t = Template { content: String::from(str),