diff --git a/package.json b/package.json index dbb217a..4d4e2ba 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "rlidentitygui", + "name": "RLIdentity", "private": true, - "version": "2.0.0", + "version": "2.0.1", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/permissions/main.toml b/src-tauri/permissions/main.toml index ef71c74..0da5f62 100644 --- a/src-tauri/permissions/main.toml +++ b/src-tauri/permissions/main.toml @@ -13,5 +13,6 @@ commands.allow = [ "inject_dll", "validate_key", "check_status", - "get_hwid" + "get_hwid", + "download_assets" ] diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 56d224d..2756671 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -37,6 +37,13 @@ pub struct KeyValidationResponse { pub user: Option, } +#[derive(Serialize, Deserialize)] +struct SaveConfigPayload { + #[serde(rename = "spoofedName")] + name: String, + platform: String, +} + #[derive(Deserialize)] struct AssetManifest { injector_hash: String, @@ -64,7 +71,7 @@ async fn get_last_epic_id(base_path: &Path) -> String { // --- commands --- -#[tauri::command] +#[tauri::command(rename_all = "snake_case")] fn get_hwid() -> String { let output = Command::new("reg") .args(["query", r"HKLM\SOFTWARE\Microsoft\Cryptography", "/v", "MachineGuid"]) @@ -78,11 +85,10 @@ fn get_hwid() -> String { } } } - // strictly avoid returning "unknown" to prevent key sharing bypasses "00000000-0000-0000-0000-000000000000".to_string() } -#[tauri::command] +#[tauri::command(rename_all = "snake_case")] async fn validate_key( key: String, hwid: String, @@ -101,18 +107,19 @@ async fn validate_key( .map_err(|e| format!("api schema mismatch: {}", e)) } -#[tauri::command] +#[tauri::command(rename_all = "snake_case")] async fn inject_dll(state: State<'_, AppState>) -> Result { let injector_path = state.app_data.join("injector.exe"); let dll_path = state.app_data.join("RLIdentity.dll"); - { + let is_running = { let mut sys = state.sys.lock().unwrap(); - // fix: use refresh_processes_specifics and add the remove_dead_processes bool -sys.refresh_processes_specifics(ProcessRefreshKind::new()); - if sys.processes_by_exact_name("RocketLeague.exe").next().is_none() { - return Err("rocket league is not running".into()); - } + sys.refresh_processes_specifics(ProcessRefreshKind::new()); + let x = sys.processes_by_exact_name("RocketLeague.exe").next().is_some(); x + }; + + if !is_running { + return Err("rocket league is not running".into()); } if !injector_path.exists() || !dll_path.exists() { @@ -132,11 +139,10 @@ sys.refresh_processes_specifics(ProcessRefreshKind::new()); } } -#[tauri::command] +#[tauri::command(rename_all = "snake_case")] async fn download_assets(state: State<'_, AppState>) -> Result<(), String> { fs::create_dir_all(&state.app_data).await.map_err(|e| e.to_string())?; - // dynamically fetch latest hashes to avoid brittle hardcoding let manifest: AssetManifest = state.client.get("https://api.rlidentity.me/manifest") .send().await.map_err(|e| e.to_string())? .json().await.map_err(|e| e.to_string())?; @@ -164,29 +170,36 @@ async fn download_assets(state: State<'_, AppState>) -> Result<(), String> { Ok(()) } -#[tauri::command] +#[tauri::command(rename_all = "snake_case")] async fn check_status(state: State<'_, AppState>) -> Result { - let mut sys = state.sys.lock().unwrap(); - // fix: use refresh_processes_specifics and add the remove_dead_processes bool -sys.refresh_processes_specifics(ProcessRefreshKind::new()); - let is_running = sys.processes_by_exact_name("RocketLeague.exe").next().is_some(); + let is_running = { + let mut sys = state.sys.lock().unwrap(); + sys.refresh_processes_specifics(ProcessRefreshKind::new()); + let x = sys.processes_by_exact_name("RocketLeague.exe").next().is_some(); x + }; + Ok(Status { is_running, is_injected: false }) } -#[tauri::command] -async fn save_config(config_data: String, state: State<'_, AppState>) -> Result<(), String> { +#[tauri::command(rename_all = "snake_case")] +async fn save_config(name: String, platform: String, state: State<'_, AppState>) -> Result<(), String> { let config_path = state.app_data.join("config.json"); - let temp_path = state.app_data.join("config.json.tmp"); + let payload = SaveConfigPayload { name, platform }; + + if !state.app_data.exists() { + fs::create_dir_all(&state.app_data).await.map_err(|e| e.to_string())?; + } - // atomic write: write to tmp then rename to prevent corruption on crash - fs::write(&temp_path, config_data).await.map_err(|e| e.to_string())?; - fs::rename(temp_path, config_path).await.map_err(|e| e.to_string()) + let json = serde_json::to_string(&payload).map_err(|e| e.to_string())?; + fs::write(config_path, json).await.map_err(|e| e.to_string()) } -#[tauri::command] + +#[tauri::command(rename_all = "snake_case")] fn get_app_version(app: tauri::AppHandle) -> String { app.package_info().version.to_string() } -#[tauri::command] + +#[tauri::command(rename_all = "snake_case")] fn minimize_to_tray(window: WebviewWindow) { let _ = window.hide(); } @@ -222,26 +235,29 @@ pub fn run() { #[cfg(target_os = "windows")] apply_acrylic(&window, Some((18, 18, 18, 125))).ok(); - let handle = app.handle().clone(); - let tray_menu = tauri::menu::Menu::with_items(app, &[ - &tauri::menu::MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?, - ])?; + let monitor_handle = app.handle().clone(); + tauri::async_runtime::spawn(async move { + let mut last_seen_running = false; + loop { + tokio::time::sleep(std::time::Duration::from_secs(3)).await; + + let state = monitor_handle.state::(); + let is_running = { + let mut sys = state.sys.lock().unwrap(); + sys.refresh_processes_specifics(ProcessRefreshKind::new()); + let x = sys.processes_by_exact_name("RocketLeague.exe").next().is_some(); x + }; - let _ = tauri::tray::TrayIconBuilder::new() - .icon(app.default_window_icon().unwrap().clone()) - .menu(&tray_menu) - .on_menu_event(move |_app, event| { - if event.id().as_ref() == "quit" { handle.exit(0); } - }) - .on_tray_icon_event(|tray, event| { - if let tauri::tray::TrayIconEvent::Click { button: tauri::tray::MouseButton::Left, .. } = event { - let _ = tray.app_handle().get_webview_window("main").unwrap().show(); + if is_running && !last_seen_running { + println!("auto-detect: rocket league started. injecting..."); + let _ = inject_dll(state).await; } - }) - .build(app)?; + last_seen_running = is_running; + } + }); Ok(()) }) .run(tauri::generate_context!()) .expect("error while running tauri application"); -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index c729667..2109cf0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -138,9 +138,20 @@ export default function App() { useEffect(() => { if (initialApiKey) authorize(initialApiKey); syncAssetsAndCheckUpdates(); - tryInvoke("get_app_version").then(v => setVersion(v as string)); + loadAppVersion(); }, []); + async function loadAppVersion() { + if (!isTauriRuntime()) return; + try { + const app = await import("@tauri-apps/api/app"); + setVersion(await app.getVersion()); + } catch (e) { + console.error("Failed to get app version:", e); + setVersion(""); + } + } + async function syncAssetsAndCheckUpdates() { if (!isTauriRuntime()) return; try { @@ -244,7 +255,7 @@ export default function App() { async function inject() { setStatus("injecting..."); try { - const res = await tryInvoke("inject_dll", { discordId: userData?.discord_id }); + const res = await tryInvoke("inject_dll"); setLastLog(res || "Successfully Injected!"); setStatus("Successfully Injected!"); window.setTimeout(() => setStatus("ready"), 1400);