feat: init commit

This commit is contained in:
2023-09-03 16:31:31 +08:00
parent d959709164
commit 8ce5206dd2
8 changed files with 281 additions and 0 deletions

127
src/v4/aliyun_util.rs Normal file
View File

@@ -0,0 +1,127 @@
use std::collections::BTreeMap;
use sm3::Digest;
use crate::v4::access_keys::DerivedAccessKey;
use crate::v4::algorithm::SignAlgorithm;
use crate::v4::common_util::{join_slices, percent_encode};
use crate::v4::constants::{ALIYUN_V4, ALIYUN_V4_REQUEST, HEADER_CONTENT_TYPE, HEADER_HOST, HEADER_X_ACS_PREFIX, REGION_CENTER};
fn get_authorization(sign_algorithm: SignAlgorithm,
access_key: &DerivedAccessKey,
date: &str, region: &str, product: &str,
pathname: &str,
method: &str,
query: &BTreeMap<String, String>,
headers: &BTreeMap<String, String>,
payload: &str) -> String {
let signature = get_signature(sign_algorithm, &access_key.derived_access_key_secret,
pathname, method, query, headers, payload);
let signed_headers_str = get_signed_headers(headers).iter().map(|(k, _)| k.as_str()).collect::<Vec<_>>().join(";");
let mut authorization = String::with_capacity(512);
authorization.push_str(sign_algorithm.as_aliyun_name());
authorization.push_str(" Credential=");
authorization.push_str(&access_key.access_key_id);
authorization.push('/');
authorization.push_str(date);
authorization.push('/');
authorization.push_str(region);
authorization.push('/');
authorization.push_str(product);
authorization.push_str("/aliyun_v4_request,SignedHeaders=");
authorization.push_str(&signed_headers_str);
authorization.push_str(",Signature=");
authorization.push_str(&signature);
authorization
}
fn get_signature(sign_algorithm: SignAlgorithm,
signing_key: &[u8],
pathname: &str,
method: &str,
query: &BTreeMap<String, String>,
headers: &BTreeMap<String, String>,
payload: &str) -> String {
let canonical_uri = if pathname.is_empty() { "/" } else { pathname };
let canonicalized_resource = build_canonicalized_resource(query);
let canonicalized_headers = build_canonicalized_headers(headers);
let signed_headers_str = get_signed_headers(headers).iter().map(|(k, _)| k.as_str()).collect::<Vec<_>>().join(";");
let mut string_to_sign = String::new();
string_to_sign.push_str(method);
string_to_sign.push('\n');
string_to_sign.push_str(canonical_uri);
string_to_sign.push('\n');
string_to_sign.push_str(&canonicalized_resource);
string_to_sign.push('\n');
string_to_sign.push_str(&canonicalized_headers);
string_to_sign.push('\n');
string_to_sign.push_str(&signed_headers_str);
string_to_sign.push('\n');
string_to_sign.push_str(payload);
let string_to_sign_digest_hex = sign_algorithm.digest(string_to_sign.as_bytes());
string_to_sign.push_str(sign_algorithm.as_aliyun_name());
string_to_sign.push('\n');
string_to_sign.push_str(&string_to_sign_digest_hex);
hex::encode(sign_algorithm.hmac_sign(string_to_sign.as_bytes(), signing_key))
}
fn get_signing_key(sign_algorithm: SignAlgorithm, secret: &str, date: &str, region: &str, product: &str) -> Vec<u8> {
let sc1 = join_slices(ALIYUN_V4.as_bytes(), secret.as_bytes());
let sc2 = sign_algorithm.hmac_sign(date.as_bytes(), &sc1);
let sc3 = sign_algorithm.hmac_sign(region.as_bytes(), &sc2);
let sc4 = sign_algorithm.hmac_sign(product.as_bytes(), &sc3);
sign_algorithm.hmac_sign(ALIYUN_V4_REQUEST.as_bytes(), &sc4)
}
fn get_region(product: &str, endpoint: &str) -> String {
if product.is_empty() || endpoint.is_empty() {
return REGION_CENTER.into();
}
let popcode = product.to_lowercase();
let mut region = endpoint.replace(popcode.as_str(), "");
region = region.replace("aliyuncs.com", "");
region = region.replace(".", "");
if region.is_empty() { REGION_CENTER.into() } else { region }
}
fn build_canonicalized_resource(query: &BTreeMap<String, String>) -> String {
let mut canonicalized_resources = Vec::with_capacity(query.len());
for (key, value) in query {
let mut resource = String::with_capacity(key.len() + 1 + value.len());
resource.push_str(&percent_encode(key));
if !value.is_empty() {
resource.push('=');
resource.push_str(&percent_encode(value));
}
canonicalized_resources.push(resource);
}
canonicalized_resources.join("&")
}
fn build_canonicalized_headers(headers: &BTreeMap<String, String>) -> String {
let mut canonicalized_headers = String::new();
let signed_headers = get_signed_headers(headers);
for (key, value) in &signed_headers {
canonicalized_headers.push_str(key);
canonicalized_headers.push(':');
canonicalized_headers.push_str(value);
canonicalized_headers.push('\n');
}
canonicalized_headers
}
fn get_signed_headers(headers: &BTreeMap<String, String>) -> Vec<(String, &String)> {
let mut signed_headers = Vec::with_capacity(headers.len());
for (key, value) in headers {
let lower_key = key.to_lowercase();
if lower_key.starts_with(HEADER_X_ACS_PREFIX) || (lower_key == HEADER_HOST) || (lower_key == HEADER_CONTENT_TYPE) {
signed_headers.push((lower_key, value));
}
}
signed_headers
}