Implement secret functionality

In order to validate requests a field called `secret` has to be sent
containing a secret key which validates the request. A hook will be
executed only if the secret sent with the request matches the hook's
secret.
This commit is contained in:
finga 2021-03-19 10:16:46 +01:00 committed by finga
parent ea19c7e413
commit b370d59b40
3 changed files with 33 additions and 12 deletions

View file

@ -53,6 +53,7 @@ Right now there is only the configuration parameter for hooks, here
each hook has to be configured, It contains following fields: each hook has to be configured, It contains following fields:
- action: optional string for the action to be executed when all - action: optional string for the action to be executed when all
filters match filters match
- secrets: list of secrets
- filters: list of filters - filters: list of filters
Each filter has to have following fields: Each filter has to have following fields:

View file

@ -1,17 +1,22 @@
--- ---
hooks: hooks:
hook1: hook1:
action: "echo hookaction1" action: /usr/bin/local/script_xy.sh
secrets:
- secret_key_01
- secret_key_02
filters: filters:
match_ref: match_ref:
pointer: "/ref" pointer: /ref
regex: "refs/heads/master" regex: refs/heads/master
hook2: hook2:
action: "echo hookaction2" action: /usr/bin/local/script_xyz.sh
secrets:
- secret_key03
filters: filters:
match_ref: match_ref:
pointer: "/ref" pointer: /ref
regex: "refs/heads/master" regex: refs/heads/master
match_after: match_after:
pointer: "/after" pointer: /after
regex: "f6e5fe4fe37df76629112d55cc210718b6a55e7e" regex: f6e5fe4fe37df76629112d55cc210718b6a55e7e

View file

@ -1,7 +1,7 @@
#![feature(proc_macro_hygiene, decl_macro)] #![feature(proc_macro_hygiene, decl_macro)]
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
use log::{debug, info, trace}; use log::{debug, info, trace, warn};
use regex::Regex; use regex::Regex;
use rocket::{fairing::AdHoc, get, post, routes, State}; use rocket::{fairing::AdHoc, get, post, routes, State};
use rocket_contrib::json::Json; use rocket_contrib::json::Json;
@ -17,6 +17,7 @@ struct Config {
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct Hook { struct Hook {
action: Option<String>, action: Option<String>,
secrets: Vec<String>,
filters: HashMap<String, Filter>, filters: HashMap<String, Filter>,
} }
@ -61,7 +62,7 @@ fn execute_hook(name: &str, hook: &Hook, data: &serde_json::Value) -> Result<()>
if let Some(action) = &hook.action { if let Some(action) = &hook.action {
info!("Execute `{}` from hook `{}`", action, name); info!("Execute `{}` from hook `{}`", action, name);
let action = action.split(" ").collect::<Vec<&str>>(); let action = action.split(' ').collect::<Vec<&str>>();
let command = Command::new(action[0]).args(&action[1..]).output()?; let command = Command::new(action[0]).args(&action[1..]).output()?;
@ -91,8 +92,22 @@ fn receive_hook(address: SocketAddr, config: State<Config>, data: Json<Data>) ->
trace!("Data received from: {}\n{}", address, data); trace!("Data received from: {}\n{}", address, data);
for (hook_name, hook) in config.hooks.iter() { if let Some(secret) = data.pointer("secret") {
execute_hook(&hook_name, &hook, &data)?; if let Some(secret) = secret.as_str() {
let hooks: HashMap<&String, &Hook> = config
.hooks
.iter()
.filter(|(_hook_name, hook)| hook.secrets.contains(&secret.to_string()))
.collect();
if hooks.is_empty() {
warn!("Secret did not match any hook");
} else {
for (hook_name, hook) in hooks {
execute_hook(&hook_name, &hook, &data)?;
}
}
}
} }
Ok("Request received.".to_string()) Ok("Request received.".to_string())