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>,
sdk_appid: String,
templated_id: String,
sign_name: String,
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{
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());
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";
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");
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
)
}