feat: v0.3.0 版本 - SSH终端、SFTP、端口转发功能实现

核心功能:
- SSH终端: 密码/密钥认证、XTerm.js终端、多主题配色、IP高亮
- SFTP管理: 双栏文件管理、上传下载、传输队列
- 端口转发: 本地/远程转发、SOCKS5动态代理、规则管理

架构改进:
- 拆分大型组件 (SFTPView/TabBar/Sidebar)
- 添加统一日志和错误处理
- 修复React严格模式下的终端黑屏问题

UI更新:
- 新增端口转发视图
- 更新UI预览文档
- 左侧栏右键菜单支持SFTP快捷打开
This commit is contained in:
Logan.Li committed 2026-04-06 01:20:47 +08:00
1 parent cf1c054381
commit 484d850abd
105 files changed
+25330 -64

No files matched your search

+95
View File
@@ -0,0 +1,95 @@
import crypto from 'crypto'
const ALGORITHM = 'aes-256-gcm'
const KEY_LENGTH = 32
const IV_LENGTH = 16
const TAG_LENGTH = 16
const SALT_LENGTH = 32
const ITERATIONS = 100000
// 从密码派生密钥
function deriveKey(password: string, salt: Buffer): Buffer {
return crypto.pbkdf2Sync(password, salt, ITERATIONS, KEY_LENGTH, 'sha256')
}
// 生成随机密钥(用于主密钥)
export function generateMasterKey(): string {
return crypto.randomBytes(KEY_LENGTH).toString('hex')
}
// 加密数据
export function encrypt(plaintext: string, password: string): string {
const salt = crypto.randomBytes(SALT_LENGTH)
const key = deriveKey(password, salt)
const iv = crypto.randomBytes(IV_LENGTH)
const cipher = crypto.createCipheriv(ALGORITHM, key, iv)
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()])
const tag = cipher.getAuthTag()
// 格式: salt:iv:tag:encrypted (全部 hex)
return [
salt.toString('hex'),
iv.toString('hex'),
tag.toString('hex'),
encrypted.toString('hex'),
].join(':')
}
// 解密数据
export function decrypt(ciphertext: string, password: string): string {
try {
const [saltHex, ivHex, tagHex, encryptedHex] = ciphertext.split(':')
if (!saltHex || !ivHex || !tagHex || !encryptedHex) {
throw new Error('Invalid ciphertext format')
}
const salt = Buffer.from(saltHex, 'hex')
const iv = Buffer.from(ivHex, 'hex')
const tag = Buffer.from(tagHex, 'hex')
const encrypted = Buffer.from(encryptedHex, 'hex')
const key = deriveKey(password, salt)
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv)
decipher.setAuthTag(tag)
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()])
return decrypted.toString('utf8')
} catch (error) {
throw new Error('Decryption failed: ' + (error as Error).message)
}
}
// 简单加密(不带 salt,用于可逆加密)
export function simpleEncrypt(plaintext: string, key: string): string {
const iv = crypto.randomBytes(IV_LENGTH)
const keyBuffer = Buffer.from(key, 'hex').slice(0, KEY_LENGTH)
const cipher = crypto.createCipheriv(ALGORITHM, keyBuffer, iv)
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()])
const tag = cipher.getAuthTag()
return iv.toString('hex') + ':' + tag.toString('hex') + ':' + encrypted.toString('hex')
}
// 简单解密
export function simpleDecrypt(ciphertext: string, key: string): string {
try {
const [ivHex, tagHex, encryptedHex] = ciphertext.split(':')
const iv = Buffer.from(ivHex, 'hex')
const tag = Buffer.from(tagHex, 'hex')
const encrypted = Buffer.from(encryptedHex, 'hex')
const keyBuffer = Buffer.from(key, 'hex').slice(0, KEY_LENGTH)
const decipher = crypto.createDecipheriv(ALGORITHM, keyBuffer, iv)
decipher.setAuthTag(tag)
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()])
return decrypted.toString('utf8')
} catch (error) {
throw new Error('Decryption failed: ' + (error as Error).message)
}
}