From c82c0fcbd5d9415906748ff81c2e511ff4f524c9 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 6 Nov 2021 11:03:27 +0100 Subject: [PATCH] Remove double parsing of data pointed to As there was an issues with the parser which checked the validity of the JSON pointer pointing to the received JSON data this part is removed. Further some checks were added to double check that case which lead to an invalid behaviour. This fixes #9. --- src/main.rs | 171 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 143 insertions(+), 28 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9751538..25fa945 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,8 +43,6 @@ enum WebhookeyError { Unauthorized(IpAddr), #[error("Unmatched hook from `{0}`")] UnmatchedHook(IpAddr), - #[error("Could not find field refered to in parameter `{0}`")] - InvalidParameterPointer(String), #[error("Could not evaluate filter request")] InvalidFilter, #[error("IO Error")] @@ -218,20 +216,10 @@ impl Hook { &self, hook_name: &str, request: &Request, - data: &mut serde_json::Value, + data: &serde_json::Value, ) -> Result { trace!("Replacing parameters for command of hook `{}`", hook_name); - for parameter in get_parameter(&self.command)? { - let parameter = parameter.trim(); - - if let Some(json_value) = data.pointer(parameter) { - *data.pointer_mut(parameter).ok_or_else(|| { - WebhookeyError::InvalidParameterPointer(parameter.to_string()) - })? = serde_json::Value::String(get_string(json_value)?); - } - } - replace_parameters(&self.command, request.headers(), data) } } @@ -288,11 +276,11 @@ impl Hooks { valid = true; - let mut data: serde_json::Value = + let data: serde_json::Value = serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?; match hook.filter.evaluate(request, &data) { - Ok(true) => match hook.get_command(hook_name, request, &mut data) { + Ok(true) => match hook.get_command(hook_name, request, &data) { Ok(command) => { info!("Filter for `{}` matched", &hook_name); result.insert(hook_name.to_string(), command); @@ -370,19 +358,6 @@ 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 get_header_field<'a>(headers: &'a HeaderMap, param: &[&str]) -> Result<&'a str> { headers .get_one( @@ -691,5 +666,145 @@ mod tests { .unwrap(), " something command" ); + + assert_eq!( + replace_parameters( + " {{ header X-Gitea-Event }} {{ /field1/foo }} command", + &headers, + &json!({ "field1": { "foo": "bar" } }) + ) + .unwrap(), + " something bar command" + ); + } + + #[rocket::async_test] + async fn parse_command_request() { + let mut hooks = HashMap::new(); + + hooks.insert( + "test_hook".to_string(), + Hook { + command: + "/usr/bin/echo {{ /repository/full_name }} --foo {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/foo".to_string(), + regex: "bar".to_string(), + }), + }, + ); + + hooks.insert( + "test_hook".to_string(), + Hook { + command: "/usr/bin/echo {{ /repository/full_name }} {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/foo".to_string(), + regex: "bar".to_string(), + }), + }, + ); + + let config = Config { + // default: None, + hooks: hooks, + }; + + let rocket = rocket::build() + .mount("/", routes![receive_hook]) + .manage(config); + + let client = Client::tracked(rocket).await.unwrap(); + + let response = client + .post("/") + .header(Header::new( + "X-Gitea-Signature", + "693b733871ecb684651a813c82936df683c9e4a816581f385353e06170545400", + )) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .body( + &serde_json::to_string(&json!({ + "foo": "bar", + "repository": { + "full_name": "keith" + }, + "pull_request": { + "base": { + "ref": "main" + } + } + })) + .unwrap(), + ) + .dispatch(); + + assert_eq!(response.await.status(), Status::Ok); + } + + #[rocket::async_test] + async fn parse_invalid_command_request() { + let mut hooks = HashMap::new(); + + hooks.insert( + "test_hook".to_string(), + Hook { + command: "/usr/bin/echo {{ /repository/full }} {{ /pull_request/base/ref }}" + .to_string(), + signature: "X-Gitea-Signature".to_string(), + ip_filter: None, + secrets: vec!["valid".to_string()], + filter: FilterType::JsonFilter(JsonFilter { + pointer: "/foo".to_string(), + regex: "bar".to_string(), + }), + }, + ); + + let config = Config { + // default: None, + hooks: hooks, + }; + + let rocket = rocket::build() + .mount("/", routes![receive_hook]) + .manage(config); + + let client = Client::tracked(rocket).await.unwrap(); + + let response = client + .post("/") + .header(Header::new( + "X-Gitea-Signature", + "693b733871ecb684651a813c82936df683c9e4a816581f385353e06170545400", + )) + .header(ContentType::JSON) + .remote("127.0.0.1:8000".parse().unwrap()) + .body( + &serde_json::to_string(&json!({ + "foo": "bar", + "repository": { + "full_name": "keith" + }, + "pull_request": { + "base": { + "ref": "main" + } + } + })) + .unwrap(), + ) + .dispatch(); + + assert_eq!(response.await.status(), Status::NotFound); } }