darra-ethercat-master 2.0.6

商业 EtherCAT 主站协议栈 · 实时内核驱动 · 抖动 1µs · Windows + Linux · 多编程语言 · 全协议 · 支持复杂拓扑 + 热插拔 · ethercat.darra.xyz · Commercial EtherCAT Master protocol stack · Real-time kernel driver · 1µs jitter · Multi-platform · Multi-language · Complex topology + hot-plug.
//! 授权管理 — 最小接口 (跟 6 SDK 完全对齐)
//!
//! 设计:
//! - 只 2 个对外 API: Authorization::activate(code) + Authorization::license_status()
//! - 激活 / HTTP / 解密 / 验签 / 完整性 / 时钟 / 过期检查全部在 native (Darra.Core.dll) 内静默完成
//! - SDK 不做密码学, 不做 HTTP, 只是 1 行 FFI wrapper
//! - 内核 WSK 走驱动多 NIC 群发, 3s 超时

use crate::utils::ffi;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;

/// 授权状态 — 镜像 native license_status_t
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LicenseStatus {
    NotVerified = 0,
    Verifying = 1,
    Verified = 2,
    Failed = 3,
    Expired = 4,
    MachineIdMismatch = 5,
}

/// 授权管理 — 最小接口
pub struct Authorization;

impl Authorization {
    /// 授权状态: 证书文件存在 = 已激活. 真实有效性由 native 静默验证.
    pub fn license_status() -> LicenseStatus {
        if license_file_exists() {
            LicenseStatus::Verified
        } else {
            LicenseStatus::NotVerified
        }
    }

    /// 激活授权 — 1 行 FFI 调用 native LicenseActivate.
    ///
    /// native 内部完成: 格式校验 / 拿机器码 / 组 HTTP / IOCTL → 内核 WSK 多 NIC 群发 (3s) /
    ///                parse 响应 / 落盘 / 自验 / DRL2 → DRL1 在线交换.
    ///
    /// # Arguments
    /// * `activation_code` - 激活码 (12 位字母, 允许 - 或空格分隔)
    ///
    /// # Returns
    /// * `Ok(message)` 成功
    /// * `Err(message)` 失败 (含错误描述)
    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,
            )
        };
        // 找 null terminator
        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 })
        }
    }
}

/// 证书文件路径 (跟 native license_get_file_path 对齐: System32\config\DKEY)
fn get_license_file_path() -> String {
    #[cfg(target_os = "windows")]
    {
        let win_dir = std::env::var("SystemRoot").unwrap_or_else(|_| "C:\\Windows".to_string());
        format!("{}\\System32\\config\\DKEY", win_dir)
    }
    #[cfg(not(target_os = "windows"))]
    {
        "/etc/darra/DKEY".to_string()
    }
}

fn license_file_exists() -> bool {
    std::path::Path::new(&get_license_file_path()).exists()
}

// ===================== 管理员权限辅助 (对应 C# AdminHelper) =====================

/// 管理员权限辅助类 (对应 C# AdminHelper)
pub struct AdminHelper;

impl AdminHelper {
    /// 检测当前进程是否以管理员身份运行
    ///
    /// Windows: 通过 Shell32 IsUserAnAdmin API 检测
    /// Linux: 通过 geteuid() == 0 检测
    pub fn ensure_running_as_admin() -> bool {
        #[cfg(target_os = "windows")]
        {
            // 使用 Shell32.dll 的 IsUserAnAdmin
            #[link(name = "shell32")]
            extern "system" {
                fn IsUserAnAdmin() -> i32;
            }
            unsafe { IsUserAnAdmin() != 0 }
        }
        #[cfg(not(target_os = "windows"))]
        {
            // Linux/macOS: 检查 euid == 0
            extern "C" {
                fn geteuid() -> u32;
            }
            unsafe { geteuid() == 0 }
        }
    }

    /// 确保以管理员身份运行, 如果不是则尝试提权重启 (仅 Windows)
    ///
    /// 返回 true 表示当前已是管理员。
    /// 返回 false 表示需要以管理员身份重新启动程序。
    /// 注意: Rust 类库无法直接触发 UAC, 此方法仅检测状态,
    /// 实际提权需要调用方通过 ShellExecuteW "runas" 实现。
    pub fn ensure_admin_or_restart() -> bool {
        if Self::ensure_running_as_admin() {
            return true;
        }

        #[cfg(target_os = "windows")]
        {
            // 尝试通过 ShellExecuteW "runas" 重启当前进程
            #[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, // SW_SHOWNORMAL
                )
            };

            // ShellExecuteW 返回 > 32 表示成功
            result > 32
        }
        #[cfg(not(target_os = "windows"))]
        {
            false // Linux 不支持自动提权
        }
    }
}

// ===================== 设备信息辅助 (对应 C# DeviceNameHelper / SystemVersionHelper) =====================

/// 设备信息辅助类 (对应 C# DeviceNameHelper + SystemVersionHelper)
pub struct DeviceInfoHelper;

impl DeviceInfoHelper {
    /// 获取 Windows 产品密钥 (通过 DLL 获取)
    ///
    /// 对应 C# DeviceNameHelper.GetWindowsProductKey()
    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());
        // DLL 返回的字符串是静态缓冲区, 不需要释放
        result.filter(|s| !s.is_empty())
    }

    /// 获取系统驱动列表 (通过 DLL 获取)
    ///
    /// 返回驱动列表, 每个元素格式: "驱动名|显示名|状态"
    /// 对应 C# DeviceNameHelper.GetDriverList()
    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(),
        }
    }

    /// 获取真实的 Windows 系统版本 (绕过应用程序兼容性清单)
    ///
    /// 通过 ntdll.dll RtlGetVersion 获取, 对应 C# SystemVersionHelper.GetRealSystemVersion()
    /// 返回格式: "Windows 10.0.19045"
    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")]
        {
            // Linux: 读取 /etc/os-release
            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()
        }
    }
}

/// 授权证书模型 (对应 C# LicenseCertificate)
#[derive(Clone, Debug, Default)]
pub struct LicenseCertificate {
    /// 证书版本
    pub version: i32,
    /// 证书ID
    pub certificate_id: String,
    /// 授权类型 ("personal" / "enterprise")
    pub license_type: String,
    /// 激活码
    pub activation_code: String,
    /// 机器码
    pub machine_id: String,
    /// 设备名称
    pub device_name: String,
    /// 企业ID
    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,
}