package admin import ( "time" "github.com/gofiber/fiber/v2" "github.com/break/junhong_cmp_fiber/internal/model/dto" auditquery "github.com/break/junhong_cmp_fiber/internal/query/audit" integrationquery "github.com/break/junhong_cmp_fiber/internal/query/integration" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/response" ) // AuditHandler 提供平台基础审计调查只读接口。 type AuditHandler struct { auditQuery *auditquery.Query integrationQuery *integrationquery.Query } // NewAuditHandler 创建平台基础审计调查 Handler。 func NewAuditHandler(auditQuery *auditquery.Query, integrationQuery *integrationquery.Query) *AuditHandler { return &AuditHandler{auditQuery: auditQuery, integrationQuery: integrationQuery} } // ListEvents 查询平台全局审计事件。 // GET /api/admin/audit/events func (h *AuditHandler) ListEvents(c *fiber.Ctx) error { var request dto.AuditEventListRequest if err := c.QueryParser(&request); err != nil { return errors.New(errors.CodeInvalidParam) } from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.List(c.UserContext(), auditquery.EventFilter{ CreatedFrom: from, CreatedTo: to, Action: request.Action, Category: request.Category, ActorKind: request.ActorKind, ActorID: request.ActorID, Source: request.Source, Result: request.Result, Risk: request.Risk, ScopeType: request.ScopeType, ScopeID: request.ScopeID, ResourceType: request.ResourceType, ResourceID: request.ResourceID, ResourceKey: request.ResourceKey, RequestID: request.RequestID, CorrelationID: request.CorrelationID, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // GetEvent 查询单个稳定审计事件详情。 // GET /api/admin/audit/events/:event_id func (h *AuditHandler) GetEvent(c *fiber.Ctx) error { result, err := h.auditQuery.Get(c.UserContext(), c.Params("event_id")) if err != nil { return err } return response.Success(c, result) } // ListActorEvents 查询操作者行为时间线。 // GET /api/admin/audit/actors/:kind/:id/events func (h *AuditHandler) ListActorEvents(c *fiber.Ctx) error { var request dto.AuditActorEventsRequest if err := c.QueryParser(&request); err != nil { return errors.New(errors.CodeInvalidParam) } request.Kind, request.ID = c.Params("kind"), c.Params("id") from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.ListActorEvents(c.UserContext(), auditquery.ActorEventFilter{ Kind: request.Kind, ID: request.ID, Action: request.Action, Result: request.Result, Risk: request.Risk, ResourceType: request.ResourceType, ResourceID: request.ResourceID, CreatedFrom: from, CreatedTo: to, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // SearchResources 按注册业务标识精确搜索资源。 // GET /api/admin/audit/resources/search func (h *AuditHandler) SearchResources(c *fiber.Ctx) error { var request dto.AuditResourceSearchRequest if err := c.QueryParser(&request); err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.SearchResources(c.UserContext(), auditquery.ResourceSearchFilter{ ResourceType: request.ResourceType, Keyword: request.Keyword, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // ResourceTimeline 查询资源作为任意关系参与的通用事件时间线。 // GET /api/admin/audit/resources/:resource_type/:resource_id/timeline func (h *AuditHandler) ResourceTimeline(c *fiber.Ctx) error { var request dto.AuditResourceTimelineRequest if err := c.QueryParser(&request); err != nil { return errors.New(errors.CodeInvalidParam) } request.ResourceType, request.ResourceID = c.Params("resource_type"), c.Params("resource_id") from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } result, err := h.auditQuery.ResourceTimeline(c.UserContext(), auditquery.ResourceTimelineFilter{ ResourceType: request.ResourceType, ResourceID: request.ResourceID, CreatedFrom: from, CreatedTo: to, Action: request.Action, Result: request.Result, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // AgentResourceActivities 查询代理范围内的安全资源活动。 // GET /api/admin/agent/resource-activities/:resource_type/:identifier func (h *AuditHandler) AgentResourceActivities(c *fiber.Ctx) error { request, err := subjectActivityRequest(c) if err != nil { return err } result, err := h.auditQuery.AgentResourceActivities(c.UserContext(), auditquery.SubjectActivityFilter{ ResourceType: request.ResourceType, Identifier: request.Identifier, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } // EnterpriseResourceActivities 查询企业当前有效授权资产的安全资源活动。 // GET /api/admin/enterprise/resource-activities/:resource_type/:identifier func (h *AuditHandler) EnterpriseResourceActivities(c *fiber.Ctx) error { request, err := subjectActivityRequest(c) if err != nil { return err } result, err := h.auditQuery.EnterpriseResourceActivities(c.UserContext(), auditquery.SubjectActivityFilter{ ResourceType: request.ResourceType, Identifier: request.Identifier, Page: request.Page, PageSize: request.PageSize, }) if err != nil { return err } return response.Success(c, result) } func subjectActivityRequest(c *fiber.Ctx) (dto.SubjectResourceActivityRequest, error) { var request dto.SubjectResourceActivityRequest if err := c.QueryParser(&request); err != nil || invalidAuditPage(request.Page, request.PageSize) { return request, errors.New(errors.CodeInvalidParam) } request.ResourceType = c.Params("resource_type") request.Identifier = c.Params("identifier") if request.ResourceType == "" || request.Identifier == "" { return request, errors.New(errors.CodeInvalidParam) } return request, nil } // IntegrationOverview 查询外部集成交互总览。 // GET /api/admin/audit/integrations/overview func (h *AuditHandler) IntegrationOverview(c *fiber.Ctx) error { var request dto.IntegrationOverviewRequest if err := c.QueryParser(&request); err != nil { return errors.New(errors.CodeInvalidParam) } filter, err := integrationFilter(request.IntegrationFilterRequest) if err != nil { return err } result, err := h.integrationQuery.Overview(c.UserContext(), integrationquery.OverviewFilter{ ListFilter: filter, Bucket: request.Bucket, }) if err != nil { return err } return response.Success(c, result) } // ListIntegrations 查询外部集成交互列表。 // GET /api/admin/audit/integrations func (h *AuditHandler) ListIntegrations(c *fiber.Ctx) error { var request dto.IntegrationListRequest if err := c.QueryParser(&request); err != nil || invalidAuditPage(request.Page, request.PageSize) { return errors.New(errors.CodeInvalidParam) } filter, err := integrationFilter(request.IntegrationFilterRequest) if err != nil { return err } filter.Page, filter.PageSize = request.Page, request.PageSize result, err := h.integrationQuery.List(c.UserContext(), filter) if err != nil { return err } return response.Success(c, result) } // GetIntegration 查询稳定外部集成记录详情。 // GET /api/admin/audit/integrations/:integration_id func (h *AuditHandler) GetIntegration(c *fiber.Ctx) error { result, err := h.integrationQuery.Get(c.UserContext(), c.Params("integration_id")) if err != nil { return err } return response.Success(c, result) } func integrationFilter(request dto.IntegrationFilterRequest) (integrationquery.ListFilter, error) { from, to, err := auditTimeRange(request.CreatedFrom, request.CreatedTo) if err != nil { return integrationquery.ListFilter{}, errors.New(errors.CodeInvalidParam) } return integrationquery.ListFilter{ CreatedFrom: from, CreatedTo: to, IntegrationID: request.IntegrationID, Provider: request.Provider, Direction: request.Direction, Operation: request.Operation, Result: request.Result, ResultCategory: request.ResultCategory, ExternalID: request.ExternalID, ResourceType: request.ResourceType, ResourceID: request.ResourceID, ResourceKey: request.ResourceKey, TriggerSource: request.TriggerSource, TriggerScene: request.TriggerScene, TriggerSeries: request.TriggerSeries, StateChanged: request.StateChanged, HTTPStatus: request.HTTPStatus, ProviderCode: request.ProviderCode, RequestID: request.RequestID, CorrelationID: request.CorrelationID, }, nil } func auditTimeRange(fromValue, toValue string) (*time.Time, *time.Time, error) { from, err := optionalAuditTime(fromValue) if err != nil { return nil, nil, err } to, err := optionalAuditTime(toValue) if err != nil { return nil, nil, err } if from != nil && to != nil && !from.Before(*to) { return nil, nil, errors.New(errors.CodeInvalidParam) } return from, to, nil } func optionalAuditTime(value string) (*time.Time, error) { if value == "" { return nil, nil } parsed, err := time.Parse(time.RFC3339, value) if err != nil { return nil, err } return &parsed, nil } func invalidAuditPage(page, pageSize int) bool { return page < 0 || pageSize < 0 || pageSize > 100 }