chore: remote forwarding integration
This commit is contained in:
@@ -42,6 +42,23 @@ CREATE TABLE IF NOT EXISTS unread (
|
||||
device_id TEXT PRIMARY KEY,
|
||||
count INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
-- 远程操作审计 (terminal / forward / usb)
|
||||
CREATE TABLE IF NOT EXISTS audit_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ts INTEGER NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
source_device TEXT,
|
||||
target_device TEXT,
|
||||
session_id TEXT,
|
||||
payload_json TEXT,
|
||||
result TEXT NOT NULL,
|
||||
bytes_in INTEGER NOT NULL DEFAULT 0,
|
||||
bytes_out INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_ts ON audit_log(ts DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_session ON audit_log(session_id);
|
||||
`)
|
||||
|
||||
// 迁移: 给老库补 ignored 列 (用 try/catch 包住, 已存在会抛)
|
||||
@@ -240,3 +257,72 @@ export function totalUnread(): number {
|
||||
const r = db.prepare(`SELECT COALESCE(SUM(count), 0) AS s FROM unread`).get() as { s: number }
|
||||
return r.s
|
||||
}
|
||||
|
||||
// 审计日志 (远程操作: terminal / forward / usb)
|
||||
export interface AuditRow {
|
||||
id: number
|
||||
ts: number
|
||||
action: string
|
||||
source_device: string | null
|
||||
target_device: string | null
|
||||
session_id: string | null
|
||||
payload_json: string | null
|
||||
result: string
|
||||
bytes_in: number
|
||||
bytes_out: number
|
||||
}
|
||||
|
||||
const insertAuditStmt = db.prepare(`
|
||||
INSERT INTO audit_log
|
||||
(ts, action, source_device, target_device, session_id, payload_json, result, bytes_in, bytes_out)
|
||||
VALUES
|
||||
(@ts, @action, @source_device, @target_device, @session_id, @payload_json, @result, @bytes_in, @bytes_out)
|
||||
`)
|
||||
|
||||
export function recordAudit(args: {
|
||||
action: string
|
||||
source?: string | null
|
||||
target?: string | null
|
||||
sessionId?: string | null
|
||||
payload?: any
|
||||
result: 'ok' | 'denied' | 'error' | 'closed'
|
||||
bytesIn?: number
|
||||
bytesOut?: number
|
||||
}): void {
|
||||
insertAuditStmt.run({
|
||||
ts: Date.now(),
|
||||
action: args.action,
|
||||
source_device: args.source ?? null,
|
||||
target_device: args.target ?? null,
|
||||
session_id: args.sessionId ?? null,
|
||||
payload_json: args.payload !== undefined ? JSON.stringify(args.payload) : null,
|
||||
result: args.result,
|
||||
bytes_in: args.bytesIn ?? 0,
|
||||
bytes_out: args.bytesOut ?? 0,
|
||||
})
|
||||
}
|
||||
|
||||
export function listAudit(opts: { limit?: number; since?: number; sessionId?: string } = {}): AuditRow[] {
|
||||
const limit = Math.min(Math.max(opts.limit ?? 200, 1), 2000)
|
||||
if (opts.sessionId) {
|
||||
return db.prepare(`SELECT * FROM audit_log WHERE session_id = ? ORDER BY ts DESC LIMIT ?`).all(opts.sessionId, limit) as AuditRow[]
|
||||
}
|
||||
if (opts.since) {
|
||||
return db.prepare(`SELECT * FROM audit_log WHERE ts >= ? ORDER BY ts DESC LIMIT ?`).all(opts.since, limit) as AuditRow[]
|
||||
}
|
||||
return db.prepare(`SELECT * FROM audit_log ORDER BY ts DESC LIMIT ?`).all(limit) as AuditRow[]
|
||||
}
|
||||
|
||||
export function pruneAudit(olderThanMs: number): number {
|
||||
const r = db.prepare(`DELETE FROM audit_log WHERE ts < ?`).run(Date.now() - olderThanMs)
|
||||
return r.changes
|
||||
}
|
||||
|
||||
// 远程操作白名单 (按 deviceId -> { terminal, forward, usb })
|
||||
// 写入 settings.json (electron-store) 而不是 DB, 便于跨设备查看与回滚
|
||||
export interface RemoteAllowRow {
|
||||
device_id: string
|
||||
terminal: number // 0/1
|
||||
forward: number
|
||||
usb: number
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user