bitbank_api/private/
auth.rs1use reqwest::header::HeaderMap;
2
3const ACCESS_KEY: &'static str = "ACCESS-KEY";
4const ACCESS_NONCE: &'static str = "ACCESS-NONCE";
5const ACCESS_SIGNATURE: &'static str = "ACCESS-SIGNATURE";
6
7fn generate_nonce() -> u64 {
8 use std::time::SystemTime;
9 let now = SystemTime::now();
10 let du = now.duration_since(SystemTime::UNIX_EPOCH).unwrap();
11 du.as_micros() as u64
12}
13
14#[derive(Debug, Clone)]
15pub struct Credential {
16 pub api_key: String,
17 pub api_secret: String,
18}
19impl Credential {
20 pub fn from_env() -> anyhow::Result<Self> {
25 use std::env;
26 let api_key = env::var("BITBANK_API_KEY")?;
27 let api_secret = env::var("BITBANK_API_SECRET")?;
28 Ok(Self {
29 api_key,
30 api_secret,
31 })
32 }
33 fn signature(&self, message: &str) -> String {
34 use crypto::hmac::Hmac;
35 use crypto::mac::Mac;
36 use crypto::sha2::Sha256;
37 use hex::ToHex;
38
39 let mut mac = Hmac::new(Sha256::new(), self.api_secret.as_bytes());
40 mac.input(message.as_bytes());
41 let signature: String = mac.result().code().encode_hex();
42 signature
43 }
44}
45
46pub struct GetAuth {
47 pub path: String,
48 pub params: String,
49}
50impl GetAuth {
51 pub fn create(self, cred: Credential) -> anyhow::Result<HeaderMap> {
52 let mut out = HeaderMap::new();
53 let nonce = generate_nonce();
54 let sig = {
55 let message = format!("{nonce}{}{}", self.path, self.params);
56 cred.signature(&message)
57 };
58 out.insert(ACCESS_KEY, cred.api_key.try_into()?);
59 out.insert(ACCESS_NONCE, nonce.try_into()?);
60 out.insert(ACCESS_SIGNATURE, sig.try_into()?);
61 Ok(out)
62 }
63}
64
65pub struct PostAuth {
66 pub body: String,
67}
68impl PostAuth {
69 pub fn create(self, cred: Credential) -> anyhow::Result<HeaderMap> {
70 let mut out = HeaderMap::new();
71 let nonce = generate_nonce();
72 let sig = {
73 let message = format!("{nonce}{}", self.body);
74 cred.signature(&message)
75 };
76 out.insert(ACCESS_KEY, cred.api_key.try_into()?);
77 out.insert(ACCESS_NONCE, nonce.try_into()?);
78 out.insert(ACCESS_SIGNATURE, sig.try_into()?);
79 Ok(out)
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn test() -> anyhow::Result<()> {
89 let cred = Credential {
90 api_key: "MY_API_KEY".to_owned(),
91 api_secret: "MY_API_SECRET".to_owned(),
92 };
93 let get = GetAuth {
94 path: "/v1/a/b/c".to_owned(),
95 params: "?a=1&b=2".to_owned(),
96 };
97 let h = get.create(cred.clone())?;
98 dbg!(h);
99
100 let post = PostAuth {
101 body: "{a:1,b:[2,3]}".to_owned(),
102 };
103 let h = post.create(cred)?;
104 dbg!(h);
105
106 Ok(())
107 }
108}