From d3c3592e671e432938a559aa172fa42321370118 Mon Sep 17 00:00:00 2001 From: mokurin000 <1348292515a@gmail.com> Date: Wed, 30 Jul 2025 13:14:06 +0800 Subject: [PATCH] feat: authlite command --- Cargo.lock | 1 + Cargo.toml | 1 + sdgb-api/Cargo.toml | 2 +- sdgb-api/src/auth_lite/mod.rs | 59 ++++++++++++++++++++++++++--------- sdgb-cli/Cargo.toml | 1 + sdgb-cli/src/commands.rs | 27 ++++++++++++---- sdgb-cli/src/main.rs | 9 ++++++ 7 files changed, 78 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ce5009..a46a8e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1124,6 +1124,7 @@ dependencies = [ "serde_json", "snafu", "spdlog-rs", + "strum 0.27.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4db59f6..9e3a459 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ sdgb-api = { path = "./sdgb-api" } snafu = { version = "0.8.6", features = ["backtrace", "rust_1_81"] } serde_json = "1.0.141" +strum = { version = "0.27.2", features = ["derive"] } [profile.release] lto = true diff --git a/sdgb-api/Cargo.toml b/sdgb-api/Cargo.toml index caa6afb..723fff3 100644 --- a/sdgb-api/Cargo.toml +++ b/sdgb-api/Cargo.toml @@ -8,6 +8,7 @@ license = "GPL-3.0" [dependencies] snafu = { workspace = true } serde_json = { workspace = true } +strum = {workspace = true} # hashing digest = "0.10.7" @@ -16,7 +17,6 @@ md5 = "0.8.0" # other utils chrono = "0.4.41" -strum = { version = "0.27.2", features = ["derive"] } # network request nyquest = { version = "0.2.0", features = ["async", "json"] } diff --git a/sdgb-api/src/auth_lite/mod.rs b/sdgb-api/src/auth_lite/mod.rs index 72dc52e..9cbd615 100644 --- a/sdgb-api/src/auth_lite/mod.rs +++ b/sdgb-api/src/auth_lite/mod.rs @@ -10,42 +10,71 @@ use nyquest::{ use crate::error::ApiError; -const AES_KEY: &[u8; 16] = br#"/?jo+"L&\Cr9(=kG"#; const AES_IV: &[u8; 16] = b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -pub async fn delivery_raw( +pub trait Delivery { + const AES_KEY: &[u8; 16]; + const TITLE_ID: &str; + const USER_AGENT: &str; +} + +/// only for fun +pub struct SDHJ; +pub struct SDGB; + +impl Delivery for SDHJ { + const AES_KEY: &[u8; 16] = b"-a57UX4y9/h(ImAQ"; + const TITLE_ID: &str = "SDHJ"; + const USER_AGENT: &str = "SDHJ;Windows/Lite"; +} + +impl Delivery for SDGB { + const AES_KEY: &[u8; 16] = br#"/?jo+"L&\Cr9(=kG"#; + const TITLE_ID: &str = "SDGB"; + const USER_AGENT: &str = "SDGB;Windows/Lite"; +} + +pub async fn delivery_raw( client: &AsyncClient, title_ver: impl AsRef, -) -> Result, ApiError> { +) -> Result, ApiError> +where + D: Delivery, +{ let title_ver = title_ver.as_ref(); - let params = format!("title_id=SDGB&title_ver={title_ver}&client_id=A63E01C2805"); - let enc_data = encrypt(params, AES_KEY, AES_IV)?; + let params = format!( + "title_id={}&title_ver={title_ver}&client_id=A63E01C2805", + D::TITLE_ID + ); + let enc_data = encrypt(params, D::AES_KEY, AES_IV)?; let req = Request::post("http://at.sys-allnet.cn/net/delivery/instruction") .with_body(Body::bytes(enc_data, "application/xxx-form-urlencoded")) - .with_header(USER_AGENT, "SDGB;Windows/Lite") + .with_header(USER_AGENT, D::USER_AGENT) .with_header("Pragma", "DFI"); let mut resp = client.request(req).await?.bytes().await?; - let dec_len = decrypt(&mut resp, AES_KEY, AES_IV)?.len(); - resp.truncate(dec_len); - Ok(resp) + let dec_len = decrypt(&mut resp, D::AES_KEY, AES_IV)?.len(); + Ok(resp[16..dec_len].to_vec()) } type Aes128CbcEnc = cbc::Encryptor; type Aes128CbcDec = cbc::Decryptor; fn encrypt(data: impl AsRef<[u8]>, key: &[u8; 16], iv: &[u8; 16]) -> Result, ApiError> { + let mut headed_data = vec![0u8; 16]; + headed_data.extend_from_slice(data.as_ref()); + let key = GenericArray::from_slice(key); let iv = GenericArray::from_slice(iv); let encryptor = Aes128CbcEnc::new(key, iv); - let data = data.as_ref(); - let bs = aes::Aes256::block_size(); - let pad_len = bs - data.len() % bs; - let mut buf = vec![0; pad_len + data.len()]; - buf[..data.len()].copy_from_slice(&data); - encryptor.encrypt_padded_mut::(&mut buf, data.len())?; + let bs = aes::Aes128::block_size(); + let pad_len = bs - headed_data.len() % bs; + + let mut buf = vec![0; pad_len + headed_data.len()]; + buf[..headed_data.len()].copy_from_slice(&headed_data); + encryptor.encrypt_padded_mut::(&mut buf, headed_data.len())?; Ok(buf) } diff --git a/sdgb-cli/Cargo.toml b/sdgb-cli/Cargo.toml index b4aa4ea..40655cb 100644 --- a/sdgb-cli/Cargo.toml +++ b/sdgb-cli/Cargo.toml @@ -9,6 +9,7 @@ description = "CLI tool for SDGB protocol" snafu = { workspace = true } sdgb-api = { workspace = true } serde_json = { workspace = true } +strum = { workspace = true } nyquest-preset = { version = "0.2.0", features = ["async"] } compio = { version = "0.15.0", default-features = false, features = [ diff --git a/sdgb-cli/src/commands.rs b/sdgb-cli/src/commands.rs index 42cd138..510d05d 100644 --- a/sdgb-cli/src/commands.rs +++ b/sdgb-cli/src/commands.rs @@ -1,5 +1,6 @@ use palc::Parser; use palc::Subcommand; +use strum::EnumString; #[derive(Parser)] #[command(about = "SDGB api tool", long_about = env!("CARGO_PKG_DESCRIPTION"))] @@ -8,8 +9,28 @@ pub struct Cli { pub command: Commands, } +#[derive(EnumString)] +pub enum AuthLiteVariant { + SDGB, + SDHJ, +} + #[derive(Subcommand)] pub enum Commands { + /// Login with QRCode from wechat + QRLogin { + /// content of the qrcode, only the last 64 characters were used + #[arg(short, long)] + qrcode_content: String, + }, + + AuthLite { + #[arg(short, long, default_value = "1.50")] + title_ver: String, + #[arg(long, default_value = "SDGB")] + variant: AuthLiteVariant, + }, + Ping, Preview { #[arg(short, long)] @@ -19,10 +40,4 @@ pub enum Commands { #[arg(short, long)] user_id: u32, }, - /// Login with QRCode from wechat - QRLogin { - /// content of the qrcode, only the last 64 characters were used - #[arg(short, long)] - qrcode_content: String, - }, } diff --git a/sdgb-cli/src/main.rs b/sdgb-cli/src/main.rs index 0cf4d04..b8bc4c2 100644 --- a/sdgb-cli/src/main.rs +++ b/sdgb-cli/src/main.rs @@ -2,6 +2,7 @@ use nyquest_preset::nyquest::ClientBuilder; use palc::Parser; use sdgb_api::{ all_net::QRCode, + auth_lite::{SDGB, SDHJ, delivery_raw}, title::{ MaiVersionExt, Sdgb1_40, Sdgb1_50, methods::APIMethod, @@ -69,6 +70,14 @@ async fn main() -> Result<(), Box> { Err(e) => error!("login failed: {e}"), } } + + commands::Commands::AuthLite { title_ver, variant } => { + let resp = match variant { + commands::AuthLiteVariant::SDGB => delivery_raw::(&client, title_ver).await?, + commands::AuthLiteVariant::SDHJ => delivery_raw::(&client, title_ver).await?, + }; + println!("{}", String::from_utf8_lossy(&resp)); + } } Ok(())