br-phone 0.1.0

This is an sms
Documentation

use std::io::Error;
use hex::encode;
use hmac::{Hmac, Mac};
use json::object;
use sha2::{Digest, Sha256};

#[derive(Clone, Debug)]
pub struct Phone {
    /// 手机号码
    phone_number: Vec<String>,
    /// appid
    sdk_appid: String,
    /// 模板id
    templated_id: String,
    /// 短信签名
    sign_name: String,
    /// 密钥ID
    secret_id: String,
    /// 密钥
    secret_key: String,
    /// 模板参数
    templated_data: Vec<String>,

}
impl Phone {
    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 {
        Self {
            phone_number:phone_number.iter().map(|s| s.to_string()).collect(),
            sdk_appid: sdk_appid.to_string(),
            templated_id: templated_id.to_string(),
            sign_name: sign_name.to_string(),
            secret_id: secret_id.to_string(),
            secret_key: secret_key.to_string(),
            templated_data:templated_data.iter().map(|s| s.to_string()).collect(),
        }
    }
    pub fn send(&mut self, authorization:&str)->Result<String, Error>{
        let mut http = br_reqwest::Client::new();
        let url= "https://sms.tencentcloudapi.com";
        match http.post(url)
            .header("Authorization", authorization)
            .header("content-type", "application/json")
            .header("X-TC-Action","SendSms")
            .header("X-TC-Region","ap-guangzhou")
            .header("X-TC-Timestamp",br_fields::datetime::Timestamp::timestamp().to_string().as_str())
            .header("X-TC-Version","2021-01-11")
            .header("Host","sms.tencentcloudapi.com")
            .raw_json(object! {
                "PhoneNumberSet": self.phone_number.clone(),
                "SmsSdkAppId": self.sdk_appid.clone(),
                "TemplateId": self.templated_id.clone(),
                "SignName": self.sign_name.clone(),
                "TemplateParamSet": self.templated_data.clone(),
            })
            .send().unwrap()
            .json() {
            Ok(e) => {
                println!("发送成功{:#}",e);
            }
            Err(e) => {
                println!("e{:?}",e);
            }
        };

        Ok("".to_string())
    }
    ///发送短信
    pub fn sign(&mut self)->String{
        //1. 拼接规范请求串
        let method = "POST";
        let uri = "/";
        let query_string = "";
        let headers = "content-type:application/json\nhost:sms.tencentcloudapi.com\nx-tc-action:sendsms\n";
        let signed_headers = "content-type;host;x-tc-action";
        let payload = object!{
            "PhoneNumberSet": self.phone_number.clone(),
            "SmsSdkAppId": self.sdk_appid.clone(),
            "TemplateId": self.templated_id.clone(),
            "SignName": self.sign_name.clone(),
            "TemplateParamSet": self.templated_data.clone(),
        };

        // 转成字符串发送
        let payload = payload.to_string();
        let canonical_request = build_canonical_request(method, uri, query_string, headers, signed_headers, payload.as_str());
        //2. 拼接待签名字符串
        let hashed_canonical_request = sha256_hex_lowercase(&canonical_request);
        let service = "sms";
        let binding = br_fields::datetime::Timestamp::timestamp().to_string();
        let timestamp = binding.as_str();
        let data = br_fields::datetime::Datetime::datetime_format("%Y-%m-%d").to_string();
        let credential_scope = format!("{}/{}/tc3_request", data, service);
        let algorithm = "TC3-HMAC-SHA256";

        // 最终拼接 StringToSign
        let string_to_sign = format!("{}\n{}\n{}\n{}", algorithm, timestamp, credential_scope, hashed_canonical_request);
        // 派生密钥
        let secret_date = hmac_sha256(format!("TC3{}", self.secret_key).as_bytes(), data.as_str());
        let secret_service = hmac_sha256(&secret_date, service);
        let secret_signing = hmac_sha256(&secret_service, "tc3_request");
        //3. 计算签名
        let signature = hmac_sha256(&secret_signing, string_to_sign.as_str());
        let hex_str: String = encode(signature);
        let auth = build_authorization(self.secret_id.as_str(), credential_scope.as_str(), signed_headers, hex_str.as_str());
        auth
    }
}
fn build_canonical_request(
    method: &str,
    uri: &str,
    query_string: &str,
    headers: &str,
    signed_headers: &str,
    payload: &str,
) -> String {
    let hashed_payload = sha256_hex_lowercase(payload);
    format!("{}\n{}\n{}\n{}\n{}\n{}", method, uri, query_string, headers, signed_headers, hashed_payload)
}

fn sha256_hex_lowercase(data: &str) -> String {
    let hash = Sha256::digest(data.as_bytes());
    format!("{:x}", hash)
}
type HmacSha256 = Hmac<Sha256>;
fn hmac_sha256(key: &[u8], data: &str) -> Vec<u8> {
    let mut mac = HmacSha256::new_from_slice(key).expect("HMAC can take key of any size");
    mac.update(data.as_bytes());
    mac.finalize().into_bytes().to_vec()
}
fn build_authorization(
    secret_id: &str,
    credential_scope: &str,
    signed_headers: &str,
    signature: &str,
) -> String {
    format!("TC3-HMAC-SHA256 Credential={}/{}, SignedHeaders={}, Signature={}", secret_id, credential_scope, signed_headers, signature
    )
}