zenlayercloud_sdk/
signer.rs1use anyhow::Context;
2use hmac::{Hmac, Mac};
3use log::debug;
4use sha2::{Digest, Sha256};
5use crate::Error;
6
7use crate::credentials::AccessKeyCredential;
8
9type HS256 = Hmac<Sha256>;
10
11pub trait Signer {
12 fn sign_request(&self, req: &mut reqwest::Request) -> Result<(), Error>;
13}
14
15pub struct Zc2HS256Signer {
17 algorithm: &'static str,
18 credential: AccessKeyCredential,
19}
20
21impl Zc2HS256Signer {
22 pub fn new(credential: AccessKeyCredential) -> Self {
23 Zc2HS256Signer {
24 algorithm: "ZC2-HMAC-SHA256",
25 credential,
26 }
27 }
28}
29
30impl Signer for Zc2HS256Signer {
31 fn sign_request(&self, req: &mut reqwest::Request) -> Result<(), Error> {
32 use reqwest::header::HeaderValue;
33
34 let canonical_uri = "/";
35 let canonical_query_string = "";
36 let canonical_headers = format!(
37 "content-type:{}\nhost:{}\n",
38 req.headers()["Content-Type"]
39 .to_str()
40 .context("header Content-Type")?,
41 req.headers()["Host"].to_str().context("header Host")?,
42 );
43
44 let signed_headers = "content-type;host";
45
46 let body_bytes = req
47 .body()
48 .context("payload not set")?
49 .as_bytes()
50 .context("failed to read payload")?;
51 let hashed_request_payload = hex_sha256(body_bytes);
52 debug!("payload={}", String::from_utf8_lossy(body_bytes));
53
54 let canonical_request = format!(
55 "{}\n{}\n{}\n{}\n{}\n{}",
56 req.method(),
57 canonical_uri,
58 canonical_query_string,
59 canonical_headers,
60 signed_headers,
61 &hashed_request_payload,
62 );
63
64 let timestamp = req.headers()["x-zc-timestamp"].to_str().context("header x-zc-timestamp")?;
65 let string_to_sign = format!(
66 "{}\n{}\n{}",
67 self.algorithm,
68 ×tamp,
69 hex_sha256(canonical_request.as_bytes()),
70 );
71
72 let mut hs256 =
73 HS256::new_from_slice(&self.credential.access_key_password.as_bytes()).unwrap();
74 hs256.update(string_to_sign.as_bytes());
75 let signature = format!("{:x}", hs256.finalize().into_bytes());
76
77 let authorization = format!(
78 "{} Credential={}, SignedHeaders={}, Signature={}",
79 self.algorithm, self.credential.access_key_id, signed_headers, signature,
80 );
81 req.headers_mut()
82 .insert("Authorization", HeaderValue::from_str(&authorization).context("set header Authorization")?);
83 req.headers_mut().insert(
84 "X-ZC-Signature-Method",
85 HeaderValue::from_str(self.algorithm).context("set header X-ZC-Signature-Method")?,
86 );
87
88 Ok(())
89 }
90}
91
92fn hex_sha256(data: &[u8]) -> String {
93 format!("{:x}", Sha256::digest(data))
94}