From 1a281e0cc71e206093540b80e9c7ecdcaa2a4851 Mon Sep 17 00:00:00 2001 From: mokurin000 <1348292515a@gmail.com> Date: Wed, 30 Jul 2025 03:20:21 +0800 Subject: [PATCH] feat: abstract method to perform action --- Cargo.lock | 1 + sdgb-api/Cargo.toml | 1 + sdgb-api/src/title/encryption/mod.rs | 19 +++++++++++++++++++ sdgb-api/src/title/error/mod.rs | 22 ++++++++++++++-------- sdgb-api/src/title/mod.rs | 19 ++++++++++++++++++- sdgb-api/src/title/model/mod.rs | 2 +- sdgb-cli/src/main.rs | 10 +++++----- 7 files changed, 59 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 862fba0..7b76365 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1099,6 +1099,7 @@ name = "sdgb-api" version = "0.1.0" dependencies = [ "aes", + "block-padding", "cbc", "chrono", "digest", diff --git a/sdgb-api/Cargo.toml b/sdgb-api/Cargo.toml index 2c0b7be..ecb8351 100644 --- a/sdgb-api/Cargo.toml +++ b/sdgb-api/Cargo.toml @@ -26,3 +26,4 @@ flate2 = "1.1.2" cbc = "0.1.2" aes = "0.8.4" md5 = "0.8.0" +block-padding = "0.3.3" diff --git a/sdgb-api/src/title/encryption/mod.rs b/sdgb-api/src/title/encryption/mod.rs index bf2b46a..d9b39e2 100644 --- a/sdgb-api/src/title/encryption/mod.rs +++ b/sdgb-api/src/title/encryption/mod.rs @@ -3,6 +3,7 @@ use std::io::{Read, Write as _}; use aes::cipher::{ BlockDecryptMut, BlockEncryptMut, BlockSizeUser, KeyIvInit, block_padding::Pkcs7, }; + use digest::generic_array::GenericArray; use flate2::write::ZlibEncoder; use flate2::{Compression, read::ZlibDecoder}; @@ -12,6 +13,20 @@ use crate::title::{MaiVersion, MaiVersionExt, Sdgb1_40, Sdgb1_50, error::ApiErro impl MaiVersionExt for Sdgb1_40 { fn decode(mut data: impl AsMut<[u8]>) -> Result, ApiError> { let mut decompressed = decompress(data.as_mut()); + if decompressed.is_empty() { + return Err(ApiError::EmptyResponse); + } + + let orig_len = decompressed.len(); + + let remain = 16 - decompressed.len() % 16; + + if + // weird but nessacary for Rust Pkcs7 + remain != 16 { + decompressed.resize(remain + orig_len, remain as _); + } + let unpad_size = decrypt(&mut decompressed, Self::AES_KEY, Self::AES_IV)?.len(); decompressed.truncate(unpad_size); Ok(decompressed) @@ -26,6 +41,10 @@ impl MaiVersionExt for Sdgb1_40 { impl MaiVersionExt for Sdgb1_50 { fn decode(mut data: impl AsMut<[u8]>) -> Result, ApiError> { + if data.as_mut().is_empty() { + return Err(ApiError::EmptyResponse); + } + let decrypted = decrypt(&mut data, Self::AES_KEY, Self::AES_IV)?; let decompressed = decompress(decrypted); Ok(decompressed) diff --git a/sdgb-api/src/title/error/mod.rs b/sdgb-api/src/title/error/mod.rs index 991bb95..42e8802 100644 --- a/sdgb-api/src/title/error/mod.rs +++ b/sdgb-api/src/title/error/mod.rs @@ -3,28 +3,34 @@ use snafu::Snafu; #[derive(Debug, Snafu)] pub enum ApiError { - #[snafu(display("pad data: {error}"))] - PadError { error: PadError }, - #[snafu(display("unpad data: {error}"))] - UnpadError { error: UnpadError }, + #[snafu(display("api returned nothing!"))] + EmptyResponse, + #[snafu(display("encrypt data: {error}"))] + Pad { error: PadError }, + #[snafu(display("decrypt data: {error}"))] + Unpad { error: UnpadError }, #[snafu(display("io error: {source}"))] #[snafu(context(false))] - IOError { source: std::io::Error }, + IO { source: std::io::Error }, #[snafu(display("json error: {source}"))] #[snafu(context(false))] - JSONError { source: serde_json::Error }, + JSON { source: serde_json::Error }, + + #[snafu(display("request error: {source}"))] + #[snafu(context(false))] + Request { source: nyquest::Error }, } impl From for ApiError { fn from(error: UnpadError) -> Self { - Self::UnpadError { error } + Self::Unpad { error } } } impl From for ApiError { fn from(error: PadError) -> Self { - Self::PadError { error } + Self::Pad { error } } } diff --git a/sdgb-api/src/title/mod.rs b/sdgb-api/src/title/mod.rs index 2b0f58b..fe4c5b0 100644 --- a/sdgb-api/src/title/mod.rs +++ b/sdgb-api/src/title/mod.rs @@ -9,7 +9,7 @@ pub mod model; mod error; pub use error::ApiError; use nyquest::{ - Body, + AsyncClient, Body, r#async::Request, header::{ACCEPT_ENCODING, CONTENT_ENCODING, EXPECT, USER_AGENT}, }; @@ -62,6 +62,23 @@ pub trait MaiVersionExt: MaiVersion { Ok(req) } + + fn request( + client: &AsyncClient, + api: APIMethod, + agent_extra: impl Display, + data: D, + ) -> impl Future, ApiError>> + where + D: Serialize, + { + async { + let req = Self::api_request(api, agent_extra, data)?; + let data = client.request(req).await?.bytes().await?; + let decoded = Self::decode(data)?; + Ok(decoded) + } + } } pub struct Sdgb1_40; diff --git a/sdgb-api/src/title/model/mod.rs b/sdgb-api/src/title/model/mod.rs index 00bfb10..9af5d52 100644 --- a/sdgb-api/src/title/model/mod.rs +++ b/sdgb-api/src/title/model/mod.rs @@ -1,4 +1,4 @@ use serde::Serialize; #[derive(Serialize)] -pub struct Ping; +pub struct Ping {} diff --git a/sdgb-cli/src/main.rs b/sdgb-cli/src/main.rs index f0f72be..1235a72 100644 --- a/sdgb-cli/src/main.rs +++ b/sdgb-cli/src/main.rs @@ -2,7 +2,7 @@ use nyquest_preset::nyquest::ClientBuilder; use palc::Parser; use sdgb_api::{ all_net::QRCode, - title::{MaiVersionExt, Sdgb1_50, methods::APIMethod, model::Ping}, + title::{MaiVersionExt, Sdgb1_40, Sdgb1_50, methods::APIMethod, model::Ping}, }; use spdlog::{error, info}; @@ -19,10 +19,10 @@ async fn main() -> Result<(), Box> { match cmd.command { commands::Commands::Ping => { - let req = Sdgb1_50::api_request(APIMethod::Ping, "", Ping)?; - let data = client.request(req).await?.bytes().await?; - let decoded = Sdgb1_50::decode(data)?; - info!("resp: {:?}", String::from_utf8_lossy(&decoded)); + let decoded = Sdgb1_40::request(&client, APIMethod::Ping, "1", Ping {}).await?; + info!("sdgb 1.40 resp: {:?}", String::from_utf8_lossy(&decoded)); + let decoded = Sdgb1_50::request(&client, APIMethod::Ping, "", Ping {}).await?; + info!("sdgb 1.50 resp: {:?}", String::from_utf8_lossy(&decoded)); } commands::Commands::QRLogin { ref qrcode_content } => { let qrcode = QRCode { qrcode_content };