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

17 KiB
Raw Permalink Blame History

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

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

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

public interface DataItemStore {
    void setDataItem(String name, byte[] value);
    byte[] getDataItem(String name);
    void removeDataItem(String name);
    int getDataItemCount();
    String getDataItemName(int index);
}

LicenseInfoQuery

public interface LicenseInfoQuery {
    LicenseInfo getLicenseInfo();
    String getSessionInfo(SessionType type);
    String getInfo(InfoType type);
    String getServerInfo(String url, String sn, String scope, ServerInfoType type);
}

CheckoutManager

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

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 句柄管理

// 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 枚举:

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 提供类型安全的结果:

public sealed interface LicenseResult {
    boolean isSuccess();
    Optional<LicenseError> error();
    String message();
}

5. 配置模型适配

AuthConfig 已有正确结构,重构后需将字段驱动到运行时:

AuthConfig 字段 驱动行为
bitanswer.url Bit_Login / Bit_UpdateOnlineszURL
bitanswer.loginMode Bit_Loginmode 参数
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: 实现 LicenseLifecyclelogin, loginEx, revoke, removeSn
  • Java: 实现 FeatureManagementread, write, query, encrypt 等)
  • Rust: 实现对应的 craft_* 函数
  • 测试: 每个能力域独立集成测试

Phase 3 — 高级功能

  • Java: 实现 DataItemStoreset/get/remove/enum
  • Java: 实现 CheckoutManagercheckOut/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.cppbitanswer_adapter_register() 是空函数

附录 BBitAnswer C API 完整清单

examples/vcsample/bitanswer.h1211 行),包含 50+ 个 Bit_* 函数声明和 200+ 个错误码枚举。