trustbase-seller-backend 0.7.9 → 0.8.0

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.
@@ -102,9 +102,12 @@ async function runChainReconcile({ db, lcdUrl }) {
102
102
  summary.checked += 1;
103
103
  const slot = activeBySku.get(p.id);
104
104
  if (slot) {
105
+ // 本地质押是卖家原始快照,链上声誉调整后的 stake_per_unit 不参与一致性比较;
106
+ // 否则每次对账都会把同一商品重复记为 recovered(本地值又按设计保留)。
107
+ const hasLocalStake = p.chain_stake_per_unit !== null && p.chain_stake_per_unit !== undefined && p.chain_stake_per_unit !== "";
105
108
  const needsRecover = !p.chain_listed || p.chain_sku_id !== slot.sku_id ||
106
109
  Number(p.chain_slot_index) !== Number(slot.slot_index) ||
107
- String(p.chain_stake_per_unit || "") !== String(slot.stake_per_unit || "");
110
+ (!hasLocalStake && String(slot.stake_per_unit || "") !== "");
108
111
  if (needsRecover) {
109
112
  updateLocalFromSlot(db, p, slot);
110
113
  summary.recovered += 1;
@@ -1,64 +1,66 @@
1
- /**
2
- * API Key Authentication - API 密钥认证
3
- *
4
- * 类似 SSH 的双重验证:
5
- * 1. API Key(类似 SSH 密钥)
6
- * 2. 密码(类似 SSH 密码)
7
- *
8
- * 使用场景:
9
- * - 外部访问必须验证
10
- * - 局域网可跳过验证
11
- */
12
- import { Request, Response, NextFunction } from 'express';
13
- interface APIKey {
14
- key: string;
15
- keyPlaintext?: string;
16
- name: string;
17
- password: string;
18
- createdAt: number;
19
- lastUsedAt?: number;
20
- permissions: string[];
21
- ipWhitelist?: string[];
22
- enabled: boolean;
23
- }
24
- /**
25
- * 生成 API Key
26
- */
27
- export declare function generateAPIKey(): string;
28
- /**
29
- * 加载 API Keys
30
- */
31
- export declare function loadAPIKeys(): APIKey[];
32
- /**
33
- * 保存 API Keys
34
- */
35
- export declare function saveAPIKeys(keys: APIKey[]): void;
36
- /**
37
- * 创建新的 API Key(银行标准:加密存储)
38
- */
39
- export declare function createAPIKey(name: string, password: string, permissions?: string[], ipWhitelist?: string[]): {
40
- key: string;
41
- password: string;
42
- };
43
- /**
44
- * 验证 API Key(银行标准:解密验证)
45
- */
46
- export declare function validateAPIKey(key: string, password: string, clientIP?: string): {
47
- valid: boolean;
48
- apiKey?: APIKey;
49
- error?: string;
50
- };
51
- /**
52
- * 撤销 API Key
53
- */
54
- export declare function revokeAPIKey(key: string): boolean;
55
- /**
56
- * 列出所有 API Keys(隐藏密码)
57
- */
58
- export declare function listAPIKeys(): Omit<APIKey, 'password'>[];
59
- /**
60
- * API Key 认证中间件(集成入侵检测)
61
- */
62
- export declare function requireAPIKey(skipLAN?: boolean, exemptPaths?: string[]): (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
63
- export {};
1
+ /**
2
+ * API Key Authentication - API 密钥认证
3
+ *
4
+ * 类似 SSH 的双重验证:
5
+ * 1. API Key(类似 SSH 密钥)
6
+ * 2. 密码(类似 SSH 密码)
7
+ *
8
+ * 使用场景:
9
+ * - 外部访问必须验证
10
+ * - 局域网可跳过验证
11
+ */
12
+ import { Request, Response, NextFunction } from 'express';
13
+ interface APIKey {
14
+ key: string;
15
+ keyPlaintext?: string;
16
+ name: string;
17
+ password: string;
18
+ createdAt: number;
19
+ lastUsedAt?: number;
20
+ permissions: string[];
21
+ ipWhitelist?: string[];
22
+ enabled: boolean;
23
+ }
24
+ /**
25
+ * 生成 API Key
26
+ */
27
+ export declare function generateAPIKey(): string;
28
+ /**
29
+ * 加载 API Keys
30
+ */
31
+ export declare function loadAPIKeys(): APIKey[];
32
+ /**
33
+ * 保存 API Keys
34
+ */
35
+ export declare function saveAPIKeys(keys: APIKey[]): void;
36
+ /**
37
+ * 创建新的 API Key(银行标准:加密存储)
38
+ */
39
+ export declare function createAPIKey(name: string, password: string, permissions?: string[], ipWhitelist?: string[]): {
40
+ key: string;
41
+ password: string;
42
+ };
43
+ /**
44
+ * 验证 API Key(银行标准:解密验证)
45
+ */
46
+ export declare function validateAPIKey(key: string, password: string, clientIP?: string): {
47
+ valid: boolean;
48
+ apiKey?: APIKey;
49
+ error?: string;
50
+ };
51
+ /**
52
+ * 撤销 API Key
53
+ */
54
+ export declare function revokeAPIKey(key: string): boolean;
55
+ /**
56
+ * 列出所有 API Keys(隐藏密码)
57
+ */
58
+ export declare function listAPIKeys(): Omit<APIKey, 'password'>[];
59
+ /**
60
+ * API Key 认证中间件(集成入侵检测)
61
+ */
62
+ export declare function requireAPIKey(skipLAN?: boolean, exemptPaths?: string[]): (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
63
+ /** 仅在回环隧道请求中采信网关注入的 XFF,其他请求使用 socket 对端 IP。 */
64
+ export declare function getRateLimitClientIP(req: Request, socketIP: string): string;
65
+ export {};
64
66
  //# sourceMappingURL=api-key-auth.d.ts.map
@@ -22,6 +22,7 @@ exports.validateAPIKey = validateAPIKey;
22
22
  exports.revokeAPIKey = revokeAPIKey;
23
23
  exports.listAPIKeys = listAPIKeys;
24
24
  exports.requireAPIKey = requireAPIKey;
25
+ exports.getRateLimitClientIP = getRateLimitClientIP;
25
26
  const crypto_1 = __importDefault(require("crypto"));
26
27
  const fs_1 = __importDefault(require("fs"));
27
28
  const path_1 = __importDefault(require("path"));
@@ -1,217 +1,218 @@
1
- "use strict";
2
- /**
3
- * Security Middleware - 安全中间件
4
- *
5
- * 功能:
6
- * 1. IP 白名单验证
7
- * 2. CORS 限制
8
- * 3. 请求日志审计
9
- * 4. 安全头部
10
- */
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.requestSizeLimit = void 0;
16
- exports.ipWhitelist = ipWhitelist;
17
- exports.createCorsOptions = createCorsOptions;
18
- exports.auditLog = auditLog;
19
- exports.securityHeaders = securityHeaders;
20
- exports.validateEnv = validateEnv;
21
- const fs_1 = __importDefault(require("fs"));
22
- const path_1 = __importDefault(require("path"));
23
- // ===================== IP 白名单 =====================
24
- /**
25
- * 检查 IP 是否在 CIDR 范围内
26
- */
27
- function isIPInCIDR(ip, cidr) {
28
- // 简化实现,生产环境建议使用 ip-range-check 库
29
- if (cidr.endsWith('/24')) {
30
- const network = cidr.replace('/24', '');
31
- const ipParts = ip.split('.');
32
- const networkParts = network.split('.');
33
- return ipParts[0] === networkParts[0] &&
34
- ipParts[1] === networkParts[1] &&
35
- ipParts[2] === networkParts[2];
36
- }
37
- return ip === cidr;
38
- }
39
- /**
40
- * IP 白名单中间件
41
- */
42
- function ipWhitelist(allowedIPs) {
43
- return (req, res, next) => {
44
- // 如果白名单为空,允许所有访问
45
- if (!allowedIPs || allowedIPs.length === 0) {
46
- return next();
47
- }
48
- const clientIP = (req.ip ||
49
- req.connection.remoteAddress ||
50
- req.headers['x-forwarded-for'] ||
51
- 'unknown')
52
- .replace('::ffff:', ''); // IPv4 映射地址
53
- const isAllowed = allowedIPs.some(ip => {
54
- if (ip.includes('/')) {
55
- return isIPInCIDR(clientIP, ip);
56
- }
57
- return clientIP === ip || clientIP.includes(ip);
58
- });
59
- if (!isAllowed) {
60
- console.warn(`[Security] 拒绝访问: ${clientIP}`);
61
- return res.status(403).json({
62
- error: '禁止访问',
63
- message: '您的 IP 不在白名单中'
64
- });
65
- }
66
- next();
67
- };
68
- }
69
- // ===================== CORS 配置 =====================
70
- /**
71
- * 动态 CORS 配置
72
- */
73
- function createCorsOptions(allowedOrigins) {
74
- return {
75
- origin: (origin, callback) => {
76
- // 允许没有 origin 的请求(如移动 APP、Postman)
77
- if (!origin)
78
- return callback(null, true);
79
- // 2026-08-13 kimi 打磨 (xiaomu 浏览器 500 根因): 同源/本机/局域网来源一律放行.
80
- // 模块脚本会带 Origin — 自己服务的 UI 打自己的 API 必须是同源自通, 与 LAN 免密同一信任模型.
81
- try {
82
- const host = new URL(origin).hostname;
83
- if (host === 'localhost' || host === '127.0.0.1' || host === '::1' || host === '[::1]' ||
84
- host.startsWith('192.168.') || host.startsWith('10.') || /^172\.(1[6-9]|2\d|3[01])\./.test(host) ||
85
- host.startsWith('fe80:') || host.startsWith('240') // 链路本地 + 国内公网 v6 段 (240e/2408/2409 等)
86
- ) {
87
- return callback(null, true);
88
- }
89
- }
90
- catch { /* 畸形 origin 继续走列表判断 */ }
91
- // 空配置 fallback (baobei 15442): 没配 allowedOrigins 时放行, 不默默拒绝所有 (开发模式).
92
- // 生产部署必须显式配 ALLOWED_ORIGINS (或依赖上面的 LAN 放行).
93
- if (allowedOrigins.length === 0) {
94
- console.warn('[CORS] ALLOWED_ORIGINS 为空, 放行所有来源 (开发模式, 生产请显式配置)');
95
- return callback(null, true);
96
- }
97
- // 检查是否在允许列表
98
- const isAllowed = allowedOrigins.some(allowedOrigin => {
99
- if (allowedOrigin.startsWith('regex:')) {
100
- // 正则表达式匹配
101
- const pattern = allowedOrigin.replace('regex:', '');
102
- return new RegExp(pattern).test(origin);
103
- }
104
- return allowedOrigin === origin;
105
- });
106
- if (isAllowed) {
107
- callback(null, true);
108
- }
109
- else {
110
- console.warn(`[CORS] 拒绝来源: ${origin}`);
111
- callback(new Error('不允许的来源'));
112
- }
113
- },
114
- credentials: true,
115
- methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
116
- allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
117
- };
118
- }
119
- // ===================== 请求审计日志 =====================
120
- const auditLogFile = path_1.default.join(__dirname, '../../logs/audit.log');
121
- /**
122
- * 确保日志目录存在
123
- */
124
- function ensureLogDir() {
125
- const logDir = path_1.default.dirname(auditLogFile);
126
- if (!fs_1.default.existsSync(logDir)) {
127
- fs_1.default.mkdirSync(logDir, { recursive: true });
128
- }
129
- }
130
- /**
131
- * 审计日志中间件
132
- */
133
- function auditLog() {
134
- ensureLogDir();
135
- return (req, res, next) => {
136
- const startTime = Date.now();
137
- // 记录响应完成
138
- res.on('finish', () => {
139
- const log = {
140
- timestamp: new Date().toISOString(),
141
- method: req.method,
142
- path: req.path,
143
- query: req.query,
144
- ip: req.ip || req.connection.remoteAddress,
145
- userAgent: req.get('user-agent'),
146
- statusCode: res.statusCode,
147
- responseTime: Date.now() - startTime,
148
- userId: req.user?.walletAddress || 'anonymous',
149
- };
150
- // 写入日志文件
151
- const logLine = JSON.stringify(log) + '\n';
152
- fs_1.default.appendFile(auditLogFile, logLine, (err) => {
153
- if (err)
154
- console.error('[Audit] 写入日志失败:', err);
155
- });
156
- // 控制台输出(可选)
157
- if (process.env.LOG_LEVEL === 'debug') {
158
- console.log('[Audit]', log.method, log.path, log.statusCode, `${log.responseTime}ms`);
159
- }
160
- });
161
- next();
162
- };
163
- }
164
- // ===================== 安全头部 =====================
165
- /**
166
- * 安全头部中间件
167
- */
168
- function securityHeaders() {
169
- return (req, res, next) => {
170
- // 防止 XSS 攻击
171
- res.setHeader('X-XSS-Protection', '1; mode=block');
172
- // 防止 MIME 类型嗅探
173
- res.setHeader('X-Content-Type-Options', 'nosniff');
174
- // 防止点击劫持
175
- res.setHeader('X-Frame-Options', 'DENY');
176
- // 内容安全策略 (baobei 15442: 扩 script-src/style-src 让 vue-i18n runtime 模板编译能跑)
177
- // 治标: Vite production bundle 用 runtime 编译 (new Function), 需要 unsafe-eval; 真修是前端 runtime-only (见 baobei 清单)
178
- res.setHeader('Content-Security-Policy', "default-src 'self'; " +
179
- "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " +
180
- "style-src 'self' 'unsafe-inline'; " +
181
- "img-src 'self' data: https:; " +
182
- "font-src 'self' data:; " +
183
- "connect-src 'self' ws: wss: https:; " +
184
- "object-src 'none'; base-uri 'self'; frame-ancestors 'none'");
185
- // 隐藏服务器信息
186
- res.removeHeader('X-Powered-By');
187
- next();
188
- };
189
- }
190
- // ===================== 请求大小限制 =====================
191
- /**
192
- * 请求体大小限制
193
- */
194
- exports.requestSizeLimit = {
195
- json: { limit: '1mb' }, // JSON 请求体最大 1MB
196
- urlencoded: { limit: '1mb', extended: true }, // URL 编码请求体最大 1MB
197
- };
198
- // ===================== 环境变量验证 =====================
199
- /**
200
- * 验证必需的环境变量
201
- */
202
- function validateEnv() {
203
- const required = ['JWT_SECRET'];
204
- const missing = required.filter(key => !process.env[key]);
205
- if (missing.length > 0) {
206
- console.error('❌ 缺少必需的环境变量:', missing.join(', '));
207
- console.error('请创建 .env 文件并设置这些变量');
208
- process.exit(1);
209
- }
210
- // 检查是否使用默认 JWT 密钥
211
- if (process.env.JWT_SECRET === 'trustchain-secret-key-2026') {
212
- console.warn('⚠️ 警告: 使用默认 JWT 密钥不安全!');
213
- console.warn('⚠️ 请在 .env 文件中设置 JWT_SECRET');
214
- }
215
- console.log('✅ 环境变量验证通过');
216
- }
1
+ "use strict";
2
+ /**
3
+ * Security Middleware - 安全中间件
4
+ *
5
+ * 功能:
6
+ * 1. IP 白名单验证
7
+ * 2. CORS 限制
8
+ * 3. 请求日志审计
9
+ * 4. 安全头部
10
+ */
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.requestSizeLimit = void 0;
16
+ exports.ipWhitelist = ipWhitelist;
17
+ exports.createCorsOptions = createCorsOptions;
18
+ exports.auditLog = auditLog;
19
+ exports.securityHeaders = securityHeaders;
20
+ exports.validateEnv = validateEnv;
21
+ const fs_1 = __importDefault(require("fs"));
22
+ const path_1 = __importDefault(require("path"));
23
+ // ===================== IP 白名单 =====================
24
+ /**
25
+ * 检查 IP 是否在 CIDR 范围内
26
+ */
27
+ function isIPInCIDR(ip, cidr) {
28
+ // 简化实现,生产环境建议使用 ip-range-check 库
29
+ if (cidr.endsWith('/24')) {
30
+ const network = cidr.replace('/24', '');
31
+ const ipParts = ip.split('.');
32
+ const networkParts = network.split('.');
33
+ return ipParts[0] === networkParts[0] &&
34
+ ipParts[1] === networkParts[1] &&
35
+ ipParts[2] === networkParts[2];
36
+ }
37
+ return ip === cidr;
38
+ }
39
+ /**
40
+ * IP 白名单中间件
41
+ */
42
+ function ipWhitelist(allowedIPs) {
43
+ return (req, res, next) => {
44
+ // 如果白名单为空,允许所有访问
45
+ if (!allowedIPs || allowedIPs.length === 0) {
46
+ return next();
47
+ }
48
+ const clientIP = (req.ip ||
49
+ req.connection.remoteAddress ||
50
+ req.headers['x-forwarded-for'] ||
51
+ 'unknown')
52
+ .replace('::ffff:', ''); // IPv4 映射地址
53
+ const isAllowed = allowedIPs.some(ip => {
54
+ if (ip.includes('/')) {
55
+ return isIPInCIDR(clientIP, ip);
56
+ }
57
+ return clientIP === ip || clientIP.includes(ip);
58
+ });
59
+ if (!isAllowed) {
60
+ console.warn(`[Security] 拒绝访问: ${clientIP}`);
61
+ return res.status(403).json({
62
+ error: '禁止访问',
63
+ message: '您的 IP 不在白名单中'
64
+ });
65
+ }
66
+ next();
67
+ };
68
+ }
69
+ // ===================== CORS 配置 =====================
70
+ /**
71
+ * 动态 CORS 配置
72
+ */
73
+ function createCorsOptions(allowedOrigins) {
74
+ return {
75
+ origin: (origin, callback) => {
76
+ // 允许没有 origin 的请求(如移动 APP、Postman)
77
+ if (!origin)
78
+ return callback(null, true);
79
+ // 2026-08-13 kimi 打磨 (xiaomu 浏览器 500 根因): 同源/本机/局域网来源一律放行.
80
+ // 模块脚本会带 Origin — 自己服务的 UI 打自己的 API 必须是同源自通, 与 LAN 免密同一信任模型.
81
+ try {
82
+ const host = new URL(origin).hostname;
83
+ if (host === 'localhost' || host === '127.0.0.1' || host === '::1' || host === '[::1]' ||
84
+ host.startsWith('192.168.') || host.startsWith('10.') || /^172\.(1[6-9]|2\d|3[01])\./.test(host) ||
85
+ host.startsWith('fe80:') || host.startsWith('240') // 链路本地 + 国内公网 v6 段 (240e/2408/2409 等)
86
+ ) {
87
+ return callback(null, true);
88
+ }
89
+ }
90
+ catch { /* 畸形 origin 继续走列表判断 */ }
91
+ // 空配置 fallback (baobei 15442): 没配 allowedOrigins 时放行, 不默默拒绝所有 (开发模式).
92
+ // 生产部署必须显式配 ALLOWED_ORIGINS (或依赖上面的 LAN 放行).
93
+ if (allowedOrigins.length === 0) {
94
+ console.warn('[CORS] ALLOWED_ORIGINS 为空, 放行所有来源 (开发模式, 生产请显式配置)');
95
+ return callback(null, true);
96
+ }
97
+ // 检查是否在允许列表
98
+ const isAllowed = allowedOrigins.some(allowedOrigin => {
99
+ if (allowedOrigin.startsWith('regex:')) {
100
+ // 正则表达式匹配
101
+ const pattern = allowedOrigin.replace('regex:', '');
102
+ return new RegExp(pattern).test(origin);
103
+ }
104
+ return allowedOrigin === origin;
105
+ });
106
+ if (isAllowed) {
107
+ callback(null, true);
108
+ }
109
+ else {
110
+ console.warn(`[CORS] 拒绝来源: ${origin}`);
111
+ callback(new Error('不允许的来源'));
112
+ }
113
+ },
114
+ credentials: true,
115
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
116
+ allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
117
+ };
118
+ }
119
+ // ===================== 请求审计日志 =====================
120
+ const auditLogFile = path_1.default.join(__dirname, '../../logs/audit.log');
121
+ /**
122
+ * 确保日志目录存在
123
+ */
124
+ function ensureLogDir() {
125
+ const logDir = path_1.default.dirname(auditLogFile);
126
+ if (!fs_1.default.existsSync(logDir)) {
127
+ fs_1.default.mkdirSync(logDir, { recursive: true });
128
+ }
129
+ }
130
+ /**
131
+ * 审计日志中间件
132
+ */
133
+ function auditLog() {
134
+ ensureLogDir();
135
+ return (req, res, next) => {
136
+ const startTime = Date.now();
137
+ // 记录响应完成
138
+ res.on('finish', () => {
139
+ const log = {
140
+ timestamp: new Date().toISOString(),
141
+ method: req.method,
142
+ path: req.path,
143
+ query: req.query,
144
+ ip: req.ip || req.connection.remoteAddress,
145
+ userAgent: req.get('user-agent'),
146
+ statusCode: res.statusCode,
147
+ responseTime: Date.now() - startTime,
148
+ userId: req.user?.walletAddress || 'anonymous',
149
+ };
150
+ // 写入日志文件
151
+ const logLine = JSON.stringify(log) + '\n';
152
+ fs_1.default.appendFile(auditLogFile, logLine, (err) => {
153
+ if (err)
154
+ console.error('[Audit] 写入日志失败:', err);
155
+ });
156
+ // 控制台输出(可选)
157
+ if (process.env.LOG_LEVEL === 'debug') {
158
+ console.log('[Audit]', log.method, log.path, log.statusCode, `${log.responseTime}ms`);
159
+ }
160
+ });
161
+ next();
162
+ };
163
+ }
164
+ // ===================== 安全头部 =====================
165
+ /**
166
+ * 安全头部中间件
167
+ */
168
+ function securityHeaders() {
169
+ return (req, res, next) => {
170
+ // 防止 XSS 攻击
171
+ res.setHeader('X-XSS-Protection', '1; mode=block');
172
+ // 防止 MIME 类型嗅探
173
+ res.setHeader('X-Content-Type-Options', 'nosniff');
174
+ // 防止点击劫持
175
+ res.setHeader('X-Frame-Options', 'DENY');
176
+ // 内容安全策略 (baobei 15442: 扩 script-src/style-src 让 vue-i18n runtime 模板编译能跑)
177
+ // 治标: Vite production bundle 用 runtime 编译 (new Function), 需要 unsafe-eval; 真修是前端 runtime-only (见 baobei 清单)
178
+ res.setHeader('Content-Security-Policy', "default-src 'self'; " +
179
+ "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " +
180
+ "style-src 'self' 'unsafe-inline'; " +
181
+ "img-src 'self' data: https:; " +
182
+ "font-src 'self' data:; " +
183
+ "connect-src 'self' ws: wss: https:; " +
184
+ "object-src 'none'; base-uri 'self'; frame-ancestors 'none'");
185
+ // 隐藏服务器信息
186
+ res.removeHeader('X-Powered-By');
187
+ next();
188
+ };
189
+ }
190
+ // ===================== 请求大小限制 =====================
191
+ /**
192
+ * 请求体大小限制
193
+ */
194
+ exports.requestSizeLimit = {
195
+ // 950KB 图片压缩阈值还要叠加 base64/JSON 字段开销,1MB 会在边界误伤正常进件。
196
+ json: { limit: '2mb' }, // JSON 请求体最大 2MB
197
+ urlencoded: { limit: '1mb', extended: true }, // URL 编码请求体最大 1MB
198
+ };
199
+ // ===================== 环境变量验证 =====================
200
+ /**
201
+ * 验证必需的环境变量
202
+ */
203
+ function validateEnv() {
204
+ const required = ['JWT_SECRET'];
205
+ const missing = required.filter(key => !process.env[key]);
206
+ if (missing.length > 0) {
207
+ console.error('❌ 缺少必需的环境变量:', missing.join(', '));
208
+ console.error('请创建 .env 文件并设置这些变量');
209
+ process.exit(1);
210
+ }
211
+ // 检查是否使用默认 JWT 密钥
212
+ if (process.env.JWT_SECRET === 'trustchain-secret-key-2026') {
213
+ console.warn('⚠️ 警告: 使用默认 JWT 密钥不安全!');
214
+ console.warn('⚠️ 请在 .env 文件中设置 JWT_SECRET');
215
+ }
216
+ console.log('✅ 环境变量验证通过');
217
+ }
217
218
  //# sourceMappingURL=security.js.map