feat: updates
This commit is contained in:
@@ -9,6 +9,7 @@ edition = "2021"
|
|||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
hmac-sha256 = "1.1.7"
|
hmac-sha256 = "1.1.7"
|
||||||
hmac-sm3 = "0.1.0"
|
hmac-sm3 = "0.1.0"
|
||||||
|
rand = "0.8.5"
|
||||||
sha256 = "1.4.0"
|
sha256 = "1.4.0"
|
||||||
sm3 = "0.4.2"
|
sm3 = "0.4.2"
|
||||||
zeroize = "1.6.0"
|
zeroize = "1.6.0"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
mod v4;
|
mod v4;
|
||||||
|
mod util;
|
||||||
// mod v4_algorithm;
|
// mod v4_algorithm;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
11
src/util.rs
Normal file
11
src/util.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
pub(crate) trait BTreeMapAddKv<K: Ord, V> {
|
||||||
|
fn insert_kv(&mut self, key: impl Into<K>, value: impl Into<V>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Ord, V> BTreeMapAddKv<K, V> for BTreeMap<K, V> {
|
||||||
|
fn insert_kv(&mut self, key: impl Into<K>, value: impl Into<V>) {
|
||||||
|
self.insert(key.into(), value.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ use zeroize::Zeroize;
|
|||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct AccessKey {
|
pub struct AccessKey {
|
||||||
pub access_key_id: String,
|
pub access_key_id: String,
|
||||||
|
pub security_token: Option<String>,
|
||||||
pub access_key_secret: String,
|
pub access_key_secret: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,7 +18,10 @@ impl Drop for AccessKey {
|
|||||||
|
|
||||||
impl Debug for AccessKey {
|
impl Debug for AccessKey {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "AccessKey{{ID: {}}}", &self.access_key_id)
|
write!(f, "AccessKey{{ID: {}, Token: {}}}", &self.access_key_id, match self.security_token {
|
||||||
|
Some(_) => "Some(...)",
|
||||||
|
None => "None",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,4 +41,29 @@ impl Debug for DerivedAccessKey {
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "DerivedAccessKey{{ID: {}}}", &self.access_key_id)
|
write!(f, "DerivedAccessKey{{ID: {}}}", &self.access_key_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_access_key() {
|
||||||
|
let access_key = AccessKey {
|
||||||
|
access_key_id: "key_id".to_string(),
|
||||||
|
security_token: None,
|
||||||
|
access_key_secret: "key_secret".to_string(),
|
||||||
|
};
|
||||||
|
assert_eq!("AccessKey{ID: key_id, Token: None}", format!("{:?}", access_key));
|
||||||
|
let access_key = AccessKey {
|
||||||
|
access_key_id: "key_id".to_string(),
|
||||||
|
security_token: Some("token".to_string()),
|
||||||
|
access_key_secret: "key_secret".to_string(),
|
||||||
|
};
|
||||||
|
assert_eq!("AccessKey{ID: key_id, Token: Some(...)}", format!("{:?}", access_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_derived_access_key() {
|
||||||
|
let access_key = DerivedAccessKey {
|
||||||
|
access_key_id: "key_id".to_string(),
|
||||||
|
derived_access_key_secret: vec![0u8; 32],
|
||||||
|
};
|
||||||
|
assert_eq!("DerivedAccessKey{ID: key_id}", format!("{:?}", access_key));
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +1,99 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use sm3::Digest;
|
use rand::random;
|
||||||
|
|
||||||
use crate::v4::access_key::DerivedAccessKey;
|
use crate::util::BTreeMapAddKv;
|
||||||
|
use crate::v4::access_key::{AccessKey, DerivedAccessKey};
|
||||||
use crate::v4::common_util::{join_slices, percent_encode};
|
use crate::v4::common_util::{join_slices, percent_encode};
|
||||||
use crate::v4::constant::{
|
use crate::v4::constant::{ALIYUN_V4, ALIYUN_V4_REQUEST, CONTENT_TYPE_APPLICATION_JSON, HEADER_ACCEPT, HEADER_AUTHORIZATION, HEADER_CONTENT_TYPE, HEADER_HOST, HEADER_USER_AGENT, HEADER_X_ACS_PREFIX, HEADER_X_ASC_ACCESS_KEY_ID, HEADER_X_ASC_ACTION, HEADER_X_ASC_CONTENT_SHA256, HEADER_X_ASC_CONTENT_SM3, HEADER_X_ASC_DATE, HEADER_X_ASC_SECURITY_TOKEN, HEADER_X_ASC_SIGNATURE_NONCE, HEADER_X_ASC_VERSION, REGION_CENTER};
|
||||||
ALIYUN_V4, ALIYUN_V4_REQUEST,
|
|
||||||
HEADER_CONTENT_TYPE,
|
|
||||||
HEADER_HOST, HEADER_X_ACS_PREFIX, REGION_CENTER,
|
|
||||||
};
|
|
||||||
use crate::v4::sign_algorithm::SignAlgorithm;
|
use crate::v4::sign_algorithm::SignAlgorithm;
|
||||||
|
|
||||||
fn get_authorization(sign_algorithm: SignAlgorithm,
|
const SEQ: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
|
struct Request {
|
||||||
|
pub version: String,
|
||||||
|
pub action: String,
|
||||||
|
pub access_key: Option<AccessKey>,
|
||||||
|
pub user_agent: String,
|
||||||
|
pub sign_algorithm: SignAlgorithm,
|
||||||
|
pub headers: BTreeMap<String, String>,
|
||||||
|
pub stream: Option<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_common_headers(header: &mut BTreeMap<String, String>, request: &Request) {
|
||||||
|
header.insert_kv(HEADER_HOST, "endpoint"); // TODO
|
||||||
|
header.insert_kv(HEADER_X_ASC_VERSION, &request.version);
|
||||||
|
header.insert_kv(HEADER_X_ASC_ACTION, &request.action);
|
||||||
|
header.insert_kv(HEADER_USER_AGENT, &request.user_agent);
|
||||||
|
header.insert_kv(HEADER_X_ASC_DATE, get_timestamp());
|
||||||
|
header.insert_kv(HEADER_X_ASC_SIGNATURE_NONCE, get_nonce());
|
||||||
|
header.insert_kv(HEADER_ACCEPT, CONTENT_TYPE_APPLICATION_JSON);
|
||||||
|
|
||||||
|
// TODO BODY ...
|
||||||
|
|
||||||
|
match &request.sign_algorithm {
|
||||||
|
// TODO ...
|
||||||
|
SignAlgorithm::Sha256 => {
|
||||||
|
header.insert_kv(HEADER_X_ASC_CONTENT_SHA256, "");
|
||||||
|
}
|
||||||
|
SignAlgorithm::Sm3 => {
|
||||||
|
header.insert_kv(HEADER_X_ASC_CONTENT_SM3, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = BTreeMap::new();
|
||||||
|
|
||||||
|
if let Some(access_key) = &request.access_key {
|
||||||
|
if let Some(security_token) = &access_key.security_token {
|
||||||
|
header.insert_kv(HEADER_X_ASC_ACCESS_KEY_ID, &access_key.access_key_id);
|
||||||
|
header.insert_kv(HEADER_X_ASC_SECURITY_TOKEN, security_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
let signing_key = get_signing_key(
|
||||||
|
&request.sign_algorithm,
|
||||||
|
&access_key.access_key_secret,
|
||||||
|
"yyyy-mm-dd",// TODO DATE,
|
||||||
|
"region", // TODO REGION
|
||||||
|
"product", // TODO PRODUCT
|
||||||
|
);
|
||||||
|
let derived_access_key = DerivedAccessKey {
|
||||||
|
access_key_id: access_key.access_key_id.clone(),
|
||||||
|
derived_access_key_secret: signing_key,
|
||||||
|
};
|
||||||
|
let authorization = get_authorization(
|
||||||
|
&request.sign_algorithm,
|
||||||
|
&derived_access_key,
|
||||||
|
"yyyy-mm-dd",// TODO DATE,
|
||||||
|
"region", // TODO REGION
|
||||||
|
"product", // TODO PRODUCT
|
||||||
|
"pathname", // TODO pathname
|
||||||
|
"method", // TODO method
|
||||||
|
&query,
|
||||||
|
header,
|
||||||
|
"payload", // TODO payload
|
||||||
|
);
|
||||||
|
header.insert_kv(HEADER_AUTHORIZATION, authorization);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn get_timestamp() -> String {
|
||||||
|
// TODO ...
|
||||||
|
"yyyy-mm-dd".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn get_nonce() -> String {
|
||||||
|
let seq = SEQ.fetch_add(1, Ordering::Relaxed);
|
||||||
|
let now = SystemTime::now();
|
||||||
|
let rand_bytes: [u8; 32] = random();
|
||||||
|
let seed = format!("{}-{:?}-{:?}", seq, now, rand_bytes);
|
||||||
|
"nonce-".to_string() + &SignAlgorithm::Sha256.digest(seed.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_authorization(sign_algorithm: &SignAlgorithm,
|
||||||
access_key: &DerivedAccessKey,
|
access_key: &DerivedAccessKey,
|
||||||
date: &str, region: &str, product: &str,
|
date: &str, region: &str, product: &str,
|
||||||
pathname: &str,
|
pathname: &str,
|
||||||
@@ -40,7 +122,7 @@ fn get_authorization(sign_algorithm: SignAlgorithm,
|
|||||||
authorization
|
authorization
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_signature(sign_algorithm: SignAlgorithm,
|
fn get_signature(sign_algorithm: &SignAlgorithm,
|
||||||
signing_key: &[u8],
|
signing_key: &[u8],
|
||||||
pathname: &str,
|
pathname: &str,
|
||||||
method: &str,
|
method: &str,
|
||||||
@@ -73,7 +155,7 @@ fn get_signature(sign_algorithm: SignAlgorithm,
|
|||||||
hex::encode(sign_algorithm.hmac_sign(string_to_sign.as_bytes(), signing_key))
|
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> {
|
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 sc1 = join_slices(ALIYUN_V4.as_bytes(), secret.as_bytes());
|
||||||
let sc2 = sign_algorithm.hmac_sign(date.as_bytes(), &sc1);
|
let sc2 = sign_algorithm.hmac_sign(date.as_bytes(), &sc1);
|
||||||
let sc3 = sign_algorithm.hmac_sign(region.as_bytes(), &sc2);
|
let sc3 = sign_algorithm.hmac_sign(region.as_bytes(), &sc2);
|
||||||
|
|||||||
@@ -5,11 +5,16 @@ pub(crate) const ALIYUN_V4_REQUEST: &str = "aliyun_v4_request";
|
|||||||
pub(crate) const HEADER_X_ACS_PREFIX: &str = "x-acs-";
|
pub(crate) const HEADER_X_ACS_PREFIX: &str = "x-acs-";
|
||||||
pub(crate) const HEADER_HOST: &str = "host";
|
pub(crate) const HEADER_HOST: &str = "host";
|
||||||
pub(crate) const HEADER_ACCEPT: &str = "accept";
|
pub(crate) const HEADER_ACCEPT: &str = "accept";
|
||||||
|
pub(crate) const HEADER_AUTHORIZATION: &str = "Authorization";
|
||||||
pub(crate) const HEADER_USER_AGENT: &str = "user-agent";
|
pub(crate) const HEADER_USER_AGENT: &str = "user-agent";
|
||||||
pub(crate) const HEADER_CONTENT_TYPE: &str = "content-type";
|
pub(crate) const HEADER_CONTENT_TYPE: &str = "content-type";
|
||||||
pub(crate) const HEADER_X_ASC_VERSION: &str = "x-acs-version";
|
pub(crate) const HEADER_X_ASC_VERSION: &str = "x-acs-version";
|
||||||
pub(crate) const HEADER_X_ASC_ACTION: &str = "x-acs-action";
|
pub(crate) const HEADER_X_ASC_ACTION: &str = "x-acs-action";
|
||||||
pub(crate) const HEADER_X_ASC_DATE: &str = "x-acs-date";
|
pub(crate) const HEADER_X_ASC_DATE: &str = "x-acs-date";
|
||||||
|
pub(crate) const HEADER_X_ASC_ACCESS_KEY_ID: &str = "x-acs-accesskey-id";
|
||||||
|
pub(crate) const HEADER_X_ASC_SECURITY_TOKEN: &str = "x-acs-security-token";
|
||||||
pub(crate) const HEADER_X_ASC_SIGNATURE_NONCE: &str = "x-acs-signature-nonce";
|
pub(crate) const HEADER_X_ASC_SIGNATURE_NONCE: &str = "x-acs-signature-nonce";
|
||||||
|
pub(crate) const HEADER_X_ASC_CONTENT_SM3: &str = "x-acs-content-sm3";
|
||||||
|
pub(crate) const HEADER_X_ASC_CONTENT_SHA256: &str = "x-acs-content-sha256";
|
||||||
|
|
||||||
pub(crate) const CONTENT_TYPE_APPLICATION_JSON: &str = "application/json";
|
pub(crate) const CONTENT_TYPE_APPLICATION_JSON: &str = "application/json";
|
||||||
|
|||||||
Reference in New Issue
Block a user