qiniu_download/base/
credential.rs

1use hmac::{Hmac, Mac};
2use sha1::Sha1;
3
4use super::base64;
5
6/// 七牛凭证,用于设置 Access Key 和 Secret Key 以访问私有空间的七牛对象
7#[derive(Debug, Clone)]
8pub struct Credential {
9    access_key: String,
10    secret_key: String,
11}
12
13impl Credential {
14    #[inline]
15    /// 创建七牛凭证
16    /// # Arguments
17    /// * `ak` - 七牛 Access Key
18    /// * `sk` - 七牛 Secret Key
19    pub fn new(ak: impl Into<String>, sk: impl Into<String>) -> Credential {
20        Credential {
21            access_key: ak.into(),
22            secret_key: sk.into(),
23        }
24    }
25
26    pub(crate) fn access_key(&self) -> &str {
27        &self.access_key
28    }
29
30    pub(crate) fn sign(&self, data: &[u8]) -> String {
31        self.access_key.to_owned() + ":" + &self.base64_hmac_digest(data)
32    }
33
34    pub(crate) fn sign_with_data(&self, data: &[u8]) -> String {
35        let encoded_data = base64::urlsafe(data);
36        self.sign(encoded_data.as_bytes()) + ":" + &encoded_data
37    }
38
39    fn base64_hmac_digest(&self, data: &[u8]) -> String {
40        let mut hmac = Hmac::<Sha1>::new_from_slice(self.secret_key.as_bytes()).unwrap();
41        hmac.update(data);
42        base64::urlsafe(&hmac.finalize().into_bytes())
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use std::{boxed::Box, error::Error, result::Result, sync::Arc, thread};
50
51    #[test]
52    fn test_sign() -> Result<(), Box<dyn Error>> {
53        env_logger::try_init().ok();
54
55        let credential = Arc::new(Credential::new("abcdefghklmnopq", "1234567890"));
56        let mut threads = Vec::new();
57        {
58            threads.push(thread::spawn(move || {
59                assert_eq!(
60                    credential.sign(b"hello"),
61                    "abcdefghklmnopq:b84KVc-LroDiz0ebUANfdzSRxa0="
62                );
63                assert_eq!(
64                    credential.sign(b"world"),
65                    "abcdefghklmnopq:VjgXt0P_nCxHuaTfiFz-UjDJ1AQ="
66                );
67            }));
68        }
69        {
70            let credential = Arc::new(Credential::new("abcdefghklmnopq", "1234567890"));
71            threads.push(thread::spawn(move || {
72                assert_eq!(
73                    credential.sign(b"-test"),
74                    "abcdefghklmnopq:vYKRLUoXRlNHfpMEQeewG0zylaw="
75                );
76                assert_eq!(
77                    credential.sign(b"ba#a-"),
78                    "abcdefghklmnopq:2d_Yr6H1GdTKg3RvMtpHOhi047M="
79                );
80            }));
81        }
82        threads
83            .into_iter()
84            .for_each(|thread| thread.join().unwrap());
85        Ok(())
86    }
87}