#!/usr/bin/env node /** * License 激活脚本 (用户首次使用) * 用法: * echo "" | node activate.js * 或: * node activate.js --key=BW-XXXX-XXXX-... * * 行为: * 1. 读取 License Key (stdin 或 --key, 不走 argv 暴露) * 2. 生成设备指纹 * 3. 向 Worker 激活 → 拿 JWT Token (7 天有效) * 4. 保存到 ~/.claude/.bw-token (600 权限) */ const fs = require("fs"); const path = require("path"); const os = require("os"); const https = require("https"); const { fingerprint } = require("./fingerprint"); const API_BASE = process.env.BW_API_BASE || "https://bookworm-router.bookworm-api.workers.dev"; const CLAUDE_DIR = path.join(os.homedir(), ".claude"); const TOKEN_FILE = path.join(CLAUDE_DIR, ".bw-token"); async function readLicenseKey() { // 优先从 --key= 读取 (但不推荐, argv 会暴露) const argKey = process.argv.find(a => a.startsWith("--key=")); if (argKey) return argKey.slice(6).trim(); // 从 stdin 读 return new Promise((resolve) => { let data = ""; process.stdin.setEncoding("utf8"); process.stdin.on("data", c => data += c); process.stdin.on("end", () => resolve(data.trim())); setTimeout(() => resolve(data.trim()), 15000); }); } function post(url, body) { return new Promise((resolve, reject) => { const u = new URL(url); const data = JSON.stringify(body); const req = https.request({ hostname: u.hostname, port: 443, path: u.pathname, method: "POST", timeout: 15000, headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(data) } }, (res) => { let buf = ""; res.on("data", c => buf += c); res.on("end", () => { try { resolve({ status: res.statusCode, body: JSON.parse(buf) }); } catch { resolve({ status: res.statusCode, body: buf }); } }); }); req.on("error", reject); req.on("timeout", () => { req.destroy(); reject(new Error("timeout")); }); req.write(data); req.end(); }); } (async () => { const key = await readLicenseKey(); if (!key || !/^BW-[A-Z0-9-]{20,}$/.test(key)) { console.error("[FAIL] License Key 为空或格式错误"); process.exit(1); } const dev = fingerprint(); console.log("[INFO] 正在激活..."); try { const r = await post(`${API_BASE}/license/activate`, { licenseKey: key, deviceFp: dev, os: `${os.platform()} ${os.release()}` }); if (r.status !== 200) { const err = r.body?.error || "unknown"; const msg = r.body?.message || ""; console.error(`[FAIL] 激活失败 (${r.status}): ${err} ${msg}`); if (err === "device_limit") { console.error(" 已达设备上限, 请联系管理员增加或吊销旧设备"); } else if (err === "invalid_license") { console.error(" License Key 无效或已被吊销"); } else if (err === "expired") { console.error(" License 已过期, 请续费"); } process.exit(1); } try { fs.mkdirSync(CLAUDE_DIR, { recursive: true, mode: 0o700 }); } catch {} fs.writeFileSync(TOKEN_FILE, JSON.stringify({ token: r.body.token, license_uuid: r.body.license_uuid, expires_at: Date.now() + r.body.expires_in * 1000, license_expires_at: r.body.license_expires_at }), { mode: 0o600 }); console.log("[OK] 激活成功"); console.log(` License: ${r.body.license_uuid}`); console.log(` License 过期: ${r.body.license_expires_at}`); console.log(` Token 有效期: 7 天 (自动续期)`); } catch (e) { console.error(`[FAIL] 网络错误: ${e.message}`); console.error(" 请检查网络和代理设置"); process.exit(1); } })();