use hmac_sha256::{Hash, HMAC};
use crate::consts::*;
use crate::{data_types::ContentType, header_params::HeaderParams, utils::encode_hex};
fn canonical_request(body: &[u8], common_params: &HeaderParams, signed_headers: &str) -> String {
let action: &'static str = common_params.action;
let action = action.to_ascii_lowercase();
let host = DNSPOD_DOMAIN_NAME;
let http_request_method = "POST";
let canonical_uri = "/";
let canonical_query_string = "";
let content_type: &'static str = ContentType::JSON.into();
let content_type = content_type.to_ascii_lowercase();
let canonical_headers =
format!("content-type:{content_type}\nhost:{host}\nx-tc-action:{action}\n");
let signed_headers = signed_headers;
let hashed_request_payload = encode_hex(&Hash::hash(body));
format!(
r#"{http_request_method}
{canonical_uri}
{canonical_query_string}
{canonical_headers}
{signed_headers}
{hashed_request_payload}"#
)
}
fn string_to_sign(
body: &[u8],
common_params: &HeaderParams,
credential_scope: &str,
signed_headers: &str,
) -> String {
let algorithm = ALGORITHM;
let timestamp = common_params.datetime.timestamp();
let credential_scope = credential_scope;
let canonical_request = canonical_request(body, common_params, signed_headers);
let hashed_canonical_request = encode_hex(&Hash::hash(canonical_request.as_bytes()));
format!(
r#"{algorithm}
{timestamp}
{credential_scope}
{hashed_canonical_request}"#
)
}
fn calc_signature(
body: &[u8],
common_params: &HeaderParams,
secret_key: &str,
credential_scope: &str,
signed_headers: &str,
) -> String {
let date = common_params.datetime.date_naive().to_string();
let secret_date = HMAC::mac(date, format!("TC3{secret_key}"));
let secret_service = HMAC::mac(SERVICE, secret_date);
let secret_signing = HMAC::mac(TERMINATOR, secret_service);
let s = string_to_sign(body, common_params, credential_scope, signed_headers);
encode_hex(&HMAC::mac(s, secret_signing))
}
pub fn calculate_authorization(
body: &[u8],
common_params: &HeaderParams,
secret_id: &str,
secret_key: &str,
) -> String {
let date = common_params.datetime.date_naive().to_string();
let algorithm = ALGORITHM;
let credential_scope = format!("{date}/{SERVICE}/{TERMINATOR}");
let signed_headers = "content-type;host;x-tc-action";
let signature = calc_signature(
body,
common_params,
secret_key,
credential_scope.as_str(),
signed_headers,
);
format!("{algorithm} Credential={secret_id}/{credential_scope}, SignedHeaders={signed_headers}, Signature={signature}")
}