feat(i18n): add multi-language support (ja/ko/vi/ru/zh-TW) with system auto-detection
- Extend AppLanguage to 7 locales: zh-CN, zh-TW, en, ja, ko, vi, ru - Auto-detect system language via navigator.languages; fallback to English - Add BCP47 locale mapping for date formatting and sorting - Create 50 translation JSON files (5 languages × 10 namespaces, 1137 keys each) - Update language selector with native language names - Extend locale key parity test to cover all 7 languages (70 assertions) - Add VNC/RDP desktop, serial terminal, AI agent, port forwarding, and SFTP features - Add credential encryption, host metrics, session backup crypto, and zmodem bridge - Update Rust backend: desktop services, host metrics, SSH/SFTP enhancements
This commit is contained in:
1 parent
fea6d8db04
commit
b0d0e3a5f3
301 files changed
+28002
-2705
No files matched your search
+30
-12
@@ -2,25 +2,27 @@
|
||||
|
||||
## 产品边界
|
||||
|
||||
OpsXShell 是轻量原生的 SSH/SFTP 运维终端,核心范围是连接、终端、文件传输、端口转发、代理、串口和多会话操作。审计、录像、审批和堡垒机能力不在客户端范围内。
|
||||
OpsXShell 是轻量原生的运维终端,核心范围是连接、终端、文件传输、端口转发、代理、RDP / VNC 远程桌面、串口和多会话操作。审计、录像、审批和堡垒机能力不在客户端范围内。
|
||||
|
||||
## 目录与职责
|
||||
|
||||
```text
|
||||
src/ React 界面、工作区和 Zustand 状态
|
||||
src/i18n/ 界面文案(zh-CN / en)与 locale 检测
|
||||
src/platform/ Tauri command/event 适配层
|
||||
shared/types/ 渲染层 TypeScript 契约
|
||||
src-tauri/src/commands/ 参数边界和统一响应
|
||||
src-tauri/src/domain/ Rust 领域模型
|
||||
src-tauri/src/services/ SSH、SFTP、隧道、PTY、串口、AI、存储和安全策略
|
||||
src-tauri/src/services/ SSH、SFTP、隧道、PTY、串口、桌面、AI、存储和安全策略
|
||||
```
|
||||
|
||||
React 不直接访问 SSH、文件系统或加密实现。Rust 服务持有连接、Shell、SFTP 和串口资源,渲染层只保存资源 ID 与界面状态。新增原生接口时必须同步更新:
|
||||
React 不直接访问 SSH、文件系统或加密实现。Rust 服务持有连接、Shell、SFTP、串口和桌面会话资源,渲染层只保存资源 ID 与界面状态。新增原生接口时必须同步更新:
|
||||
|
||||
1. Rust command 和 `src-tauri/src/lib.rs` 注册
|
||||
2. `src/desktop.d.ts` 类型契约
|
||||
3. `src/platform/desktop.ts` 适配实现
|
||||
3. 对应 `src/platform/*.ts` 适配实现(通用能力走 `desktop.ts`,RDP / VNC 走 `rdp.ts` / `vnc.ts`)
|
||||
4. `test/setup.ts` 测试替身
|
||||
5. 若有用户可见文案:同步 `src/i18n/locales/{zh-CN,en}/` 并保证 key 对齐
|
||||
|
||||
Rust SSH 服务保留 `ssh.rs` 作为连接与 Shell 门面,已将独立边界拆出:
|
||||
|
||||
@@ -34,13 +36,18 @@ services/
|
||||
│ ├── path.rs 本机路径展开
|
||||
│ └── sftp.rs 远程文件系统与断点传输
|
||||
├── tunnel.rs TunnelManager 与启动/停止编排
|
||||
└── tunnel/
|
||||
├── model.rs 运行实例、计数器和取消令牌
|
||||
├── socks5.rs SOCKS5 服务端协议
|
||||
└── relay.rs TCP/libssh2 双向流转发
|
||||
├── tunnel/
|
||||
│ ├── model.rs 运行实例、计数器和取消令牌
|
||||
│ ├── socks5.rs SOCKS5 服务端协议
|
||||
│ └── relay.rs TCP/libssh2 双向流转发
|
||||
└── desktop/
|
||||
├── rdp.rs / rdp_engine.rs IronRDP 会话与帧
|
||||
├── vnc.rs / vnc_engine.rs RFB 会话与帧
|
||||
├── cliprdr_backend.rs RDP 剪贴板
|
||||
└── rdpdr_fs.rs RDP 共享盘
|
||||
```
|
||||
|
||||
模块化只约束内部职责,不引入插件框架,也不把 libssh2 资源暴露到 command 层。后续 connection/shell 拆分继续保持现有 Tauri command 契约不变。
|
||||
模块化只约束内部职责,不引入插件框架,也不把 libssh2 或桌面协议引擎资源暴露到 command 层。后续 connection/shell 拆分继续保持现有 Tauri command 契约不变。
|
||||
|
||||
## 原生服务
|
||||
|
||||
@@ -50,12 +57,15 @@ services/
|
||||
| HTTP/SOCKS5 连接代理 | Rust TCP 握手后交给 libssh2 |
|
||||
| ProxyJump | libssh2 direct-tcpip + loopback relay,最多 8 跳 |
|
||||
| 本地/远程/动态转发 | libssh2 channel + Rust TCP relay |
|
||||
| RDP | IronRDP(帧 / 输入 / Cliprdr / RDPDR) |
|
||||
| VNC | `vnc-rs` RFB |
|
||||
| 本地终端 | `portable-pty` |
|
||||
| 串口 | `serialport` |
|
||||
| 会话与设置 | 应用数据目录内原子写入 JSON |
|
||||
| 凭据 | AES-256-GCM + `~/.opsxshsell/master.key` |
|
||||
| 凭据 | AES-256-GCM + `~/.opsxshell/master.key` |
|
||||
| 主机信任 | OpenSSH `~/.ssh/known_hosts` |
|
||||
| 终端 AI | Rust `reqwest` + OpenAI/Anthropic 兼容协议 |
|
||||
| 界面语言 | i18next;zh-CN / en,首启按系统语言检测 |
|
||||
|
||||
## SSH Agent CLI 边界
|
||||
|
||||
@@ -94,13 +104,21 @@ XTerm 当前焦点分屏
|
||||
|
||||
转发规则和运行实例是两种不同状态:
|
||||
|
||||
- `ForwardRule` 由 React 管理并按保存会话 ID 写入设置,只保存类型、端口和目标。
|
||||
- `ForwardRule` 由 React 管理并按会话 / 标签 / 连接维度写入设置,只保存类型、端口和目标。
|
||||
- `ForwardStatus` 由 Rust `TunnelManager` 管理,只在当前进程有效,包含监听端口、开始时间、连接数和流量。
|
||||
- 每个运行实例有唯一 `forwardId` 和取消标志。停止、删除正在运行的规则或断开 SSH 连接时,Rust 必须关闭真实 Listener。
|
||||
- 规则支持编辑和复制。复制只产生新的规则 ID,不复制运行态;运行中的规则必须先停止真实 Listener 才能编辑。
|
||||
- 应用重启后不得根据上次 UI 状态显示“运行中”,必须以 `ssh_forward_list` 返回的原生状态为准。
|
||||
- 状态栏「转发」打开右侧抽屉:动态 SOCKS5 固定 `127.0.0.1:1080`(每台 SSH 主机一条),本地 / 远程规则可列表启停;右键状态栏项复制 `socks5://127.0.0.1:1080`。
|
||||
|
||||
当前动态 SOCKS5 默认仅绑定 `127.0.0.1`,不对局域网暴露。客户端仅支持 SOCKS5 CONNECT 和无认证方式。
|
||||
当前动态 SOCKS5 默认仅绑定 `127.0.0.1`,不对局域网暴露。客户端仅支持 SOCKS5 CONNECT 和无认证方式。流量经当前 SSH 服务器出口 IP 访问外网。
|
||||
|
||||
## 远程桌面生命周期
|
||||
|
||||
- RDP / VNC 仅在 Tauri 原生应用中可用;浏览器预览不得显示为可连接。
|
||||
- 会话运行态只存在原生内存;Canvas 帧与输入经 Tauri 事件传递;断开即取消 worker。
|
||||
- RDP 可选剪贴板与共享盘(本机下载目录映射);VNC 剪贴板按 UTF-8 发送。
|
||||
- 桌面会话不参与批量命令与终端广播。
|
||||
|
||||
## SFTP 写入策略
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ npm run acceptance:full
|
||||
- SSH 连接关闭后的状态回收
|
||||
- HTTP CONNECT、SOCKS5 和断点复制
|
||||
- 转发规则不持久化运行状态,复制产生新 ID;原生隧道可启动、查询、停止并在 SSH 断开时清理
|
||||
- 状态栏「转发」抽屉启停动态 `127.0.0.1:1080`,右键复制 SOCKS 地址;每台 SSH 主机仅一条动态规则
|
||||
- i18n:zh-CN / en 的 namespace key 对齐(`test/i18n/localeKeys.test.ts`)
|
||||
- RDP / VNC 仅原生可用;非 Tauri 环境不得显示为可连接;桌面会话不参与批量命令
|
||||
- SFTP 本地/远程路径参数方向、原生路径上传、选中文件下载、双栏双向拖拽、目录落点、远程文本读写和错误反馈
|
||||
- 终端分屏、剪贴板、快捷键、分片 UTF-8 解码、高输出背压和异步输入错误
|
||||
- `ssh://` 安全解析、冷启动队列、IPv6 格式和快速连接预填充
|
||||
@@ -96,12 +99,21 @@ cargo test --manifest-path src-tauri/Cargo.toml \
|
||||
|
||||
Rust 单元测试会用随机本地端口验证动态监听器的唯一 ID、运行查询、重复启动拒绝和真实停止。实机验收还必须包含:
|
||||
|
||||
1. 在保存会话上一键启动 `127.0.0.1:1080`,用 `curl --proxy socks5h://127.0.0.1:1080 https://example.com` 验证。
|
||||
2. 确认连接数和流量会变化,复制出的代理地址正确。
|
||||
3. 停止后确认端口无法再连接,不能只检查 UI 颜色。
|
||||
4. 重启应用后规则仍在,但状态必须为未运行。
|
||||
5. 断开 SSH 主连接后,关联的本地、远程和 SOCKS5 监听器全部清理。
|
||||
6. 复制规则后确认新规则 ID 独立且状态为未运行;编辑运行中的规则必须先停止原 Listener。
|
||||
1. 在状态栏打开「转发」抽屉,启动 `127.0.0.1:1080`,用 `curl --proxy socks5h://127.0.0.1:1080 https://example.com` 验证(出口 IP 应为当前 SSH 服务器)。
|
||||
2. 右键状态栏「转发」复制 `socks5://127.0.0.1:1080`,确认剪贴板正确。
|
||||
3. 确认连接数和流量会变化(若界面展示统计)。
|
||||
4. 停止后确认端口无法再连接,不能只检查 UI 颜色。
|
||||
5. 重启应用后规则仍在,但状态必须为未运行。
|
||||
6. 断开 SSH 主连接后,关联的本地、远程和 SOCKS5 监听器全部清理。
|
||||
7. 复制规则后确认新规则 ID 独立且状态为未运行;编辑运行中的规则必须先停止原 Listener。
|
||||
8. 同一 SSH 主机不得出现第二条动态规则。
|
||||
|
||||
## 远程桌面验收
|
||||
|
||||
1. 非 Tauri / 浏览器预览中,RDP / VNC 不得表现为可连接。
|
||||
2. 原生应用中分别建立 RDP、VNC 会话,确认画面、键盘鼠标与断开清理。
|
||||
3. RDP:验证剪贴板同步与共享盘放入/打开本机下载目录。
|
||||
4. 批量命令入口不得包含桌面会话。
|
||||
|
||||
## ssh:// 验收
|
||||
|
||||
@@ -116,4 +128,4 @@ open -a OpsXShell 'ssh://root@opsbase.cn:55555'
|
||||
|
||||
## 发版验收
|
||||
|
||||
候选发布必须在目标系统完成:安装、首次启动、窗口操作、SSH、SFTP、代理、跳板、串口枚举、休眠恢复、卸载及重新安装。CI 构建成功不能替代 Windows 或 macOS 实机验收。
|
||||
候选发布必须在目标系统完成:安装、首次启动、窗口操作、SSH、SFTP、代理、跳板、端口转发、RDP/VNC、串口枚举、休眠恢复、卸载及重新安装。CI 构建成功不能替代 Windows 或 macOS 实机验收。
|
||||
+18
-5
@@ -27,20 +27,29 @@ ssh://root@opsbase.cn:55555
|
||||
|
||||
## 端口转发与 SOCKS5
|
||||
|
||||
端口转发页面支持本地转发、远程转发和动态 SOCKS5。普通用户可直接点击“启动 SOCKS5”,默认创建:
|
||||
SSH 连接后,可在状态栏点击「转发」打开右侧抽屉,管理本地转发、远程转发和动态 SOCKS5。动态转发使本机成为 SOCKS5 代理,流量经当前 SSH 服务器出口 IP 访问外网。默认地址:
|
||||
|
||||
```text
|
||||
socks5://127.0.0.1:1080
|
||||
```
|
||||
|
||||
- 启动后卡片显示真实绑定端口、活动连接数和上下行流量。
|
||||
- 复制按钮复制 `socks5://127.0.0.1:<端口>`。需要远程 DNS 解析的命令行工具应使用 `socks5h`,例如 `curl --proxy socks5h://127.0.0.1:1080 https://example.com`。
|
||||
- “停止”会关闭 Rust Listener,不是只改界面图标。删除运行中的规则会先停止再删除。
|
||||
- 动态转发每台 SSH 主机仅一条,端口固定 `1080`;在抽屉中直接启停。
|
||||
- 状态栏「转发」右键可复制 `socks5://127.0.0.1:1080`。需要远程 DNS 解析的命令行工具应使用 `socks5h`,例如 `curl --proxy socks5h://127.0.0.1:1080 https://example.com`。
|
||||
- 本地 / 远程规则在抽屉列表中添加、启停和删除;“停止”会关闭 Rust Listener,不是只改界面图标。
|
||||
- “复制规则”会创建独立的新规则,便于只修改端口或目标;不会复制原规则的运行状态。
|
||||
- 运行中的规则选择“编辑”时,会先提示停止真实监听,再允许保存新配置。
|
||||
- 保存的是规则,不是“运行中”状态;应用重启后需要用户再次启动。
|
||||
- SOCKS5 默认仅监听本机,当前不提供局域网开放和客户端密码认证。
|
||||
|
||||
## 远程桌面(RDP / VNC)
|
||||
|
||||
欢迎页或会话入口可打开 RDP / VNC 连接对话框(仅原生桌面应用):
|
||||
|
||||
- RDP:填写主机、端口、用户名、密码与可选域名;原生 IronRDP 引擎,支持剪贴板同步与共享盘(本机下载目录对应远端共享盘)。
|
||||
- VNC:填写主机、端口与可选密码;原生 RFB 引擎,剪贴板按 UTF-8 发送。
|
||||
- 连接后在独立标签中显示画面;工具栏可粘贴本机剪贴板、放入共享盘文件(RDP)或断开。
|
||||
- 桌面会话不参与批量命令与终端广播。
|
||||
|
||||
## 导入 OpenSSH 配置
|
||||
|
||||
从应用菜单选择“文件 > 导入会话”,打开 `~/.ssh/config`。当前解析以下常用字段:
|
||||
@@ -111,12 +120,16 @@ SFTP 使用双栏文件管理器。上传和下载先写入 `.opsx-part` 临时
|
||||
|
||||
云模型会把所选上下文发给相应供应商;有严格数据边界时使用本机 Ollama,并仅在可信本机上开启 HTTP。OpsXShell 不保存 AI 对话、终端上下文或长期记忆。
|
||||
|
||||
## 界面语言
|
||||
|
||||
设置中可切换中文(zh-CN)与 English。首次启动按系统语言自动选择;验收与单元测试默认中文文案。
|
||||
|
||||
## 本地数据
|
||||
|
||||
设置“关于”页会显示当前系统的实际数据路径。会话密码、私钥口令、代理密码和大模型 API Key 使用 AES-256-GCM 加密。主密钥位于:
|
||||
|
||||
```text
|
||||
~/.opsxshsell/master.key
|
||||
~/.opsxshell/master.key
|
||||
```
|
||||
|
||||
Unix 系统中目录权限为 `0700`,密钥文件权限为 `0600`。主机信任记录使用 `~/.ssh/known_hosts`。
|
||||
Reference in new issue
Block a user