diff --git a/native/craft-core/Cargo.toml b/native/craft-core/Cargo.toml index 351b2a9..7bf6f2b 100644 --- a/native/craft-core/Cargo.toml +++ b/native/craft-core/Cargo.toml @@ -6,13 +6,20 @@ description = "CraftLabs 授权核心库 — Rust 实现,导出 craft_* C ABI [lib] crate-type = ["cdylib", "staticlib"] -name = "craftlabs_auth_bitanswer" +name = "craftlabs_auth_core" [dependencies] obfstr = "0.4" sha2 = "0.10" libloading = "0.8" once_cell = "1" +rsa = { version = "0.9", features = ["sha2"] } +aes-gcm = "0.10" +hkdf = "0.12" +base64 = "0.22" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +chrono = { version = "0.4", features = ["serde"] } [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { version = "0.52", features = ["Win32_System_Diagnostics_Debug"], optional = true } diff --git a/native/craft-core/src/error.rs b/native/craft-core/src/error.rs index 69a72fc..448b873 100644 --- a/native/craft-core/src/error.rs +++ b/native/craft-core/src/error.rs @@ -1,82 +1,91 @@ +// Error codes for selfhosted + BitAnswer licensing use crate::CraftResult; -/// BitAnswer BIT_STATUS 错误码到结构化错误的精简映射。 -/// 完整 200+ 码请参考 bitanswer.h,此处映射文档中明确列出的高频码。 #[derive(Debug, Clone, PartialEq)] pub enum LicenseError { + // ── 通用 ── Success, - NetworkError, - WrongHandle, - InvalidParameter, - ApplicationDataError, - LicenseExpired, - LicenseNotFound, - LicenseDisabled, - FeatureNotFound(u32), - FeatureExpired(u32), - FeatureTypeNotMatch(u32), - SnInvalid, - SnNotFound, - SnDisabled, - SnRevoked, - SnExpired, - CapacityExhausted, - ServerBusy, - ServerDown, - Timeout, - Unknown(u32), + ConfigMissing(&'static str), + Network(String), + NotInitialized, + + // ── 签名 / 加密 ── + InvalidFormat(&'static str), + InvalidSignature, + SignatureMismatch, + CryptoError, + DecryptionFailed, + CorruptedPayload, + LicenseIdMismatch, + + // ── 许可状态 ── + NotYetValid, + Expired, + NoCachedLicense, + OfflineGraceExceeded { days_offline: u32, max_days: u32 }, + InvalidLicense, + LicenseRevoked, + DeviceLimitReached, + ConcurrentUserLimitReached, + ActivationLimitReached, + + // ── 兼容比特 ── + BitAnswerStatus(u32), + + // ── 未知 ── + UnknownStatus(u16), } impl LicenseError { - /// 将 BitAnswer BIT_STATUS (u32) 映射为 LicenseError + /// Map BitAnswer BIT_STATUS (u32) → LicenseError (双线共存保留) pub fn from_bit_status(status: u32) -> Self { match status { 0x0000 => LicenseError::Success, - 0x0101 => LicenseError::NetworkError, - 0x0102 => LicenseError::WrongHandle, - 0x0103 => LicenseError::InvalidParameter, - 0x0105 => LicenseError::ApplicationDataError, - 0x0701 => LicenseError::LicenseExpired, - 0x0114 => LicenseError::LicenseNotFound, - 0x0705 => LicenseError::LicenseDisabled, - 0x0503 => LicenseError::FeatureNotFound(0), - 0x0509 => LicenseError::FeatureExpired(0), - 0x0504 => LicenseError::FeatureTypeNotMatch(0), - 0x011C => LicenseError::SnInvalid, - 0x0706 => LicenseError::SnNotFound, - // 继续保留对相关码的映射 - 0x0123 => LicenseError::SnRevoked, - 0x0107 => LicenseError::ServerBusy, - 0x0108 => LicenseError::ServerDown, - 0x0141 => LicenseError::Timeout, - 0x0712 => LicenseError::CapacityExhausted, - _ => LicenseError::Unknown(status), + 0x0101 => LicenseError::Network("bitanswer network error".into()), + 0x0102 => LicenseError::ConfigMissing("bitanswer wrong handle"), + 0x0103 => LicenseError::ConfigMissing("bitanswer invalid parameter"), + 0x0105 => LicenseError::ConfigMissing("bitanswer application data error"), + 0x0114 => LicenseError::InvalidLicense, + 0x011C => LicenseError::InvalidLicense, + 0x0701 => LicenseError::Expired, + 0x0705 => LicenseError::LicenseRevoked, + 0x0706 => LicenseError::InvalidLicense, + 0x0712 => LicenseError::DeviceLimitReached, + 0x0123 => LicenseError::LicenseRevoked, + 0x0503 => LicenseError::InvalidLicense, + 0x0504 => LicenseError::InvalidLicense, + 0x0509 => LicenseError::Expired, + 0x0107 => LicenseError::Network("bitanswer server busy".into()), + 0x0108 => LicenseError::Network("bitanswer server down".into()), + 0x0141 => LicenseError::Network("bitanswer timeout".into()), + _ => LicenseError::BitAnswerStatus(status), } } pub fn message(&self) -> &'static str { match self { LicenseError::Success => "ok", - LicenseError::NetworkError => "network error", - LicenseError::WrongHandle => "wrong handle", - LicenseError::InvalidParameter => "invalid parameter", - LicenseError::ApplicationDataError => "application data error", - LicenseError::LicenseExpired => "license expired", - LicenseError::LicenseNotFound => "license not found", - LicenseError::LicenseDisabled => "license disabled", - LicenseError::FeatureNotFound(_) => "feature not found", - LicenseError::FeatureExpired(_) => "feature expired", - LicenseError::FeatureTypeNotMatch(_) => "feature type not match", - LicenseError::SnInvalid => "sn invalid", - LicenseError::SnNotFound => "sn not found", - LicenseError::SnDisabled => "sn disabled", - LicenseError::SnRevoked => "sn revoked", - LicenseError::SnExpired => "sn expired", - LicenseError::CapacityExhausted => "capacity exhausted", - LicenseError::ServerBusy => "server busy", - LicenseError::ServerDown => "server down", - LicenseError::Timeout => "timeout", - LicenseError::Unknown(_) => "unknown error", + LicenseError::ConfigMissing(_) => "config missing", + LicenseError::Network(_) => "network error", + LicenseError::NotInitialized => "not initialized", + LicenseError::InvalidFormat(_) => "invalid format", + LicenseError::InvalidSignature => "invalid signature", + LicenseError::SignatureMismatch => "signature verification failed", + LicenseError::CryptoError => "crypto error", + LicenseError::DecryptionFailed => "decryption failed", + LicenseError::CorruptedPayload => "corrupted payload", + LicenseError::LicenseIdMismatch => "license id mismatch", + LicenseError::NotYetValid => "license not yet valid", + LicenseError::Expired => "license expired", + LicenseError::NoCachedLicense => "no cached license", + LicenseError::OfflineGraceExceeded { .. } => "offline grace period exceeded", + LicenseError::InvalidLicense => "invalid license", + LicenseError::LicenseRevoked => "license revoked", + LicenseError::DeviceLimitReached => "device limit reached", + LicenseError::ConcurrentUserLimitReached => "concurrent user limit reached", + LicenseError::ActivationLimitReached => "activation limit reached", + LicenseError::BitAnswerStatus(_) => "bitanswer error", + LicenseError::UnknownStatus(_) => "unknown error", } } @@ -85,19 +94,14 @@ impl LicenseError { } } -/// 将 LicenseError 转为 C ABI 兼容的 CraftResult +/// Convert LicenseError to C ABI CraftResult pub fn to_craft_result(error: LicenseError) -> CraftResult { if error.is_success() { - // 对于成功场景,返回一个最小的 CraftResult(message 指针为 NULL,调用方通过成功状态判断) CraftResult { success: 1, message: std::ptr::null() } } else { - // 使用堆分配的消息指针(调用方通过 craft_free_license_info 类似方式释放) let msg = format!("{}\0", error.message()); let msg_ptr = msg.as_ptr() as *const std::os::raw::c_char; - std::mem::forget(msg); // 内存由调用方管理 - CraftResult { - success: 0, - message: msg_ptr, - } + std::mem::forget(msg); + CraftResult { success: 0, message: msg_ptr } } }