Files
JRedisDesktop/docs/PROJECT_REVIEW.md
T
Jokul 9d73ff019c fix(security): patch all P0 vulnerabilities from project review
- credential: encrypt/decrypt now throw when safeStorage unavailable instead of base64 fallback
- ipc-handlers: encrypt auth/sshPassword/sshPassphrase before storing, decrypt on read (avoid mutation)
- ipc-handlers: block FLUSHALL/FLUSHDB/SHUTDOWN/DEBUG in redis:execute, add redis:executeUnsafe for CLI
- format: whitelist allowed external formatters (xxd/jq/python3/python/php/column), clean up tmpDir
- connection: clearTimeout on ready/error paths to fix timeout race in Sentinel/Cluster/normal modes
- index: add app.on('will-quit') to disconnectAll + stopAllPubSubClients on exit
- pubsub: add stopAllPubSubClients() to clean up all sub/monitor connections
- docs: add PROJECT_REVIEW.md with full audit report and fix status
2026-07-12 14:13:44 +08:00

14 KiB
Raw Blame History

JRedisDesktop 项目审查报告

审查日期:2026-07-12 审查方式:并行扫描主进程、渲染进程、IPC 契约一致性 审查范围:主进程 10 文件、渲染进程 ~40 文件、IPC 65 通道 发现问题:54 个(P0×6, P1×12, P2×17, P3×19) 已修复:P0×6 全部修复 (2026-07-12) 可开发需求:26 项(高优先级 6,中 11,低 9)


目录


一、缺陷清单(按优先级)

P0 - 必须立即修复(安全/数据丢失) — 全部已修复

# 位置 问题 状态
1 src/main/ipc-handlers.ts:55-62 凭据明文存储:storage:saveConnection 加密 auth/sshPassword/sshPassphrase (enc: 前缀);storage:getConnections 读取时解密 已修复
2 src/main/redis/format.ts:51-79 命令注入:新增 ALLOWED_FORMATTERS 白名单(xxd/jq/python3/python/php/column),不在白名单则拒绝执行 已修复
3 src/main/ipc-handlers.ts:105-121 无命令白名单:新增 BLOCKED_COMMANDS (FLUSHALL/FLUSHDB/SHUTDOWN/DEBUG);redis:execute 拦截危险命令;新增 redis:executeUnsafe 供 CLI 绕过 已修复
4 src/main/index.ts:67-70 退出无清理:新增 app.on('will-quit') 调用 disconnectAll() + stopAllPubSubClients() 已修复
5 src/main/redis/connection.ts (3处) 超时竞态:Sentinel/Cluster/普通模式的 setTimeout 均保存 timer ID,在 ready/error 路径调用 clearTimeout 已修复
6 src/main/credential.ts:4-5 safeStorage 不可用时回退明文:encrypt/decrypt 在 safeStorage 不可用时抛出错误,decrypt catch 保留 base64 兼容旧数据并加 console.warn 已修复

P1 - 严重 Bug(功能错误)

# 位置 问题
7 CliView.vue:52-101 MULTI/EXEC 事务逻辑错误:事务模式下每条命令仍通过 IPC 单独发送到 Redis,服务器立即执行而非排队。完全破坏事务语义。应本地排队,EXEC 时 pipeline 一次性发送。
8 KeyDetail.vue:43-68 TTL 定时器模块级泄漏:setInterval<script setup> 顶层立即创建,非 onMounted。组件销毁后定时器仍每秒运行访问已卸载响应式数据。
9 CliView.vue:380-391 IPC 监听器未清理:onSubscribeMessage/onMonitorMessageonUnmounted 中未移除。每次切换标签页累积监听器。
10 src/main/redis/pubsub.ts:13,24-31 PubSub sender 失效:存储 WebContents 引用,窗口重载(HMR/导航)后失效,消息静默丢弃。无检测/重建机制。
11 src/main/redis/pubsub.ts:57 Monitor 未处理 rejection:monitor.monitor().then(...).catch(),失败时未处理 Promise 拒绝。
12 src/main/redis/connection.ts:96-104 SSH error 监听器注册过晚:server.listen()server.on('error') 之前,期间错误未捕获。
13 key.ts:135-203 loadKeyData 竞态:快速点击不同 key 时后 resolve 的响应覆盖最新选中 key 的数据。
14 ListEditor.vue:84-93 LREM 按值删除删错项:重复值时删除第一个匹配,非当前选中索引。
15 connection.ts:80-84(store) saveConnection 突变传入对象:直接修改 conn.auth 为加密串,若调用方传响应式对象则 UI 显示加密密码。
16 ipc-handlers.ts:71 reorderConnections 崩溃:非空断言 !,ID 不匹配时 TypeError
17 StreamEditor.vue:357-361 Trim 对话框无确认按钮:打开后只能关闭,无法执行 trim。
18 KeyBrowser.vue + DbSelector.vue 双重扫描:KeyBrowser 的 watch immediate 与 DbSelector 的 onMounted 都调 scanKeys,首次连接扫两次。

P2 - 应修复(质量/性能)

# 位置 问题
19 ReJsonEditor.vue:88 Monaco 主题硬编码 vs-dark,亮色主题下对比度极差。
20 ipc-handlers.ts:13,16 withLog 记录 'current' 而非实际连接 ID,命令日志无用。
21 keys.ts:96 空模式 '' 导致 SCAN 匹配空字符串键,应规范化为 '*'
22 key.ts:115-119 每次扫描都调 getConnections() IPC,连接信息已在 store 中。
23 KeyList.vue:143-180 批量导出串行 DUMP,1000 key = 1000 次 IPC 往返。
24 HashEditor.vue:80-89 逐个字段 HTTL,大 hash 数百次 IPC。
25 updater.ts:15,25,35 重复调用 initUpdateripcMain.handle 抛重复注册错误。
26 win-state.ts:47 写错误空回调静默吞噬。
27 format.ts:56-58 临时目录 mkdtemp 创建后成功路径不清理,/tmp/jrdm-fmt-*/ 累积。
28 format.ts:46 detectFormat 仅检查前 100 字符,前 100 为 ASCII 的二进制值误判为 text。
29 SlowLogView.vue:241-283 重复 <style scoped> 块。
30 NewConnectionDialog.vue:46-95 异步 watch 返回后可能对话框已关闭仍在设状态。
31 KeyList.vue:254 dangerouslyUseHTMLString: true 潜在 XSS(依赖 escapeHtml 完整性)。
32 commandLogger.ts:16-25 WRITE_COMMANDSJSON.SET/JSON.DEL/COPY/RESTORE 等。
33 CliView.vue:167-183 writeCommands Set 含重复 XGROUP 三次。
34 所有编辑器 大数据量无虚拟滚动,数万条记录一次性渲染。
35 StatusView.vue:144 refreshTimer 模块级变量,重新挂载丢引用。

P3 - 代码质量改进

# 问题
36 any 滥用:ipc-handlers.tsconnection.ts(sshConfig/tlsOpts/clusterOptions)、string.tsstream.tspreload/index.d.ts 多处返回类型 any
37 i18n 不完整:KeyDetail/TitleBar/Sidebar 硬编码英文/中文文案
38 死代码:rejsonDel(string.ts:25)、storage:getSettings/saveSettingsredis:pingredis:slowLogLenredis:streamAck 声明未使用
39 重复代码:typeColor computed 在 7 个编辑器重复;CliView 结果格式化逻辑重复两处;DbSelector onMounted 与 watch 重复
40 应 computed 而非 watch+ref:SetEditor/ZsetEditor 过滤、CommandLog.filteredEntries
41 AGENTS.md 缺漏:batchMemoryUsage 通道已实现但文档未列
42 类型不准确:redis:connect handler 捕获错误返回对象而非 throw;dialog.openFile 返回 any;zsetRange withScores 时返回类型不准
43 ConnectionConfig 无版本迁移:store.ts 直接 JSON 存取,字段变更无迁移路径
44 静默 catch:TLS/SSH 文件读取失败静默回退,用户不知密钥未生效

二、系统性架构问题

问题 A:资源生命周期管理完全缺失

表现:连接泄漏(P0#4)、定时器泄漏(P1#8,P2#35)、IPC 监听器泄漏(P1#9)、主题监听器无清理、healthTimers Map 无 dispose、PubSub sender 失效(P1#10)。

根因:无统一的资源注册与清理机制,各组件/store 自行管理,遗忘清理。

架构级方案:引入 Disposable 模式 -- 统一的资源注册表(连接、定时器、监听器、订阅),在窗口/应用生命周期事件统一释放。主进程加 app.on('will-quit')disconnectAll+stopAllPubSub;渲染进程用 tryOnScopeDispose 或统一 composable 管理 setInterval/IPC 监听。

问题 B:安全模型不完整

表现:凭据明文(P0#1)、safeStorage 回退明文(P0#6)、命令注入(P0#2)、无命令白名单(P0#3)、XSS 风险(P2#31)。

根因:安全作为事后补丁而非设计原则,无统一的安全边界。

架构级方案:

  • 凭据:所有敏感字段(auth/sshPassword/sshPassphrase)在 store 层自动加解密,safeStorage 不可用时拒绝存储而非明文回退
  • 命令:redis:execute 加中间件层,非 CLI 视图禁用破坏性命令;customFormat 加白名单
  • 输入:移除 dangerouslyUseHTMLString 或用严格 sanitizer

问题 C:错误处理策略不统一

表现:redis:connect 吞错误返回对象,其他 handler throw;disconnect 无 try/catch;win-state 静默;PubSub Promise 未 await;Monitor 无 catch;TLS/SSH 文件读取静默。

根因:无统一 IPC 错误处理中间件。

架构级方案:所有 ipcMain.handle 包统一 wrapper,自动 try/catch 并以标准错误对象 throw;渲染进程封装 safeInvoke 统一 ElMessage 错误提示。

问题 D:类型安全形同虚设

表现:大量 anyas any、preload d.ts 返回类型 any、ConnectionConfig 无 schema 版本。

架构级方案:定义 Redis 操作的完整类型(替换 ioredis as any);preload d.ts 用泛型精确化返回类型;ConnectionConfig 加 version 字段与迁移函数。

问题 E:性能策略缺失

表现:无虚拟滚动、串行 IPC、重复 IPC 调用、SCAN 全量加载。

架构级方案:编辑器引入 el-table-v2/虚拟列表;批量操作用 pipeline;key.ts 从 store 取连接信息而非重复 IPC。


三、可开发需求清单(按优先级)

高优先级

# 需求 用户价值 复杂度 实现思路
N1 凭据加密加固 修复 P0 安全漏洞,密码不再明文落盘 storage:saveConnection 前 encrypt 敏感字段,getConnections 时 decrypt;safeStorage 不可用拒绝存储
N2 资源生命周期管理器 修复所有泄漏,退出干净释放 主进程 app.on('will-quit') 调清理;渲染进程 useDisposable composable
N3 CLI 事务正确实现 MULTI/EXEC 真正生效 事务模式本地排队,EXEC 时 pipeline 一次性发送
N4 虚拟滚动 数万字段/成员不卡顿 Hash/List/Set/ZsetEditor 用 el-table-v2 或自定义虚拟列表
N5 Stream Consumer Group 完整化 ACK 已实现但未用,消费组可视化不全 StreamEditor 接入 redis:streamAck;加消费组详情面板、pending entries 列表、claim 功能
N6 命令白名单中间件 防误操作 FLUSHALL/SHUTDOWN redis:execute 加危险命令二次确认

中优先级

# 需求 用户价值 复杂度 实现思路
N7 Cluster/Sentinel 支持 生产环境主流部署方式,当前仅单机+SSH connection.ts 已有 cluster 分支需完善;加节点拓扑可视化、failover 操作
N8 ACL 用户管理 Redis 6+ ACL 已普及 新建 ACL 管理视图:用户 CRUD、权限矩阵、ACL WHOAMI/ACL LIST
N9 数据导入导出 迁移/备份场景 导出:RDB/DUMP/JSON 格式;导入:批量 SET/管道;KeyList 已有导出雏形需完善
N10 Function 管理(Redis 7+) 替代 EVAL 的服务端函数 新建 Function 视图:LIST/LOAD/DELETE/调用
N11 大 Key 扫描 生产排障刚需 MEMORY USAGE 扫描已有,扩展为后台任务 + 排序 + 导出报告
N12 Latency Monitor 补充慢日志的延迟诊断 LATENCY HISTORY/LATENCY DOCTOR 视图
N13 PubSub 可视化改进 当前仅 CLI 内嵌,无独立视图 新建 PubSub 视图:频道树、消息流、JSON 高亮、订阅状态
N14 连接分组/标签 连接多了难管理 ConnectionList 加分组折叠、颜色标签、搜索过滤已有可扩展
N15 TTL 实时倒计时优化 修复泄漏 + 加批量设 TTL 移到 onMounted;KeyList 批量设 TTL/过期时间
N16 主题完整适配 ReJsonEditor 主题修复 + Monaco 跟随 Monaco 编辑器 theme 绑定到 monacoTheme 响应式变量
N17 i18n 补全 中/日/韩/德文案完整 扫描硬编码文案替换为 t()

低优先级

# 需求 用户价值 复杂度 实现思路
N18 Key 详情对比 编辑前后 diff StringEditor/HashEditor 加 diff 视图
N19 命令收藏夹 常用命令快速调用 CliView 加收藏侧栏,localStorage 持久化
N20 连接 SSH 跳板机 多跳 SSH 场景 ssh2 隧道级联
N21 慢日志分析图表 趋势可视化 SlowLogView 加 ECharts 时间分布图
N22 快捷键体系完善 当前仅 5 个 加 Ctrl+F 搜索、Ctrl+1~9 切 tab、Ctrl+L 聚焦 CLI
N23 测试体系 当前无测试 Vitest 渲染进程单元测试;主进程 Redis 模块用 ioredis-mock
N24 CI/CD 自动化构建发布 GitHub Actions:lint+typecheck+build 三平台
N25 TypeScript 严格化 类型安全 逐步消除 any,preload d.ts 精确化
N26 错误上报 收集崩溃信息 主进程 crashReporter + 渲染进程 errorHandler

四、修复路线图建议

立即(P0):     [已完成] N1 凭据加密 -> N2 资源管理 -> N6 命令白名单 -> P0#2/5/6
本周(P1):     N3 事务修复 -> P1 定时器/监听器泄漏 -> N5 Stream ACK -> N16 主题
本月(P2):     N4 虚拟滚动 -> N7 Cluster -> N9 导入导出 -> N11 大Key扫描 -> N13 PubSub视图
季度(P3):     N8 ACL -> N10 Function -> N23 测试 -> N25 严格化 -> N24 CI

五、关键数据

  • 审查范围:主进程 10 文件、渲染进程 ~40 文件、IPC 65 通道
  • 发现问题:54 个(P0×6, P1×12, P2×17, P3×19)
  • 已修复:P0×6 + P1×1 = 7 个 (2026-07-12)
  • 安全问题:6 个(P0 全部已修复)
  • 死代码:6 处
  • 可开发需求:26 项(高优先级 6,中 11,低 9)

修复记录 (2026-07-12)

缺陷 修复内容 涉及文件
P0#1 凭据明文 storage:saveConnection 加密敏感字段;getConnections 读取时解密 ipc-handlers.ts
P0#2 命令注入 customFormat 白名单(xxd/jq/python3/python/php/column) format.ts
P0#3 无命令白名单 BLOCKED_COMMANDS 拦截 FLUSHALL/SHUTDOWN/DEBUG;新增 executeUnsafe ipc-handlers.ts, preload/index.ts, preload/index.d.ts, CliView.vue, StatusView.vue
P0#4 退出无清理 app.on('will-quit') 调 disconnectAll + stopAllPubSubClients index.ts, pubsub.ts
P0#5 超时竞态 3处 setTimeout 保存 timer ID,ready/error 路径 clearTimeout connection.ts
P0#6 safeStorage 回退 encrypt/decrypt 在 safeStorage 不可用时抛出错误 credential.ts
P1#15 突变副作用 saveConnection 创建副本而非修改原对象(随 P0#1 修复) ipc-handlers.ts