fix: 修复多个安全缺陷和功能问题

- 移除加密相关代码(服务端和所有客户端)
- 修复 JWT 验证未检查签名算法的问题
- 修复重置密码使用不安全随机数的问题
- 实现 Logout 服务端失效机制
- 修复历史版本对比 diff 颜色标记错误
- 修复占位符解析循环引用风险
- 添加用户禁用状态检查
- 更新 bug 清单文档
This commit is contained in:
2026-03-10 21:07:22 +08:00
parent f41d53da41
commit 932db9fbdc
27 changed files with 292 additions and 721 deletions
+2 -21
View File
@@ -1,7 +1,6 @@
import { Config } from './config.js';
import { Cache } from './cache.js';
import { Listener } from './listener.js';
import { decryptConfig } from './crypto.js';
export class ConfigClient {
constructor(config) {
@@ -9,8 +8,6 @@ export class ConfigClient {
this.cache = new Cache(config.cacheDir);
this.listener = new Listener();
this.configs = {};
this.secret = '';
this.globalSecret = '';
this.lastTime = 0;
this.started = false;
this.timer = null;
@@ -86,14 +83,6 @@ export class ConfigClient {
throw new Error(`server error: ${data.msg || 'unknown'}`);
}
const secret = data['kenaito.config.encrypt-secret'];
if (secret) {
this.secret = secret;
}
const globalSecret = data['kenaito.config.global-encrypt-secret'];
if (globalSecret) {
this.globalSecret = globalSecret;
}
const ts = data['latest.fetch.timestamp'];
if (ts) {
this.lastTime = parseInt(ts, 10);
@@ -140,7 +129,7 @@ export class ConfigClient {
const changed = {};
for (const [k, v] of Object.entries(changedData)) {
changed[k] = this.tryDecrypt(v);
changed[k] = v;
}
Object.assign(this.configs, changed);
@@ -156,17 +145,9 @@ export class ConfigClient {
if (typeof v !== 'string') {
continue;
}
this.configs[k] = this.tryDecrypt(v);
this.configs[k] = v;
}
}
tryDecrypt(value) {
let decrypted = decryptConfig(this.secret, value);
if (decrypted === value && this.globalSecret) {
decrypted = decryptConfig(this.globalSecret, value);
}
return decrypted;
}
}
export { Config } from './config.js';
-24
View File
@@ -1,24 +0,0 @@
import crypto from 'node:crypto';
const CRYPT_PREFIX = '{Cipher}';
export function decryptConfig(secret, data) {
if (!data.startsWith(CRYPT_PREFIX)) {
return data;
}
const encrypted = data.slice(CRYPT_PREFIX.length);
return decryptWithAES(secret, encrypted);
}
export function decryptWithAES(key, data) {
const md5Hash = crypto.createHash('md5').update(key).digest('hex');
const aesKey = md5Hash.slice(16);
const cipherText = Buffer.from(data, 'base64');
const iv = Buffer.alloc(16, 0);
const decipher = crypto.createDecipheriv('aes-128-cbc', aesKey, iv);
decipher.setAutoPadding(false);
let plainText = Buffer.concat([decipher.update(cipherText), decipher.final()]);
const padding = plainText[plainText.length - 1];
plainText = plainText.slice(0, plainText.length - padding);
return plainText.toString('utf8');
}