- 内置 SSH 终端(/terminal):复用已保存的 SSH 密码/私钥与独立 known_hosts 校验 - 终端二次认证、会话审计(/terminal/audits)、录像审计与常用命令 - DDNS 服务商名称与自定义 IP,新增迁移 037/038/039 - CHANGELOG 与 VERSION 更新至 2.0.0
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/havline/havline/internal/db"
|
||||
"github.com/havline/havline/internal/terminal"
|
||||
)
|
||||
|
||||
// TestListAuditsHandler:审计接口返回落库记录;未接存储时返回空数组而不是 null。
|
||||
func TestListAuditsHandler(t *testing.T) {
|
||||
conn, err := db.Open(filepath.Join(t.TempDir(), "audit.db"))
|
||||
if err != nil {
|
||||
t.Fatalf("打开数据库失败:%v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
if err := db.Migrate(context.Background(), conn, filepath.Join("..", "..", "migrations")); err != nil {
|
||||
t.Fatalf("迁移失败:%v", err)
|
||||
}
|
||||
|
||||
store := terminal.NewAuditStore(conn)
|
||||
now := time.Now().UTC()
|
||||
entry := terminal.AuditEntry{
|
||||
SessionID: "s1", ServerID: 3, Target: "东京 VPS · root@10.0.0.1",
|
||||
User: "admin", ClientIP: "192.168.1.9",
|
||||
StartedAt: now.Format(time.RFC3339), EndedAt: now.Add(time.Second).Format(time.RFC3339),
|
||||
DurationMS: 1_000, Reason: "用户关闭",
|
||||
}
|
||||
if err := store.WriteAudit(context.Background(), entry); err != nil {
|
||||
t.Fatalf("写入审计失败:%v", err)
|
||||
}
|
||||
|
||||
handler := NewTerminalHandler(TerminalHandlerOptions{Audits: store})
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ListAudits(rec, httptest.NewRequest(http.MethodGet, "/api/terminal/audits", nil))
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("状态码不符:%d %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var body struct {
|
||||
Entries []terminal.AuditEntry `json:"entries"`
|
||||
}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
|
||||
t.Fatalf("解析响应失败:%v", err)
|
||||
}
|
||||
if len(body.Entries) != 1 {
|
||||
t.Fatalf("期望 1 条审计,实际 %d 条", len(body.Entries))
|
||||
}
|
||||
if body.Entries[0].User != "admin" || body.Entries[0].Reason != "用户关闭" {
|
||||
t.Fatalf("审计字段不符:%+v", body.Entries[0])
|
||||
}
|
||||
|
||||
// 未接存储时也要给前端一个数组,避免前端拿到 null 崩掉
|
||||
empty := NewTerminalHandler(TerminalHandlerOptions{})
|
||||
emptyRec := httptest.NewRecorder()
|
||||
empty.ListAudits(emptyRec, httptest.NewRequest(http.MethodGet, "/api/terminal/audits", nil))
|
||||
if got := emptyRec.Body.String(); got != "{\"entries\":[]}\n" {
|
||||
t.Fatalf("空审计响应不符:%s", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user