From 30a2efce3f26b161b3bdb3610600a4e9052b50f7 Mon Sep 17 00:00:00 2001 From: dekun Date: Fri, 17 Jul 2026 17:46:15 +0800 Subject: [PATCH] feat: license page uses per-customer client token wording. Align redeem/validate UX with per-code tokens from the auth server. Co-authored-by: Cursor --- docs/license.md | 24 ++++++++++++------------ lib/license/license_lib.py | 10 +++++----- lib/license/templates/license.html | 8 ++++---- license.env.example | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/license.md b/docs/license.md index 003f241..fc77b84 100644 --- a/docs/license.md +++ b/docs/license.md @@ -7,8 +7,8 @@ 1. 部署并启动本系统(三所或中控任一页面)。 2. 浏览器打开 **`/license`**(未授权时会自动跳转)。 3. 复制页面上的 **设备 ID**。 -4. 联系微信 **dekun03** 购买(备注设备 ID),按约定支付 **USDT** 后获得 **CLIENT_API_KEY** 与激活码。 -5. 在 `/license` 填写 **CLIENT_API_KEY** 与激活码并兑换(密钥会写入本地 `data/license_state.json`,下次可留空)。 +4. 联系微信 **dekun03** 购买(备注设备 ID),按约定支付 **USDT** 后获得 **激活码 + 客户密钥**(每张码一把密钥)。 +5. 在 `/license` 填写 **客户密钥** 与激活码并兑换(密钥写入本地 `data/license_state.json`;续费一般可留空)。 ## 定价(整机授权) @@ -18,19 +18,21 @@ | 部署费 | 一次性代部署/装机(自装是否收取以约定为准) | **100 USDT** | - 仅售年卡,无月卡/季卡。 -- 续费:年卡 **1000 USDT**(一般不再收部署费)。 -- 换机:旧设备立即失效,需换机码(向卖家申请)。 +- 续费:年卡 **1000 USDT**(一般不再收部署费);续费码沿用原客户密钥。 +- 换机:旧设备立即失效,需换机码(向卖家申请);密钥不变。 - USDT 收款地址由卖家提供(链与地址以当时通知为准)。 -## CLIENT_API_KEY(推荐) +## 客户密钥(Client Token) -卖家在授权站后台 **系统设置** 可查看/复制 `CLIENT_API_KEY`,发给用户后填入软件 `/license` 页即可,**不必再手改 `license.env`**。 +卖家在授权站后台 **新激活码** Tab 可复制「激活码 + 客户密钥」。 +每张新购码绑定独立密钥;兑换后归该订阅长期使用。 +**不要**再使用后台「系统设置」里的全局 `CLIENT_API_KEY` 发给新用户(那仅兼容旧数据)。 -优先级:环境变量 `LICENSE_CLIENT_KEY` > 授权页保存的本地密钥。 +本地优先级:环境变量 `LICENSE_CLIENT_KEY` > 授权页保存的密钥。 ## 环境变量(可选) -在**仓库根目录**创建 **`license.env`**(勿提交 Git),可预先写好密钥: +在**仓库根目录**创建 **`license.env`**(勿提交 Git): ```bash cd /opt/crypto_monitor_user # 或你的安装目录 @@ -39,16 +41,14 @@ cp license.env.example license.env ```env LICENSE_API_URL=https://sq.bz121.com -# 可选:与授权站 CLIENT_API_KEY 相同;也可只在 /license 页填写 +# 可选:也可只在 /license 页填写卖家发的客户密钥 # LICENSE_CLIENT_KEY= -# 可选:断网宽限小时数(默认 72) # LICENSE_OFFLINE_GRACE_HOURS=72 -# 本地调试可临时关闭门禁(生产勿开) # LICENSE_DISABLED=false ``` 改完环境变量后**重启** Flask / 中控进程。也可在各实例 `.env` 里写同样的 `LICENSE_*`(不要留空键)。 -许可状态保存在仓库根目录 **`data/license_state.json`**(三所 + 中控共用,含本地保存的 `client_api_key`)。 +许可状态保存在仓库根目录 **`data/license_state.json`**(三所 + 中控共用,含本地保存的客户密钥)。 系统约每 **3 天** 向授权站校验一次;明确过期或换机后旧设备将无法使用。 diff --git a/lib/license/license_lib.py b/lib/license/license_lib.py index 2f8ea3a..c0794ef 100644 --- a/lib/license/license_lib.py +++ b/lib/license/license_lib.py @@ -72,16 +72,16 @@ def client_key() -> str: def set_client_api_key(key: str) -> dict[str, Any]: - """保存用户在授权页填写的 CLIENT_API_KEY(写入 license_state.json)。""" + """保存用户在授权页填写的客户密钥 / client token(写入 license_state.json)。""" key = (key or "").strip() if len(key) < 8: - return {"ok": False, "message": "CLIENT_API_KEY 太短"} + return {"ok": False, "message": "客户密钥太短"} with _lock: st = _read_state() st["client_api_key"] = key _write_state(st) os.environ["LICENSE_CLIENT_KEY"] = key - return {"ok": True, "message": "CLIENT_API_KEY 已保存"} + return {"ok": True, "message": "客户密钥已保存"} def offline_grace_hours() -> float: @@ -180,7 +180,7 @@ def _parse_expires_at(value: str | None) -> float | None: def _http_json(method: str, path: str, body: dict[str, Any]) -> dict[str, Any]: key = client_key() if not key: - return {"ok": False, "message": "未配置 CLIENT_API_KEY。请在软件授权页填写卖家提供的密钥,或在 license.env 中设置 LICENSE_CLIENT_KEY。"} + return {"ok": False, "message": "未配置客户密钥。请在软件授权页填写卖家提供的客户密钥(与激活码一起发放)。"} url = f"{api_base_url()}{path}" payload = json.dumps(body).encode("utf-8") req = Request( @@ -221,7 +221,7 @@ def redeem_code(code: str, client_api_key: str | None = None) -> dict[str, Any]: if not client_key(): return { "ok": False, - "message": "请先填写 CLIENT_API_KEY(向卖家索取,与授权站后台「系统设置」中的密钥一致)", + "message": "请先填写客户密钥(与激活码一起由卖家提供;续费时可留空沿用本地已保存的密钥)", } device_id = get_device_id() result = _http_json("POST", "/v1/redeem", {"device_id": device_id, "code": code}) diff --git a/lib/license/templates/license.html b/lib/license/templates/license.html index 5fb59c5..f2dc0e2 100644 --- a/lib/license/templates/license.html +++ b/lib/license/templates/license.html @@ -73,7 +73,7 @@

软件授权

-

复制设备 ID,联系微信 {{ wechat }} 获取 CLIENT_API_KEY 与激活码。授权站:{{ api_url }}

+

复制设备 ID,联系微信 {{ wechat }} 获取 客户密钥 与激活码。授权站:{{ api_url }}

{% if message %}

{{ message }}

{% endif %} {% if error %}

{{ error }}

{% endif %} @@ -85,9 +85,9 @@
- - -
与授权站后台「系统设置」中的密钥一致,本地保存后下次可留空。
+ + +
每张激活码绑定独立密钥;兑换后本地保存,续费一般可留空。
diff --git a/license.env.example b/license.env.example index b7df8af..9b10cf1 100644 --- a/license.env.example +++ b/license.env.example @@ -1,6 +1,6 @@ # LICENSE_API_URL / LICENSE_CLIENT_KEY(可选) # 复制为仓库根目录 license.env(已 gitignore)。 -# CLIENT_API_KEY 也可直接在软件 /license 页填写,不必改本文件。 +# 客户密钥也可直接在软件 /license 页填写(与激活码一起由卖家发放)。 LICENSE_API_URL=https://sq.bz121.com # LICENSE_CLIENT_KEY=