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.
This commit is contained in:
finga 2021-04-16 09:58:15 +02:00 committed by finga
parent ea3121a985
commit 6af7d29833
2 changed files with 54 additions and 22 deletions

4
Cargo.lock generated
View file

@ -1041,9 +1041,9 @@ dependencies = [
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.1.1" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
dependencies = [ dependencies = [
"tinyvec_macros", "tinyvec_macros",
] ]

View file

@ -149,6 +149,19 @@ fn validate_request(secret: &str, signature: &str, data: &[u8]) -> Result<()> {
mac.verify(&raw_signature).map_err(|e| anyhow!("{}", e)) mac.verify(&raw_signature).map_err(|e| anyhow!("{}", e))
} }
fn get_parameter(input: &str) -> Result<Vec<&str>> {
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<String> { fn replace_parameter(input: &str, headers: &HeaderMap, data: &serde_json::Value) -> Result<String> {
let parse: IResult<&str, Vec<&str>> = many0(alt(( let parse: IResult<&str, Vec<&str>> = many0(alt((
map_res( map_res(
@ -189,13 +202,15 @@ fn replace_parameter(input: &str, headers: &HeaderMap, data: &serde_json::Value)
Ok(result.join("")) Ok(result.join(""))
} }
fn number_to_string(number: &serde_json::Number) -> String { fn get_string(value: &serde_json::Value) -> Result<String> {
if number.is_f64() { match &value {
return number.as_f64().unwrap().to_string(); serde_json::Value::Null => unimplemented!(),
} else if number.is_i64() { serde_json::Value::Bool(_bool) => unimplemented!(),
return number.as_i64().unwrap().to_string(); 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( fn filter_match(
@ -204,27 +219,45 @@ fn filter_match(
filter_name: &str, filter_name: &str,
filter: &Filter, filter: &Filter,
request: &Request, request: &Request,
data: &serde_json::Value, data: &mut serde_json::Value,
) -> Result<Option<String>> { ) -> Result<Option<String>> {
trace!("Matching filter `{}` of hook `{}`", filter_name, hook_name); trace!("Matching filter `{}` of hook `{}`", filter_name, hook_name);
let regex = Regex::new(&filter.regex)?; let regex = Regex::new(&filter.regex)?;
let parameters = hook.command.clone();
let parameters = get_parameter(&parameters)?;
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) { if let Some(value) = data.pointer(&filter.pointer) {
let value = match &value { let value = get_string(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!(),
};
if regex.is_match(&value) { if regex.is_match(&value) {
debug!("Filter `{}` of hook `{}` matched", filter_name, hook_name); debug!("Filter `{}` of hook `{}` matched", filter_name, hook_name);
return Ok(Some(replace_parameter( return Ok(Some(replace_parameter(
&hook.command.to_string(), &hook.command,
&request.headers(), &request.headers(),
data, data,
)?)); )?));
@ -233,8 +266,7 @@ fn filter_match(
debug!( debug!(
"Filter `{}` of hook `{}` did not match", "Filter `{}` of hook `{}` did not match",
filter_name, filter_name, hook_name
hook_name
); );
Ok(None) Ok(None)
@ -265,7 +297,7 @@ fn execute_hooks(request: &Request, data: Data) -> Result<Hooks, WebhookeyError>
valid = true; valid = true;
let data: serde_json::Value = let mut data: serde_json::Value =
serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?;
for (filter_name, filter) in &hook.filters { for (filter_name, filter) in &hook.filters {
@ -275,7 +307,7 @@ fn execute_hooks(request: &Request, data: Data) -> Result<Hooks, WebhookeyError>
&filter_name, &filter_name,
&filter, &filter,
&request, &request,
&data, &mut data,
) { ) {
Ok(Some(command)) => { Ok(Some(command)) => {
hooks.insert(hook_name.to_string(), command); hooks.insert(hook_name.to_string(), command);