build(native): rename lib to craftlabs_auth_core, add crypto deps

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