diff --git a/Cargo.lock b/Cargo.lock index 2fca88d..508088c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2075,8 +2075,11 @@ dependencies = [ "dns-lookup", "etherparse", "futures-util", + "hex", + "hmac", "libc", "local-ip-address", + "md-5", "myactor", "num_enum", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 2890bd9..59b9fcc 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,9 @@ clap = { version = "4.5.60", features = ["derive", "env"] } rpassword = "7.4.0" serde_json = "1.0.149" chacha20poly1305 = "0.10.1" +hmac = "0.12.1" +md-5 = "0.10.6" +hex = "0.4.3" # rolling-file = { path = "../rolling-file" } [target.'cfg(unix)'.dependencies] diff --git a/src/bin/punchnet/api/mod.rs b/src/bin/punchnet/api/mod.rs index efba5f3..a777d7c 100644 --- a/src/bin/punchnet/api/mod.rs +++ b/src/bin/punchnet/api/mod.rs @@ -1,9 +1,22 @@ +use hmac::{Hmac, Mac as HamcMac}; +use punchnet::TokenLogin; use reqwest::Client; use sdlan_sn_rs::utils::{Mac, Result, SDLanError}; use serde::{Deserialize, Serialize}; +use md5::Md5; pub const TEST_PREFIX: &'static str = "https://punchnet.s5s8.com/api"; +const DIGEST_KEY: &'static str = "H6p*2RfEu4ITcL"; +type HmacMd5 = Hmac; + +trait HMacCalculator { + fn calculate_hmac(&self) -> Result; +} + +fn calculate_hmac(cal: T) -> Result { + cal.calculate_hmac() +} #[derive(Serialize)] struct TokenLoginData<'a> { @@ -14,6 +27,29 @@ struct TokenLoginData<'a> { version: &'a str, } +fn do_calculate(data: &[u8]) -> Result{ + let Ok(mut mac) = HmacMd5::new_from_slice(DIGEST_KEY.as_bytes()) else { + return Err(SDLanError::IOError("failed to new hmac".to_owned())); + }; + mac.update(data); + let result = mac.finalize().into_bytes(); + Ok(hex::encode(result)) +} + +impl <'a> HMacCalculator for TokenLoginData<'a> { + fn calculate_hmac(&self) -> Result { + let data = format!("client_id={}&mac={}&system={}&token={}&version={}", + self.client_id, + self.mac, + self.system, + self.token, + self.version, + ); + do_calculate(data.as_bytes()) + } +} + + #[derive(Serialize)] struct UserPassLoginData<'a> { client_id: &'a str, @@ -24,6 +60,20 @@ struct UserPassLoginData<'a> { version: &'a str, } +impl HMacCalculator for UserPassLoginData<'_> { + fn calculate_hmac(&self) -> Result { + let data = format!("client_id={}&mac={}&password={}&system={}&username={}&version={}", + self.client_id, + self.mac, + self.password, + self.system, + self.username, + self.version, + ); + do_calculate(data.as_bytes()) + } +} + #[derive(Debug, Deserialize)] pub struct LoginResponse { pub code: i32, @@ -54,14 +104,18 @@ async fn post_with_data( url: &str, data: T, ) -> Result -where T: Serialize, +where T: Serialize + HMacCalculator, R: for<'de> Deserialize<'de> { - let client = Client::new(); - + + let Ok(hmac) = data.calculate_hmac() else { + return Err(SDLanError::IOError("failed to calculate hmac".to_owned())); + }; + let Ok(response) = client .post(url) + .header("X-sign", hmac) .json(&data) .send() .await else { @@ -70,7 +124,6 @@ where T: Serialize, // println!("status: {}", response.status()); let text = response.text().await.unwrap(); - // println!("text = {}", text); let data = serde_json::from_str(&text).unwrap(); @@ -137,6 +190,16 @@ struct ConnectDisconnectRequest<'a> { access_token: &'a str, } +impl HMacCalculator for ConnectDisconnectRequest<'_> { + fn calculate_hmac(&self) -> Result { + let data = format!("access_token={}&client_id={}", + self.access_token, + self.client_id + ); + do_calculate(data.as_bytes()) + } +} + #[derive(Deserialize, Debug)] pub struct ConnectResponse { pub code: i32, @@ -210,6 +273,17 @@ struct GetResourceRequest<'a> { id: i32, } +impl HMacCalculator for GetResourceRequest<'_> { + fn calculate_hmac(&self) -> Result { + let data = format!("access_token={}&client_id={}&id={}", + self.access_token, + self.client_id, + self.id, + ); + do_calculate(data.as_bytes()) + } +} + #[derive(Deserialize, Debug)] pub struct GetResourceResponse { pub code: i32, diff --git a/src/bin/punchnet/main.rs b/src/bin/punchnet/main.rs index cb2253a..b0d5cb9 100755 --- a/src/bin/punchnet/main.rs +++ b/src/bin/punchnet/main.rs @@ -354,7 +354,7 @@ fn main() { } } - let should_daemonize = true; + let should_daemonize = false; #[cfg(not(target_os = "windows"))] if should_daemonize {