|
| 1 | +use hmac::{Hmac, KeyInit, Mac}; |
1 | 2 | use serde::Serialize; |
2 | 3 | use sha2::Digest; |
| 4 | +use std::time::{SystemTime, UNIX_EPOCH}; |
| 5 | + |
| 6 | +type HmacSha256 = Hmac<sha2::Sha256>; |
3 | 7 |
|
4 | 8 | const DEFAULT_API_URL: &str = "https://api.ferrflow.com"; |
5 | 9 |
|
| 10 | +fn hmac_secret() -> &'static str { |
| 11 | + option_env!("FERRFLOW_HMAC_SECRET").unwrap_or(env!("FERRFLOW_HMAC_SECRET")) |
| 12 | +} |
| 13 | + |
6 | 14 | #[derive(Debug, Clone, Copy, Serialize)] |
7 | 15 | #[serde(rename_all = "snake_case")] |
8 | 16 | #[allow(dead_code)] |
@@ -83,11 +91,30 @@ pub fn send_event( |
83 | 91 | let url = format!("{}/events", api_url()); |
84 | 92 |
|
85 | 93 | std::thread::spawn(move || { |
| 94 | + let body = match serde_json::to_string(&payload) { |
| 95 | + Ok(b) => b, |
| 96 | + Err(_) => return, |
| 97 | + }; |
| 98 | + |
| 99 | + let timestamp = SystemTime::now() |
| 100 | + .duration_since(UNIX_EPOCH) |
| 101 | + .unwrap() |
| 102 | + .as_secs() |
| 103 | + .to_string(); |
| 104 | + |
| 105 | + let message = format!("{timestamp}.{body}"); |
| 106 | + let mut mac = HmacSha256::new_from_slice(hmac_secret().as_bytes()) |
| 107 | + .expect("HMAC accepts any key length"); |
| 108 | + mac.update(message.as_bytes()); |
| 109 | + let signature = hex::encode(mac.finalize().into_bytes()); |
| 110 | + |
86 | 111 | let agent = ureq::Agent::new_with_defaults(); |
87 | 112 | let _ = agent |
88 | 113 | .post(&url) |
89 | 114 | .header("Content-Type", "application/json") |
90 | | - .send_json(&payload); |
| 115 | + .header("X-Timestamp", ×tamp) |
| 116 | + .header("X-Signature", &signature) |
| 117 | + .send(body.as_bytes()); |
91 | 118 | }); |
92 | 119 | } |
93 | 120 |
|
|
0 commit comments