feat: Windows Setup Wizard (ostp-setup) with Tauri
- Tauri 2.0 based graphical installer - Access Key parsing with AES-256-GCM encryption - Windows Service installation via sc.exe - WinTUN driver extraction from embedded resources - System requirements checking (admin, AES-NI, OS version) - Modern dark UI with step-by-step wizard flow - Country/region selection for SNI mimicry
This commit is contained in:
225
ostp-setup/src/system_check.rs
Normal file
225
ostp-setup/src/system_check.rs
Normal file
@@ -0,0 +1,225 @@
|
||||
//! System requirements checking
|
||||
//!
|
||||
//! Verifies that the target system meets all requirements for OSTP Client.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// System check result
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SystemCheckResult {
|
||||
pub wintun_installed: bool,
|
||||
pub aes_ni_supported: bool,
|
||||
pub admin_privileges: bool,
|
||||
pub os_version: String,
|
||||
}
|
||||
use anyhow::Result;
|
||||
|
||||
/// Run all system checks
|
||||
pub async fn run_checks() -> Result<SystemCheckResult> {
|
||||
Ok(SystemCheckResult {
|
||||
wintun_installed: check_wintun_installed(),
|
||||
aes_ni_supported: check_aes_ni_support(),
|
||||
admin_privileges: check_admin_privileges(),
|
||||
os_version: get_os_version(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Check if wintun.dll is already installed
|
||||
fn check_wintun_installed() -> bool {
|
||||
crate::wintun::is_installed()
|
||||
}
|
||||
|
||||
/// Check if CPU supports AES-NI instructions
|
||||
fn check_aes_ni_support() -> bool {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
// Check CPUID for AES-NI support
|
||||
return is_x86_feature_detected!("aes");
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
// ARM64 typically has crypto extensions
|
||||
// Check for ARMv8 Crypto extensions
|
||||
#[cfg(target_feature = "aes")]
|
||||
return true;
|
||||
|
||||
#[cfg(not(target_feature = "aes"))]
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fallback: assume software AES is acceptable
|
||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
||||
true
|
||||
}
|
||||
|
||||
/// Check if running with administrator privileges
|
||||
fn check_admin_privileges() -> bool {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::ptr;
|
||||
|
||||
// Use Windows API to check elevation
|
||||
unsafe {
|
||||
let mut token_handle: *mut std::ffi::c_void = ptr::null_mut();
|
||||
let current_process = GetCurrentProcess();
|
||||
|
||||
if OpenProcessToken(
|
||||
current_process,
|
||||
TOKEN_QUERY,
|
||||
&mut token_handle,
|
||||
) == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut elevation = TOKEN_ELEVATION { TokenIsElevated: 0 };
|
||||
let mut size: u32 = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
|
||||
|
||||
let result = GetTokenInformation(
|
||||
token_handle,
|
||||
TokenElevation,
|
||||
&mut elevation as *mut _ as *mut _,
|
||||
size,
|
||||
&mut size,
|
||||
);
|
||||
|
||||
CloseHandle(token_handle);
|
||||
|
||||
result != 0 && elevation.TokenIsElevated != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
// On non-Windows, check if running as root
|
||||
unsafe { libc::geteuid() == 0 }
|
||||
}
|
||||
}
|
||||
|
||||
/// Get Windows version string
|
||||
fn get_os_version() -> String {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use winreg::{enums::*, RegKey};
|
||||
|
||||
if let Ok(hklm) = RegKey::predef(HKEY_LOCAL_MACHINE)
|
||||
.open_subkey(r"SOFTWARE\Microsoft\Windows NT\CurrentVersion")
|
||||
{
|
||||
let product_name: String = hklm.get_value("ProductName").unwrap_or_default();
|
||||
let build: String = hklm.get_value("CurrentBuild").unwrap_or_default();
|
||||
|
||||
if !product_name.is_empty() {
|
||||
return format!("{} (Build {})", product_name, build);
|
||||
}
|
||||
}
|
||||
|
||||
"Windows (Unknown Version)".to_string()
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
"Non-Windows OS".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Check minimum Windows version (Windows 10 1607+)
|
||||
#[allow(dead_code)]
|
||||
pub fn check_minimum_version() -> bool {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use winreg::{enums::*, RegKey};
|
||||
|
||||
if let Ok(hklm) = RegKey::predef(HKEY_LOCAL_MACHINE)
|
||||
.open_subkey(r"SOFTWARE\Microsoft\Windows NT\CurrentVersion")
|
||||
{
|
||||
let build: String = hklm.get_value("CurrentBuild").unwrap_or_default();
|
||||
if let Ok(build_num) = build.parse::<u32>() {
|
||||
// Windows 10 1607 is build 14393
|
||||
return build_num >= 14393;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
true
|
||||
}
|
||||
|
||||
/// Check available disk space (need at least 50MB)
|
||||
#[allow(dead_code)]
|
||||
pub fn check_disk_space(path: &std::path::Path) -> bool {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::ffi::OsStr;
|
||||
|
||||
let path_wide: Vec<u16> = OsStr::new(path)
|
||||
.encode_wide()
|
||||
.chain(std::iter::once(0))
|
||||
.collect();
|
||||
|
||||
let mut free_bytes: u64 = 0;
|
||||
let mut total_bytes: u64 = 0;
|
||||
let mut total_free_bytes: u64 = 0;
|
||||
|
||||
unsafe {
|
||||
if GetDiskFreeSpaceExW(
|
||||
path_wide.as_ptr(),
|
||||
&mut free_bytes,
|
||||
&mut total_bytes,
|
||||
&mut total_free_bytes,
|
||||
) != 0 {
|
||||
// Need at least 50MB
|
||||
return free_bytes >= 50 * 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
true // Assume OK if check fails
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let _ = path;
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// Windows API bindings
|
||||
#[cfg(windows)]
|
||||
unsafe extern "system" {
|
||||
fn GetCurrentProcess() -> *mut std::ffi::c_void;
|
||||
fn OpenProcessToken(
|
||||
process: *mut std::ffi::c_void,
|
||||
access: u32,
|
||||
token: *mut *mut std::ffi::c_void,
|
||||
) -> i32;
|
||||
fn GetTokenInformation(
|
||||
token: *mut std::ffi::c_void,
|
||||
info_class: u32,
|
||||
info: *mut std::ffi::c_void,
|
||||
info_len: u32,
|
||||
return_len: *mut u32,
|
||||
) -> i32;
|
||||
fn CloseHandle(handle: *mut std::ffi::c_void) -> i32;
|
||||
#[allow(dead_code)]
|
||||
fn GetDiskFreeSpaceExW(
|
||||
directory: *const u16,
|
||||
free_bytes: *mut u64,
|
||||
total_bytes: *mut u64,
|
||||
total_free_bytes: *mut u64,
|
||||
) -> i32;
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
const TOKEN_QUERY: u32 = 0x0008;
|
||||
#[cfg(windows)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
const TokenElevation: u32 = 20;
|
||||
|
||||
#[cfg(windows)]
|
||||
#[repr(C)]
|
||||
#[allow(non_snake_case)]
|
||||
struct TOKEN_ELEVATION {
|
||||
TokenIsElevated: u32,
|
||||
}
|
||||
Reference in New Issue
Block a user