rusty_common/auth/
mod.rs

1//! Authentication utilities for various exchanges
2
3pub mod ed25519;
4pub mod exchanges;
5pub mod hmac;
6pub mod jwt;
7pub mod pem;
8pub mod signature;
9
10#[cfg(test)]
11pub mod ed25519_tests;
12
13use crate::collections::FxHashMap;
14use crate::{Exchange, Result, SmartString};
15use std::fmt::Debug;
16
17/// Common trait for exchange authentication
18pub trait ExchangeAuthentication: Send + Sync + Debug {
19    /// Generate authentication headers for a request
20    fn generate_authentication_headers(
21        &self,
22        method: &str,
23        path: &str,
24        parameters: Option<(&str, &str)>,
25    ) -> Result<FxHashMap<SmartString, SmartString>>;
26
27    /// Generate authentication headers for a request with body
28    /// Default implementation calls generate_authentication_headers without body
29    fn generate_authentication_headers_with_body(
30        &self,
31        method: &str,
32        path: &str,
33        parameters: Option<(&str, &str)>,
34        _body: Option<&str>,
35    ) -> Result<FxHashMap<SmartString, SmartString>> {
36        self.generate_authentication_headers(method, path, parameters)
37    }
38
39    /// Generate WebSocket authentication message
40    fn generate_websocket_authentication(&self) -> Result<SmartString>;
41
42    /// Get API key
43    fn api_key(&self) -> &str;
44}
45
46/// Common authentication configuration
47#[derive(Debug, Clone)]
48pub struct AuthenticationConfiguration {
49    /// The API key for the exchange.
50    pub api_key: SmartString,
51    /// The secret key for the exchange.
52    pub secret_key: SmartString,
53    /// The passphrase for the exchange, if applicable.
54    pub passphrase: Option<SmartString>,
55}
56
57impl AuthenticationConfiguration {
58    #[must_use]
59    /// Creates a new `AuthenticationConfiguration` with the given API and secret keys.
60    pub const fn new(api_key: SmartString, secret_key: SmartString) -> Self {
61        Self {
62            api_key,
63            secret_key,
64            passphrase: None,
65        }
66    }
67
68    #[must_use]
69    /// Sets the passphrase for the `AuthenticationConfiguration`.
70    pub fn with_passphrase(mut self, passphrase: SmartString) -> Self {
71        self.passphrase = Some(passphrase);
72        self
73    }
74}
75
76/// Compile-time authentication constants and validation
77/// Maximum HMAC signature length for buffer sizing
78#[inline]
79#[must_use]
80pub const fn max_hmac_signature_length() -> usize {
81    128 // Conservative maximum for HMAC-SHA256 hex-encoded
82}
83
84/// Maximum JWT token length for buffer sizing
85#[inline]
86#[must_use]
87pub const fn max_jwt_token_length() -> usize {
88    2048 // Conservative maximum for JWT tokens
89}
90
91/// Maximum nonce length for buffer sizing
92#[inline]
93#[must_use]
94pub const fn max_nonce_length() -> usize {
95    64 // Conservative maximum for nonce values
96}
97
98/// Calculate authentication header count for pre-allocation
99#[inline]
100#[must_use]
101pub const fn max_auth_headers_count() -> usize {
102    8 // Conservative maximum number of auth headers
103}
104
105/// Check if authentication method requires timestamp
106#[inline]
107#[must_use]
108pub const fn auth_requires_timestamp(exchange: Exchange) -> bool {
109    match exchange {
110        Exchange::Binance | Exchange::Bybit | Exchange::Coinbase => true,
111        Exchange::Upbit | Exchange::Bithumb => false,
112    }
113}
114
115// Re-export the trait with a shorter name for compatibility
116pub use self::ExchangeAuthentication as ExchangeAuth;
117// Provide compatibility alias for configuration
118/// A type alias for `AuthenticationConfiguration`.
119pub type AuthConfig = AuthenticationConfiguration;
120
121#[cfg(test)]
122mod const_fn_tests {
123    use super::*;
124
125    #[test]
126    fn test_auth_const_functions() {
127        // Test const fn operations can be used in const contexts
128        const MAX_HMAC_LEN: usize = max_hmac_signature_length();
129        const MAX_JWT_LEN: usize = max_jwt_token_length();
130        const MAX_NONCE_LEN: usize = max_nonce_length();
131        const MAX_HEADERS: usize = max_auth_headers_count();
132        const BINANCE_NEEDS_TIMESTAMP: bool = auth_requires_timestamp(Exchange::Binance);
133        const UPBIT_NEEDS_TIMESTAMP: bool = auth_requires_timestamp(Exchange::Upbit);
134
135        assert_eq!(MAX_HMAC_LEN, 128);
136        assert_eq!(MAX_JWT_LEN, 2048);
137        assert_eq!(MAX_NONCE_LEN, 64);
138        assert_eq!(MAX_HEADERS, 8);
139        assert!(BINANCE_NEEDS_TIMESTAMP);
140        assert!(!UPBIT_NEEDS_TIMESTAMP);
141    }
142}