Open al-maisan opened 1 year ago
use actix_web::{HttpRequest, error::ErrorBadRequest};
use hmac::{Hmac, Mac};
use sha2::Sha256;
use base64;
use chrono::prelude::*;
use bip32;
#[derive(Debug, PartialEq)]
pub struct PublicKey(pub [u8; 33]);
impl PublicKey {
pub fn from_hex(hex: &str) -> Result<Self, bip32::Error> {
let mut key = [0; 33];
let mut key_iter = hex.split(':').map(|byte_str| u8::from_str_radix(byte_str, 16));
for (i, byte) in key_iter.enumerate() {
key[i] = byte?;
}
Ok(PublicKey(key))
}
pub fn to_bytes(&self) -> [u8; 33] {
self.0
}
}
fn verify_sig(req: &HttpRequest) -> Result<bool, ErrorBadRequest> {
let ts_header = req.headers().get("HM-TS");
let signature_header = req.headers().get("HM-SIGN");
let key_header = req.headers().get("HM-KEY");
if ts_header.is_none() || signature_header.is_none() || key_header.is_none() {
return Err(ErrorBadRequest("Missing header"));
}
let ts = ts_header.unwrap().to_str().unwrap();
let signature = signature_header.unwrap().to_str().unwrap();
let key = key_header.unwrap().to_str().unwrap();
let ts = ts.parse::<i64>().unwrap();
let current_timestamp = Utc::now().timestamp() * 1000;
if (current_timestamp - ts).abs() > 5000 {
return Ok(false);
}
let public_key = PublicKey::from_hex(key)?;
let signature_payload = format!("{}{}{}{}", ts, req.method().as_str(), req.path(), req.body());
let signature_payload = signature_payload.as_bytes();
let mut mac = Hmac::<Sha256>::new_varkey(public_key.to_bytes().as_slice()).unwrap();
mac.input(signature_payload);
let result = mac.verify(base64::decode(signature).unwrap().as_slice());
if result.is_err() {
return Ok(false);
}
Ok(true)
}
assume the
HM-SIGN
header was computed as followswrite a
rust
function with the following signature and package it in autils
crate:fn verify_sig(req: &HttpRequest) -> bool
i.e. itactix_web
HttpRequesttrue
if the signature is correct and the timestamp is 5 seconds old or newer,false
otherwise.Please note: the
HM-KEY
header contains a bip32::PublicKey (33 bytes) in the following format:03:b6:bd:48:8a:40:1d:e1:64:2f:5c:bf:b7:10:68:4a:df:3d:e0:70:de:93:e9:68:e4:15:c2:21:4d:f2:86:7f:65