rusty-oss 0.2.1

Simple pure Rust Aliyun OSS Client following a Sans-IO approach
Documentation
use sha2::{Digest as _, Sha256};
use time::OffsetDateTime;

use crate::time_::{ISO8601, YYYYMMDD};

pub fn string_to_sign(date: &OffsetDateTime, region: &str, canonical_request: &str) -> String {
    let iso8601 = date.format(&ISO8601).expect("invalid format");
    let yyyymmdd = date.format(&YYYYMMDD).expect("invalid format");

    let scope = format!("{yyyymmdd}/{region}/oss/aliyun_v4_request");

    let hash = Sha256::digest(canonical_request.as_bytes());
    format!("OSS4-HMAC-SHA256\n{iso8601}\n{scope}\n{hash:x}")
}

#[cfg(test)]
mod tests {
    use pretty_assertions::assert_eq;
    use time::OffsetDateTime;

    use super::*;

    #[test]
    fn oss_example() {
        let date = OffsetDateTime::from_unix_timestamp(1738860711).unwrap();

        let region = "cn-hangzhou";

        let expected = concat!(
            "OSS4-HMAC-SHA256\n",
            "20250206T165151Z\n",
            "20250206/cn-hangzhou/oss/aliyun_v4_request\n",
            "52e1b60ba52b66305c1a0a90d6b1ee228cc023e9a27a46fe26ceee8a81bab11b",
        );

        let got = string_to_sign(&date, region, create_canonical_request());

        assert_eq!(got, expected);
    }

    fn create_canonical_request() -> &'static str {
        concat!(
            "GET\n",
            "/examplebucket/test.html\n",
            "x-oss-additional-headers=host&x-oss-credential=access_key_id%2F20250206%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-date=20250206T165151Z&x-oss-expires=86400&x-oss-signature-version=OSS4-HMAC-SHA256\n",
            "host:examplebucket.oss-cn-hangzhou.aliyuncs.com\n",
            "\n",
            "host\n",
            "UNSIGNED-PAYLOAD",
        )
    }
}