3 Commits

5 changed files with 116 additions and 7 deletions

3
src-tauri/Cargo.lock generated
View File

@@ -1094,8 +1094,9 @@ dependencies = [
[[package]] [[package]]
name = "ezpplauncher" name = "ezpplauncher"
version = "3.0.0-beta.5" version = "3.0.0"
dependencies = [ dependencies = [
"base64 0.21.7",
"discord-rich-presence", "discord-rich-presence",
"hardware-id", "hardware-id",
"md5", "md5",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "ezpplauncher" name = "ezpplauncher"
version = "3.0.0-beta.5" version = "3.0.0"
description = "EZPPLauncher redefined." description = "EZPPLauncher redefined."
authors = ["HorizonCode"] authors = ["HorizonCode"]
edition = "2024" edition = "2024"
@@ -39,7 +39,8 @@ once_cell = "1.21.3"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winreg = "0.55.0" winreg = "0.55.0"
winapi = { version = "0.3", features = ["winuser"] } winapi = { version = "0.3", features = ["winuser", "wincrypt", "memoryapi", "winbase", "dpapi"] }
base64 = "0.21"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-single-instance = "2.3.0" tauri-plugin-single-instance = "2.3.0"

View File

@@ -27,9 +27,6 @@ pub fn run() {
{ {
builder = builder.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| { builder = builder.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
let app_window = app.get_webview_window("main").expect("no main window"); let app_window = app.get_webview_window("main").expect("no main window");
app_window
.set_always_on_top(true)
.expect("failed to set always on top");
app_window.set_focus().expect("failed to focus"); app_window.set_focus().expect("failed to focus");
})); }));
} }

View File

@@ -307,3 +307,113 @@ pub async fn is_net8_installed() -> bool {
Err(_) => false, Err(_) => false,
} }
} }
//TODO: maybe switch to this crate: https://crates.io/crates/windows-dpapi
#[cfg(windows)]
pub fn encrypt_password(password: &str) -> Result<String, String> {
use std::ptr;
use std::slice;
use winapi::shared::minwindef::{BYTE, DWORD, LPVOID};
use winapi::um::dpapi::{CRYPTPROTECT_UI_FORBIDDEN, CryptProtectData};
use winapi::um::winbase::LocalFree;
use winapi::um::wincrypt::DATA_BLOB;
use base64::{engine::general_purpose, Engine as _};
let password_bytes = password.as_bytes();
let mut input_blob = DATA_BLOB {
cbData: password_bytes.len() as DWORD,
pbData: password_bytes.as_ptr() as *mut BYTE,
};
let mut output_blob = DATA_BLOB {
cbData: 0,
pbData: ptr::null_mut(),
};
let result = unsafe {
CryptProtectData(
&mut input_blob,
ptr::null(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
CRYPTPROTECT_UI_FORBIDDEN,
&mut output_blob,
)
};
if result == 0 {
return Err("CryptProtectData failed".to_string());
}
let encrypted_data =
unsafe { slice::from_raw_parts(output_blob.pbData, output_blob.cbData as usize).to_vec() };
unsafe {
LocalFree(output_blob.pbData as LPVOID);
}
let base64_string = general_purpose::STANDARD.encode(&encrypted_data);
Ok(base64_string)
}
#[cfg(windows)]
pub fn decrypt_password(encrypted_password_base64: &str) -> Result<String, String> {
use std::ptr;
use std::slice;
use winapi::shared::minwindef::{BYTE, DWORD, LPVOID};
use winapi::um::dpapi::{CRYPTPROTECT_UI_FORBIDDEN, CryptUnprotectData};
use winapi::um::winbase::LocalFree;
use winapi::um::wincrypt::DATA_BLOB;
use base64::{engine::general_purpose, Engine as _};
// 1. Decode the Base64 string back into raw bytes
let encrypted_password_bytes = general_purpose::STANDARD.decode(encrypted_password_base64)
.map_err(|e| format!("Base64 decoding failed: {}", e))?;
// 2. Prepare the input data structure
let mut input_blob = DATA_BLOB {
cbData: encrypted_password_bytes.len() as DWORD,
pbData: encrypted_password_bytes.as_ptr() as *mut BYTE,
};
// 3. Prepare the output data structure
let mut output_blob = DATA_BLOB {
cbData: 0,
pbData: ptr::null_mut(),
};
// 4. Call the Windows API function
let result = unsafe {
CryptUnprotectData(
&mut input_blob,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
CRYPTPROTECT_UI_FORBIDDEN,
&mut output_blob,
)
};
// 5. Check the result
if result == 0 {
return Err("CryptUnprotectData failed".to_string());
}
// 6. Copy the decrypted data into a safe Rust Vec
let decrypted_bytes = unsafe {
slice::from_raw_parts(output_blob.pbData, output_blob.cbData as usize).to_vec()
};
// 7. Free the memory allocated by the Windows API
unsafe {
LocalFree(output_blob.pbData as LPVOID);
}
// 8. Convert the decrypted bytes back to a UTF-8 string
String::from_utf8(decrypted_bytes)
.map_err(|e| format!("UTF-8 conversion failed: {}", e))
}

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "ezpplauncher", "productName": "ezpplauncher",
"version": "3.0.0-beta.5", "version": "3.0.0",
"identifier": "farm.ezpp.launcher", "identifier": "farm.ezpp.launcher",
"build": { "build": {
"beforeDevCommand": "bun run vite:dev", "beforeDevCommand": "bun run vite:dev",