feat: abstract method to perform action
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1099,6 +1099,7 @@ name = "sdgb-api"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
|
"block-padding",
|
||||||
"cbc",
|
"cbc",
|
||||||
"chrono",
|
"chrono",
|
||||||
"digest",
|
"digest",
|
||||||
|
|||||||
@@ -26,3 +26,4 @@ flate2 = "1.1.2"
|
|||||||
cbc = "0.1.2"
|
cbc = "0.1.2"
|
||||||
aes = "0.8.4"
|
aes = "0.8.4"
|
||||||
md5 = "0.8.0"
|
md5 = "0.8.0"
|
||||||
|
block-padding = "0.3.3"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::io::{Read, Write as _};
|
|||||||
use aes::cipher::{
|
use aes::cipher::{
|
||||||
BlockDecryptMut, BlockEncryptMut, BlockSizeUser, KeyIvInit, block_padding::Pkcs7,
|
BlockDecryptMut, BlockEncryptMut, BlockSizeUser, KeyIvInit, block_padding::Pkcs7,
|
||||||
};
|
};
|
||||||
|
|
||||||
use digest::generic_array::GenericArray;
|
use digest::generic_array::GenericArray;
|
||||||
use flate2::write::ZlibEncoder;
|
use flate2::write::ZlibEncoder;
|
||||||
use flate2::{Compression, read::ZlibDecoder};
|
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 {
|
impl MaiVersionExt for Sdgb1_40 {
|
||||||
fn decode(mut data: impl AsMut<[u8]>) -> Result<Vec<u8>, ApiError> {
|
fn decode(mut data: impl AsMut<[u8]>) -> Result<Vec<u8>, ApiError> {
|
||||||
let mut decompressed = decompress(data.as_mut());
|
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();
|
let unpad_size = decrypt(&mut decompressed, Self::AES_KEY, Self::AES_IV)?.len();
|
||||||
decompressed.truncate(unpad_size);
|
decompressed.truncate(unpad_size);
|
||||||
Ok(decompressed)
|
Ok(decompressed)
|
||||||
@@ -26,6 +41,10 @@ impl MaiVersionExt for Sdgb1_40 {
|
|||||||
|
|
||||||
impl MaiVersionExt for Sdgb1_50 {
|
impl MaiVersionExt for Sdgb1_50 {
|
||||||
fn decode(mut data: impl AsMut<[u8]>) -> Result<Vec<u8>, ApiError> {
|
fn decode(mut data: impl AsMut<[u8]>) -> Result<Vec<u8>, ApiError> {
|
||||||
|
if data.as_mut().is_empty() {
|
||||||
|
return Err(ApiError::EmptyResponse);
|
||||||
|
}
|
||||||
|
|
||||||
let decrypted = decrypt(&mut data, Self::AES_KEY, Self::AES_IV)?;
|
let decrypted = decrypt(&mut data, Self::AES_KEY, Self::AES_IV)?;
|
||||||
let decompressed = decompress(decrypted);
|
let decompressed = decompress(decrypted);
|
||||||
Ok(decompressed)
|
Ok(decompressed)
|
||||||
|
|||||||
@@ -3,28 +3,34 @@ use snafu::Snafu;
|
|||||||
|
|
||||||
#[derive(Debug, Snafu)]
|
#[derive(Debug, Snafu)]
|
||||||
pub enum ApiError {
|
pub enum ApiError {
|
||||||
#[snafu(display("pad data: {error}"))]
|
#[snafu(display("api returned nothing!"))]
|
||||||
PadError { error: PadError },
|
EmptyResponse,
|
||||||
#[snafu(display("unpad data: {error}"))]
|
#[snafu(display("encrypt data: {error}"))]
|
||||||
UnpadError { error: UnpadError },
|
Pad { error: PadError },
|
||||||
|
#[snafu(display("decrypt data: {error}"))]
|
||||||
|
Unpad { error: UnpadError },
|
||||||
|
|
||||||
#[snafu(display("io error: {source}"))]
|
#[snafu(display("io error: {source}"))]
|
||||||
#[snafu(context(false))]
|
#[snafu(context(false))]
|
||||||
IOError { source: std::io::Error },
|
IO { source: std::io::Error },
|
||||||
|
|
||||||
#[snafu(display("json error: {source}"))]
|
#[snafu(display("json error: {source}"))]
|
||||||
#[snafu(context(false))]
|
#[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<UnpadError> for ApiError {
|
impl From<UnpadError> for ApiError {
|
||||||
fn from(error: UnpadError) -> Self {
|
fn from(error: UnpadError) -> Self {
|
||||||
Self::UnpadError { error }
|
Self::Unpad { error }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PadError> for ApiError {
|
impl From<PadError> for ApiError {
|
||||||
fn from(error: PadError) -> Self {
|
fn from(error: PadError) -> Self {
|
||||||
Self::PadError { error }
|
Self::Pad { error }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub mod model;
|
|||||||
mod error;
|
mod error;
|
||||||
pub use error::ApiError;
|
pub use error::ApiError;
|
||||||
use nyquest::{
|
use nyquest::{
|
||||||
Body,
|
AsyncClient, Body,
|
||||||
r#async::Request,
|
r#async::Request,
|
||||||
header::{ACCEPT_ENCODING, CONTENT_ENCODING, EXPECT, USER_AGENT},
|
header::{ACCEPT_ENCODING, CONTENT_ENCODING, EXPECT, USER_AGENT},
|
||||||
};
|
};
|
||||||
@@ -62,6 +62,23 @@ pub trait MaiVersionExt: MaiVersion {
|
|||||||
|
|
||||||
Ok(req)
|
Ok(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn request<D>(
|
||||||
|
client: &AsyncClient,
|
||||||
|
api: APIMethod,
|
||||||
|
agent_extra: impl Display,
|
||||||
|
data: D,
|
||||||
|
) -> impl Future<Output = Result<Vec<u8>, 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;
|
pub struct Sdgb1_40;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Ping;
|
pub struct Ping {}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use nyquest_preset::nyquest::ClientBuilder;
|
|||||||
use palc::Parser;
|
use palc::Parser;
|
||||||
use sdgb_api::{
|
use sdgb_api::{
|
||||||
all_net::QRCode,
|
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};
|
use spdlog::{error, info};
|
||||||
|
|
||||||
@@ -19,10 +19,10 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
|
|||||||
|
|
||||||
match cmd.command {
|
match cmd.command {
|
||||||
commands::Commands::Ping => {
|
commands::Commands::Ping => {
|
||||||
let req = Sdgb1_50::api_request(APIMethod::Ping, "", Ping)?;
|
let decoded = Sdgb1_40::request(&client, APIMethod::Ping, "1", Ping {}).await?;
|
||||||
let data = client.request(req).await?.bytes().await?;
|
info!("sdgb 1.40 resp: {:?}", String::from_utf8_lossy(&decoded));
|
||||||
let decoded = Sdgb1_50::decode(data)?;
|
let decoded = Sdgb1_50::request(&client, APIMethod::Ping, "", Ping {}).await?;
|
||||||
info!("resp: {:?}", String::from_utf8_lossy(&decoded));
|
info!("sdgb 1.50 resp: {:?}", String::from_utf8_lossy(&decoded));
|
||||||
}
|
}
|
||||||
commands::Commands::QRLogin { ref qrcode_content } => {
|
commands::Commands::QRLogin { ref qrcode_content } => {
|
||||||
let qrcode = QRCode { qrcode_content };
|
let qrcode = QRCode { qrcode_content };
|
||||||
|
|||||||
Reference in New Issue
Block a user