qiniu_upload_rs/utils/
auth.rs

1use crypto::hmac::Hmac;
2use crypto::mac::Mac;
3use crypto::sha1::Sha1;
4use serde_json::json;
5use std::time::{SystemTime, UNIX_EPOCH};
6
7pub struct Auth {
8    pub access_key: String,
9    pub secret_key: String,
10}
11
12impl Auth {
13    pub fn upload_token(&self, bucket: &str, key: &str, expired_seconds: u64) -> String {
14        let json_data = json!({
15            "scope": self.scope(bucket, key),
16            "deadline": self.deadline(expired_seconds),
17        })
18        .to_string();
19
20        let data = base64::encode_config(&json_data, base64::URL_SAFE);
21
22        let sha1_digest = self.sha1_digest(&data);
23        let digest = base64::encode_config(&sha1_digest, base64::URL_SAFE);
24
25        format!("{}:{}:{}", self.access_key, digest, data)
26    }
27
28    fn deadline(&self, expired_seconds: u64) -> u64 {
29        if expired_seconds == 0 {
30            panic!("param `expired_seconds` must be positive")
31        }
32
33        let time_now_secs = SystemTime::now()
34            .duration_since(UNIX_EPOCH)
35            .unwrap()
36            .as_secs();
37
38        time_now_secs + expired_seconds
39    }
40
41    fn scope(&self, bucket: &str, key: &str) -> String {
42        if bucket.is_empty() {
43            panic!("param `bucket` cannot be empty")
44        }
45
46        if key.is_empty() {
47            panic!("param `key` cannot be empty")
48        }
49
50        format!("{}:{}", bucket, key)
51    }
52
53    fn sha1_digest(&self, data: &str) -> Vec<u8> {
54        let mut hmac = Hmac::new(Sha1::new(), self.secret_key.as_bytes());
55        hmac.input(data.as_bytes());
56
57        hmac.result().code().to_vec()
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    const DUMMY_ACCESS_KEY: &str = "dummy_access_key";
66    const DUMMY_SECRET_KEY: &str = "dummy_secret_key";
67    const DUMMY_BUCKET: &str = "dummy_bucket";
68    const DUMMY_KEY: &str = "dummy_key";
69
70    #[test]
71    fn test_upload_token() {
72        let auth = Auth {
73            access_key: DUMMY_ACCESS_KEY.to_string(),
74            secret_key: DUMMY_SECRET_KEY.to_string(),
75        };
76
77        let new_upload_token = auth.upload_token(DUMMY_BUCKET, DUMMY_KEY, 600);
78
79        let items: Vec<&str> = new_upload_token.split(":").collect();
80        assert_eq!(items[0], "dummy_access_key");
81    }
82}