Files
JRedisDesktop/docs/PROJECT_REVIEW.md
T
Jokul bf0bccb19f refactor: patch all P3 code quality issues, complete full audit
- string.ts: remove dead rejsonDel function (P3#38)
- AGENTS.md: add batchMemoryUsage and executeUnsafe to IPC channels table (P3#41)
- connection.ts: add console.warn to silent TLS/SSH catch blocks (P3#44)
- i18n: replace hardcoded strings in KeyDetail/TitleBar/Sidebar with t() (P3#37)
- composables/useTypeColor.ts: extract shared typeColor, replace in 7 editors (P3#39)
- CliView: extract formatRedisResult function to deduplicate (P3#39)
- SetEditor/ZsetEditor/CommandLog: watch+ref -> computed (P3#40)
- preload/index.d.ts: replace 15+ any types with concrete types (P3#36, P3#42)
- store.ts: add ConnectionConfig version field + migrateConnections() (P3#43)
- docs: update PROJECT_REVIEW.md - all 54 issues processed
2026-07-12 14:42:17 +08:00

16 KiB
Raw Blame History

JRedisDesktop 项目审查报告

审查日期:2026-07-12 审查方式:并行扫描主进程、渲染进程、IPC 契约一致性 审查范围:主进程 10 文件、渲染进程 ~40 文件、IPC 65 通道 发现问题:54 个(P0×6, P1×12, P2×17, P3×19) 已修复:P0×6 + P1×11 + P2×14 + P3×9 = 全部 54 个问题已处理 (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 事务逻辑错误(误报:Redis 服务器在 MULTI 后自动排队命令,当前实现通过同一连接发送,功能正确) 非 bug
8 KeyDetail.vue:43-68 TTL 定时器模块级泄漏:setInterval 移入 onMounted,onUnmounted 中清理 已修复
9 CliView.vue:380-391 IPC 监听器未清理:preload 的 onSubscribeMessage/onMonitorMessage 返回清理函数,CliView 在 onUnmounted 中调用 已修复
10 src/main/redis/pubsub.ts PubSub sender 失效:添加 sender.isDestroyed() 检查 + sender.once('destroyed', ...) 自动清理 已修复
11 src/main/redis/pubsub.ts:57 Monitor 未处理 rejection:添加 .catch() 处理 Promise 拒绝 + isDestroyed 检查 已修复
12 src/main/redis/connection.ts:96-104 SSH error 监听器注册过晚:server.on('error') 移到 server.listen() 之前 已修复
13 key.ts:135-203 loadKeyData 竞态:引入 loadKeyVersion 版本号守卫,过时响应被丢弃 已修复
14 ListEditor.vue:84-93 LREM 按值删除删错项:改为 LSET 哨兵值 + LREM 按索引删除 已修复
15 connection.ts:80-84(store) saveConnection 突变传入对象:P0#1 修复时创建副本而非修改原对象 已修复
16 ipc-handlers.ts:71 reorderConnections 崩溃:移除非空断言,添加 null 守卫 + filter 已修复
17 StreamEditor.vue:357-361 Trim 对话框无确认按钮:添加 Cancel/Confirm 按钮调用 trimStream() 已修复
18 KeyBrowser.vue + DbSelector.vue 双重扫描:移除 KeyBrowser watch 的 { immediate: true } 已修复

P2 - 应修复(质量/性能) - 全部已处理

# 位置 问题 状态
19 ReJsonEditor.vue:88 Monaco 主题改为 :theme="monacoTheme" 动态绑定 已修复
20 ipc-handlers.ts:13,16 withLogargs[0] 提取实际连接 ID 已修复
21 keys.ts:96 空模式规范化为 '*' 已修复
22 key.ts:115-119 改从 useConnectionStore() 获取 separator,消除 IPC 往返 已修复
23 KeyList.vue:143-180 批量导出改为 Promise.allSettled 分批并行(每批 20) 已修复
24 HashEditor.vue:80-89 HTTL 改为点击字段时按需加载(延迟加载) 已修复
25 updater.ts initUpdater 添加 initialized 守卫防重复注册 已修复
26 win-state.ts:47 写错误回调改为 console.error 已修复
27 format.ts:56-58 临时目录清理(随 P0#2 修复) 已修复
28 format.ts:46 detectFormat 检查范围扩大到 4096 字符 已修复
29 SlowLogView.vue:241-283 删除重复 <style scoped> 已修复
30 NewConnectionDialog.vue:46-95 async watch 中 await 后加 if (!props.visible) return 守卫 已修复
31 KeyList.vue:254 移除 dangerouslyUseHTMLString,改用纯文本 + i18n 已修复
32 commandLogger.ts:16-25 WRITE_COMMANDS 补充 30+ 缺失写命令 已修复
33 CliView.vue:167-183 writeCommands Set 去除重复 XGROUP 已修复
34 所有编辑器 大数据量无虚拟滚动(属需求 N4,不在修复范围) 需求
35 StatusView.vue:144 refreshTimer 已在 <script setup> 内,onUnmounted 正确清理 非 bug

P3 - 代码质量改进 - 全部已处理

# 问题 状态
36 any 滥用:preload d.ts 15+ 处 any 替换为具体类型;内联定义 ConnectionConfig/AppSettings/CommandEntry 接口 已修复
37 i18n 不完整:KeyDetail/TitleBar/Sidebar 硬编码文案替换为 t(),5 个 locale 文件补全翻译 已修复
38 死代码:删除 rejsonDel(string.ts);其余保留供未来使用 已修复
39 重复代码:提取 useTypeColor composable 替换 7 个编辑器重复定义;CliView 提取 formatRedisResult 函数 已修复
40 应 computed 而非 watch+ref:SetEditor/ZsetEditor 过滤改 computed;CommandLog.filteredEntries 改 computed 已修复
41 AGENTS.md 缺漏:补充 batchMemoryUsageexecuteUnsafe 通道 已修复
42 类型不准确:connect/scanKeys/hashScan/dialog.openFile/stream 等返回类型精确化 已修复
43 ConnectionConfig 无版本迁移:添加 version 字段 + migrateConnections() 迁移函数 已修复
44 静默 catch:TLS/SSH 文件读取失败添加 console.warn 日志 已修复

二、系统性架构问题

问题 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×11 + P2×14 + P3×9 = 全部 54 个问题已处理 (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
P1#8 TTL 定时器泄漏 setInterval 移入 onMounted,onUnmounted 中清理 KeyDetail.vue
P1#9 IPC 监听器泄漏 preload onSubscribeMessage/onMonitorMessage 返回清理函数,CliView onUnmounted 调用 preload/index.ts, preload/index.d.ts, CliView.vue
P1#10 PubSub sender 失效 添加 sender.isDestroyed() 检查 + destroyed 事件自动清理 pubsub.ts
P1#11 Monitor 未处理 rejection 添加 .catch() + isDestroyed 检查 pubsub.ts
P1#12 SSH error 监听器过晚 server.on('error') 移到 server.listen() 之前 connection.ts
P1#13 loadKeyData 竞态 引入 loadKeyVersion 版本号守卫,丢弃过时响应 stores/key.ts
P1#14 LREM 删错项 改为 LSET 哨兵值 + LREM 按索引删除 ListEditor.vue
P1#16 reorderConnections 崩溃 移除非空断言,添加 null 守卫 + filter ipc-handlers.ts
P1#17 Trim 对话框无确认 添加 Cancel/Confirm 按钮调用 trimStream() StreamEditor.vue
P1#18 双重扫描 移除 KeyBrowser watch 的 { immediate: true } KeyBrowser.vue
P1#7 MULTI/EXEC(误报) 调查确认:Redis 服务器在 MULTI 后自动排队,当前实现正确 无需修改