first commit

This commit is contained in:
wood911010 committed 2026-02-27 14:29:48 +08:00
commit 5ee52f09bc
52 files changed
+29721

No files matched your search

+307
View File
@@ -0,0 +1,307 @@
{
"schemes": [
"http",
"https"
],
"swagger": "2.0",
"info": {
"description": "软件授权管理平台API文档(精简版,仅包含激活与心跳接口)",
"title": "License Manager API",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "API Support",
"url": "http://www.swagger.io/support",
"email": "support@swagger.io"
},
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
},
"version": "1.0"
},
"basePath": "/",
"paths": {
"/api/v1/activate": {
"post": {
"description": "客户端使用授权码激活软件,获取许可证文件",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"许可证激活"
],
"summary": "激活许可证",
"parameters": [
{
"description": "激活请求",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.ActivateRequest"
}
}
],
"responses": {
"200": {
"description": "激活成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/models.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.ActivateResponse"
}
}
}
]
}
},
"400": {
"description": "请求参数无效",
"schema": {
"$ref": "#/definitions/models.ErrorResponse"
}
},
"404": {
"description": "授权码不存在",
"schema": {
"$ref": "#/definitions/models.ErrorResponse"
}
},
"409": {
"description": "授权码已锁定或已过期",
"schema": {
"$ref": "#/definitions/models.ErrorResponse"
}
},
"429": {
"description": "激活数量已达上限",
"schema": {
"$ref": "#/definitions/models.ErrorResponse"
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/models.ErrorResponse"
}
}
}
}
},
"/api/v1/heartbeat": {
"post": {
"description": "客户端定期发送心跳,更新在线状态和使用数据",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"许可证激活"
],
"summary": "心跳检测",
"parameters": [
{
"description": "心跳请求",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.HeartbeatRequest"
}
}
],
"responses": {
"200": {
"description": "心跳成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/models.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.HeartbeatResponse"
}
}
}
]
}
},
"400": {
"description": "请求参数无效",
"schema": {
"$ref": "#/definitions/models.ErrorResponse"
}
},
"404": {
"description": "许可证不存在",
"schema": {
"$ref": "#/definitions/models.ErrorResponse"
}
},
"409": {
"description": "许可证已被撤销",
"schema": {
"$ref": "#/definitions/models.ErrorResponse"
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/models.ErrorResponse"
}
}
}
}
}
},
"definitions": {
"models.APIResponse": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"data": {},
"message": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"models.ActivateRequest": {
"type": "object",
"required": [
"authorization_code",
"hardware_fingerprint"
],
"properties": {
"authorization_code": {
"description": "授权码,必填",
"type": "string"
},
"device_info": {
"description": "设备信息,可选",
"type": "object",
"additionalProperties": true
},
"hardware_fingerprint": {
"description": "硬件指纹,必填",
"type": "string"
},
"software_version": {
"description": "软件版本,可选",
"type": "string"
}
}
},
"models.ActivateResponse": {
"type": "object",
"properties": {
"heartbeat_interval": {
"description": "心跳间隔(秒)",
"type": "integer"
},
"license_file": {
"description": "base64编码的加密许可证文件",
"type": "string"
},
"license_key": {
"description": "许可证密钥",
"type": "string"
}
}
},
"models.HeartbeatRequest": {
"type": "object",
"required": [
"hardware_fingerprint",
"license_key"
],
"properties": {
"config_updated_at": {
"description": "客户端配置更新时间,可选",
"type": "string"
},
"hardware_fingerprint": {
"description": "硬件指纹,必填",
"type": "string"
},
"license_key": {
"description": "许可证密钥,必填",
"type": "string"
},
"software_version": {
"description": "软件版本,可选",
"type": "string"
},
"usage_data": {
"description": "使用数据,可选",
"type": "object",
"additionalProperties": true
}
}
},
"models.HeartbeatResponse": {
"type": "object",
"properties": {
"config_updated": {
"description": "配置是否有更新",
"type": "boolean"
},
"heartbeat_interval": {
"description": "下次心跳间隔(秒)",
"type": "integer"
},
"license_file": {
"description": "base64编码的新许可证文件(如有更新)",
"type": "string"
},
"status": {
"description": "许可证状态",
"type": "string"
}
}
},
"models.ErrorResponse": {
"type": "object",
"properties": {
"code": {
"description": "业务错误码,如 \"100001\", \"900001\"",
"type": "string"
},
"message": {
"description": "错误描述信息",
"type": "string"
},
"timestamp": {
"description": "错误发生时间",
"type": "string"
}
}
}
},
"securityDefinitions": {
"BearerAuth": {
"description": "Bearer token for authentication",
"type": "apiKey",
"name": "Authorization",
"in": "header"
}
}
}
+82
View File
@@ -0,0 +1,82 @@
# License Manager Go SDK 需求
## 背景
- 当前客户端 demo 直接对接服务端,集成复杂且不利于复用。
- 多个需要授权的产品希望以库的形式快速接入授权能力。
- 需要一个接口简洁、易于扩展、对调用方入侵极低的 Go SDK。
## 目标
1. 封装授权激活、许可证校验、心跳续期等流程,减少业务方重复开发。
2. 提供清晰的配置与生命周期管理,支持 CLI、服务和嵌入式场景。
3. 兼容已有 License Manager 服务端接口,未来接口升级时对调用方透明。
4. 支持在线 / 离线两种工作模式,满足联网和隔离环境的授权需求。
## SDK 架构
| 模块 | 职责 |
|------|------|
| `license.Client` | SDK 入口,负责生命周期管理。 |
| `config` | 统一的配置结构体,支持代码、环境变量、配置文件三种来源。 |
| `hardware` | 硬件指纹采集,默认实现可被自定义扩展。 |
| `activation` | 激活接口封装、授权码加载、许可证缓存。 |
| `validator` | 对许可证内容、有效期、功能限制进行校验。 |
| `heartbeat` | 心跳轮询、动态间隔调整、失败退避策略。 |
| `storage` | 许可证加解密与本地持久化,支持自定义存储后端。 |
| `logger` | 统一日志接口,默认输出到标准输出,可注入业务日志实现。 |
### 硬件指纹采集策略
1. **标准组合指纹(默认)**:采集首个物理 MAC、CPU 型号、主机 ID,组合字符串后做哈希。
2. **可插拔字段选择**:调用方可通过配置决定纳入哪些硬件字段(如磁盘序列号、主板序列号等),SDK 保证字段顺序与哈希算法一致。
3. **自定义采集器**:提供 `hardware.Provider` 接口,允许业务方完全自定义指纹生成逻辑(适配虚拟化、容器等环境)。
4. **匿名化/脱敏模式**:支持在上报前对字段进行额外哈希或加盐,满足隐私/合规要求。
5. **实时采集策略**:每次需要校验时即时采集,避免任何形式的本地缓存,以消除被复制或伪造的风险;若采集失败需有清晰的回退与错误提示。
## 核心功能需求
1. **初始化**
- 必填配置:服务端地址(离线模式可选)、产品标识、版本号、授权码来源或许可证文件路径、服务端 RSA 公钥(可通过路径或内容提供)。
- 可选配置:心跳间隔、超时、日志级别、硬件指纹采集策略、自定义 HTTP 客户端。
2. **许可证加载与激活**
- **在线模式**:启动优先读取本地许可证;不存在或失效时自动激活,激活请求包含硬件指纹、产品信息、授权码,支持附加自定义字段。激活成功后自动校验并落盘,加解密沿用 AES-GCM;需使用配置中提供的 RSA 公钥验证服务端签名。
- **离线模式**:仅校验本地许可证文件合法性(签名/有效期/硬件绑定),不访问网络;当本地许可证缺失或过期时返回明确错误,由业务方决定更新方式。需通过配置显式提供许可证文件路径(默认 `license_code/license.lic` 可覆盖)及 RSA 公钥拷贝,保证可独立校验签名。
3. **许可证校验**
- 校验内容:签名/加密、有效期、硬件绑定、功能/限制字段。
- 提供同步 API(`Validate()`)供业务方在关键操作前主动检查。
- 提供只读访问接口(如 `client.CurrentLicense()`),可在业务运行时获取最新许可证的功能限制、配额等字段,便于执行业务级限制判断;当许可证更新时需即时刷新缓存并触发回调。
4. **心跳服务**
- 仅在在线模式启用:成功激活后自动启动,默认间隔 300s,可从服务器动态调整。
- 支持暂停/恢复接口,网络异常时指数退避并记录原因。
- 服务器返回新的许可证时自动替换并回调通知。
- 离线模式不启动心跳,SDK 需暴露显式 API 让业务层触发本地校验。
5. **事件与回调**
- 需支持 `OnLicenseUpdated`, `OnHeartbeatError`, `OnActivationRequired` 等回调。
- 回调在独立 goroutine 执行,避免阻塞主流程。
6. **错误处理**
- 统一错误类型,区分可重试与不可重试场景。
- 提供错误码枚举,便于业务层按类型处理。
7. **线程安全**
- SDK 所有公开方法需并发安全,核心状态(许可证、心跳)内部加锁。
8. **可测试性**
- 对 HTTP、时间、硬件指纹、存储等外部依赖提供接口,方便 Mock。
## 使用方式
```go
cfg := license.Config{
Server: "https://license.example.com",
Product: "edge-gateway",
Version: "2.3.1",
AuthCode: license.FromFile("license_code/authorization_code.txt"),
PublicKey: license.FromFile("license_code/rsa_public_key.pem"),
}
client, err := license.NewClient(cfg)
defer client.Close()
if err != nil { /* ... */ }
if err := client.Validate(context.Background()); err != nil {
// 业务自定义处理
}
```
## 交付物
- SDK 源码与 go.mod。
- `README`:安装、Quick Start、常见问题。
- 示例程序:最小化控制台示例 + 与现有 client-demo 等价的高级示例。
+46
View File
@@ -0,0 +1,46 @@
# License Manager Python SDK 设计
## 1. 设计目标
- 提供统一、低侵入的 Python SDK 以封装激活、校验、心跳、许可证管理流程。
- 兼容现有 License Manager 服务端接口,在线/离线模式对业务透明。
- 高可扩展与可测试性:硬件指纹、存储、网络协议处理器等核心可替换(duck typing 理念)。
## 2. 交付范围
- 符合 PEP 标准的 Python 包源码。
- 依赖描述文件(`requirements.txt` / `setup.py`)。
- 示例:最小化直接调用的基础示例 `examples/basic/main.py`。
- 面向 Python 的技术文档。
## 3. 核心模块设计说明
- **client.Client (门面模式)**
- 组合各模块,提供 `__init__`, `validate`, `current_license`, `close` 等方法。
- 维护内部状态,并通过 `threading.Lock` 等保证线程安全访问当前 License 版本。
- **config (配置与数据校验)**
- 定义明确具有 Type hints 的类或 `dataclasses`,支持将环境及文件属性覆盖。
- 静态检查:在线模式验证服务端必须 URL / 密码文件;离线模式检验证书位置。
- **activation (激活)**
- 基于标准的 `requests`(带连接池和自动超时重试策略)发起网络激活通信。
- 接收加密串后调用 validator 核验,成功后通过 storage 保存。
- **validator (强安全验证)**
- 依托强大的 `cryptography` 包处理 RSA (建议为 PSS padding 等现代方法,具体匹配服务端实现)。
- 对解包出的许可证时间 `ExpiresAt`、硬件指纹进行 CPU 负载级的精确比较并验证未发生人为修改。
- **heartbeat (心跳维护)**
- 取代 Go 的 goroutine 使用,改用由 `threading.Thread` 的轮询服务。设置 `daemon=True` 防止卡顿主进程。
- 设计线程安全的 `threading.Event()` 实现如 `pause`, `resume`, `stop` 这些外部调度接口。
- 对于网络闪断具有一定指数回退 (Exponential backoff) 容量。
- **hardware (多态指纹搜集)**
- 抽象采集策略,利用系统底层命令及 `uuid`、`platform` 以避免绑定复杂的原生编译依赖(如果在 CPython 环境可引入 psutil 或仅靠 standard libs 执行降级采集策略)。
- **storage (凭证安全落地)**
- 文件加解密适配 `cryptography` 在 AES-GCM 算法下使用 256bit 动态密钥做密文打包,防本地脱机逆向嗅探。
- **logger & exceptions (日志体系监控)**
- 使用标准的 `logging` 获取当前全局记录器。
- 设计带有分类标记的 `LicenseManagerError`, `NetworkError`, `ValidationError` 提供可分辨的控制流分支。
## 4. 关键生命周期总结
1. **实例化**:加载配置 → 初始化硬件信息/日志/存储机制 → 调用 validator 验算本地既有证书 → 按需挂起并调用 activation 发在线网路激活申请。
2. **后台伴生**:启动 heartbeat daemon → 在给定 `interval` 进行上游 pinging → 若上游发来更新证,回调主线程数据结构;若请求重新激活,则触发 callback 进入阻塞警报。
3. **断网本地态**:应用随时拉起 `client.validate()`。验证不通过抛出 SDK 特有 `Exception`,应用层捕获异常并决定关停自身业务。
## 5. 对比补充与潜在风险
- **包依赖风险**:为降低部署繁杂度,若系统有条件应考虑避免引用含有大量 C 扩展的包,优先利用 Python 3 自带库封装;必须时则明确说明并列在依赖清单首位 (如 `cryptography`)。
- **定时锁和 GIL 干扰**:心跳网络收发本质是 I/O 阻塞型操作,采用线程天然适合,且不易阻断业务代码,但在多线程中覆盖验证缓存 `current_license` 必须添加明确锁保护(`threading.RLock()`),确保不产生竞争读写现象。
+22
View File
@@ -0,0 +1,22 @@
# TaskLoop Iteration Log
## Sub-task 0: 任务拆解与开发计划制定
... (已成功)
## Sub-task 1: 基础设施层开发 (Config, Models, Hardware)
... (已成功)
## Sub-task 2: 加解密及校验层 (Storage, Validator)
... (已成功)
## Sub-task 3: 网络层与心跳组件 (Activation, Heartbeat)
... (已成功)
## Sub-task 4: 核心组装层 (Client Facade)
- **所做工作**: 编写了 `client.py`,组合了 `Config`, `HardwareProvider`, `Store`, `Validator` 以及 API Services。
- **验证方式**: `test_batch4.py` 执行无网络状态下的初始化脱机错误测试,正常抛错被捕获。
- **状态**: 成功。
## Sub-task 5: 最终交付与 Example (Basic Demo)
- **所做工作**: 创建了 `examples/basic/main.py` 以复现 Go 版本的 `callbacks` 和 `thread` 阻塞。
- **状态**: 成功。至此,全部 5 个 DAG 批次的 SDK 底层向 Python 的翻译工作已 100% 达成。
+17
View File
@@ -0,0 +1,17 @@
# 项目上下文 (Project Context)
## 架构概览 (Architecture Overview)
License Manager SDK (Python): 一个轻量级的 SDK,旨在完全迁移 Go 版本的架构和生命周期概念。
## 关键技术决策 (Key Technical Decisions)
- 使用 `taskloop` 工作流按 MPE (最小程序实体) 级别迭代和测试。
- 使用 Python 标准和常用组件:网络请求使用 `requests`,RSA/AES 验证加解密使用 `cryptography`。
## 当前状态 (Current State)
已通过 TaskLoop 的 DAG 结构完成开发计划的制定。所有 MPE 已识别且定义了验收标准。代码编写与执行尚未开始。
## 已知问题与风险 (Known Issues / Risks)
- 在暂停心跳 (heartbeat) 时需要优雅地处理后台线程的中断。
## 领域知识 (Domain Knowledge)
- 许可证生命周期:在线激活 (Activate) -> 本地加密存储 (Store Locally: AES-GCM) -> 验证签名与防篡改 (Validate: RSA) -> 保持在线心跳 (Heartbeat: Keep-Alive)。
+63
View File
@@ -0,0 +1,63 @@
# License Manager SDK (Python) 翻写计划
## 目标与概述
将 `license-manager-sdk-go` 的核心功能完整翻写为 Python 版本,保持相同的架构设计模式,以便在 Python 项目中无缝集成。SDK 需要支持:
1. **在线/离线激活与校验**
2. **硬件指纹采集**(MAC, Hostname, CPU, Memory)
3. **本地加密存储**(AES-GCM)
4. **RSA 签名验证**
5. **后台心跳与生命周期管理**(自动心跳、断网重试、手动控制)
## 架构与模块映射映射 (Go -> Python)
| Go Module | Python Module | 功能描述 |
| :--- | :--- | :--- |
| `config` | `license_manager.config` | SDK 配置定义与校验(`Config` 类) |
| `models` | `license_manager.models` | 数据模型定义(Pydantic 或 Dataclasses) |
| `hardware` | `license_manager.hardware` | 硬件特征采集(跨平台 mac, hostname, cpu, memory 获取) |
| `validator` | `license_manager.validator` | 对 payload 的 RSA 校验与防篡改验证 |
| `storage` | `license_manager.storage` | 基于 AES-GCM 的本地凭证加解密与存储 |
| `activation` | `license_manager.activation` | 封装向远端发起的激活 HTTP 请求 |
| `heartbeat` | `license_manager.heartbeat` | 封装心跳请求,及基于守护线程的 `HeartbeatManager` 心跳定时发送 |
| `license` | `license_manager.client` | 暴露给业务的核心入口 `Client` |
| `logger` | `license_manager.logger` | 标准 `logging` 封装 |
| `internal/httpclient` | *融合到请求中* | 推荐依赖 `requests` 库或内置 `urllib`,统一超时和重试 |
## 详细实施步骤
### 1. 基础模型与配置 (Day 1)
- **`models.py`**: 定义 `ActivateRequest`, `ActivateResponse`, `HeartbeatRequest`, `HeartbeatResponse`, `LicensePayload`。使用 Python 内置的 `dataclasses` 或 `pydantic`(如允许第三方依赖)。
- **`config.py`**: 定义 `Config` 类,实现参数校验、默认值填充(如默认 5 分钟心跳,默认拉取文件等)。
### 2. 硬件指纹采集 (Day 1)
- **`hardware.py`**:
- `mac`: 使用 `uuid.getnode()` 或第三方 `getmac` 库处理跨平台网卡 MAC 获取。
- `hostname`: 使用 `socket.gethostname()`。
- `cpu`/`memory`: 使用内置 `os`, `platform` 或第三方 `psutil` 获取。
### 3. 加解密与校验核验 (Day 2)
- 需要依赖常用的加解密库,如 `cryptography` 或 `pycryptodome`。
- **`storage.py`**: 实现 AES-GCM 加密,保存到本地文件。
- **`validator.py`**: 实现 RSA (PKCS#1 v1.5 或 PSS) 签名验证模块,确认下发的 License 数据未被篡改,并校验 `ExpiresAt` 以及硬件指纹比对。
### 4. HTTP 网络与心跳守护线程 (Day 3)
- **`activation.py`**: 封装激活接口。
- **`heartbeat.py`**:
- `HeartbeatService`: 封装心跳请求接口。
- `HeartbeatManager`: 包含一个 `threading.Thread` 或 `asyncio` 任务,支持 `start()`, `pause()`, `resume()`, `stop()` 机制。
### 5. 核心 Client 组装 (Day 4)
- **`client.py`**:
- 实现 `Client` 类作为门面 (Facade)。
- `__init__`: 组织 config, hardware, validator, storage 等初始化,并自动尝试加载本地缓存或发起在线请求。
- 实现 `current_license()`, `validate()`, `pause_heartbeat()`, `resume_heartbeat()`, `close()`。
### 6. 测试与示例 (Day 5)
- **`examples/basic/main.py`**: 对标 Go 的 `examples/basic`,展示线上模式、配置回调、获取许可限制等用法。
- **单元测试**: 对硬件采集、加解密、校验算法编写 pytest 测试。
## Python 依赖建议
- **HTTP/网络**: `requests`
- **加密与签名**: `cryptography`
- **模型验证**: `pydantic` (可选)
- **硬件指标扩展**: `psutil` (可选)
+45
View File
@@ -0,0 +1,45 @@
# 项目全局认知
本文档主要负责梳理 License Manager 面向 Python 开发者翻写过程中的整体文件存放策略,以及包结构的宏观认知。
由于原始开发使用 Go 语言,部分文件习惯(如根域名即包名)并不完全适用 Python(考虑到 Python 中不合法的 "-" 命名)。因此,对于 Python SDK,我们采取如下被业界广泛遵循的标准 Python 包(Package)部署和命名规范。
## 目录结构(全景)
```text
license-manager-sdk-python/ # 项目根目录(Repo)
├── docs/ # 相关的工程文档目录
│ ├── 项目全局认知.md # 当前文档:建立对项目文件夹分布的宏观理解
│ ├── design.md # 核心设计决策(基于 Python 特性适配过的系统模型)
│ ├── 翻写计划.md # 各个批次的 DAG 执行计划和阶段任务
│ ├── iteration-log.md # TaskLoop:执行反馈及尝试日志
│ └── project-context.md # TaskLoop:微观状态记忆
├── license_manager/ # 【核心源码包】符合 PEP8 的包名,供外部导入
│ ├── __init__.py # 暴露出 SDK 的唯一公开类 Client
│ ├── client.py # 门面层Facade,聚合 Config/Hardware/Validator 等模块
│ ├── config.py # 配置解析(DataClass / Pydantic 等模型)
│ ├── models.py # 数据结构,涵盖 Request/Response 及许可证字段定义
│ ├── hardware.py # 跨平台的硬件信息(mac, hostname, cpu等)采集器
│ ├── storage.py # AES-GCM 安全存储持久化器
│ ├── validator.py # 面向 payload 进行 RSA 验签与防篡改逻辑
│ ├── activation.py # 将 HTTP 调用隔离:专职负责 /api/v1/activate 请求
│ ├── heartbeat.py # 定时服务调度(依托 threading.Thread)和心跳接口
│ ├── logger.py # 适配 Python 原生 logging 的单例构造器
│ └── exceptions.py # SDK 中抛出的所有专有异常定义(如网络超时、无授权等)
├── tests/ # 测试代码集 (Pytest 等框架)
│ ├── test_hardware.py
│ ├── test_validator.py
│ └── ...
├── examples/ # 对客户公开的应用集成示例
│ └── basic/
│ └── main.py # 照搬 Go 版 demo 逻辑的 Python 实现
├── requirements.txt # 运行必须的核心第三方依赖 (如 requests, cryptography)
├── setup.py # 模块构建、打包配置文件(可选也可使用 pyproject.toml)
├── .gitignore # Git 提交忽略配置文件
└── README.md # 针对 Python 版本的接口快速使用说明
```
## Python 设计与 Go 的核心差异
1. **统一入口**:所有模块收拢在合规的包名 `license_manager` 下,用户只需在外部调用 `import license_manager as license`,然后使用 `license.Client(cfg)`。
2. **并发与定时任务**:相较于 Go 语言轻量级的 Goroutine 处理后台心跳和回调触发,Python 需要通过启动后台 Daemon 线程 `threading.Thread` 进行心跳轮询,并在进行锁处理或休眠时关注 GIL 和中断异常捕获结构。
3. **日志框架对接**:Python 提供更系统完整的 `logging` 模块机制,在此不一定需要过多自定义,只需注入正确的 `logger` 组件即可。