Some checks are pending
Security Checks / security (push) Waiting to run
统一 frontend、backend、test、test-log 和 out 目录,更新构建、部署及测试入口;纳入配置管理兼容与首次安全引导修复;排除本机配置、密钥和测试产物。
123 lines
3.5 KiB
Go
123 lines
3.5 KiB
Go
package controllers
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.pcux.cn/xuans/Smail/config"
|
|
"git.pcux.cn/xuans/Smail/dto/response"
|
|
"git.pcux.cn/xuans/Smail/services/access"
|
|
appcontext "git.pcux.cn/xuans/Smail/utils/context"
|
|
)
|
|
|
|
// GetConfigAuditDetail 返回一条已脱敏的配置审计事件。
|
|
func GetConfigAuditDetail(ctx *appcontext.Context, w http.ResponseWriter, req *http.Request) {
|
|
manager, ok := configManagerOrError(w)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := authorizeCapability(ctx, access.CapabilityAuditRead, "", false); err != nil {
|
|
writeConfigAccessError(w, err)
|
|
return
|
|
}
|
|
parts := strings.Split(strings.Trim(req.URL.Path, "/"), "/")
|
|
if len(parts) != 5 || parts[0] != "api" || parts[1] != "v1" || parts[2] != "audits" || parts[3] != "config" || strings.TrimSpace(parts[4]) == "" {
|
|
writeConfigError(w, config.ErrInvalidAuditQuery)
|
|
return
|
|
}
|
|
event, err := manager.AuditDetail(req.Context(), parts[4])
|
|
if err != nil {
|
|
writeConfigError(w, err)
|
|
return
|
|
}
|
|
response.NewSuccessResponse(event).FPrint(w)
|
|
}
|
|
|
|
type configAuditExportRequest struct {
|
|
Format string `json:"format"`
|
|
ID string `json:"id"`
|
|
ActorID string `json:"actorId"`
|
|
Operation string `json:"operation"`
|
|
Section string `json:"section"`
|
|
Limit int `json:"limit"`
|
|
From string `json:"from"`
|
|
To string `json:"to"`
|
|
}
|
|
|
|
// ExportConfigAuditFormal 实现正式配置审计导出接口。
|
|
func ExportConfigAuditFormal(ctx *appcontext.Context, w http.ResponseWriter, req *http.Request) {
|
|
manager, ok := configManagerOrError(w)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := authorizeCapability(ctx, access.CapabilityAuditExport, "", false); err != nil {
|
|
writeConfigAccessError(w, err)
|
|
return
|
|
}
|
|
var input configAuditExportRequest
|
|
if err := decodeJSONRequest(w, req, &input); err != nil {
|
|
writeConfigError(w, err)
|
|
return
|
|
}
|
|
query, err := auditExportQuery(input)
|
|
if err != nil {
|
|
writeConfigError(w, err)
|
|
return
|
|
}
|
|
format := strings.ToLower(strings.TrimSpace(input.Format))
|
|
if format == "" {
|
|
format = "json"
|
|
}
|
|
if format != "json" && format != "csv" {
|
|
writeConfigError(w, config.ErrInvalidAuditFormat)
|
|
return
|
|
}
|
|
var data []byte
|
|
if format == "csv" {
|
|
data, err = manager.ExportAuditCSV(req.Context(), query)
|
|
} else {
|
|
data, err = manager.ExportAuditJSON(req.Context(), query)
|
|
}
|
|
if err != nil {
|
|
writeConfigError(w, err)
|
|
return
|
|
}
|
|
w.Header().Set("Cache-Control", "no-store")
|
|
w.Header().Set("Content-Disposition", `attachment; filename="config-audit.`+format+`"`)
|
|
if format == "csv" {
|
|
w.Header().Set("Content-Type", "text/csv; charset=utf-8")
|
|
} else {
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
}
|
|
_, _ = w.Write(data)
|
|
}
|
|
|
|
func auditExportQuery(input configAuditExportRequest) (config.ConfigAuditQuery, error) {
|
|
query := config.ConfigAuditQuery{
|
|
ID: strings.TrimSpace(input.ID),
|
|
ActorID: strings.TrimSpace(input.ActorID),
|
|
Operation: config.ConfigOperation(strings.TrimSpace(input.Operation)),
|
|
Section: config.Section(strings.TrimSpace(input.Section)),
|
|
Limit: input.Limit,
|
|
}
|
|
if raw := strings.TrimSpace(input.From); raw != "" {
|
|
value, err := time.Parse(time.RFC3339, raw)
|
|
if err != nil {
|
|
return config.ConfigAuditQuery{}, config.ErrInvalidAuditQuery
|
|
}
|
|
query.From = value
|
|
}
|
|
if raw := strings.TrimSpace(input.To); raw != "" {
|
|
value, err := time.Parse(time.RFC3339, raw)
|
|
if err != nil {
|
|
return config.ConfigAuditQuery{}, config.ErrInvalidAuditQuery
|
|
}
|
|
query.To = value
|
|
}
|
|
if err := config.ValidateConfigAuditQuery(query); err != nil {
|
|
return config.ConfigAuditQuery{}, err
|
|
}
|
|
return query, nil
|
|
}
|