use hmac::{Hmac, Mac};
use sha2::Sha256;
type HmacSha256 = Hmac<Sha256>;
pub fn sign(timestamp: i64, secret: &str) -> String {
use base64::engine::Engine;
let content = format!("{}\n{}", timestamp, secret);
let mut mac =
HmacSha256::new_from_slice(secret.as_bytes()).expect("HMAC can take key of any size");
mac.update(content.as_bytes());
base64::engine::general_purpose::STANDARD.encode(mac.finalize().into_bytes())
}
pub fn current_timestamp() -> i64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went backwards")
.as_secs() as i64
}
pub fn verify_signature(timestamp: i64, secret: &str, signature: &str) -> bool {
let computed = sign(timestamp, secret);
computed == signature
}
#[cfg(test)]
#[allow(unused_imports)]
mod tests {
use super::*;
#[test]
fn test_sign_known_input() {
let timestamp = 1599360473i64;
let secret = "test-secret";
let signature = sign(timestamp, secret);
assert!(!signature.is_empty());
}
#[test]
fn test_sign_different_secrets() {
let timestamp = 1599360473i64;
let sig1 = sign(timestamp, "secret1");
let sig2 = sign(timestamp, "secret2");
assert_ne!(sig1, sig2);
}
#[test]
fn test_sign_different_timestamps() {
let secret = "test-secret";
let sig1 = sign(1599360473, secret);
let sig2 = sign(1599360474, secret);
assert_ne!(sig1, sig2);
}
#[test]
fn test_verify_signature_valid() {
let timestamp = 1599360473i64;
let secret = "test-secret";
let signature = sign(timestamp, secret);
assert!(verify_signature(timestamp, secret, &signature));
}
#[test]
fn test_verify_signature_invalid() {
let timestamp = 1599360473i64;
let secret = "test-secret";
assert!(!verify_signature(timestamp, secret, "invalid-signature"));
}
#[test]
fn test_verify_signature_wrong_secret() {
let timestamp = 1599360473i64;
let secret = "test-secret";
let signature = sign(timestamp, secret);
assert!(!verify_signature(timestamp, "wrong-secret", &signature));
}
#[test]
fn test_current_timestamp() {
let ts = current_timestamp();
assert!(ts > 1577836800); assert!(ts < 2000000000); }
}