1use std::collections::hash_map::HashMap;
8use std::fs::File;
9use std::io;
10use std::path::PathBuf;
11
12use chrono::Utc;
13use hex::FromHex;
14use http::HeaderMap;
15use log::{debug, info};
16use rand::Rng;
17use ring::hmac;
18use serde::Deserialize;
19use serde_json::{json, Value};
20use thiserror::Error;
21
22#[derive(Deserialize, Debug, Clone)]
23struct Filter {
24 kind: String,
25 #[serde(default)]
26 use_header_value: bool,
27
28 #[serde(default)]
29 have_keys: Vec<String>,
30 #[serde(default)]
31 items: HashMap<String, Value>,
32
33 header_value: Option<String>,
34}
35
36impl Filter {
37 fn is_match(&self, header: &Option<&[u8]>, object: &Value) -> bool {
38 if let (&Some(actual), Some(expected)) = (header, &self.header_value) {
39 return actual == expected.as_bytes();
40 }
41
42 for key in &self.have_keys {
43 if object.pointer(key).is_none() {
44 return false;
45 }
46 }
47
48 for (pointer, expected) in &self.items {
49 let matches = object.pointer(pointer).map(|value| value == expected);
50
51 if !matches.unwrap_or(false) {
52 return false;
53 }
54 }
55
56 true
57 }
58}
59
60#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
61pub enum Algorithm {
62 #[serde(rename = "sha1")]
63 Sha1,
64 #[serde(rename = "sha256")]
65 Sha256,
66}
67
68impl Algorithm {
69 fn mac_with(self, key: &[u8]) -> hmac::Key {
70 let algo = match self {
71 Algorithm::Sha1 => hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
72 Algorithm::Sha256 => hmac::HMAC_SHA256,
73 };
74
75 hmac::Key::new(algo, key)
76 }
77}
78
79#[derive(Deserialize, Debug, Clone)]
80#[serde(tag = "type")]
81pub enum Comparison {
82 #[serde(rename = "hmac")]
83 Hmac {
84 algorithm: Algorithm,
85 prefix: String,
86 },
87 #[serde(rename = "token")]
88 Token,
89}
90
91impl Comparison {
92 fn verify(&self, given: &[u8], secret: &str, data: &[u8]) -> bool {
93 match *self {
94 Comparison::Token => given == secret.as_bytes(),
95 Comparison::Hmac {
96 ref algorithm,
97 ref prefix,
98 } => {
99 if given.starts_with(prefix.as_bytes()) {
100 if let Ok(digest) = Vec::<u8>::from_hex(&given[prefix.len()..]) {
101 let mac = algorithm.mac_with(secret.as_ref());
102 hmac::verify(&mac, data, &digest)
103 .map(|()| true)
104 .unwrap_or(false)
105 } else {
106 false
107 }
108 } else {
109 false
110 }
111 },
112 }
113 }
114}
115
116#[derive(Deserialize, Debug, Clone)]
117pub struct Verification {
118 secret_key_lookup: String,
119 verification_header: String,
120 compare: Comparison,
121}
122
123impl Verification {
124 fn verify(&self, headers: &HeaderMap, secret: &str, data: &[u8]) -> bool {
125 headers
126 .get(&self.verification_header)
127 .map_or(false, |value| {
128 self.compare.verify(value.as_bytes(), secret, data)
129 })
130 }
131}
132
133#[derive(Debug, Error)]
134pub enum HandlerError {
135 #[error("create file error: {}", source)]
136 Create {
137 filepath: PathBuf,
138 #[source]
139 source: io::Error,
140 },
141 #[error("create file error: {}", source)]
142 Write {
143 #[source]
144 source: serde_json::Error,
145 },
146}
147
148#[derive(Deserialize, Debug, Clone)]
149pub struct Handler {
150 path: String,
151 filters: Vec<Filter>,
152 header_name: Option<String>,
153
154 verification: Option<Verification>,
155}
156
157impl Handler {
158 pub fn lookup_secret<'a>(&self, secrets: &'a Value, object: &Value) -> Option<&'a str> {
159 self.verification.as_ref().and_then(|verification| {
160 let secret_key = if verification.secret_key_lookup.starts_with('/') {
161 object.pointer(&verification.secret_key_lookup).map(|key| {
162 key.as_str().map(Into::into).unwrap_or_else(|| {
163 serde_json::to_string(key).expect("JSON values should be serializable")
164 })
165 })
166 } else {
167 Some(verification.secret_key_lookup.clone())
168 };
169
170 secret_key
171 .and_then(|key| secrets.get(key))
172 .and_then(Value::as_str)
173 })
174 }
175
176 pub fn verify(&self, headers: &HeaderMap, secret: Option<&str>, data: &[u8]) -> bool {
177 if let Some(ref verification) = self.verification {
178 secret.map_or(false, |secret_value| {
179 verification.verify(headers, secret_value, data)
180 })
181 } else {
182 true
183 }
184 }
185
186 pub fn kind(&self, headers: &HeaderMap, object: &Value) -> Option<String> {
187 let header = self
188 .header_name
189 .as_ref()
190 .and_then(|name| headers.get(name).map(|value| value.as_bytes()));
191
192 for filter in &self.filters {
193 if filter.is_match(&header, object) {
194 info!("matched an event of kind {}", filter.kind);
195
196 if filter.use_header_value {
197 if let Some(value) = header {
198 let value_str = String::from_utf8_lossy(value);
199 return Some(filter.kind.replace("HEADER", &value_str));
200 }
201 }
202
203 return Some(filter.kind.clone());
204 }
205 }
206
207 None
208 }
209
210 pub fn write_object(&self, kind: &str, object: Value) -> Result<PathBuf, HandlerError> {
211 let rndpart = rand::thread_rng()
212 .sample_iter(&rand::distributions::Alphanumeric)
213 .map(char::from)
214 .take(12)
215 .collect::<String>();
216 let filename = format!("{}-{}.json", Utc::now().to_rfc3339(), rndpart);
217
218 let mut filepath = PathBuf::from(&self.path);
219 filepath.push(filename);
220
221 debug!(
222 "writing an event of kind {} to {}",
223 kind,
224 filepath.display(),
225 );
226
227 let mut fout = File::create(&filepath).map_err(|source| {
228 HandlerError::Create {
229 filepath: filepath.clone(),
230 source,
231 }
232 })?;
233
234 let output = json!({
235 "kind": kind,
236 "data": object,
237 });
238
239 serde_json::to_writer(&mut fout, &output).map_err(|source| {
240 HandlerError::Write {
241 source,
242 }
243 })?;
244
245 Ok(filepath)
246 }
247}
248
249#[cfg(test)]
250mod test {
251 use std::collections::hash_map::HashMap;
252 use std::fs;
253 use std::path::Path;
254
255 use http::{HeaderMap, HeaderValue};
256 use serde_json::{json, Value};
257 use tempfile::TempDir;
258
259 use crate::handler::{Algorithm, Comparison, Filter, Handler, HandlerError, Verification};
260 use crate::test_utils;
261
262 const WEBHOOK_HEADER_NAME: &str = "X-Webhook-Listen-Kind";
263 const WEBHOOK_HEADER_NAME_LOWER: &str = "x-webhook-listen-kind";
264 const VERIFICATION_HEADER: &str = "X-Webhook-Listen-Verification";
265 const VERIFICATION_HEADER_LOWER: &str = "x-webhook-listen-verification";
266
267 fn create_handler<'a, I>(filters: I) -> Handler
268 where
269 I: IntoIterator<Item = &'a Filter>,
270 {
271 Handler {
272 path: String::new(),
273 filters: filters.into_iter().cloned().collect(),
274 header_name: Some(WEBHOOK_HEADER_NAME.into()),
275 verification: None,
276 }
277 }
278
279 fn static_value(value: &'static str) -> HeaderValue {
280 HeaderValue::from_static(value)
281 }
282
283 #[test]
284 fn test_empty_filter() {
285 let handler = create_handler(&[Filter {
286 kind: "empty".into(),
287 use_header_value: false,
288 have_keys: Vec::new(),
289 items: HashMap::new(),
290 header_value: None,
291 }]);
292
293 let empty = json!({});
294 let array = json!({
295 "array": [0],
296 });
297 let array_non_array = json!({
298 "array": 0,
299 });
300 let with_slash = json!({
301 "with/slash": 0,
302 });
303 let with_tilde = json!({
304 "with~tilde": 0,
305 });
306 let string_keys = json!({
307 "dict": {
308 "0": 0,
309 },
310 });
311 let string_keys_missing = json!({
312 "dict": {
313 "1": 0,
314 },
315 });
316 let many_keys = json!({
317 "first_key": 0,
318 "second_key": 0,
319 });
320 let many_keys_missing = json!({
321 "first_key": 0,
322 });
323 let all = json!({
324 "array": [0],
325 "with/slash": 0,
326 "with~tilde": 0,
327 "dict": {
328 "0": 0,
329 },
330 "first_key": 0,
331 "second_key": 0,
332 });
333
334 let headers = HeaderMap::new();
335
336 assert_eq!(handler.kind(&headers, &empty), Some("empty".into()));
337 assert_eq!(handler.kind(&headers, &array), Some("empty".into()));
338 assert_eq!(
339 handler.kind(&headers, &array_non_array),
340 Some("empty".into()),
341 );
342 assert_eq!(handler.kind(&headers, &with_slash), Some("empty".into()));
343 assert_eq!(handler.kind(&headers, &with_tilde), Some("empty".into()));
344 assert_eq!(handler.kind(&headers, &string_keys), Some("empty".into()));
345 assert_eq!(
346 handler.kind(&headers, &string_keys_missing),
347 Some("empty".into()),
348 );
349 assert_eq!(handler.kind(&headers, &many_keys), Some("empty".into()));
350 assert_eq!(
351 handler.kind(&headers, &many_keys_missing),
352 Some("empty".into()),
353 );
354 assert_eq!(handler.kind(&headers, &all), Some("empty".into()));
355 }
356
357 #[test]
358 fn test_have_keys() {
359 let handler = create_handler(&[
360 Filter {
361 kind: "array".into(),
362 use_header_value: false,
363 have_keys: vec!["/array/0".into()],
364 items: HashMap::new(),
365 header_value: None,
366 },
367 Filter {
368 kind: "with_slash".into(),
369 use_header_value: false,
370 have_keys: vec!["/with~1slash".into()],
371 items: HashMap::new(),
372 header_value: None,
373 },
374 Filter {
375 kind: "with_tilde".into(),
376 use_header_value: false,
377 have_keys: vec!["/with~0tilde".into()],
378 items: HashMap::new(),
379 header_value: None,
380 },
381 Filter {
382 kind: "string_keys".into(),
383 use_header_value: false,
384 have_keys: vec!["/dict/0".into()],
385 items: HashMap::new(),
386 header_value: None,
387 },
388 Filter {
389 kind: "many_keys".into(),
390 use_header_value: false,
391 have_keys: vec!["/first_key".into(), "/second_key".into()],
392 items: HashMap::new(),
393 header_value: None,
394 },
395 ]);
396
397 let empty = json!({});
398 let array = json!({
399 "array": [0],
400 });
401 let array_non_array = json!({
402 "array": 0,
403 });
404 let with_slash = json!({
405 "with/slash": 0,
406 });
407 let with_tilde = json!({
408 "with~tilde": 0,
409 });
410 let string_keys = json!({
411 "dict": {
412 "0": 0,
413 },
414 });
415 let string_keys_missing = json!({
416 "dict": {
417 "1": 0,
418 },
419 });
420 let many_keys = json!({
421 "first_key": 0,
422 "second_key": 0,
423 });
424 let many_keys_missing = json!({
425 "first_key": 0,
426 });
427 let all = json!({
428 "array": [0],
429 "with/slash": 0,
430 "with~tilde": 0,
431 "dict": {
432 "0": 0,
433 },
434 "first_key": 0,
435 "second_key": 0,
436 });
437
438 let headers = HeaderMap::new();
439
440 assert_eq!(handler.kind(&headers, &empty), None);
441 assert_eq!(handler.kind(&headers, &array), Some("array".into()));
442 assert_eq!(handler.kind(&headers, &array_non_array), None);
443 assert_eq!(
444 handler.kind(&headers, &with_slash),
445 Some("with_slash".into()),
446 );
447 assert_eq!(
448 handler.kind(&headers, &with_tilde),
449 Some("with_tilde".into()),
450 );
451 assert_eq!(
452 handler.kind(&headers, &string_keys),
453 Some("string_keys".into()),
454 );
455 assert_eq!(handler.kind(&headers, &string_keys_missing), None);
456 assert_eq!(handler.kind(&headers, &many_keys), Some("many_keys".into()));
457 assert_eq!(handler.kind(&headers, &many_keys_missing), None);
458 assert_eq!(handler.kind(&headers, &all), Some("array".into()));
459 }
460
461 #[test]
462 fn test_items() {
463 let handler = create_handler(&[
464 Filter {
465 kind: "multi".into(),
466 use_header_value: false,
467 have_keys: Vec::new(),
468 items: [("/number".into(), json!(1)), ("/null".into(), Value::Null)]
469 .iter()
470 .cloned()
471 .collect(),
472 header_value: None,
473 },
474 Filter {
475 kind: "null".into(),
476 use_header_value: false,
477 have_keys: Vec::new(),
478 items: [("/null".into(), Value::Null)].iter().cloned().collect(),
479 header_value: None,
480 },
481 Filter {
482 kind: "number".into(),
483 use_header_value: false,
484 have_keys: Vec::new(),
485 items: [("/number".into(), json!(0))].iter().cloned().collect(),
486 header_value: None,
487 },
488 Filter {
489 kind: "string".into(),
490 use_header_value: false,
491 have_keys: Vec::new(),
492 items: [("/string".into(), json!("string"))]
493 .iter()
494 .cloned()
495 .collect(),
496 header_value: None,
497 },
498 Filter {
499 kind: "array".into(),
500 use_header_value: false,
501 have_keys: Vec::new(),
502 items: [("/array".into(), json!([0]))].iter().cloned().collect(),
503 header_value: None,
504 },
505 Filter {
506 kind: "dict".into(),
507 use_header_value: false,
508 have_keys: Vec::new(),
509 items: [("/dict".into(), json!({"0": 0}))]
510 .iter()
511 .cloned()
512 .collect(),
513 header_value: None,
514 },
515 ]);
516
517 let empty = json!({});
518 let null = json!({
519 "null": Value::Null,
520 });
521 let null_mismatch = json!({
522 "null": 0,
523 });
524 let number = json!({
525 "number": 0,
526 });
527 let number_mismatch = json!({
528 "number": 1,
529 });
530 let string = json!({
531 "string": "string",
532 });
533 let string_mismatch = json!({
534 "string": "mismatch",
535 });
536 let array = json!({
537 "array": [0],
538 });
539 let array_mismatch = json!({
540 "array": 0,
541 });
542 let dict = json!({
543 "dict": {
544 "0": 0,
545 },
546 });
547 let dict_mismatch = json!({
548 "dict": {
549 "1": 0,
550 },
551 });
552 let multi = json!({
553 "null": Value::Null,
554 "number": 1,
555 });
556 let multi_missing = json!({
557 "number": 1,
558 });
559
560 let headers = HeaderMap::new();
561
562 assert_eq!(handler.kind(&headers, &empty), None);
563 assert_eq!(handler.kind(&headers, &null), Some("null".into()));
564 assert_eq!(handler.kind(&headers, &null_mismatch), None);
565 assert_eq!(handler.kind(&headers, &number), Some("number".into()));
566 assert_eq!(handler.kind(&headers, &number_mismatch), None);
567 assert_eq!(handler.kind(&headers, &string), Some("string".into()));
568 assert_eq!(handler.kind(&headers, &string_mismatch), None);
569 assert_eq!(handler.kind(&headers, &array), Some("array".into()));
570 assert_eq!(handler.kind(&headers, &array_mismatch), None);
571 assert_eq!(handler.kind(&headers, &dict), Some("dict".into()));
572 assert_eq!(handler.kind(&headers, &dict_mismatch), None);
573 assert_eq!(handler.kind(&headers, &multi), Some("multi".into()));
574 assert_eq!(handler.kind(&headers, &multi_missing), None);
575 }
576
577 #[test]
578 fn test_have_keys_and_items() {
579 let handler = create_handler(&[Filter {
580 kind: "match".into(),
581 use_header_value: false,
582 have_keys: vec!["/array".into()],
583 items: [("/null".into(), Value::Null)].iter().cloned().collect(),
584 header_value: None,
585 }]);
586
587 let empty = json!({});
588 let has_keys = json!({
589 "array": 0,
590 });
591 let has_item = json!({
592 "null": Value::Null,
593 });
594 let has_everything = json!({
595 "array": 0,
596 "null": Value::Null,
597 });
598 let has_mismatch = json!({
599 "array": 0,
600 "null": 0,
601 });
602
603 let headers = HeaderMap::new();
604
605 assert_eq!(handler.kind(&headers, &empty), None);
606 assert_eq!(handler.kind(&headers, &has_keys), None);
607 assert_eq!(handler.kind(&headers, &has_item), None);
608 assert_eq!(
609 handler.kind(&headers, &has_everything),
610 Some("match".into()),
611 );
612 assert_eq!(handler.kind(&headers, &has_mismatch), None);
613 }
614
615 #[test]
616 fn test_headers() {
617 let handler = create_handler(&[
618 Filter {
619 kind: "also_keys".into(),
620 use_header_value: false,
621 have_keys: vec!["/array".into()],
622 items: HashMap::new(),
623 header_value: Some("also_keys".into()),
624 },
625 Filter {
626 kind: "multi".into(),
627 use_header_value: false,
628 have_keys: Vec::new(),
629 items: HashMap::new(),
630 header_value: Some("multi".into()),
631 },
632 ]);
633
634 let empty = json!({});
635 let array = json!({
636 "array": [0],
637 });
638
639 let mut headers = HeaderMap::new();
640
641 assert_eq!(handler.kind(&headers, &empty), Some("multi".into()));
642 assert_eq!(handler.kind(&headers, &array), Some("also_keys".into()));
643
644 headers.insert(WEBHOOK_HEADER_NAME, static_value("multi"));
645
646 assert_eq!(handler.kind(&headers, &empty), Some("multi".into()));
647 assert_eq!(handler.kind(&headers, &array), Some("multi".into()));
648
649 headers.insert(WEBHOOK_HEADER_NAME, static_value("also_keys"));
650
651 assert_eq!(handler.kind(&headers, &empty), Some("also_keys".into()));
652 assert_eq!(handler.kind(&headers, &array), Some("also_keys".into()));
653
654 headers.insert(WEBHOOK_HEADER_NAME_LOWER, static_value("also_keys"));
655
656 assert_eq!(handler.kind(&headers, &empty), Some("also_keys".into()));
657 assert_eq!(handler.kind(&headers, &array), Some("also_keys".into()));
658
659 headers.insert(WEBHOOK_HEADER_NAME, static_value("unmatched"));
660
661 assert_eq!(handler.kind(&headers, &empty), None);
662 assert_eq!(handler.kind(&headers, &array), None);
663 }
664
665 #[test]
666 fn test_headers_replaced() {
667 let handler = create_handler(&[
668 Filter {
669 kind: "ignore".into(),
670 use_header_value: true,
671 have_keys: vec!["/have_keys".into()],
672 items: HashMap::new(),
673 header_value: Some("ignore".into()),
674 },
675 Filter {
676 kind: "unreplaced".into(),
677 use_header_value: true,
678 have_keys: vec!["/have_keys".into()],
679 items: HashMap::new(),
680 header_value: Some("unreplaced".into()),
681 },
682 Filter {
683 kind: "unused:HEADER".into(),
684 use_header_value: false,
685 have_keys: vec!["/have_keys".into()],
686 items: HashMap::new(),
687 header_value: Some("unused".into()),
688 },
689 Filter {
690 kind: "catchall:HEADER".into(),
691 use_header_value: true,
692 have_keys: Vec::new(),
693 items: HashMap::new(),
694 header_value: None,
695 },
696 ]);
697
698 let empty = json!({});
699 let data = json!({
700 "have_keys": false,
701 });
702
703 let mut headers = HeaderMap::new();
704
705 assert_eq!(
706 handler.kind(&headers, &empty),
707 Some("catchall:HEADER".into()),
708 );
709 assert_eq!(handler.kind(&headers, &data), Some("ignore".into()));
710
711 headers.insert(WEBHOOK_HEADER_NAME, static_value("ignore"));
712
713 assert_eq!(handler.kind(&headers, &data), Some("ignore".into()));
714
715 headers.insert(WEBHOOK_HEADER_NAME, static_value("unreplaced"));
716
717 assert_eq!(handler.kind(&headers, &data), Some("unreplaced".into()));
718
719 headers.insert(WEBHOOK_HEADER_NAME, static_value("unused"));
720
721 assert_eq!(handler.kind(&headers, &data), Some("unused:HEADER".into()));
722
723 headers.insert(WEBHOOK_HEADER_NAME, static_value("other"));
724
725 assert_eq!(handler.kind(&headers, &data), Some("catchall:other".into()));
726 }
727
728 #[test]
729 fn test_verification_lookup_secret() {
730 let mut handler = create_handler(&[]);
731
732 let no_secrets = json!({});
733 let with_secret = json!({
734 "key": "secret",
735 "123": "secret with int",
736 "literal": "direct lookup",
737 });
738 let data = json!({
739 "secret_key": "key",
740 });
741 let data_non_str = json!({
742 "secret_key": 123,
743 });
744
745 assert_eq!(handler.lookup_secret(&no_secrets, &data), None);
746 assert_eq!(handler.lookup_secret(&no_secrets, &data_non_str), None);
747 assert_eq!(handler.lookup_secret(&with_secret, &data), None);
748 assert_eq!(handler.lookup_secret(&with_secret, &data_non_str), None);
749
750 handler.verification = Some(Verification {
751 secret_key_lookup: "/secret_key".into(),
752 verification_header: VERIFICATION_HEADER.into(),
753 compare: Comparison::Token,
754 });
755
756 assert_eq!(handler.lookup_secret(&no_secrets, &data), None);
757 assert_eq!(handler.lookup_secret(&no_secrets, &data_non_str), None);
758 assert_eq!(handler.lookup_secret(&with_secret, &data), Some("secret"));
759 assert_eq!(
760 handler.lookup_secret(&with_secret, &data_non_str),
761 Some("secret with int"),
762 );
763
764 handler.verification = Some(Verification {
765 secret_key_lookup: "literal".into(),
766 verification_header: VERIFICATION_HEADER.into(),
767 compare: Comparison::Token,
768 });
769
770 assert_eq!(handler.lookup_secret(&no_secrets, &data), None);
771 assert_eq!(handler.lookup_secret(&no_secrets, &data_non_str), None);
772 assert_eq!(
773 handler.lookup_secret(&with_secret, &data),
774 Some("direct lookup"),
775 );
776 assert_eq!(
777 handler.lookup_secret(&with_secret, &data_non_str),
778 Some("direct lookup"),
779 );
780 }
781
782 #[test]
783 fn test_verification_no_header() {
784 let mut handler = create_handler(&[]);
785
786 handler.verification = Some(Verification {
787 secret_key_lookup: "/secret".into(),
788 verification_header: VERIFICATION_HEADER.into(),
789 compare: Comparison::Token,
790 });
791
792 let data = Vec::new();
793 let headers = HeaderMap::new();
794
795 assert!(!handler.verify(&headers, None, &data));
796 assert!(!handler.verify(&headers, Some("secret"), &data));
797 }
798
799 #[test]
800 fn test_no_verification() {
801 let handler = create_handler(&[]);
802
803 let data = Vec::new();
804 let mut headers = HeaderMap::new();
805
806 headers.insert(VERIFICATION_HEADER, static_value("secret"));
807
808 assert!(handler.verify(&headers, None, &data));
809 assert!(handler.verify(&headers, Some("secret"), &data));
810 assert!(handler.verify(&headers, Some("wrong_secret"), &data));
811 }
812
813 #[test]
814 fn test_verification_token() {
815 let mut handler = create_handler(&[]);
816
817 handler.verification = Some(Verification {
818 secret_key_lookup: "/secret".into(),
819 verification_header: VERIFICATION_HEADER.into(),
820 compare: Comparison::Token,
821 });
822
823 let data = Vec::new();
824 let mut headers = HeaderMap::new();
825
826 headers.insert(VERIFICATION_HEADER, static_value("secret"));
827
828 assert!(!handler.verify(&headers, None, &data));
829 assert!(handler.verify(&headers, Some("secret"), &data));
830 }
831
832 #[test]
833 fn test_verification_token_icase() {
834 let mut handler = create_handler(&[]);
835
836 handler.verification = Some(Verification {
837 secret_key_lookup: "/secret".into(),
838 verification_header: VERIFICATION_HEADER.into(),
839 compare: Comparison::Token,
840 });
841
842 let data = Vec::new();
843 let mut headers = HeaderMap::new();
844
845 headers.insert(VERIFICATION_HEADER_LOWER, static_value("secret"));
846
847 assert!(!handler.verify(&headers, None, &data));
848 assert!(handler.verify(&headers, Some("secret"), &data));
849 }
850
851 #[test]
852 fn test_verification_hmac_sha1() {
853 let mut handler = create_handler(&[]);
854
855 handler.verification = Some(Verification {
856 secret_key_lookup: "/secret".into(),
857 verification_header: VERIFICATION_HEADER.into(),
858 compare: Comparison::Hmac {
859 algorithm: Algorithm::Sha1,
860 prefix: String::new(),
861 },
862 });
863
864 let data = Vec::new();
865 let mut headers = HeaderMap::new();
866
867 headers.insert(
868 VERIFICATION_HEADER,
869 static_value("25af6174a0fcecc4d346680a72b7ce644b9a88e8"),
870 );
871
872 assert!(!handler.verify(&headers, None, &data));
873 assert!(handler.verify(&headers, Some("secret"), &data));
874 assert!(!handler.verify(&headers, Some("wrong_secret"), &data));
875 }
876
877 #[test]
878 fn test_verification_hmac_sha256() {
879 let mut handler = create_handler(&[]);
880
881 handler.verification = Some(Verification {
882 secret_key_lookup: "/secret".into(),
883 verification_header: VERIFICATION_HEADER.into(),
884 compare: Comparison::Hmac {
885 algorithm: Algorithm::Sha256,
886 prefix: String::new(),
887 },
888 });
889
890 let data = Vec::new();
891 let mut headers = HeaderMap::new();
892
893 headers.insert(
894 VERIFICATION_HEADER,
895 static_value("f9e66e179b6747ae54108f82f8ade8b3c25d76fd30afde6c395822c530196169"),
896 );
897
898 assert!(!handler.verify(&headers, None, &data));
899 assert!(handler.verify(&headers, Some("secret"), &data));
900 assert!(!handler.verify(&headers, Some("wrong_secret"), &data));
901 }
902
903 #[test]
904 fn test_verification_hmac_prefix() {
905 let mut handler = create_handler(&[]);
906
907 handler.verification = Some(Verification {
908 secret_key_lookup: "/secret".into(),
909 verification_header: VERIFICATION_HEADER.into(),
910 compare: Comparison::Hmac {
911 algorithm: Algorithm::Sha1,
912 prefix: "sha1=".into(),
913 },
914 });
915
916 let data = Vec::new();
917 let mut headers = HeaderMap::new();
918
919 headers.insert(
920 VERIFICATION_HEADER,
921 static_value("sha1=25af6174a0fcecc4d346680a72b7ce644b9a88e8"),
922 );
923
924 assert!(!handler.verify(&headers, None, &data));
925 assert!(handler.verify(&headers, Some("secret"), &data));
926 assert!(!handler.verify(&headers, Some("wrong_secret"), &data));
927 }
928
929 #[test]
930 fn test_verification_hmac_not_hex() {
931 let mut handler = create_handler(&[]);
932
933 handler.verification = Some(Verification {
934 secret_key_lookup: "/secret".into(),
935 verification_header: VERIFICATION_HEADER.into(),
936 compare: Comparison::Hmac {
937 algorithm: Algorithm::Sha1,
938 prefix: "sha1=".into(),
939 },
940 });
941
942 let data = Vec::new();
943 let mut headers = HeaderMap::new();
944
945 headers.insert(
946 VERIFICATION_HEADER,
947 static_value("sha1=notvalidhexadecimaldigitsequenceofdigits"),
948 );
949
950 assert!(!handler.verify(&headers, None, &data));
951 assert!(!handler.verify(&headers, Some("secret"), &data));
952 assert!(!handler.verify(&headers, Some("wrong_secret"), &data));
953 }
954
955 #[test]
956 fn test_verification_hmac_wrong_prefix() {
957 let mut handler = create_handler(&[]);
958
959 handler.verification = Some(Verification {
960 secret_key_lookup: "/secret".into(),
961 verification_header: VERIFICATION_HEADER.into(),
962 compare: Comparison::Hmac {
963 algorithm: Algorithm::Sha1,
964 prefix: "sha12nope=".into(),
965 },
966 });
967
968 let data = Vec::new();
969 let mut headers = HeaderMap::new();
970
971 headers.insert(
972 VERIFICATION_HEADER,
973 static_value("sha1=25af6174a0fcecc4d346680a72b7ce644b9a88e8"),
974 );
975
976 assert!(!handler.verify(&headers, None, &data));
977 assert!(!handler.verify(&headers, Some("secret"), &data));
978 assert!(!handler.verify(&headers, Some("wrong_secret"), &data));
979 }
980
981 fn create_handler_with_dir() -> (Handler, TempDir) {
982 let tempdir = test_utils::create_tempdir();
983
984 let handler = Handler {
985 path: tempdir
986 .path()
987 .to_str()
988 .expect("test path to be valid UTF-8")
989 .into(),
990 filters: Vec::new(),
991 header_name: Some(WEBHOOK_HEADER_NAME.into()),
992 verification: None,
993 };
994
995 (handler, tempdir)
996 }
997
998 fn check_written_object(path: &Path, object: &Value) {
999 let contents = fs::read_to_string(path).unwrap();
1000 let actual: Value = serde_json::from_str(&contents).unwrap();
1001 assert_eq!(&actual, object);
1002 }
1003
1004 #[test]
1005 fn test_write_object_to_dir() {
1006 let (handler, tempdir) = create_handler_with_dir();
1007 let kind = "kind";
1008 let value = json!({
1009 "blah": null,
1010 });
1011
1012 let output = handler.write_object(kind, value.clone()).unwrap();
1013
1014 let expected = json!({
1015 "kind": kind,
1016 "data": value,
1017 });
1018 check_written_object(&output, &expected);
1019
1020 let _ = tempdir;
1022 }
1023
1024 #[test]
1025 fn test_write_object_to_dir_err() {
1026 let (handler, tempdir_path) = {
1027 let (handler, tempdir) = create_handler_with_dir();
1028 let tempdir_path = tempdir.path().to_path_buf();
1029 (handler, tempdir_path)
1030 };
1031
1032 let kind = "kind";
1033 let value = json!({
1034 "blah": null,
1035 });
1036
1037 let err = handler.write_object(kind, value).unwrap_err();
1038
1039 if let HandlerError::Create {
1040 filepath, ..
1041 } = err
1042 {
1043 assert!(filepath.starts_with(tempdir_path))
1044 } else {
1045 panic!("unexpected error: {:?}", err);
1046 }
1047 }
1048}