payload.rs 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839
  1. use openssl::{hash::MessageDigest, memcmp, pkey::PKey, sign::Signer};
  2. use std::fmt;
  3. #[derive(Debug)]
  4. pub struct SignedPayloadError;
  5. impl fmt::Display for SignedPayloadError {
  6. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  7. write!(f, "failed to validate payload")
  8. }
  9. }
  10. impl std::error::Error for SignedPayloadError {}
  11. pub fn assert_signed(signature: &str, payload: &[u8]) -> Result<(), SignedPayloadError> {
  12. let signature = signature.get("sha1=".len()..).ok_or(SignedPayloadError)?;
  13. let signature = match hex::decode(&signature) {
  14. Ok(e) => e,
  15. Err(e) => {
  16. log::trace!("hex decode failed for {:?}: {:?}", signature, e);
  17. return Err(SignedPayloadError);
  18. }
  19. };
  20. let key = PKey::hmac(
  21. std::env::var("GITHUB_WEBHOOK_SECRET")
  22. .expect("Missing GITHUB_WEBHOOK_SECRET")
  23. .as_bytes(),
  24. )
  25. .unwrap();
  26. let mut signer = Signer::new(MessageDigest::sha1(), &key).unwrap();
  27. signer.update(&payload).unwrap();
  28. let hmac = signer.sign_to_vec().unwrap();
  29. if !memcmp::eq(&hmac, &signature) {
  30. return Err(SignedPayloadError);
  31. }
  32. Ok(())
  33. }