v2.0.0: 主题系统+SSH私钥解析修复+会话持久化+连接池优化+UI打磨
核心修复:
- ssh-service.ts: 新增 resolvePrivateKey(),将私钥文件路径(~/.ssh/id_rsa)解析为内容后传给 ssh2,
解决 'Cannot parse privateKey: Unsupported key format' 错误
- useTerminalConnection.ts + sessionHelper.ts: 根据 authType 过滤字段,password/agent 认证不再传 privateKey
- sessionStore.ts: addSession() 现在先调用 sessionCreate() 持久化到 SQLite,解决恢复标签'无可用连接信息'问题
- database-service.ts: updateSession() 补充 private_key_path 字段持久化
- SessionDialog.tsx: 默认 username='root'、privateKey='~/.ssh/id_rsa'
UI/UX:
- 语义化主题系统(app-theme.ts),强制深色模式,全局无边框设计
- macOS 标题栏支持双击最大化(window:toggleMaximize IPC)
- macOS 菜单栏('OpsXShell' 应用菜单 + Settings Cmd+,)
- WelcomeView 4卡片布局,移除 Settings 按钮
- TabBar/TabItem 背景色统一(bg-dark-800/900),消除白色边框线
架构优化:
- SFTP 生命周期修复(useSFTP.ts useRef + autoConnectAttempted guard)
- 连接池竞态修复,支持快速多标签连接
- IPC 接口规范化,安全错误处理
- Vite 代码分割优化
质量: lint零错误 | tsc零错误 | build成功 | 49 tests pass
This commit is contained in:
1 parent
37e65be823
commit
514d62644e
77 files changed
+2563
-931
No files matched your search
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Crypto Service Integration Tests
|
||||
* 验证加密/解密核心逻辑的正确性和安全性
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { encrypt, decrypt, encryptAsync, simpleEncrypt, simpleDecrypt } from '../../electron/services/crypto'
|
||||
|
||||
describe('Crypto Service', () => {
|
||||
const testPassword = 'test-password-123'
|
||||
const testData = 'Hello, OpsXShell! 你好,世界!'
|
||||
const testKey = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
|
||||
|
||||
describe('encrypt / decrypt', () => {
|
||||
it('应该能正确加密和解密数据', () => {
|
||||
const encrypted = encrypt(testData, testPassword)
|
||||
expect(encrypted).toBeTruthy()
|
||||
expect(encrypted).toContain(':') // 格式: version:salt:iv:tag:ciphertext
|
||||
|
||||
const decrypted = decrypt(encrypted, testPassword)
|
||||
expect(decrypted).toBe(testData)
|
||||
})
|
||||
|
||||
it('密文应该包含版本标识', () => {
|
||||
const encrypted = encrypt(testData, testPassword)
|
||||
const parts = encrypted.split(':')
|
||||
expect(parts.length).toBe(5)
|
||||
expect(parts[0]).toBe('v1')
|
||||
})
|
||||
|
||||
it('不同密码应该产生不同密文', () => {
|
||||
const encrypted1 = encrypt(testData, testPassword)
|
||||
const encrypted2 = encrypt(testData, 'different-password')
|
||||
expect(encrypted1).not.toBe(encrypted2)
|
||||
})
|
||||
|
||||
it('相同数据多次加密应该产生不同密文(随机 salt/iv)', () => {
|
||||
const encrypted1 = encrypt(testData, testPassword)
|
||||
const encrypted2 = encrypt(testData, testPassword)
|
||||
expect(encrypted1).not.toBe(encrypted2)
|
||||
|
||||
// 但都能正确解密
|
||||
expect(decrypt(encrypted1, testPassword)).toBe(testData)
|
||||
expect(decrypt(encrypted2, testPassword)).toBe(testData)
|
||||
})
|
||||
|
||||
it('错误密码应该抛出异常', () => {
|
||||
const encrypted = encrypt(testData, testPassword)
|
||||
expect(() => decrypt(encrypted, 'wrong-password')).toThrow('Decryption failed')
|
||||
})
|
||||
|
||||
it('应该向后兼容旧格式密文(4部分,无版本标识)', () => {
|
||||
// 构造一个旧格式密文: salt:iv:tag:ciphertext
|
||||
const encrypted = encrypt(testData, testPassword)
|
||||
const parts = encrypted.split(':')
|
||||
const oldFormat = parts.slice(1).join(':') // 去掉版本标识
|
||||
|
||||
expect(decrypt(oldFormat, testPassword)).toBe(testData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('encryptAsync / decrypt', () => {
|
||||
it('异步加密应该产生可解密的结果', async () => {
|
||||
const encrypted = await encryptAsync(testData, testPassword)
|
||||
const decrypted = decrypt(encrypted, testPassword)
|
||||
expect(decrypted).toBe(testData)
|
||||
})
|
||||
|
||||
it('异步加密密文应该包含版本标识', async () => {
|
||||
const encrypted = await encryptAsync(testData, testPassword)
|
||||
const parts = encrypted.split(':')
|
||||
expect(parts.length).toBe(5)
|
||||
expect(parts[0]).toBe('v1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('simpleEncrypt / simpleDecrypt', () => {
|
||||
it('应该能正确加密和解密数据', () => {
|
||||
const encrypted = simpleEncrypt(testData, testKey)
|
||||
expect(encrypted).toBeTruthy()
|
||||
|
||||
const decrypted = simpleDecrypt(encrypted, testKey)
|
||||
expect(decrypted).toBe(testData)
|
||||
})
|
||||
|
||||
it('错误密钥应该抛出异常', () => {
|
||||
const encrypted = simpleEncrypt(testData, testKey)
|
||||
expect(() => simpleDecrypt(encrypted, 'wrong-key')).toThrow('Decryption failed')
|
||||
})
|
||||
|
||||
it('无效密钥长度应该抛出异常', () => {
|
||||
expect(() => simpleEncrypt(testData, 'short')).toThrow('Invalid key length')
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user