1use chrono::Utc;
25use hmac::{Hmac, Mac};
26use sha2::Sha256;
27
28type HmacSha256 = Hmac<Sha256>;
29
30#[derive(Debug, Clone)]
31pub struct Credentials {
32 pub api_key: String,
33 pub api_secret: String,
34}
35
36impl Credentials {
37 pub fn new(api_key: String, api_secret: String) -> Self {
38 Self {
39 api_key,
40 api_secret,
41 }
42 }
43}
44
45pub fn generate_signature(
46 timestamp: i64,
47 api_key: &str,
48 recv_window: u64,
49 payload: &str,
50 secret: &str,
51) -> String {
52 let sign_str = format!("{}{}{}{}", timestamp, api_key, recv_window, payload);
53
54 let mut mac = HmacSha256::new_from_slice(secret.as_bytes()).expect("Invalid key length");
55 mac.update(sign_str.as_bytes());
56
57 hex::encode(mac.finalize().into_bytes())
58}
59
60pub fn get_current_timestamp_ms() -> i64 {
61 Utc::now().timestamp_millis()
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn test_generate_signature() {
70 let timestamp = 1658384314791;
71 let api_key = "XXXXXXXXXX";
72 let recv_window = 5000;
73 let query_string = "category=option&symbol=BTC-29JUL22-25000-C";
74 let secret = "test_secret";
75
76 let signature = generate_signature(timestamp, api_key, recv_window, query_string, secret);
77 assert!(!signature.is_empty());
78 assert_eq!(signature.len(), 64);
79 }
80
81 #[test]
82 fn test_generate_signature_post() {
83 let timestamp = 1658385579423;
84 let api_key = "XXXXXXXXXX";
85 let recv_window = 5000;
86 let body = "{\"category\": \"option\"}";
87 let secret = "test_secret";
88
89 let signature = generate_signature(timestamp, api_key, recv_window, body, secret);
90 assert!(!signature.is_empty());
91 assert_eq!(signature.len(), 64);
92 }
93}