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.
This commit is contained in:
parent
87d6f58f72
commit
c82c0fcbd5
1 changed files with 143 additions and 28 deletions
171
src/main.rs
171
src/main.rs
|
@ -43,8 +43,6 @@ enum WebhookeyError {
|
||||||
Unauthorized(IpAddr),
|
Unauthorized(IpAddr),
|
||||||
#[error("Unmatched hook from `{0}`")]
|
#[error("Unmatched hook from `{0}`")]
|
||||||
UnmatchedHook(IpAddr),
|
UnmatchedHook(IpAddr),
|
||||||
#[error("Could not find field refered to in parameter `{0}`")]
|
|
||||||
InvalidParameterPointer(String),
|
|
||||||
#[error("Could not evaluate filter request")]
|
#[error("Could not evaluate filter request")]
|
||||||
InvalidFilter,
|
InvalidFilter,
|
||||||
#[error("IO Error")]
|
#[error("IO Error")]
|
||||||
|
@ -218,20 +216,10 @@ impl Hook {
|
||||||
&self,
|
&self,
|
||||||
hook_name: &str,
|
hook_name: &str,
|
||||||
request: &Request,
|
request: &Request,
|
||||||
data: &mut serde_json::Value,
|
data: &serde_json::Value,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
trace!("Replacing parameters for command of hook `{}`", hook_name);
|
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)
|
replace_parameters(&self.command, request.headers(), data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,11 +276,11 @@ impl Hooks {
|
||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
|
|
||||||
let mut data: serde_json::Value =
|
let data: serde_json::Value =
|
||||||
serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?;
|
serde_json::from_slice(&buffer).map_err(WebhookeyError::Serde)?;
|
||||||
|
|
||||||
match hook.filter.evaluate(request, &data) {
|
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) => {
|
Ok(command) => {
|
||||||
info!("Filter for `{}` matched", &hook_name);
|
info!("Filter for `{}` matched", &hook_name);
|
||||||
result.insert(hook_name.to_string(), command);
|
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))
|
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 get_header_field<'a>(headers: &'a HeaderMap, param: &[&str]) -> Result<&'a str> {
|
fn get_header_field<'a>(headers: &'a HeaderMap, param: &[&str]) -> Result<&'a str> {
|
||||||
headers
|
headers
|
||||||
.get_one(
|
.get_one(
|
||||||
|
@ -691,5 +666,145 @@ mod tests {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
" something command"
|
" 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue