yunli

Crates.ioyunli
lib.rsyunli
version0.1.4
created_at2025-09-23 07:26:59.914184+00
updated_at2025-09-24 08:48:13.02258+00
descriptionAdditional utilities for working with Yunli.
homepage
repository
max_upload_size
id1851087
size103,668
(penghcn)

documentation

README

Useage

// util
// 生成随机数,如
let salt = util::generate_nonce_ascii_str(32);

// crypt
// 封装好的一些加密工具,如生成ed25519和X25519密钥对,aes-256-gcm加解密等
let peer: ([u8; 32], [u8; 32]) = crypt::gen_ed25519()?;
println!("{},{}", crypt::b64(&peer.0)?, crypt::b64(&peer.1)?);

// client
// 从注册中心获取配置,并重载到ENV中
if let Err(_) = client::load_config().await {};

// http_header
// 构建客户端的authorization,兼容大部分主流V3版本,如aliyun、腾讯云、aws、yunli

struct YunLiUtcHeaderV3;
impl UtcHeaderV3 for YunLiUtcHeaderV3 {
    fn host(&self) -> &'static str {
        "pass.lellm.com:8883"
        //"localhost:8080"
    }

    fn alg(&self) -> &'static str {
        //"YUN3-HMAC-SHA256"
        "YUN3-ED25519"
    }

    fn canonical(&self, action: String, _hashed_payload: &[u8], map: &mut BTreeMap<&str, String>) {
        let utc = self.datetime_ymd();

        map.insert("x-yun-action", action);
        map.insert("x-yun-date", utc.0);
        map.insert("x-yun-timestamp", utc.1);
        map.insert("x-yun-nonce", utc.2);
    }

    fn sign(&self, key: &[u8], hashed_canonical: &[u8], _btm: &BTreeMap<&str, String>) -> Result<String> {
        crypt::b64(&crypt::sign_ed25519(hashed_canonical, key)?)
    }
}

let (app_key, token) = app_key(&envs).await?;
let req = RequestV3::new(&action, &json, app_id.to_string(), app_key);
let auth_header = AuthorizationHeader::new(YunLiUtcHeaderV3, req);
let mut headers = auth_header.authorization()?;

// 解析服务端的authorization,验证签名
fn auth_headers<'a>(
    authorization: Option<&'a str>,
    headers: &'a HeaderMap<HeaderValue>,
) -> Result<(u32, &'a str, &'a str, &'a str, BTreeMap<&'a str, &'a str>), StatusCode> {
    let auth_str = authorization.ok_or(StatusCode::UNAUTHORIZED)?;

    let (key_id, alg, _credential, signed_header, sign) =
        yunli::http_header::parse_auth_yun3(auth_str).ok_or(StatusCode::UNAUTHORIZED)?;

    let key_id: u32 = key_id.parse().map_err(|_| StatusCode::UNAUTHORIZED)?;
    let signed_headers_map = yunli::http_header::signed_headers_map(signed_header, headers);

    Ok((key_id, alg, signed_header, sign, signed_headers_map))
}

async fn auth_signature<'a>(
    key_id: u32,
    alg: &str,
    sign: &str,
    signed_headers: &str,
    signed_headers_map: &BTreeMap<&'a str, &'a str>,
    uri: &str,
    payload_bytes: Bytes,
) -> Result<(), StatusCode> {
    let key_bytes = cache::key::get().await.sign_verify_key(key_id).await.map_err(|e| {
        warn!("key_bytes err, {}", e);
        StatusCode::UNAUTHORIZED
    })?;

    let reqv3 = RequestV3::new_post(uri, payload_bytes, key_id.to_string(), key_bytes, alg, sign)
        .map_err(|_| StatusCode::UNAUTHORIZED)?;

    let valid = yunli::http_header::valid_auth_yun3(&reqv3, signed_headers, signed_headers_map)
        .map_err(|_| StatusCode::UNAUTHORIZED)?;

    if !valid {
        warn!("sign err, uri:{}, sign:{}", uri, sign);
        return Err(StatusCode::UNAUTHORIZED);
    }
    Ok(())
}
Commit count: 0

cargo fmt