Compare commits

...

7 Commits
v0.3.0 ... main

2
Cargo.lock generated

@ -593,7 +593,7 @@ dependencies = [
[[package]]
name = "multihook"
version = "0.3.0"
version = "0.4.2"
dependencies = [
"chrono",
"colored",

@ -4,7 +4,7 @@ description = "A webhook server"
authors = ["trivernis <trivernis@protonmail.com>"]
license = "GPL-3.0"
readme = "README.md"
version = "0.3.0"
version = "0.4.2"
edition = "2018"
repository = "https://github.com/Trivernis/multihook.git"

@ -34,6 +34,14 @@ After running the program for the first time the config directory and config fil
[server]
address = '127.0.0.1:8080'
[hooks]
# executed before all endpoint actions
pre_action = "echo 'pre action'"
# executed after all endpoint actions
post_action = "echo 'post action'"
# executed when an action fails
err_action = "echo \"Hook $HOOK_NAME failed with error: $HOOK_ERROR\""
# the name needs to be unique
[endpoints.ls]
# the path needs to be unique
@ -42,13 +50,15 @@ path = "path/on/the/server"
action = "ls {{$.filepath}}"
# allows multiple instances of this action to run concurrently
allow_parallel = true
# additional hooks on endpoint-level
hooks = {pre_action = "echo 'before something bad happens'"}
[endpoints.error]
path = "error"
action = "echo '{{$.books.*.title}}'"
# Validate secrets according to different parsing rules
# Currently only GitHub secrets are supported
secret = { value = "my secret", format = "GitHub"}
# Currently only HMac based secrets with sha256 are supported
secret = { value = "my secret", format = "HMac"}
[endpoints.testscript]
path = "script"

@ -1,28 +0,0 @@
use crate::secret_validation::SecretValidator;
use hmac::{Hmac, Mac};
use hyper::HeaderMap;
use sha2::Sha256;
pub struct GithubSecretValidator;
static X_HUB_SIGNATURE_256_HEADER: &str = "X-Hub-Signature-256";
impl SecretValidator for GithubSecretValidator {
fn validate(&self, headers: &HeaderMap, body: &[u8], secret: &[u8]) -> bool {
log::debug!("Validating GitHub Secret");
if let Some(github_sum) = headers.get(X_HUB_SIGNATURE_256_HEADER) {
let mut mac = Hmac::<Sha256>::new_from_slice(secret).unwrap();
mac.update(body);
let decoded_secret = if let Ok(decoded) = hex::decode(github_sum) {
decoded
} else {
return false;
};
mac.verify_slice(&decoded_secret).is_ok()
} else {
log::debug!("Missing Signature Header");
false
}
}
}

@ -0,0 +1,43 @@
use crate::secret_validation::SecretValidator;
use hmac::{Hmac, Mac};
use hyper::HeaderMap;
use sha2::Sha256;
pub struct HMacSecretValidator;
static SUM_HEADERS: &[&str] = &[
"X-Forgejo-Signature",
"X-Gitea-Signature",
"X-Gogs-Signature",
"X-Hub-Signature-256",
];
impl SecretValidator for HMacSecretValidator {
fn validate(&self, headers: &HeaderMap, body: &[u8], secret: &[u8]) -> bool {
log::debug!("Validating HMac Secret");
let header = headers
.iter()
.filter(|(name, _)| SUM_HEADERS.iter().find(|h| **name == **h).is_some())
.next();
if let Some((_, sum)) = header {
let mut mac = Hmac::<Sha256>::new_from_slice(secret).unwrap();
mac.update(body);
let Ok(sum) = sum.to_str() else {
log::error!("Received signature is not a valid string");
return false;
};
let Ok(decoded_secret) = hex::decode(sum.trim_start_matches("sha256=")) else {
log::error!("Received signature cannot be decoded from hex");
return false;
};
log::debug!("Verifying found signature");
mac.verify_slice(&decoded_secret).is_ok()
} else {
log::error!("Missing Signature Header");
false
}
}
}

@ -1,18 +1,18 @@
mod github;
mod hash_mac;
use crate::secret_validation::github::GithubSecretValidator;
use crate::secret_validation::hash_mac::HMacSecretValidator;
use hyper::HeaderMap;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SecretFormat {
GitHub,
HMac,
}
impl SecretFormat {
pub fn validator(&self) -> impl SecretValidator {
match self {
SecretFormat::GitHub => GithubSecretValidator,
SecretFormat::HMac => HMacSecretValidator,
}
}
}

@ -54,11 +54,11 @@ impl Action {
let stdout = String::from_utf8_lossy(&output.stdout[..]);
log::debug!("Command output is: {}", stdout);
if stderr.len() > 0 {
if output.status.success() {
Ok(())
} else {
log::error!("Errors occurred during command execution: {}", stderr);
Err(MultihookError::ActionError(stderr.into_owned()))
} else {
Ok(())
}
}
}

@ -82,7 +82,7 @@ fn load_settings() -> MultihookResult<Settings> {
.collect::<Vec<_>>(),
)
.add_source(config::Environment::with_prefix("MULTIHOOK"))
.add_source(File::from(PathBuf::from(".multihook.toml")))
.add_source(File::from(PathBuf::from(".multihook.toml")).required(false))
.build()?;
let settings: Settings = settings.try_deserialize()?;

Loading…
Cancel
Save