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); } }