use bytes::Bytes;
use hmac::{Hmac, Mac};
use sha2::Sha256;
use crate::{error::WiError, types::Event};
type HmacSha256 = Hmac<Sha256>;
const SIGNATURE_HEADER: &str = "x-wi-signature";
pub fn verify_signature(body: &[u8], signature: &str, secret: &[u8]) -> bool {
let hex_part = match signature.strip_prefix("sha256=") {
Some(h) => h,
None => return false,
};
let expected = match hex::decode(hex_part) {
Ok(b) => b,
Err(_) => return false,
};
let mut mac = HmacSha256::new_from_slice(secret).expect("HMAC accepts any key length");
mac.update(body);
mac.verify_slice(&expected).is_ok()
}
pub fn parse_event(body: &[u8]) -> Result<Event, WiError> {
serde_json::from_slice(body).map_err(WiError::Serialize)
}
pub struct WebhookPayload {
pub event: Event,
pub raw: Bytes,
}
impl WebhookPayload {
pub fn from_parts(body: Bytes, signature: &str, secret: &[u8]) -> Option<Result<Self, WiError>> {
if !verify_signature(&body, signature, secret) {
return None;
}
Some(parse_event(&body).map(|event| WebhookPayload { event, raw: body }))
}
pub const HEADER: &'static str = SIGNATURE_HEADER;
}