meow
Some checks failed
Build & Release / build-windows (push) Has been cancelled

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
bits 2026-04-28 17:34:02 +03:00
parent e6404f781c
commit 7117b65cf5
4 changed files with 74 additions and 46 deletions

View File

@ -1,7 +1,7 @@
{
"name": "rlidentitygui",
"name": "RLIdentity",
"private": true,
"version": "2.0.0",
"version": "2.0.1",
"type": "module",
"scripts": {
"dev": "vite",

View File

@ -13,5 +13,6 @@ commands.allow = [
"inject_dll",
"validate_key",
"check_status",
"get_hwid"
"get_hwid",
"download_assets"
]

View File

@ -37,6 +37,13 @@ pub struct KeyValidationResponse {
pub user: Option<UserInfo>,
}
#[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,19 +107,20 @@ 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<String, String> {
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() {
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() {
return Err("files missing, please update".into());
@ -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<Status, String> {
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());
let is_running = sys.processes_by_exact_name("RocketLeague.exe").next().is_some();
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 };
// 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())
if !state.app_data.exists() {
fs::create_dir_all(&state.app_data).await.map_err(|e| e.to_string())?;
}
#[tauri::command]
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(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,23 +235,26 @@ 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 _ = 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();
let state = monitor_handle.state::<AppState>();
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
};
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(())
})

View File

@ -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<string>("inject_dll", { discordId: userData?.discord_id });
const res = await tryInvoke<string>("inject_dll");
setLastLog(res || "Successfully Injected!");
setStatus("Successfully Injected!");
window.setTimeout(() => setStatus("ready"), 1400);