From 3441eb94782e77b726d4605b48570b3dc92d430c Mon Sep 17 00:00:00 2001 From: canglan Date: Wed, 19 Aug 2026 20:16:16 +0800 Subject: [PATCH] chore: pure-random 32-char secret, no default source, legacy migration - genSecret: drop SeaReport- prefix, plain 32-char random hex - users.source: no default anywhere (register/admin/external), ADD COLUMN migration now VARCHAR DEFAULT '' (was ENUM netease default) - legacy upgrade path kept: ENUM->VARCHAR MODIFY + user_identities MODIFY + sources seeded netease/skin idempotently - docs updated (credential format, no prefix) --- backend/db.js | 2 +- backend/routes/external.js | 4 ++-- docs/API.md | 2 +- docs/EXTERNAL-API.md | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/db.js b/backend/db.js index f305c57..32c9b9e 100644 --- a/backend/db.js +++ b/backend/db.js @@ -353,7 +353,7 @@ async function migrateAdditions(db) { try { await db.execute("ALTER TABLE tickets ADD COLUMN parent_ticket_id INT"); } catch {} try { await db.execute("ALTER TABLE tickets MODIFY type ENUM('report','suggestion','appeal','result_appeal') NOT NULL"); } catch {} try { await db.execute("ALTER TABLE tickets MODIFY status ENUM('pending','processing','awaiting_info','appealing','resolved','rejected','closed') NOT NULL"); } catch {} - try { await db.execute("ALTER TABLE users ADD COLUMN source ENUM('netease','skin') NOT NULL DEFAULT 'netease'"); } catch {} + try { await db.execute("ALTER TABLE users ADD COLUMN source VARCHAR(20) NOT NULL DEFAULT ''"); } catch {} try { await db.execute(`CREATE TABLE IF NOT EXISTS user_servers (user_id INT NOT NULL, group_name VARCHAR(100) NOT NULL, server_name VARCHAR(100) NOT NULL, UNIQUE KEY uk_user_server (user_id, group_name, server_name), INDEX idx_user (user_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`); } catch {} try { await db.execute(`CREATE TABLE IF NOT EXISTS bans (id INT AUTO_INCREMENT PRIMARY KEY, player_name VARCHAR(50) NOT NULL, player_uid VARCHAR(50), source VARCHAR(10) DEFAULT '', reason TEXT, type ENUM('ban','mute','warn','other') NOT NULL DEFAULT 'ban', duration VARCHAR(20) DEFAULT '', ticket_id INT, created_by INT, status ENUM('active','expired','appealed','lifted') NOT NULL DEFAULT 'active', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, expires_at DATETIME) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`); } catch {} try { await db.execute("ALTER TABLE bans ADD COLUMN source VARCHAR(10) DEFAULT ''"); } catch {} diff --git a/backend/routes/external.js b/backend/routes/external.js index 24a5eb8..3447a1f 100644 --- a/backend/routes/external.js +++ b/backend/routes/external.js @@ -24,8 +24,8 @@ function genClientId() { } function genSecret() { - // SeaReport- + 32 位随机字符串 - return 'SeaReport-' + crypto.randomBytes(16).toString('hex'); // 16 bytes = 32 hex chars + // 32 位全随机字符串(hex = 32 chars) + return crypto.randomBytes(16).toString('hex'); } async function createSession(clientId) { diff --git a/docs/API.md b/docs/API.md index 5f95fad..9d3ac6d 100644 --- a/docs/API.md +++ b/docs/API.md @@ -350,7 +350,7 @@ Base URL: `http://:3100/api` | 阶段 | 请求头 | 说明 | |------|--------|------| -| 换取 SESSION | `x-api-client-id` + `x-api-secret` | 仅 `POST /external/auth/session` 使用;ID 为 16 位随机数字,Secret 为 `SeaReport-` + 32 位 | +| 换取 SESSION | `x-api-client-id` + `x-api-secret` | 仅 `POST /external/auth/session` 使用;ID 为 16 位随机数字,Secret 为 32 位随机字符串 | | 后续请求 | `Authorization: Bearer ` | 所有其余接口;24 小时有效,重换即旧 SESSION 失效,客户端停用立即失效 | ### 子服务器定位(`server` 参数) diff --git a/docs/EXTERNAL-API.md b/docs/EXTERNAL-API.md index 2871a44..8dd664d 100644 --- a/docs/EXTERNAL-API.md +++ b/docs/EXTERNAL-API.md @@ -14,7 +14,7 @@ ```text Client ID: 1829473056482917 # 16 位纯数字, 随机生成 -Secret: SeaReport-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4 # SeaReport- + 32 位 +Secret: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 # 32 位全随机字符串 ``` > ⚠️ Secret 只在创建时显示一次,请立即保存。支持创建多个客户端、单独停用/删除,互不影响。 @@ -70,7 +70,7 @@ BASE = "https://你的域名/api/external" # 1) 用 ID + Secret 换取 SESSION r = requests.post(f"{BASE}/auth/session", headers={ "x-api-client-id": "1829473056482917", - "x-api-secret": "SeaReport-a1b2c3d4...", + "x-api-secret": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6", }) session = r.json()["session_token"] HEADERS = {"Authorization": f"Bearer {session}", "Content-Type": "application/json"} @@ -96,7 +96,7 @@ const BASE = 'https://你的域名/api/external'; // 1) 换取 SESSION const authRes = await fetch(`${BASE}/auth/session`, { method: 'POST', - headers: { 'x-api-client-id': '1829473056482917', 'x-api-secret': 'SeaReport-a1b2c3d4...' }, + headers: { 'x-api-client-id': '1829473056482917', 'x-api-secret': 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6' }, }); const { session_token } = await authRes.json(); const H = { Authorization: `Bearer ${session_token}`, 'Content-Type': 'application/json' };