Files
ospab.network/ostp-setup/src/system_check.rs
ospab 7e1c87e70b 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
2026-01-01 21:49:37 +03:00

226 lines
5.9 KiB
Rust

//! 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,
}