授權 SDK 規範
vv3.1
授權 SDK 規範(v3)
依據:
ps-help/v3/doc/售卖方式与授权购买链路_v3.md、幫助中心 LICENSE_API_DOC(v3)。 目標:Node / Python / Java 三語言 SDK 行爲一致(機器碼、簽名、接口、緩存、錯誤碼、購買頁跳轉)。
1. 機器碼算法(跨語言一致)
同一臺機器上三語言 SDK 必須生成相同的 machineCode。
指紋來源按優先級選取,取到有效值即停止:
fingerprint = 硬件序列号 → 系统机器 ID → hostname | os | arch(兜底)
優先級 1:硬件序列號(BIOS SN,重裝系統不變)
| 系統 | 來源 | 獲取方式 | 權限 |
|---|---|---|---|
| Windows | BIOS SerialNumber | wmic bios get serialnumber(降級 PowerShell Get-CimInstance Win32_BIOS) |
普通用戶 |
| macOS | 硬件序列號 | system_profiler SPHardwareDataType 提取 Serial Number |
普通用戶 |
| Linux | 產品序列號 | 讀 /sys/class/dmi/id/product_serial(降級 dmidecode -s system-serial-number) |
需 root |
優先級 2:系統機器 ID(安裝時生成,同機不變)
| 系統 | 來源 | 獲取方式 | 權限 |
|---|---|---|---|
| Windows | MachineGuid | 註冊表 HKLM\SOFTWARE\Microsoft\Cryptography |
普通用戶 |
| macOS | IOPlatformUUID | ioreg -d2 -c IOPlatformPlatformDevice |
普通用戶 |
| Linux | machine-id | 讀 /etc/machine-id(降級 /var/lib/dbus/machine-id) |
所有用戶 |
優先級 3:兜底(hostname | os | arch)
當硬件序列號和系統機器 ID 均獲取失敗時使用。
| 字段 | Node | Python | Java |
|---|---|---|---|
| hostname | os.hostname() |
socket.gethostname() |
InetAddress.getLocalHost().getHostName() |
| os | os.platform() |
sys.platform |
System.getProperty("os.name") |
| arch | os.arch() |
platform.machine() |
System.getProperty("os.arch") |
統一處理
- 所有字段去除首尾空白並轉小寫;
- 過濾廠商佔位值(
To be filled by O.E.M./None/0/Default/Not Available/Not Specified); - 拼接符統一爲
|,整體再toLowerCase()。
machineCode = 'M' + base64url( sha256( fingerprint ) ).slice(0, 32)
machineCode 至少 8 位,全平臺唯一,且 SDK 內部緩存(進程內)。
2. 簽名規則(software/generate、software/upgrade 必須)
簽名串按固定順序、換行分隔(缺省填空值:edition 空串、expiryDays 0、licenseCode 空串):
productUniqueCode \n machineCode \n edition \n expiryDays \n clientOrderId \n licenseCode \n timestamp
signature = base64url( HMAC-SHA256( licenseApiSecret, 签名串 ) );timestamp 爲毫秒,平臺校驗與服務器時間差 ≤ 5 分鐘(防重放)。
3. 接口清單
前綴:https://www.powersoftware.app/frontApi(可通過 baseUrl 覆蓋)。
| 接口 | 路徑 | 鑑權 | SDK 方法 |
|---|---|---|---|
| 激活 | POST /license/activate |
無 | activate(licenseCode, machineCode) |
| 校驗 | POST /license/verify |
無 | verify(licenseCode, machineCode, activationToken) |
| 解綁 | POST /license/deactivate |
登錄(瀏覽器場景) | deactivate(licenseCode, machineCode) |
| 軟件內發碼 | POST /license/software/generate |
HMAC 簽名 | generateForSoftware({...}) |
| 軟件內升級/續費 | POST /license/software/upgrade |
HMAC 簽名 | upgradeForSoftware({...}) |
| 領取試用 | POST /license/trial/claim |
無 | claimTrial(machineCode) |
generateForSoftware / upgradeForSoftware 自動補 timestamp + signature;claimTrial 需產品爲先用後付。
4. 本地憑證與校驗緩存
- 本地只存:
licenseCode、activationToken、最近一次 verify 結果({ valid, edition, expiryTime, trialExpiryTime }+ 時間戳)。 其中trialExpiryTime為試用到期時間快照(ISO8601,非試用轉購買為null),可用於高階功能寬限。 - 不存可解密的完整授權信息(防逆向無意義,只作緩存)。
- 校驗緩存 TTL 60s:點擊付費功能時先查緩存,未過期直接用;過期或失敗再調服務端
verify。 - 服務端吊銷/退款/升級會主動失效緩存(平臺側已實現),SDK 無需感知。
5. 付費功能攔截與購買頁跳轉
付費菜單按鈕點擊:
verifyCached(licenseCode, machineCode, activationToken)返回有效且未過期 → 放行;- 返回無效/過期/未激活 → 彈窗提示"需要購買激活授權";
- 生成
machineCode,跳轉購買頁(產品標識爲productUniqueCode,攜帶機器碼):
https://www.powersoftware.app/product/license/purchase?productUniqueCode={productUniqueCode}&machineCode={machineCode}
(多語言站點在路徑前加語言前綴,如 /en-US/product/license/purchase;productUniqueCode 由構造器傳入。)
5.1 購買站選擇:.app(國際站) vs .cn(國內站)
冪棧網有兩個站點,SDK 的 purchaseUrl() 通過 base 參數切換:
powersoftware.app(國際站) |
powersoftware.cn(國內站) |
|
|---|---|---|
| 支付方式 | 支付寶 + PayPal | 僅支付寶 |
| 國家/幣種 | Cloudflare 按 IP 自動識別(CN→CNY,其餘→USD) | 固定 country=CN,人民幣 |
| 語言 | 按 URL 前綴 / Accept-Language 自動檢測 |
固定 zh-CN |
| 適用用戶 | 國際用戶 / 海外 | 中國大陸用戶 |
SDK 默認 .app,不做自動判斷。 客戶端軟件需自行決定傳哪個 base。
判斷方式
方式一:按系統語言(推薦)
import locale
def get_purchase_base():
sys_lang = locale.getdefaultlocale()[0] or ""
if sys_lang.startswith("zh"):
return "https://www.powersoftware.cn"
return "https://www.powersoftware.app"
function getPurchaseBase() {
const lang = process.env.LANG || "";
return lang.toLowerCase().startsWith("zh")
? "https://www.powersoftware.cn"
: "https://www.powersoftware.app";
}
String getPurchaseBase() {
return "zh".equals(Locale.getDefault().getLanguage())
? "https://www.powersoftware.cn"
: "https://www.powersoftware.app";
}
方式二:用戶設置項 — 設置界面提供“地區”選項,用戶自行選擇。
方式三:硬編碼 — 僅面向國內用戶的軟件直接寫死 base="https://www.powersoftware.cn"。
詳見 语言与国家逻辑 第 2.4 節。
6. 錯誤碼(SDK 拋錯統一攜帶 errorCode)
codeNotFound、revoked、expired、machineLimit、tooManyAttempts、signatureInvalid、apiSecretMissing、productNotEnabled、trialNotEnabled、trialAlreadyPurchased、trialAlreadyPurchased、machineCodeInvalid、orderAlreadyUsed、editionRequired、productNotFound、trialFirstRequired、alreadyOwned 等;網絡/超時錯誤統一爲 NETWORK_ERROR。
7. 包結構
ps-sdk/
node/ @mizhanchengxi/ps-license-sdk(ESM,零依赖)
python/ ps-license-sdk(py3,零依赖)
java/ com.powersoftware:sdk(Java 8+,JDK 自带 HTTP/加密)
三個包均提供:machineCode()、sign()、LicenseClient(上述 6 方法 + verifyCached + purchaseUrl)。