diff --git a/Cargo.lock b/Cargo.lock index 2f3bb6a..b4a590c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,6 +104,19 @@ dependencies = [ "x11rb", ] +[[package]] +name = "async-compression" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-io" version = "1.7.0" @@ -2278,6 +2291,7 @@ version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" dependencies = [ + "async-compression", "base64", "bytes", "encoding_rs", diff --git a/exalta_core/Cargo.toml b/exalta_core/Cargo.toml index 99e0e9f..776634c 100644 --- a/exalta_core/Cargo.toml +++ b/exalta_core/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] once_cell = "1.12" -reqwest = { version = "0.11.0", features = ["stream"] } +reqwest = { version = "0.11.0", features = ["stream", "deflate", "gzip"] } futures-util = "0.3" tokio = { version = "1", features = ["full"] } diff --git a/exalta_core/src/auth/mod.rs b/exalta_core/src/auth/mod.rs index c7e37e4..1ec3489 100644 --- a/exalta_core/src/auth/mod.rs +++ b/exalta_core/src/auth/mod.rs @@ -104,7 +104,11 @@ pub async fn verify_access_token(access_token: &str) -> Result { ]); let userpassparams = [tokenparams, crate::DEFAULT_PARAMS.read().await.to_vec()].concat(); let resp = CLIENT - .post(get_base_url().await.join("account/verifyAccessTokenClient")?) + .post( + get_base_url() + .await + .join("account/verifyAccessTokenClient")?, + ) .form(&userpassparams) .send() .await?; diff --git a/exalta_core/src/download/mod.rs b/exalta_core/src/download/mod.rs index 6e0bd7e..9707aed 100644 --- a/exalta_core/src/download/mod.rs +++ b/exalta_core/src/download/mod.rs @@ -1,7 +1,10 @@ use std::{fs, path::PathBuf, sync::Arc}; use once_cell::sync::Lazy; -use reqwest::{header::HeaderMap, Method, Response, Url}; +use reqwest::{ + header::{HeaderMap, HeaderValue}, + Method, Response, Url, +}; use tokio::sync::RwLock; use crate::{download::err::UpdateError, CLIENT}; @@ -21,10 +24,7 @@ static BUILD_URL: Lazy> = pub async fn request_checksums(build_hash: &str, platform: &str) -> Result { let url = get_base_url(build_hash, platform, "checksum.json").await?; - let resp = CLIENT - .request(Method::GET, url) - .send() - .await?; + let resp = CLIENT.request(Method::GET, url).send().await?; let resp_text = resp.text().await?; Ok(serde_json::from_str::(&resp_text)?) @@ -115,6 +115,7 @@ pub async fn request_file(build_hash: &str, platform: &str, file: &str) -> Resul let mut defheaders = HeaderMap::new(); defheaders.append("Host", BUILD_URL.read().await.host_str().unwrap().parse()?); + defheaders.append("Accept-Encoding", HeaderValue::from_static("gzip, deflate")); let resp = CLIENT .request(Method::GET, url) @@ -129,6 +130,8 @@ async fn get_base_url(build_hash: &str, platform: &str, file: &str) -> Result "build-release", crate::Build::Testing => "build", }; - Ok(BUILD_URL.try_read().unwrap().join(format!("{}/{}/{}/{}", build_branch, build_hash, platform, file).as_str())?) + Ok(BUILD_URL + .try_read() + .unwrap() + .join(format!("{}/{}/{}/{}", build_branch, build_hash, platform, file).as_str())?) } - diff --git a/exalta_core/src/lib.rs b/exalta_core/src/lib.rs index c13b3e6..068c013 100644 --- a/exalta_core/src/lib.rs +++ b/exalta_core/src/lib.rs @@ -10,8 +10,10 @@ pub mod auth; pub mod download; pub mod misc; -static BASE_URL_STRING: Lazy = Lazy::new(|| Url::parse("https://www.realmofthemadgod.com/").unwrap()); -static TESTING_BASE_URL_STRING: Lazy = Lazy::new(|| Url::parse("https://test.realmofthemadgod.com/").unwrap()); +static BASE_URL_STRING: Lazy = + Lazy::new(|| Url::parse("https://www.realmofthemadgod.com/").unwrap()); +static TESTING_BASE_URL_STRING: Lazy = + Lazy::new(|| Url::parse("https://test.realmofthemadgod.com/").unwrap()); pub static BUILD_TYPE: Lazy> = Lazy::new(|| RwLock::new(Build::Production)); static CLIENT_TOKEN: Lazy> = Lazy::new(|| RwLock::new(String::new())); @@ -26,7 +28,6 @@ pub static DEFAULT_PARAMS: Lazy>> = Lazy::new(|| { static CLIENT: Lazy = Lazy::new(|| { let mut defheaders = HeaderMap::new(); defheaders.insert("Accept", "*/*".parse().unwrap()); - defheaders.insert("Accept-Encoding", HeaderValue::from_static("gzip, deflate")); defheaders.insert("X-Unity-Version", HeaderValue::from_static("2020.3.30f1")); Client::builder() .http1_title_case_headers() @@ -39,7 +40,7 @@ static CLIENT: Lazy = Lazy::new(|| { #[derive(Clone, Copy, Debug, PartialEq)] pub enum Build { Production, - Testing + Testing, } impl std::fmt::Display for Build { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -56,7 +57,7 @@ pub fn get_base_url_force() -> &'static Url { fn get_base_url_from_build_type(build_type: &Build) -> &'static Url { return match *build_type { Build::Production => &BASE_URL_STRING, - Build::Testing => &TESTING_BASE_URL_STRING + Build::Testing => &TESTING_BASE_URL_STRING, }; } @@ -88,4 +89,4 @@ pub fn coll_to_owned(vec: Vec<(&str, &str)>) -> Vec<(String, String)> { vec.iter() .map(|e| (e.0.to_owned(), e.1.to_owned())) .collect() -} \ No newline at end of file +} diff --git a/exalta_core/src/misc.rs b/exalta_core/src/misc.rs index 7f3d0c3..0e83e39 100644 --- a/exalta_core/src/misc.rs +++ b/exalta_core/src/misc.rs @@ -15,7 +15,11 @@ pub async fn init(game_net: Option<&str>, access_token: Option<&str>) -> Result< } let resp = CLIENT - .post(get_base_url().await.join("app/init?platform=standalonewindows64&key=9KnJFxtTvLu2frXv")?) + .post( + get_base_url() + .await + .join("app/init?platform=standalonewindows64&key=9KnJFxtTvLu2frXv")?, + ) .form(¶ms) .send() .await?; diff --git a/src/main.rs b/src/main.rs index 96c4dc2..78edbbf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use exalta_core::{ auth::{account::Account, *}, download::err::UpdateError, }; -use main_ext::{LauncherAuth, ResultTimeWrapper, get_device_token, SavedLauncherAuth}; +use main_ext::{get_device_token, LauncherAuth, ResultTimeWrapper, SavedLauncherAuth}; use pages::{config, HistoryVec, Route}; use poll_promise::Promise; use tokio::{runtime::Runtime, sync::RwLock}; @@ -40,7 +40,7 @@ fn main() { } else { _cc.egui_ctx.set_visuals(egui::Visuals::light()); } - Box::new(ExaltaLauncher::default()) + Box::::default() }), ); } @@ -68,7 +68,7 @@ struct ExaltaLauncher { impl Default for ExaltaLauncher { fn default() -> Self { - let entry = keyring::Entry::new(&"exalt", &"jsondata"); + let entry = keyring::Entry::new("exalt", "jsondata"); let mut run_res = ResultTimeWrapper::default(); @@ -109,13 +109,11 @@ impl Default for ExaltaLauncher { config.build_hash = buildhash; config.save()?; } - } else { - if ®istry_build_hash == &buildhash { - config.build_hash = buildhash; - config.save()?; - } else if &config.build_hash != &buildhash { - return Err(update_error); - } + } else if ®istry_build_hash == &buildhash { + config.build_hash = buildhash; + config.save()?; + } else if &config.build_hash != &buildhash { + return Err(update_error); } #[cfg(not(windows))] @@ -176,10 +174,12 @@ impl Default for ExaltaLauncher { if let Ok(foundauthvec) = serde_json::from_str::(&val) { self_inst.saved_auth = foundauthvec; if self_inst.config.save_login { - if let Some(foundauth) = self_inst.saved_auth.saved.get(self_inst.saved_auth.current) { + if let Some(foundauth) = + self_inst.saved_auth.saved.get(self_inst.saved_auth.current) + { self_inst.auth = foundauth.clone(); } - + let res = self_inst.login(); if self_inst.run_res.result.is_ok() { self_inst.run_res = ResultTimeWrapper::default(); diff --git a/src/main_ext.rs b/src/main_ext.rs index b60aff4..bc50446 100644 --- a/src/main_ext.rs +++ b/src/main_ext.rs @@ -3,32 +3,20 @@ use std::collections::HashMap; #[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Default)] pub struct SavedLauncherAuth { pub saved: Vec, pub current: usize, } -impl Default for SavedLauncherAuth { - fn default() -> Self { - Self { - saved: Vec::new(), - current: 0, - } - } -} + #[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Default)] pub struct LauncherAuth { pub guid: String, pub password: String, } -impl Default for LauncherAuth { - fn default() -> Self { - Self { - guid: String::new(), - password: String::new() - } - } -} + pub struct ResultTimeWrapper { pub result: Result<(), Box>, pub time: std::time::Instant, @@ -43,8 +31,8 @@ impl Default for ResultTimeWrapper { } pub fn get_device_token() -> String { + use sha1::{Digest, Sha1}; use smbioslib::*; - use sha1::{Sha1, Digest}; let mut concat = String::new(); if let Ok(data) = table_load_from_device() { @@ -59,8 +47,8 @@ pub fn get_device_token() -> String { if concat.is_empty() { concat += "None0" } - - if let Some(d) = get_product_id().ok() { + + if let Ok(d) = get_product_id() { concat += &d; } @@ -74,14 +62,15 @@ pub fn get_device_token() -> String { #[cfg(windows)] fn get_product_id() -> Result> { use wmi::*; - + let com_con = COMLibrary::new()?; let wmi_con = WMIConnection::new(com_con.into())?; - let results: Vec> = wmi_con.raw_query("SELECT * FROM Win32_OperatingSystem")?; + let results: Vec> = + wmi_con.raw_query("SELECT * FROM Win32_OperatingSystem")?; for os in results { if let Some(var) = os.get("SerialNumber") { if let Variant::String(s) = var { - return Ok(s.clone()) + return Ok(s.clone()); } } } @@ -92,23 +81,26 @@ fn get_product_id() -> Result> { ))) } -#[cfg(target_os="linux")] +#[cfg(target_os = "linux")] fn get_product_id() -> Result> { use std::process::Command; use regex::Regex; - let output= Command::new("wine") - .args(&["wmic", "os", "get" , "SerialNumber"]) + let output = Command::new("wine") + .args(&["wmic", "os", "get", "SerialNumber"]) .output()?; let out = String::from_utf8_lossy( - &output.stdout.clone() - .iter() - .filter(|e| **e != 0) - .map(|e| *e) - .collect::>() - ).to_string(); - + &output + .stdout + .clone() + .iter() + .filter(|e| **e != 0) + .map(|e| *e) + .collect::>(), + ) + .to_string(); + if let Some(s) = Regex::new(r"SerialNumber\s*\r\n([^\s\\]*)")?.captures(&out) { if let Some(e) = s.get(1) { return Ok(e.as_str().to_string()); @@ -127,4 +119,4 @@ where { let mut i = 0; move |item| (f(i, item), i += 1).0 -} \ No newline at end of file +} diff --git a/src/pages/config/mod.rs b/src/pages/config/mod.rs index d3799c6..3de436b 100644 --- a/src/pages/config/mod.rs +++ b/src/pages/config/mod.rs @@ -27,7 +27,7 @@ impl Default for AppConfig { dark: false, save_login: true, build_hash: String::new(), - game_folder_path: game_folder_path, + game_folder_path, } } } @@ -36,7 +36,7 @@ impl AppConfig { fn get_location() -> Result> { let location = match ProjectDirs::from("com", "AyanAmy", "Exalta") { Some(v) => { - std::fs::create_dir_all(&v.config_dir())?; + std::fs::create_dir_all(v.config_dir())?; v.config_dir().to_path_buf() } None => std::env::current_dir()?, diff --git a/src/pages/login.rs b/src/pages/login.rs index ffe91a1..a515850 100644 --- a/src/pages/login.rs +++ b/src/pages/login.rs @@ -3,7 +3,10 @@ use eframe::egui::{self, Ui}; use exalta_core::auth::{err::AuthError, request_account, request_forgot_password, AuthInfo}; use regex::Regex; -use crate::{ExaltaLauncher, main_ext::{LauncherAuth, with_index}}; +use crate::{ + main_ext::{with_index, LauncherAuth}, + ExaltaLauncher, +}; impl ExaltaLauncher { pub fn render_login(&mut self, ui: &mut Ui) -> Result<(), Box> { @@ -22,7 +25,8 @@ impl ExaltaLauncher { ui.add_space(10.); ui.vertical_centered_justified(|ui| -> Result<(), Box> { ui.label("Password: "); - let re = ui.add(egui::TextEdit::singleline(&mut self.auth.password).password(true)); + let re = + ui.add(egui::TextEdit::singleline(&mut self.auth.password).password(true)); if re.lost_focus() && re.ctx.input().key_pressed(egui::Key::Enter) { self.login()?; } @@ -42,27 +46,45 @@ impl ExaltaLauncher { let mut saved_auth_changed = false; ui.with_layout(egui::Layout::right_to_left(), |ui| { egui::ComboBox::from_id_source("saved_combo") - .selected_text(self.saved_auth.saved.iter().map(|e| e.guid.as_str()).nth(self.saved_auth.current).unwrap_or("Saved Logins")) - .show_ui(ui, |ui| { - egui::Grid::new("saved_grid").num_columns(2).show(ui, |ui| { - self.saved_auth.saved.retain(with_index(|i, auth: &LauncherAuth| { - let mut retained = true; - if ui.selectable_value(&mut self.saved_auth.current, i, &auth.guid).clicked() { - self.auth = auth.clone(); - saved_auth_changed = true; - }; - if ui.button("❌").clicked() { - retained = false; - if i == self.saved_auth.current { - if self.saved_auth.current != 0 {self.saved_auth.current -= 1}; - saved_auth_changed = true; - } - } - ui.end_row(); - retained - })); + .selected_text( + self.saved_auth + .saved + .iter() + .map(|e| e.guid.as_str()) + .nth(self.saved_auth.current) + .unwrap_or("Saved Logins"), + ) + .show_ui(ui, |ui| { + egui::Grid::new("saved_grid").num_columns(2).show(ui, |ui| { + self.saved_auth.saved.retain(with_index( + |i, auth: &LauncherAuth| { + let mut retained = true; + if ui + .selectable_value( + &mut self.saved_auth.current, + i, + &auth.guid, + ) + .clicked() + { + self.auth = auth.clone(); + saved_auth_changed = true; + }; + if ui.button("❌").clicked() { + retained = false; + if i == self.saved_auth.current { + if self.saved_auth.current != 0 { + self.saved_auth.current -= 1 + }; + saved_auth_changed = true; + } + } + ui.end_row(); + retained + }, + )); + }); }); - }); ui.label("Saved Logins"); }); if saved_auth_changed { @@ -128,16 +150,20 @@ impl ExaltaLauncher { pub fn login(&mut self) -> Result<(), Box> { let acc = self.runtime.block_on(request_account( &AuthInfo::default() - .username_password(&self.auth.guid.as_str(), &self.auth.password.as_str()), + .username_password(self.auth.guid.as_str(), self.auth.password.as_str()), ))?; self.account = Some(acc); self.router_path.set(Route::Play); if self.config.save_login { - if let Some(existing_auth) = self.saved_auth.saved.iter().position(|e| e.guid == self.auth.guid) { + if let Some(existing_auth) = self + .saved_auth + .saved + .iter() + .position(|e| e.guid == self.auth.guid) + { self.saved_auth.saved.remove(existing_auth); - } self.saved_auth.saved.push(self.auth.clone()); self.saved_auth.current = self.saved_auth.saved.len() - 1; diff --git a/src/pages/play.rs b/src/pages/play.rs index 35fe674..153c75a 100644 --- a/src/pages/play.rs +++ b/src/pages/play.rs @@ -2,8 +2,8 @@ use std::{path::Path, sync::Arc}; use eframe::egui::{self, Ui}; use poll_promise::Promise; -use tokio::{sync::RwLock}; use std::process::Command; +use tokio::sync::RwLock; use crate::{launchargs::LaunchArgs, main_ext::ResultTimeWrapper, ExaltaLauncher}; @@ -88,7 +88,7 @@ impl ExaltaLauncher { self.download_finished_build_hash = None; self.download_prog = Arc::new(RwLock::new(0.0)); self.config.build_hash = build_hash.to_string(); - if let Ok(_) = self.config.save() { + if self.config.save().is_ok() { println!("Saved build hash: {}", build_hash); } @@ -102,7 +102,8 @@ impl ExaltaLauncher { let game_folder_path = Path::new(&self.config.game_folder_path).to_path_buf(); self.runtime.spawn(async move { println!("Download Started!"); - let game_path = game_folder_path.join(format!("{}/", exalta_core::BUILD_TYPE.read().await)); + let game_path = + game_folder_path.join(format!("{}/", exalta_core::BUILD_TYPE.read().await)); let platform = "rotmg-exalt-win-64"; let build_hash = exalta_core::misc::init(None, None).await?.build_hash; let checksums = exalta_core::download::request_checksums(&build_hash, platform).await?; @@ -115,7 +116,7 @@ impl ExaltaLauncher { Some(prog_clone_1), ) .await - .map(|_| return build_hash), + .map(|_| build_hash), ); println!("Download Ended!"); Ok::<(), anyhow::Error>(()) @@ -125,14 +126,16 @@ impl ExaltaLauncher { } fn load(&self) -> Result<(), Box> { if let Some(account) = &self.account { - let execpath = - Path::new(&self.config.game_folder_path).join(format!("{}/RotMG Exalt.exe", exalta_core::BUILD_TYPE.blocking_read())); + let execpath = Path::new(&self.config.game_folder_path).join(format!( + "{}/RotMG Exalt.exe", + exalta_core::BUILD_TYPE.blocking_read() + )); let args = if let Some(steam_creds) = &self.steam_credentials { serde_json::to_string(&LaunchArgs { platform: "Steam".to_string(), guid: base64::encode(&self.auth.guid), platform_token: Some(base64::encode(&steam_creds.platform_token)), - steam_id: Some(base64::encode(&self.auth.guid.replace("steamworks:", ""))), + steam_id: Some(base64::encode(self.auth.guid.replace("steamworks:", ""))), token: base64::encode(account.access_token.clone()), token_timestamp: base64::encode(account.access_token_timestamp.clone()), token_expiration: base64::encode(account.access_token_expiration.clone()), @@ -152,18 +155,26 @@ impl ExaltaLauncher { server_name: String::new(), })? } - .replace("\"", ""); + .replace('"', ""); println!("{}", args); - #[cfg(target_os="windows")] + #[cfg(target_os = "windows")] Command::new(execpath.to_str().unwrap()) .args(&[format!("data:{}", args)]) .spawn()?; - #[cfg(target_os="linux")] + #[cfg(target_os = "linux")] Command::new("sh") - .args(&["-c", &format!("wine \"{}\" \"{}\"", execpath.to_str().unwrap(), &format!("data:{}", args))]) - .spawn().ok(); + .args(&[ + "-c", + &format!( + "wine \"{}\" \"{}\"", + execpath.to_str().unwrap(), + &format!("data:{}", args) + ), + ]) + .spawn() + .ok(); } Ok(()) } diff --git a/src/registries.rs b/src/registries.rs index ef3813e..fa68eb7 100644 --- a/src/registries.rs +++ b/src/registries.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; + use winreg::{enums::*, RegKey}; @@ -8,14 +8,14 @@ pub fn get_build_id() -> Result> { hklm.open_subkey("SOFTWARE\\DECA Live Operations GmbH\\RotMG Exalt Launcher")?; let mut found_string = None; for row in launcherloc.enum_values() { - if let Some((key, val)) = row.ok() { + if let Ok((key, val)) = row { if key.contains("buildId_v2_Production") { found_string = Some(String::from_utf8_lossy(&val.bytes).to_string()); } } } if let Some(val) = found_string { - Ok(val.replace("\u{0}", "")) + Ok(val.replace('\u{0}', "")) } else { Err(Box::new(std::io::Error::new( std::io::ErrorKind::NotFound, @@ -30,7 +30,7 @@ pub fn set_build_id(build_id: &str) -> Result<(), Box> { hklm.open_subkey("SOFTWARE\\DECA Live Operations GmbH\\RotMG Exalt Launcher")?; let mut found_key = None; for row in launcherloc.enum_keys() { - if let Some(key) = row.ok() { + if let Ok(key) = row { if key.contains("buildId_v2_Production") { found_key = Some(key); }