use crate::utils::ffi;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LicenseStatus {
NotVerified = 0,
Verifying = 1,
Verified = 2,
Failed = 3,
Expired = 4,
MachineIdMismatch = 5,
TimeRollback = 6,
}
pub struct Authorization;
impl Authorization {
pub fn license_status() -> LicenseStatus {
let raw = unsafe { ffi::GetLicenseStatusEx() };
match raw {
0 => LicenseStatus::NotVerified,
1 => LicenseStatus::Verifying,
2 => LicenseStatus::Verified,
3 => LicenseStatus::Failed,
4 => LicenseStatus::Expired,
5 => LicenseStatus::MachineIdMismatch,
6 => LicenseStatus::TimeRollback,
_ => LicenseStatus::NotVerified,
}
}
pub fn activate(activation_code: &str) -> Result<String, String> {
let code_c = match CString::new(activation_code) {
Ok(s) => s,
Err(_) => return Err("激活码包含空字节".to_string()),
};
let mut err_buf = vec![0u8; 512];
let ret = unsafe {
ffi::LicenseActivate(
code_c.as_ptr(),
err_buf.as_mut_ptr() as *mut c_char,
err_buf.len() as i32,
)
};
let null_pos = err_buf.iter().position(|&b| b == 0).unwrap_or(err_buf.len());
let msg = String::from_utf8_lossy(&err_buf[..null_pos]).to_string();
if ret == 0 {
Ok(if msg.is_empty() { "激活成功".to_string() } else { msg })
} else {
Err(if msg.is_empty() { format!("激活失败 (code={})", ret) } else { msg })
}
}
}
pub struct AdminHelper;
impl AdminHelper {
pub fn ensure_running_as_admin() -> bool {
#[cfg(target_os = "windows")]
{
#[link(name = "shell32")]
extern "system" {
fn IsUserAnAdmin() -> i32;
}
unsafe { IsUserAnAdmin() != 0 }
}
#[cfg(not(target_os = "windows"))]
{
extern "C" {
fn geteuid() -> u32;
}
unsafe { geteuid() == 0 }
}
}
pub fn ensure_admin_or_restart() -> bool {
if Self::ensure_running_as_admin() {
return true;
}
#[cfg(target_os = "windows")]
{
#[link(name = "kernel32")]
extern "system" {
fn GetModuleFileNameW(hModule: *const std::ffi::c_void, lpFilename: *mut u16, nSize: u32) -> u32;
}
#[link(name = "shell32")]
extern "system" {
fn ShellExecuteW(
hwnd: *const std::ffi::c_void,
lpOperation: *const u16,
lpFile: *const u16,
lpParameters: *const u16,
lpDirectory: *const u16,
nShowCmd: i32,
) -> isize;
}
let mut path_buf = vec![0u16; 260];
let len = unsafe {
GetModuleFileNameW(std::ptr::null(), path_buf.as_mut_ptr(), 260)
};
if len == 0 {
return false;
}
path_buf.truncate(len as usize);
path_buf.push(0);
let runas: Vec<u16> = "runas\0".encode_utf16().collect();
let empty: Vec<u16> = "\0".encode_utf16().collect();
let result = unsafe {
ShellExecuteW(
std::ptr::null(),
runas.as_ptr(),
path_buf.as_ptr(),
empty.as_ptr(),
empty.as_ptr(),
1,
)
};
result > 32
}
#[cfg(not(target_os = "windows"))]
{
false
}
}
}
pub struct DeviceInfoHelper;
impl DeviceInfoHelper {
pub fn get_windows_product_key() -> Option<String> {
let ptr = unsafe { ffi::GetWindowsProductKey() };
if ptr.is_null() {
return None;
}
let s = unsafe { CStr::from_ptr(ptr) };
let result = s.to_str().ok().map(|s| s.to_string());
result.filter(|s| !s.is_empty())
}
pub fn get_driver_list() -> Vec<String> {
let ptr = unsafe { ffi::GetDriverList() };
if ptr.is_null() {
return Vec::new();
}
let s = unsafe { CStr::from_ptr(ptr) };
match s.to_str() {
Ok(list) if !list.is_empty() => {
list.split(';')
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect()
}
_ => Vec::new(),
}
}
pub fn get_real_system_version() -> String {
#[cfg(target_os = "windows")]
{
#[repr(C)]
struct OsVersionInfoExW {
os_version_info_size: u32,
major_version: u32,
minor_version: u32,
build_number: u32,
platform_id: u32,
sz_csd_version: [u16; 128],
service_pack_major: u16,
service_pack_minor: u16,
suite_mask: u16,
product_type: u8,
reserved: u8,
}
#[link(name = "ntdll")]
extern "system" {
fn RtlGetVersion(lpVersionInformation: *mut OsVersionInfoExW) -> i32;
}
let mut info: OsVersionInfoExW = unsafe { std::mem::zeroed() };
info.os_version_info_size = std::mem::size_of::<OsVersionInfoExW>() as u32;
let status = unsafe { RtlGetVersion(&mut info) };
if status == 0 {
return format!("Windows {}.{}.{}",
info.major_version, info.minor_version, info.build_number);
}
"Windows (版本未知)".to_string()
}
#[cfg(target_os = "linux")]
{
if let Ok(content) = std::fs::read_to_string("/etc/os-release") {
for line in content.lines() {
if line.starts_with("PRETTY_NAME=") {
return line.trim_start_matches("PRETTY_NAME=")
.trim_matches('"')
.to_string();
}
}
}
"Linux (版本未知)".to_string()
}
#[cfg(not(any(target_os = "windows", target_os = "linux")))]
{
"未知操作系统".to_string()
}
}
}
#[derive(Clone, Debug, Default)]
pub struct LicenseCertificate {
pub version: i32,
pub certificate_id: String,
pub license_type: String,
pub activation_code: String,
pub machine_id: String,
pub device_name: String,
pub enterprise_id: Option<String>,
pub enterprise_name: Option<String>,
pub max_devices: Option<i32>,
pub issue_date: String,
pub expiration_date: String,
pub platform: String,
pub library_version: String,
pub core_version: String,
pub system_version: String,
pub library_hash: String,
pub core_hash: String,
pub signature: String,
}