rusty_bybit/
auth.rs

1//! Authentication utilities for Bybit v5 API
2//!
3//! Provides HMAC-SHA256 signature generation for authenticated requests.
4//!
5//! # Signature Generation
6//!
7//! Bybit v5 API uses HMAC-SHA256 signatures with the format:
8//! `timestamp + api_key + recv_window + payload`
9//!
10//! # Example
11//!
12//! ````rust
13//! use rusty_bybit::auth::generate_signature;
14//!
15//! let signature = generate_signature(
16//!     1658384314791,
17//!     "api_key",
18//!     5000,
19//!     "category=option&symbol=BTC-29JUL22-25000-C",
20//!     "api_secret"
21//! );
22//! ```
23
24use 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}