Skip to main content

br_phone/
lib.rs

1
2use std::io::Error;
3use hex::encode;
4use hmac::{Hmac, Mac};
5use json::object;
6use sha2::{Digest, Sha256};
7
8#[derive(Clone, Debug)]
9pub struct Phone {
10    /// 手机号码
11    phone_number: Vec<String>,
12    /// appid
13    sdk_appid: String,
14    /// 模板id
15    templated_id: String,
16    /// 短信签名
17    sign_name: String,
18    /// 密钥ID
19    secret_id: String,
20    /// 密钥
21    secret_key: String,
22    /// 模板参数
23    templated_data: Vec<String>,
24
25}
26impl Phone {
27    pub fn new(phone_number: Vec<&str>, sdk_appid: &str, templated_id: &str, sign_name: &str,secret_id: &str,secret_key: &str,templated_data: Vec<&str>,) -> Self {
28        Self {
29            phone_number:phone_number.iter().map(|s| s.to_string()).collect(),
30            sdk_appid: sdk_appid.to_string(),
31            templated_id: templated_id.to_string(),
32            sign_name: sign_name.to_string(),
33            secret_id: secret_id.to_string(),
34            secret_key: secret_key.to_string(),
35            templated_data:templated_data.iter().map(|s| s.to_string()).collect(),
36        }
37    }
38    pub fn send(&mut self, authorization:&str)->Result<String, Error>{
39        let mut http = br_reqwest::Client::new();
40        let url= "https://sms.tencentcloudapi.com";
41        match http.post(url)
42            .header("Authorization", authorization)
43            .header("content-type", "application/json")
44            .header("X-TC-Action","SendSms")
45            .header("X-TC-Region","ap-guangzhou")
46            .header("X-TC-Timestamp",br_fields::datetime::Timestamp::timestamp().to_string().as_str())
47            .header("X-TC-Version","2021-01-11")
48            .header("Host","sms.tencentcloudapi.com")
49            .raw_json(object! {
50                "PhoneNumberSet": self.phone_number.clone(),
51                "SmsSdkAppId": self.sdk_appid.clone(),
52                "TemplateId": self.templated_id.clone(),
53                "SignName": self.sign_name.clone(),
54                "TemplateParamSet": self.templated_data.clone(),
55            })
56            .send().unwrap()
57            .json() {
58            Ok(e) => {
59                println!("发送成功{:#}",e);
60            }
61            Err(e) => {
62                println!("e{:?}",e);
63            }
64        };
65
66        Ok("".to_string())
67    }
68    ///发送短信
69    pub fn sign(&mut self)->String{
70        //1. 拼接规范请求串
71        let method = "POST";
72        let uri = "/";
73        let query_string = "";
74        let headers = "content-type:application/json\nhost:sms.tencentcloudapi.com\nx-tc-action:sendsms\n";
75        let signed_headers = "content-type;host;x-tc-action";
76        let payload = object!{
77            "PhoneNumberSet": self.phone_number.clone(),
78            "SmsSdkAppId": self.sdk_appid.clone(),
79            "TemplateId": self.templated_id.clone(),
80            "SignName": self.sign_name.clone(),
81            "TemplateParamSet": self.templated_data.clone(),
82        };
83
84        // 转成字符串发送
85        let payload = payload.to_string();
86        let canonical_request = build_canonical_request(method, uri, query_string, headers, signed_headers, payload.as_str());
87        //2. 拼接待签名字符串
88        let hashed_canonical_request = sha256_hex_lowercase(&canonical_request);
89        let service = "sms";
90        let binding = br_fields::datetime::Timestamp::timestamp().to_string();
91        let timestamp = binding.as_str();
92        let data = br_fields::datetime::Datetime::datetime_format("%Y-%m-%d").to_string();
93        let credential_scope = format!("{}/{}/tc3_request", data, service);
94        let algorithm = "TC3-HMAC-SHA256";
95
96        // 最终拼接 StringToSign
97        let string_to_sign = format!("{}\n{}\n{}\n{}", algorithm, timestamp, credential_scope, hashed_canonical_request);
98        // 派生密钥
99        let secret_date = hmac_sha256(format!("TC3{}", self.secret_key).as_bytes(), data.as_str());
100        let secret_service = hmac_sha256(&secret_date, service);
101        let secret_signing = hmac_sha256(&secret_service, "tc3_request");
102        //3. 计算签名
103        let signature = hmac_sha256(&secret_signing, string_to_sign.as_str());
104        let hex_str: String = encode(signature);
105        let auth = build_authorization(self.secret_id.as_str(), credential_scope.as_str(), signed_headers, hex_str.as_str());
106        auth
107    }
108}
109fn build_canonical_request(
110    method: &str,
111    uri: &str,
112    query_string: &str,
113    headers: &str,
114    signed_headers: &str,
115    payload: &str,
116) -> String {
117    let hashed_payload = sha256_hex_lowercase(payload);
118    format!("{}\n{}\n{}\n{}\n{}\n{}", method, uri, query_string, headers, signed_headers, hashed_payload)
119}
120
121fn sha256_hex_lowercase(data: &str) -> String {
122    let hash = Sha256::digest(data.as_bytes());
123    format!("{:x}", hash)
124}
125type HmacSha256 = Hmac<Sha256>;
126fn hmac_sha256(key: &[u8], data: &str) -> Vec<u8> {
127    let mut mac = HmacSha256::new_from_slice(key).expect("HMAC can take key of any size");
128    mac.update(data.as_bytes());
129    mac.finalize().into_bytes().to_vec()
130}
131fn build_authorization(
132    secret_id: &str,
133    credential_scope: &str,
134    signed_headers: &str,
135    signature: &str,
136) -> String {
137    format!("TC3-HMAC-SHA256 Credential={}/{}, SignedHeaders={}, Signature={}", secret_id, credential_scope, signed_headers, signature
138    )
139}