diff --git a/README.md b/README.md index bf38123..108a029 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,8 @@ hooks = {pre_action = "echo 'before something bad happens'"} 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" diff --git a/src/secret_validation/github.rs b/src/secret_validation/github.rs deleted file mode 100644 index 7ef144f..0000000 --- a/src/secret_validation/github.rs +++ /dev/null @@ -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::::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 - } - } -} diff --git a/src/secret_validation/hash_mac.rs b/src/secret_validation/hash_mac.rs new file mode 100644 index 0000000..707c13e --- /dev/null +++ b/src/secret_validation/hash_mac.rs @@ -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::::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 + } + } +} diff --git a/src/secret_validation/mod.rs b/src/secret_validation/mod.rs index 93e7933..acc3282 100644 --- a/src/secret_validation/mod.rs +++ b/src/secret_validation/mod.rs @@ -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, } } }