Files
opsxshell/test/services/crypto.test.ts
T
Logan.Li 514d62644e 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
2026-04-22 11:15:41 +08:00

96 lines
3.4 KiB
TypeScript

/**
* 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')
})
})
})