授權 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 + signatureclaimTrial 需產品爲先用後付。

4. 本地憑證與校驗緩存

  • 本地只存licenseCodeactivationToken、最近一次 verify 結果({ valid, edition, expiryTime, trialExpiryTime } + 時間戳)。 其中 trialExpiryTime 為試用到期時間快照(ISO8601,非試用轉購買為 null),可用於高階功能寬限。
  • 不存可解密的完整授權信息(防逆向無意義,只作緩存)。
  • 校驗緩存 TTL 60s:點擊付費功能時先查緩存,未過期直接用;過期或失敗再調服務端 verify
  • 服務端吊銷/退款/升級會主動失效緩存(平臺側已實現),SDK 無需感知。

5. 付費功能攔截與購買頁跳轉

付費菜單按鈕點擊:

  1. verifyCached(licenseCode, machineCode, activationToken) 返回有效且未過期 → 放行;
  2. 返回無效/過期/未激活 → 彈窗提示"需要購買激活授權";
  3. 生成 machineCode,跳轉購買頁(產品標識爲 productUniqueCode,攜帶機器碼):
https://www.powersoftware.app/product/license/purchase?productUniqueCode={productUniqueCode}&machineCode={machineCode}

(多語言站點在路徑前加語言前綴,如 /en-US/product/license/purchaseproductUniqueCode 由構造器傳入。)

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)

codeNotFoundrevokedexpiredmachineLimittooManyAttemptssignatureInvalidapiSecretMissingproductNotEnabledtrialNotEnabledtrialAlreadyPurchasedtrialAlreadyPurchasedmachineCodeInvalidorderAlreadyUsededitionRequiredproductNotFoundtrialFirstRequiredalreadyOwned 等;網絡/超時錯誤統一爲 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)。