@sfmc-bds/db-server 0.2.0-beta.0 → 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,7 +37,7 @@ function buildModuleAuth(opts) {
37
37
  if (process.env.SFMC_LOG_MODULE_TOKEN === "1") {
38
38
  log.info("[auth] module tokens (SFMC_LOG_MODULE_TOKEN=1):");
39
39
  for (const [id, t] of Object.entries(tokens)) {
40
- console.log(` ${id} = ${t}`);
40
+ log.info(` ${id} = ${t}`);
41
41
  }
42
42
  } else {
43
43
  const lines = Object.entries(tokens).map(([id, t]) => ` ${id} = ${t.slice(0, 6)}\u2026${t.slice(-4)}`).join("\n");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/module-auth.ts"],
4
- "sourcesContent": ["/**\n * module-auth.ts \u2014 \u6A21\u5757\u8EAB\u4EFD\u7684 HMAC token \u6D3E\u751F\u4E0E\u6821\u9A8C\n *\n * \u4E24\u5957\u5E76\u5B58:\n * - `env.AUTH_TOKEN` (config db_config.json http_auth):sfmc \u7BA1\u63A7 / \u5E73\u53F0\u5185\u90E8\u7528\n * - `moduleTokens[moduleId]`:db-server \u7ED9\u6BCF\u4E2A enabled \u6A21\u5757\u5728\u542F\u52A8\u65F6\u6D3E\u751F,\n * \u5199\u5230\u300C\u4E0E\u6570\u636E\u5E93\u540C\u76EE\u5F55\u300D\u7684 module-tokens.json\uFF08\u8DDF db_config.dbDir \u8D70\uFF0C\u52FF\u5199\u6B7B ROOT/data\uFF09,\n * SAPI \u7ECF loopback API \u6CE8\u5165 setDbModuleContext\u3002\n *\n * \u6D3E\u751F\u516C\u5F0F:\n * module_token = HMAC-SHA256(auth_secret, \"sfmc-module:\" + moduleId).hex\n *\n * auth_secret \u4F18\u5148\u7EA7:\n * 1. env.AUTH_TOKEN\n * 2. \u542F\u52A8\u65F6\u968F\u673A\u751F\u6210(\u65E0 AUTH_TOKEN \u65F6),\u5199\u5230 module-tokens.json,\n * \u53EA\u8B66\u544A\u4E00\u6B21(\u6BCF\u6B21\u91CD\u542F\u6A21\u5757 token \u90FD\u53D8,SAPI host \u5FC5\u987B\u91CD\u8BFB\u6587\u4EF6)\n *\n * \u6821\u9A8C:\n * - HTTP `Authorization: Bearer <module_token>` \u5934\n * - Query `?moduleId=<id>`\n * - \u4E24\u90FD\u5339\u914D = \u8C03\u7528\u65B9\u8EAB\u4EFD\n * - \u6821\u9A8C\u8C03\u7528\u65B9 moduleId \u5728 enabled \u5217\u8868(\u5426\u5219 403)\n */\n\nimport { readJson, writeJson, type TokenStore } from \"@sfmc-bds/sdk/node/config\";\nimport { createHmac, randomBytes } from \"node:crypto\";\nimport { dirname, join } from \"node:path\";\nimport { log } from \"./lib/log.js\";\n\nexport interface ModuleAuthMap {\n /** moduleId \u2192 hex token */\n tokens: Record<string, string>;\n /** \u7528\u4E8E\u6D3E\u751F token \u7684 secret (env.AUTH_TOKEN \u6216\u672C\u6B21\u542F\u52A8\u968F\u673A\u751F\u6210) */\n secret: string;\n}\n\nconst IDENT = /^[A-Za-z0-9_\\-]+$/;\n\nfunction safeId(id: string): string {\n if (!IDENT.test(id)) throw new Error(`[auth] invalid module id: ${id}`);\n return id;\n}\n\n/** token \u6587\u4EF6\u4E0E SQLite \u540C\u76EE\u5F55\uFF08\u7531 dbDir \u51B3\u5B9A\uFF0C\u907F\u514D\u5411\u5BFC\u9009\u76EE\u5F55\u524D\u5C31\u521B\u5EFA ROOT/data\uFF09 */\nexport function moduleTokensFile(dbPath: string): string {\n return join(dirname(dbPath), \"module-tokens.json\");\n}\n\nexport function deriveToken(moduleId: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(`sfmc-module:${safeId(moduleId)}`).digest(\"hex\");\n}\n\n/**\n * \u542F\u52A8\u65F6\u8C03\u7528\u4E00\u6B21:\n * - \u628A env.AUTH_TOKEN \u5F53 secret\n * - \u7ED9\u6BCF\u4E2A enabled moduleId \u6D3E\u751F token\n * - \u5199 module-tokens.json\uFF08\u4E0E DB \u540C\u76EE\u5F55\uFF09\n * - \u63A7\u5236\u53F0\u6253\u5370\u6458\u8981(env var SFMC_LOG_MODULE_TOKEN=1 \u65F6\u6253\u5B8C\u6574)\n */\nexport function buildModuleAuth(opts: {\n dbPath: string;\n envAuthToken: string;\n enabledModuleIds: string[];\n}): ModuleAuthMap {\n const secret = opts.envAuthToken || randomBytes(32).toString(\"hex\");\n const tokens: Record<string, string> = {};\n for (const id of opts.enabledModuleIds) {\n tokens[id] = deriveToken(id, secret);\n }\n\n const outFile = moduleTokensFile(opts.dbPath);\n writeJson(outFile, {\n tokens,\n secret,\n generatedAt: new Date().toISOString(),\n secretGenerated: !opts.envAuthToken,\n });\n\n log.success(\n `[auth] \u5DF2\u4E3A ${opts.enabledModuleIds.length} \u4E2A\u6A21\u5757\u6D3E\u751F HMAC token,\u5199\u5165 ${outFile}`\n );\n if (!opts.envAuthToken) {\n log.warn(\n \"[auth] \u672A\u914D\u7F6E env.AUTH_TOKEN(\u51B2\u7A81 config http_auth),\u672C\u6B21\u542F\u52A8\u4F7F\u7528\u4E86\u968F\u673A secret;\"\n + \" \u91CD\u542F\u540E token \u4F1A\u53D8,host-bootstrap \u5FC5\u987B\u6BCF\u6B21\u91CD\u65B0\u8BFB module-tokens.json\"\n );\n }\n if (process.env.SFMC_LOG_MODULE_TOKEN === \"1\") {\n log.info(\"[auth] module tokens (SFMC_LOG_MODULE_TOKEN=1):\");\n for (const [id, t] of Object.entries(tokens)) {\n console.log(` ${id} = ${t}`);\n }\n } else {\n const lines = Object.entries(tokens)\n .map(([id, t]) => ` ${id} = ${t.slice(0, 6)}\u2026${t.slice(-4)}`)\n .join(\"\\n\");\n log.info(`[auth] token \u6458\u8981:\\n${lines}`);\n }\n\n return { tokens, secret };\n}\n\nexport function loadModuleAuth(dbPath: string): ModuleAuthMap | null {\n const parsed = readJson<TokenStore>(moduleTokensFile(dbPath));\n if (!parsed || !parsed.tokens || !parsed.secret) return null;\n return { tokens: parsed.tokens, secret: parsed.secret };\n}\n\n/** \u628A\u5F53\u524D auth map \u5199\u56DE module-tokens.json(\u70ED\u66F4\u65B0 token \u65F6\u590D\u7528) */\nexport function persistModuleAuth(dbPath: string, auth: ModuleAuthMap, envAuthToken: string): void {\n const outFile = moduleTokensFile(dbPath);\n writeJson(outFile, {\n tokens: auth.tokens,\n secret: auth.secret,\n generatedAt: new Date().toISOString(),\n secretGenerated: !envAuthToken,\n } satisfies TokenStore);\n}\n\n/**\n * \u786E\u4FDD moduleId \u5728 auth.tokens \u4E2D\u6709\u6D3E\u751F\u503C(\u590D\u7528\u73B0\u6709 secret,\u52FF\u91CD\u5EFA\u968F\u673A secret)\u3002\n * @returns \u662F\u5426\u65B0\u5199\u5165\u4E86 token\n */\nexport function ensureModuleToken(auth: ModuleAuthMap, moduleId: string): boolean {\n if (auth.tokens[moduleId]) return false;\n auth.tokens[moduleId] = deriveToken(moduleId, auth.secret);\n return true;\n}\n\n/** \u7981\u7528\u65F6\u64A4\u9500\u5185\u5B58\u4E2D\u7684 token(\u78C1\u76D8\u7531 persistModuleAuth \u540C\u6B65) */\nexport function revokeModuleToken(auth: ModuleAuthMap, moduleId: string): boolean {\n if (!(moduleId in auth.tokens)) return false;\n delete auth.tokens[moduleId];\n return true;\n}\n\n/**\n * \u6821\u9A8C\u8BF7\u6C42\u65B9\u8EAB\u4EFD:\n * - Bearer \u5934 / X-Module-Token \u4E8C\u9009\u4E00\n * - ?moduleId=<id> \u5FC5\u987B\u5B58\u5728\n * - \u6A21\u5757\u5FC5\u987B\u5728 enabledModuleIds \u96C6\u5408\u4E2D\n * - token \u5FC5\u987B = deriveToken(moduleId, secret)\n * \u8FD4\u56DE\u6A21\u5757 ID \u6216 null\u3002\n */\nexport function verifyModuleAuth(opts: {\n headers: NodeJS.Dict<string | string[]>;\n params: URLSearchParams;\n auth: ModuleAuthMap;\n enabledModuleIds: Set<string>;\n}): string | null {\n const moduleId = opts.params.get(\"moduleId\") || \"\";\n if (!moduleId || !opts.enabledModuleIds.has(moduleId)) return null;\n\n let provided = \"\";\n const auth = opts.headers[\"authorization\"];\n const token = opts.headers[\"x-module-token\"];\n if (typeof auth === \"string\" && auth.startsWith(\"Bearer \")) {\n provided = auth.slice(7);\n } else if (typeof token === \"string\") {\n provided = token;\n }\n if (!provided) return null;\n\n const expected = opts.auth.tokens[moduleId];\n if (!expected) return null;\n // constant-time \u6BD4\u8F83\n if (provided.length !== expected.length) return null;\n let diff = 0;\n for (let i = 0; i < provided.length; i++) {\n diff |= provided.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return diff === 0 ? moduleId : null;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * module-auth.ts \u2014 \u6A21\u5757\u8EAB\u4EFD\u7684 HMAC token \u6D3E\u751F\u4E0E\u6821\u9A8C\n *\n * \u4E24\u5957\u5E76\u5B58:\n * - `env.AUTH_TOKEN` (config db_config.json http_auth):sfmc \u7BA1\u63A7 / \u5E73\u53F0\u5185\u90E8\u7528\n * - `moduleTokens[moduleId]`:db-server \u7ED9\u6BCF\u4E2A enabled \u6A21\u5757\u5728\u542F\u52A8\u65F6\u6D3E\u751F,\n * \u5199\u5230\u300C\u4E0E\u6570\u636E\u5E93\u540C\u76EE\u5F55\u300D\u7684 module-tokens.json\uFF08\u8DDF db_config.dbDir \u8D70\uFF0C\u52FF\u5199\u6B7B ROOT/data\uFF09,\n * SAPI \u7ECF loopback API \u6CE8\u5165 setDbModuleContext\u3002\n *\n * \u6D3E\u751F\u516C\u5F0F:\n * module_token = HMAC-SHA256(auth_secret, \"sfmc-module:\" + moduleId).hex\n *\n * auth_secret \u4F18\u5148\u7EA7:\n * 1. env.AUTH_TOKEN\n * 2. \u542F\u52A8\u65F6\u968F\u673A\u751F\u6210(\u65E0 AUTH_TOKEN \u65F6),\u5199\u5230 module-tokens.json,\n * \u53EA\u8B66\u544A\u4E00\u6B21(\u6BCF\u6B21\u91CD\u542F\u6A21\u5757 token \u90FD\u53D8,SAPI host \u5FC5\u987B\u91CD\u8BFB\u6587\u4EF6)\n *\n * \u6821\u9A8C:\n * - HTTP `Authorization: Bearer <module_token>` \u5934\n * - Query `?moduleId=<id>`\n * - \u4E24\u90FD\u5339\u914D = \u8C03\u7528\u65B9\u8EAB\u4EFD\n * - \u6821\u9A8C\u8C03\u7528\u65B9 moduleId \u5728 enabled \u5217\u8868(\u5426\u5219 403)\n */\n\nimport { readJson, writeJson, type TokenStore } from \"@sfmc-bds/sdk/node/config\";\nimport { createHmac, randomBytes } from \"node:crypto\";\nimport { dirname, join } from \"node:path\";\nimport { log } from \"./lib/log.js\";\n\nexport interface ModuleAuthMap {\n /** moduleId \u2192 hex token */\n tokens: Record<string, string>;\n /** \u7528\u4E8E\u6D3E\u751F token \u7684 secret (env.AUTH_TOKEN \u6216\u672C\u6B21\u542F\u52A8\u968F\u673A\u751F\u6210) */\n secret: string;\n}\n\nconst IDENT = /^[A-Za-z0-9_\\-]+$/;\n\nfunction safeId(id: string): string {\n if (!IDENT.test(id)) throw new Error(`[auth] invalid module id: ${id}`);\n return id;\n}\n\n/** token \u6587\u4EF6\u4E0E SQLite \u540C\u76EE\u5F55\uFF08\u7531 dbDir \u51B3\u5B9A\uFF0C\u907F\u514D\u5411\u5BFC\u9009\u76EE\u5F55\u524D\u5C31\u521B\u5EFA ROOT/data\uFF09 */\nexport function moduleTokensFile(dbPath: string): string {\n return join(dirname(dbPath), \"module-tokens.json\");\n}\n\nexport function deriveToken(moduleId: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(`sfmc-module:${safeId(moduleId)}`).digest(\"hex\");\n}\n\n/**\n * \u542F\u52A8\u65F6\u8C03\u7528\u4E00\u6B21:\n * - \u628A env.AUTH_TOKEN \u5F53 secret\n * - \u7ED9\u6BCF\u4E2A enabled moduleId \u6D3E\u751F token\n * - \u5199 module-tokens.json\uFF08\u4E0E DB \u540C\u76EE\u5F55\uFF09\n * - \u63A7\u5236\u53F0\u6253\u5370\u6458\u8981(env var SFMC_LOG_MODULE_TOKEN=1 \u65F6\u6253\u5B8C\u6574)\n */\nexport function buildModuleAuth(opts: {\n dbPath: string;\n envAuthToken: string;\n enabledModuleIds: string[];\n}): ModuleAuthMap {\n const secret = opts.envAuthToken || randomBytes(32).toString(\"hex\");\n const tokens: Record<string, string> = {};\n for (const id of opts.enabledModuleIds) {\n tokens[id] = deriveToken(id, secret);\n }\n\n const outFile = moduleTokensFile(opts.dbPath);\n writeJson(outFile, {\n tokens,\n secret,\n generatedAt: new Date().toISOString(),\n secretGenerated: !opts.envAuthToken,\n });\n\n log.success(\n `[auth] \u5DF2\u4E3A ${opts.enabledModuleIds.length} \u4E2A\u6A21\u5757\u6D3E\u751F HMAC token,\u5199\u5165 ${outFile}`\n );\n if (!opts.envAuthToken) {\n log.warn(\n \"[auth] \u672A\u914D\u7F6E env.AUTH_TOKEN(\u51B2\u7A81 config http_auth),\u672C\u6B21\u542F\u52A8\u4F7F\u7528\u4E86\u968F\u673A secret;\"\n + \" \u91CD\u542F\u540E token \u4F1A\u53D8,host-bootstrap \u5FC5\u987B\u6BCF\u6B21\u91CD\u65B0\u8BFB module-tokens.json\"\n );\n }\n if (process.env.SFMC_LOG_MODULE_TOKEN === \"1\") {\n log.info(\"[auth] module tokens (SFMC_LOG_MODULE_TOKEN=1):\");\n for (const [id, t] of Object.entries(tokens)) {\n log.info(` ${id} = ${t}`);\n }\n } else {\n const lines = Object.entries(tokens)\n .map(([id, t]) => ` ${id} = ${t.slice(0, 6)}\u2026${t.slice(-4)}`)\n .join(\"\\n\");\n log.info(`[auth] token \u6458\u8981:\\n${lines}`);\n }\n\n return { tokens, secret };\n}\n\nexport function loadModuleAuth(dbPath: string): ModuleAuthMap | null {\n const parsed = readJson<TokenStore>(moduleTokensFile(dbPath));\n if (!parsed || !parsed.tokens || !parsed.secret) return null;\n return { tokens: parsed.tokens, secret: parsed.secret };\n}\n\n/** \u628A\u5F53\u524D auth map \u5199\u56DE module-tokens.json(\u70ED\u66F4\u65B0 token \u65F6\u590D\u7528) */\nexport function persistModuleAuth(dbPath: string, auth: ModuleAuthMap, envAuthToken: string): void {\n const outFile = moduleTokensFile(dbPath);\n writeJson(outFile, {\n tokens: auth.tokens,\n secret: auth.secret,\n generatedAt: new Date().toISOString(),\n secretGenerated: !envAuthToken,\n } satisfies TokenStore);\n}\n\n/**\n * \u786E\u4FDD moduleId \u5728 auth.tokens \u4E2D\u6709\u6D3E\u751F\u503C(\u590D\u7528\u73B0\u6709 secret,\u52FF\u91CD\u5EFA\u968F\u673A secret)\u3002\n * @returns \u662F\u5426\u65B0\u5199\u5165\u4E86 token\n */\nexport function ensureModuleToken(auth: ModuleAuthMap, moduleId: string): boolean {\n if (auth.tokens[moduleId]) return false;\n auth.tokens[moduleId] = deriveToken(moduleId, auth.secret);\n return true;\n}\n\n/** \u7981\u7528\u65F6\u64A4\u9500\u5185\u5B58\u4E2D\u7684 token(\u78C1\u76D8\u7531 persistModuleAuth \u540C\u6B65) */\nexport function revokeModuleToken(auth: ModuleAuthMap, moduleId: string): boolean {\n if (!(moduleId in auth.tokens)) return false;\n delete auth.tokens[moduleId];\n return true;\n}\n\n/**\n * \u6821\u9A8C\u8BF7\u6C42\u65B9\u8EAB\u4EFD:\n * - Bearer \u5934 / X-Module-Token \u4E8C\u9009\u4E00\n * - ?moduleId=<id> \u5FC5\u987B\u5B58\u5728\n * - \u6A21\u5757\u5FC5\u987B\u5728 enabledModuleIds \u96C6\u5408\u4E2D\n * - token \u5FC5\u987B = deriveToken(moduleId, secret)\n * \u8FD4\u56DE\u6A21\u5757 ID \u6216 null\u3002\n */\nexport function verifyModuleAuth(opts: {\n headers: NodeJS.Dict<string | string[]>;\n params: URLSearchParams;\n auth: ModuleAuthMap;\n enabledModuleIds: Set<string>;\n}): string | null {\n const moduleId = opts.params.get(\"moduleId\") || \"\";\n if (!moduleId || !opts.enabledModuleIds.has(moduleId)) return null;\n\n let provided = \"\";\n const auth = opts.headers[\"authorization\"];\n const token = opts.headers[\"x-module-token\"];\n if (typeof auth === \"string\" && auth.startsWith(\"Bearer \")) {\n provided = auth.slice(7);\n } else if (typeof token === \"string\") {\n provided = token;\n }\n if (!provided) return null;\n\n const expected = opts.auth.tokens[moduleId];\n if (!expected) return null;\n // constant-time \u6BD4\u8F83\n if (provided.length !== expected.length) return null;\n let diff = 0;\n for (let i = 0; i < provided.length; i++) {\n diff |= provided.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return diff === 0 ? moduleId : null;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sfmc-bds/db-server",
3
- "version": "0.2.0-beta.0",
3
+ "version": "0.2.0-beta.1",
4
4
  "description": "SFMC SQLite HTTP REST backend — configs, modules, gameplay data, QQ message relay",
5
5
  "type": "module",
6
6
  "license": "ISC",