Files
craftlabs-authorization-sdk/docs/superpowers/specs/2026-05-01-bitanswer-1to1-refactor-design.md
huangping 7af83b089e docs: add BitAnswer 1:1 mapping refactor design spec
Architecture audit revealed AuthProvider (8 methods) only covers
~15% of BitAnswer's 50+ C API surface. This spec proposes:
- 6 capability interfaces (LicenseLifecycle, FeatureManagement,
  DataItemStore, LicenseInfoQuery, CheckoutManager, LicenseUtility)
- 40+ JNI → Rust → BitAnswer C API mappings
- 4-phase migration path with backward compatibility
2026-05-01 13:45:43 +08:00

424 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BitAnswer 1:1 映射重构设计
> **状态**: 待审核
> **日期**: 2026-05-01
> **触发**: 架构审计发现 `AuthProvider` (8 方法) 与 BitAnswer C API (50+ 函数) 之间存在显著缺口
> **策略**: 大幅重构为 BitAnswer 1:1 原语映射,按能力域拆分接口
---
## 1. 审计摘要
### 1.1 当前状态
```
Java AuthProvider (8 methods)
└─ BitAnswerProvider / SelfHostedAuthProvider
└─ NativeBridge (JNI, 9 native methods)
└─ craft-core cdylib (Rust, 9 craft_* C ABI functions)
└─ ⚠️ 全部返回 ok_result(桩实现,未调用真实 BitAnswer API
└─ [已废弃] .deprecated-cmake/ bitanswer_adapter(空实现)
```
### 1.2 覆盖度缺口
| BitAnswer API 分组 | 原生函数数 | 当前覆盖 | 缺失 |
|---|---|---|---|
| 认证与会话 | 10+ | 3 (activate/release/close) | LoginEx, LoginByToken, Revoke, RemoveSn, SessionControl |
| 激活与升级 | 6 | 1 (activate) | 离线升级三步骤 |
| **特征项** | **15+** | **1 (hasFeature)** | Read/Write/Query/Release/Encrypt/Decrypt/Convert/Sign/Batch |
| 配置项(Data) | 5 | **0** | Set/Get/Remove/Enum |
| 借出/归还 | 9 | **0** | CheckOut/In, Borrow |
| 信息查询 | 5+ | 1 (getLicenseInfo) | SessionInfo, ServerInfo, FeatureInfo |
| 工具类 | 8+ | **0** | SetRootPath, SetProxy, SetAttr, CustomInfo |
---
## 2. 目标架构
### 2.1 接口分层(6 能力接口 + 1 入口)
```
CraftLicense (顶层入口)
- initialize(configJson) → LicenseSession
- getVersion() → String
- setRootPath(path) / setProxy(...) / setLocalServer(...)
LicenseSession (会话句柄,实现 5 个能力接口)
├─ LicenseLifecycle — 认证/激活/心跳/释放
├─ FeatureManagement — 特征项读写/加解密/占用释放
├─ DataItemStore — 配置项(Data Item)存储
├─ LicenseInfoQuery — 信息查询
├─ CheckoutManager — 浮动授权借出/归还
├─ LicenseUtility — 工具方法(SetAttr, CustomInfo, SessionState)
└─ close() / isClosed() / getNativeHandle()
```
### 2.2 能力接口详细定义
#### LicenseLifecycle
```java
public interface LicenseLifecycle {
LoginResult login(LoginRequest request);
LoginResult loginEx(LoginExRequest request);
LoginResult loginByToken(LoginByTokenRequest request);
LoginResult loginByPassword(LoginByPasswordRequest request);
ActivationResult activate(ActivationRequest request);
UpdateResult updateOnline(String url, String sn);
OfflineUpdateRequest getRequestInfo(String sn, BindingType type);
UpdateInfo getUpdateInfo(String url, String sn, String requestInfo);
ApplyResult applyUpdateInfo(String updateInfo);
HeartbeatResult heartbeat();
ReleaseResult release();
RevokeResult revoke(String sn);
void removeSn(String sn);
void sessionControl(String url, String sessionId, SessionCtlType type);
}
```
#### FeatureManagement
```java
public interface FeatureManagement {
int readFeature(int featureId);
void writeFeature(int featureId, int value);
int convertFeature(int featureId, int p1, int p2, int p3, int p4);
byte[] encryptFeature(int featureId, byte[] plainData);
byte[] decryptFeature(int featureId, byte[] cipherData);
int queryFeature(int featureId);
int queryFeatureEx(int featureId, QueryMode mode, int required, String scope);
Ticket queryFeatureEx2(String featureName, QueryMode mode, int required, String scope);
int releaseFeature(int featureId);
int releaseFeatureEx(int featureId, int consumed, String scope);
void releaseFeatureEx2(Ticket ticket, int consumed);
FeatureInfo getFeatureInfo(int featureId);
int getFeatureInfo2(String featureName, String scope);
FeatureInfoEx getFeatureInfoEx2(String featureName, String scope);
TicketInfo getTicketInfo(Ticket ticket, TicketInfoType type);
byte[] signFeature(int featureId, byte[] data);
FeatureInfo getFeatureInfoByIndex(int index);
// 批量操作
BatchResult batchBegin(BatchMode mode);
BatchResult batchEnd();
}
```
#### DataItemStore
```java
public interface DataItemStore {
void setDataItem(String name, byte[] value);
byte[] getDataItem(String name);
void removeDataItem(String name);
int getDataItemCount();
String getDataItemName(int index);
}
```
#### LicenseInfoQuery
```java
public interface LicenseInfoQuery {
LicenseInfo getLicenseInfo();
String getSessionInfo(SessionType type);
String getInfo(InfoType type);
String getServerInfo(String url, String sn, String scope, ServerInfoType type);
}
```
#### CheckoutManager
```java
public interface CheckoutManager {
void checkOut(String url, String scope, String featureList, int durationDays);
void checkOutSn(String url, int featureId, int durationDays);
void checkOutSnEx(String url, int featureId, String scope, int durationDays);
void checkOutFeatures(String url, int[] featureIds, int durationDays);
void checkIn(String url, int featureId);
void checkInEx(String url, int featureId, String scope);
String getBorrowRequest(String sn, int durationDays);
String getBorrowFeatureRequest(int durationDays, String scope);
void applyBorrowInfo(String borrowInfo);
}
```
#### LicenseUtility
```java
public interface LicenseUtility {
void setAttr(int type, byte[] value);
void setCustomInfo(int infoId, byte[] data);
void setSessionState(int state);
String getProductPath();
int getLastError();
String getErrorMessage();
void testBitService(String url, String sn, int featureId);
}
```
---
## 3. 原生 Rust 层重构
### 3.1 目录结构
```
native/craft-core/src/
├── lib.rs # C ABI 入口,craft_* 函数声明
├── ffi/
│ ├── mod.rs
│ ├── bitanswer.rs # BitAnswer C API 的 Rust extern 声明
│ └── bridge.rs # craft_* → Bit_* 的桥接实现
├── session.rs # 会话管理,BIT_HANDLE 映射
├── activate.rs # 对接 Bit_Login / Bit_UpdateOnline
├── license.rs # 对接 Bit_GetSessionInfo / Bit_GetInfo
├── feature.rs # 对接 Bit_ReadFeature / Bit_WriteFeature / Bit_QueryFeature 等
├── data_item.rs # 对接 Bit_SetDataItem / Bit_GetDataItem 等
├── checkout.rs # 对接 Bit_CheckOutSn / Bit_CheckIn 等
├── heartbeat.rs # 对接 Bit_Heartbeat
├── security/ # 安全模块(保持不变)
│ ├── mod.rs
│ ├── anti_debug.rs
│ ├── dynamic_api.rs
│ ├── integrity.rs
│ ├── obfuscation.rs
│ └── string_encrypt.rs
└── error.rs # BIT_ERROR_CODES → LicenseError 映射
```
### 3.2 JNI 映射表(NativeBridge 扩展)
| Java 方法 | Rust craft_* | BitAnswer C API |
|---|---|---|
| `nativeInitialize(String)` | `craft_initialize` | 内部引导 |
| `nativeLogin(long, String, int)` | `craft_login` | `Bit_Login` |
| `nativeLoginEx(long, String, int, String, int)` | `craft_login_ex` | `Bit_LoginEx` |
| `nativeLoginByToken(long, String, String)` | `craft_login_by_token` | `Bit_LoginByToken` |
| `nativeLoginByPassword(long, ...)` | `craft_login_by_password` | `Bit_LoginByPassword` |
| `nativeLogout(long)` | `craft_logout` | `Bit_Logout` |
| `nativeActivate(long, String)` | `craft_activate` | `Bit_UpdateOnline` |
| `nativeGetRequestInfo(long, String, int)` | `craft_get_request_info` | `Bit_GetRequestInfo` |
| `nativeGetUpdateInfo(long, String, String, String)` | `craft_get_update_info` | `Bit_GetUpdateInfo` |
| `nativeApplyUpdateInfo(long, String)` | `craft_apply_update_info` | `Bit_ApplyUpdateInfo` |
| `nativeReadFeature(long, int)` | `craft_read_feature` | `Bit_ReadFeature` |
| `nativeWriteFeature(long, int, int)` | `craft_write_feature` | `Bit_WriteFeature` |
| `nativeConvertFeature(long, int, int, int, int, int)` | `craft_convert_feature` | `Bit_ConvertFeature` |
| `nativeEncryptFeature(long, int, byte[], int)` | `craft_encrypt_feature` | `Bit_EncryptFeature` |
| `nativeDecryptFeature(long, int, byte[], int)` | `craft_decrypt_feature` | `Bit_DecryptFeature` |
| `nativeQueryFeature(long, int)` | `craft_query_feature` | `Bit_QueryFeature` |
| `nativeQueryFeatureEx(long, int, int, int, String)` | `craft_query_feature_ex` | `Bit_QueryFeatureEx` |
| `nativeReleaseFeature(long, int)` | `craft_release_feature` | `Bit_ReleaseFeature` |
| `nativeSignFeature(long, int, byte[], int)` | `craft_sign_feature` | `Bit_SignFeature` |
| `nativeSetDataItem(long, String, byte[], int)` | `craft_set_data_item` | `Bit_SetDataItem` |
| `nativeGetDataItem(long, String)` | `craft_get_data_item` | `Bit_GetDataItem` |
| `nativeRemoveDataItem(long, String)` | `craft_remove_data_item` | `Bit_RemoveDataItem` |
| `nativeGetDataItemNum(long)` | `craft_get_data_item_num` | `Bit_GetDataItemNum` |
| `nativeGetDataItemName(long, int)` | `craft_get_data_item_name` | `Bit_GetDataItemName` |
| `nativeCheckLicense(long)` | `craft_check_license` | `Bit_GetSessionInfo` |
| `nativeGetLicenseInfo(long)` | `craft_get_license_info` | `Bit_GetInfo` |
| `nativeGetSessionInfo(long, int)` | `craft_get_session_info` | `Bit_GetSessionInfo` |
| `nativeGetServerInfo(long, String, String, String, int)` | `craft_get_server_info` | `Bit_GetServerInfo` |
| `nativeGetFeatureInfo(long, int)` | `craft_get_feature_info` | `Bit_GetFeatureInfo` |
| `nativeCheckOutSn(long, String, int, int)` | `craft_check_out_sn` | `Bit_CheckOutSn` |
| `nativeCheckOutFeatures(long, String, int[], int, int)` | `craft_check_out_features` | `Bit_CheckOutFeatures` |
| `nativeCheckIn(long, String, int)` | `craft_check_in` | `Bit_CheckIn` |
| `nativeHeartbeat(long)` | `craft_heartbeat` | `Bit_Heartbeat` |
| `nativeRevoke(long, String)` | `craft_revoke` | `Bit_Revoke` |
| `nativeRemoveSn(long, String)` | `craft_remove_sn` | `Bit_RemoveSn` |
| `nativeSetAttr(long, int, byte[])` | `craft_set_attr` | `Bit_SetAttr` |
| `nativeSetCustomInfo(long, int, byte[])` | `craft_set_custom_info` | `Bit_SetCustomInfo` |
| `nativeSetRootPath(long, String)` | `craft_set_root_path` | `Bit_SetRootPath` |
| `nativeSetProxy(...)` | `craft_set_proxy` | `Bit_SetProxy` |
| `nativeSetLocalServer(...)` | `craft_set_local_server` | `Bit_SetLocalServer` |
| `nativeGetProductPath(long)` | `craft_get_product_path` | `Bit_GetProductPath` |
| `nativeGetVersion()` | `craft_get_version` | `Bit_GetVersion` |
| `nativeGetLastError(long)` | `craft_get_last_error` | `Bit_GetLastError` |
| `nativeDestroy(long)` | `craft_destroy` | 资源释放 |
### 3.3 句柄管理
```rust
// session.rs
struct SessionState {
bit_handle: BIT_HANDLE, // Bit_Login 返回的句柄
config: AuthConfig, // 解析后的配置
application_data: Vec<u8>, // 产品识别码(来自 AuthConfig
logged_in: bool,
}
static SESSIONS: Lazy<Mutex<HashMap<i64, SessionState>>> = ...;
```
---
## 4. 数据流
### 4.1 完整调用链(浮动作业激活)
```
Java: CraftLicense.initialize(configJson)
└─> Rust: craft_initialize(config_json)
├─ 解析 JSON → AuthConfig
├─ 安全加固检查(anti_debug, integrity
├─ 创建 SessionState,分配 session_id
└─ 返回 session_id (i64)
Java: session.activate(ActivationRequest { sn: "SN-XXXX" })
└─> Rust: craft_activate(session_id, sn)
├─ 从 AuthConfig 获取 bitanswer.url, loginMode
├─ 调用 Bit_UpdateOnline(url, sn, &app_data)
└─ 返回 ActivationResult
Java: session.login(LoginRequest { sn: "SN-XXXX", mode: AUTO })
└─> Rust: craft_login(session_id, sn, mode)
├─ 调用 Bit_Login(url, sn, &app_data, &bit_handle, BIT_MODE_AUTO)
├─ 存储 bit_handle → SessionState
└─ 返回 LoginResult { handle }
Java: session.readFeature(FACE_FEATURE_ID)
└─> Rust: craft_read_feature(session_id, feature_id)
├─ 获取 bit_handle
├─ 调用 Bit_ReadFeature(bit_handle, feature_id, &value)
└─ 返回 value (i32)
Java: session.checkOutSn(url, FEATURE_ZERO, 30)
└─> Rust: craft_check_out_sn(session_id, url, feature_id, duration)
├─ 调用 Bit_CheckOutSn(url, feature_id, &app_data, duration)
└─ 返回 CraftResult
Java: session.release()
└─> Rust: craft_release(session_id)
├─ 调用 Bit_Logout(bit_handle)
└─ 返回 CraftResult
Java: session.close()
└─> Rust: craft_destroy(session_id)
├─ 如果未 logout,调用 Bit_Logout
├─ 移除 SessionState
└─ 释放内存
```
### 4.2 错误码映射
Rust 侧将 200+ 个 `BIT_ERROR_CODES` 分组映射为 `LicenseError` 枚举:
```rust
pub enum LicenseError {
Success,
NetworkError,
WrongHandle,
InvalidParameter,
ApplicationDataError,
LicenseExpired,
LicenseNotFound,
LicenseDisabled,
FeatureNotFound(i32),
FeatureExpired(i32),
FeatureTypeNotMatch(i32),
SnInvalid,
SnNotFound,
SnDisabled,
SnRevoked,
SnExpired,
CapacityExhausted,
ServerBusy,
ServerDown,
Revoked,
Timeout,
TokenError,
BorrowError,
Unknown(i32), // 兜底
}
```
Java 侧使用 sealed interface 提供类型安全的结果:
```java
public sealed interface LicenseResult {
boolean isSuccess();
Optional<LicenseError> error();
String message();
}
```
---
## 5. 配置模型适配
`AuthConfig` 已有正确结构,重构后需将字段驱动到运行时:
| AuthConfig 字段 | 驱动行为 |
|---|---|
| `bitanswer.url` | `Bit_Login` / `Bit_UpdateOnline``szURL` |
| `bitanswer.loginMode` | `Bit_Login``mode` 参数 |
| `bitanswer.rootPath` | `Bit_SetRootPath` |
| `bitanswer.applicationData` | 替代硬编码的 `application_data[]`,使不同产品可携带不同识别码 |
| `features[].bitanswerFeatureId` | `readFeature(featureId)` / `queryFeature(featureId)` |
| `features[].bitanswerFeatureName` | `queryFeatureEx2(featureName, ...)` |
| `floating.projectId` | floating 场景校验(schema 已有) |
| `school.edgeDeviceId` | school 场景标识 |
---
## 6. 迁移路径
### Phase 1 — 基础设施(不破坏现有接口)
- Rust: `ffi/bitanswer.rs` FFI 声明 + `bridge.rs` 桥接实现
- Rust: 实现 `craft_activate`, `craft_check_license`, `craft_heartbeat` 的真实调用
- Java: `AuthProvider` 标记 `@Deprecated`,内部委托给 `CraftLicense`
- Java: 新增 `CraftLicense` + `LicenseSession` + 5 个能力接口(空实现)
- 测试: 现有测试保持通过
### Phase 2 — 核心 API 扩展
- Java: 实现 `LicenseLifecycle`login, loginEx, revoke, removeSn
- Java: 实现 `FeatureManagement`read, write, query, encrypt 等)
- Rust: 实现对应的 `craft_*` 函数
- 测试: 每个能力域独立集成测试
### Phase 3 — 高级功能
- Java: 实现 `DataItemStore`set/get/remove/enum
- Java: 实现 `CheckoutManager`checkOut/In 系列)
- Rust: 实现离线升级流程(GetRequestInfo → GetUpdateInfo → ApplyUpdateInfo
- 文档: 更新 `bitanswer-client-api-overview.md` 映射表
### Phase 4 — 清理
- 移除 `@Deprecated AuthProvider`
- 移除 `.deprecated-cmake/` 下的旧适配器代码
- 全量回归测试
---
## 7. 兼容性
- `schemas/craftlabs-auth-config.schema.json`**不变**
- 现有 `examples/config/*.json`**不变**
- `AuthConfig` / `AuthConfigs`**不变**
- `AuthProvider` — Phase 1-3 保持可用(`@Deprecated`),Phase 4 移除
- `NativeBridge` — 现有 9 个方法保留,新增 30+ 方法
- `craft-core` C ABI — 现有 9 个函数签名不变,新增 30+ 函数
---
## 8. 风险与缓解
| 风险 | 缓解 |
|------|------|
| Rust FFI 调用 BitAnswer .so/.dll 的链接问题 | Phase 1 先用 `libloading` 动态加载 BitAnswer 库,验证 ABI 兼容性 |
| 200+ 错误码映射不完整 | 只映射文档中明确列出的错误码,其余走 `Unknown(code)` |
| 多线程安全(BIT_HANDLE 是线程局部的) | `LicenseSession` 文档注明非线程安全,建议调用方池化或加锁 |
| native 库缺失时测试无法运行 | 单元测试 mock native 层,集成测试用 `@EnabledIfNativeLibraryPresent` |
---
## 附录 A:审计发现记录
审计过程中发现的具体代码问题:
1. **Rust `activate.rs:core_activate`** — 返回硬编码 `ok_result`,未调用任何 BitAnswer API
2. **Rust `license.rs:check_license`** — 返回硬编码 `ok_result`
3. **Rust `license.rs:get_license_info`** — 返回固定数据(`is_licensed=1`, `expiration_date="2099-12-31"`, `feature_count=0`
4. **Rust `license.rs:has_feature`** — 无条件返回 `true`
5. **Rust `heartbeat.rs:do_heartbeat`** — 返回硬编码 `ok_result`
6. **Java `BitAnswerProvider.initialize`** — 配置 JSON 未被传递给 native 层做运行时行为驱动
7. **`NativeBridge`** — 只有 9 个 JNI 方法,BitAnswer 有 50+ 函数
8. **`.deprecated-cmake/bitanswer_adapter.cpp`** — `bitanswer_adapter_register()` 是空函数
## 附录 BBitAnswer C API 完整清单
`examples/vcsample/bitanswer.h`1211 行),包含 50+ 个 `Bit_*` 函数声明和 200+ 个错误码枚举。