github_webhook_message_validator/
lib.rs

1//! The `github_webhook_message_validator` crate provides functions to validating GitHub webhook
2//! notifications.
3
4extern crate hmac;
5extern crate sha1;
6
7use hmac::{Hmac, Mac};
8use sha1::Sha1;
9
10
11/// Check a signature and a message against a shared secret.
12///
13/// Note that if you get the signature from the `X-Hub-Signature` header, you'll need to convert it
14/// to bytes via hex. Use the `rustc_serialize` `From_Hex` trait to do this.
15///
16/// # Examples
17///
18/// ```
19/// use github_webhook_message_validator::validate;
20///
21/// let signature = &vec![
22///     115, 109, 127, 147, 66, 242, 167, 210, 57, 175, 165, 81, 58, 75, 178, 40, 62, 14, 21, 136
23/// ];
24/// let secret = b"some-secret";
25/// let message = b"blah-blah-blah";
26///
27/// assert_eq!(validate(secret, signature, message), true);
28/// ```
29pub fn validate(secret: &[u8], signature: &[u8], message: &[u8]) -> bool {
30    let mut hmac = Hmac::<Sha1>::new_from_slice(secret)
31        .expect("HMAC can take key of any size");
32    hmac.update(message);
33    hmac.verify_slice(signature).is_ok()
34}
35
36#[cfg(test)]
37mod test {
38    use validate;
39
40    #[test]
41    fn it_returns_true_when_signature_and_message_match() {
42        let signature = &vec![
43            0x73, 0x6d, 0x7f, 0x93, 0x42,
44            0xf2, 0xa7, 0xd2, 0x39, 0xaf,
45            0xa5, 0x51, 0x3a, 0x4b, 0xb2,
46            0x28, 0x3e, 0x0e, 0x15, 0x88
47        ];
48        let secret = b"some-secret";
49        let message = b"blah-blah-blah";
50
51        assert_eq!(validate(secret, signature, message), true);
52    }
53
54    #[test]
55    fn it_returns_false_when_signature_and_message_do_not_match() {
56        let signature = &vec![
57            0x31, 0x30, 0x2b, 0x00, 0xba,
58            0xd4, 0xd6, 0xd1, 0x10, 0xa1,
59            0x18, 0x82, 0x77, 0xc4, 0xd1,
60            0x06, 0x0c, 0xb2, 0xc3, 0x73
61        ];
62        let secret = b"some-secret";
63        let message = b"blah-blah-blah?";
64
65        assert_eq!(validate(secret, signature, message), false);
66    }
67}