From 6af7d298331e23a77194b870c798ad303a68fa61 Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 16 Apr 2021 09:58:15 +0200 Subject: [PATCH] Enable command parser to parse all values To be able to parse other values than `serde_json::Value::String(String)` we parse the pointer parameters and replace all those values in the JSON data with strings. --- Cargo.lock | 4 +-- src/main.rs | 72 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53a9ba2..324d425 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1041,9 +1041,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" dependencies = [ "tinyvec_macros", ] diff --git a/src/main.rs b/src/main.rs index 01ee2e7..d2b7ba0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -149,6 +149,19 @@ fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> { mac.verify(&raw_signature).map_err(|e| anyhow!("{}", e)) } +fn get_parameter(input: &str) -> Result> { + let parse: IResult<&str, Vec<&str>> = many0(alt(( + delimited(tag("{{"), take_until("}}"), tag("}}")), + take_until("{{"), + )))(&input); + + let (_last, result) = parse + .finish() + .map_err(|e| anyhow!("Could not get parameters from command: {}", e))?; + + Ok(result) +} + fn replace_parameter(input: &str, headers: &HeaderMap, data: &serde_json::Value) -> Result { let parse: IResult<&str, Vec<&str>> = many0(alt(( map_res( @@ -189,13 +202,15 @@ fn replace_parameter(input: &str, headers: &HeaderMap, data: &serde_json::Value) Ok(result.join("")) } -fn number_to_string(number: &serde_json::Number) -> String { - if number.is_f64() { - return number.as_f64().unwrap().to_string(); - } else if number.is_i64() { - return number.as_i64().unwrap().to_string(); +fn get_string(value: &serde_json::Value) -> Result { + match &value { + serde_json::Value::Null => unimplemented!(), + serde_json::Value::Bool(_bool) => unimplemented!(), + serde_json::Value::Number(number) => Ok(number.to_string()), + serde_json::Value::String(string) => Ok(string.as_str().to_string()), + serde_json::Value::Array(_array) => unimplemented!(), + serde_json::Value::Object(_object) => unimplemented!(), } - number.as_u64().unwrap().to_string() } fn filter_match( @@ -204,27 +219,45 @@ fn filter_match( filter_name: &str, filter: &Filter, request: &Request, - data: &serde_json::Value, + data: &mut serde_json::Value, ) -> Result> { trace!("Matching filter `{}` of hook `{}`", filter_name, hook_name); let regex = Regex::new(&filter.regex)?; + let parameters = hook.command.clone(); + let parameters = get_parameter(¶meters)?; + + for parameter in parameters { + let parameter = parameter.trim(); + trace!("Replacing parameter `{}`", parameter); + trace!("Pointer parameter `{:?}`", data.pointer(parameter)); + if let Some(json_value) = data.pointer(parameter) { + *data.pointer_mut(parameter).unwrap() = match json_value { + serde_json::Value::String(string) => { + serde_json::Value::String(string.to_string()) + } + serde_json::Value::Number(number) => { + serde_json::Value::String(number.to_string()) + } + x => { + error!("Could not get string from: {:?}", x); + unimplemented!() + } + } + } else { + trace!("Ignoring parameter `{}`", parameter); + } + } + if let Some(value) = data.pointer(&filter.pointer) { - let value = match &value { - serde_json::Value::Null => unimplemented!(), - serde_json::Value::Bool(_bool) => unimplemented!(), - serde_json::Value::Number(number) => number_to_string(number), - serde_json::Value::String(string) => string.as_str().to_string(), - serde_json::Value::Array(_array) => unimplemented!(), - serde_json::Value::Object(_object) => unimplemented!(), - }; + let value = get_string(value)?; if regex.is_match(&value) { debug!("Filter `{}` of hook `{}` matched", filter_name, hook_name); return Ok(Some(replace_parameter( - &hook.command.to_string(), + &hook.command, &request.headers(), data, )?)); @@ -233,8 +266,7 @@ fn filter_match( debug!( "Filter `{}` of hook `{}` did not match", - filter_name, - hook_name + filter_name, hook_name ); Ok(None) @@ -265,7 +297,7 @@ fn execute_hooks(request: &Request, data: Data) -> Result valid = true; - let data: serde_json::Value = + let mut data: serde_json::Value = serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; for (filter_name, filter) in &hook.filters { @@ -275,7 +307,7 @@ fn execute_hooks(request: &Request, data: Data) -> Result &filter_name, &filter, &request, - &data, + &mut data, ) { Ok(Some(command)) => { hooks.insert(hook_name.to_string(), command);