134 lines
3.4 KiB
Go
134 lines
3.4 KiB
Go
// Package api provides gRPC server implementation for Audit Service.
|
|
package api
|
|
|
|
import (
|
|
"context"
|
|
"math"
|
|
|
|
auditv1 "git.dcentral.systems/toolz/goplt/api/proto/generated/audit/v1"
|
|
"git.dcentral.systems/toolz/goplt/services/audit/internal/service"
|
|
"go.uber.org/zap"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
// Server implements the AuditService gRPC server.
|
|
type Server struct {
|
|
auditv1.UnimplementedAuditServiceServer
|
|
service *service.AuditService
|
|
logger *zap.Logger
|
|
}
|
|
|
|
// NewServer creates a new Audit Service gRPC server.
|
|
func NewServer(auditService *service.AuditService, logger *zap.Logger) *Server {
|
|
return &Server{
|
|
service: auditService,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// Record records an audit log entry.
|
|
func (s *Server) Record(ctx context.Context, req *auditv1.RecordRequest) (*auditv1.RecordResponse, error) {
|
|
if req.Entry == nil {
|
|
return nil, status.Error(codes.InvalidArgument, "entry is required")
|
|
}
|
|
|
|
entry := req.Entry
|
|
|
|
// Convert proto entry to service entry
|
|
serviceEntry := &service.AuditLogEntry{
|
|
UserID: entry.UserId,
|
|
Action: entry.Action,
|
|
Resource: entry.Resource,
|
|
ResourceID: entry.ResourceId,
|
|
IPAddress: entry.IpAddress,
|
|
UserAgent: entry.UserAgent,
|
|
Metadata: entry.Metadata,
|
|
Timestamp: entry.Timestamp,
|
|
}
|
|
|
|
// Record the audit log
|
|
if err := s.service.Record(ctx, serviceEntry); err != nil {
|
|
s.logger.Error("Failed to record audit log",
|
|
zap.Error(err),
|
|
zap.String("user_id", entry.UserId),
|
|
zap.String("action", entry.Action),
|
|
)
|
|
return nil, status.Errorf(codes.Internal, "failed to record audit log: %v", err)
|
|
}
|
|
|
|
return &auditv1.RecordResponse{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// Query queries audit logs based on filters.
|
|
func (s *Server) Query(ctx context.Context, req *auditv1.QueryRequest) (*auditv1.QueryResponse, error) {
|
|
// Convert proto filters to service filters
|
|
filters := &service.AuditLogFilters{
|
|
Limit: int(req.Limit),
|
|
Offset: int(req.Offset),
|
|
}
|
|
|
|
if req.UserId != nil {
|
|
userID := *req.UserId
|
|
filters.UserID = &userID
|
|
}
|
|
if req.Action != nil {
|
|
action := *req.Action
|
|
filters.Action = &action
|
|
}
|
|
if req.Resource != nil {
|
|
resource := *req.Resource
|
|
filters.Resource = &resource
|
|
}
|
|
if req.ResourceId != nil {
|
|
resourceID := *req.ResourceId
|
|
filters.ResourceID = &resourceID
|
|
}
|
|
if req.StartTime != nil {
|
|
startTime := *req.StartTime
|
|
filters.StartTime = &startTime
|
|
}
|
|
if req.EndTime != nil {
|
|
endTime := *req.EndTime
|
|
filters.EndTime = &endTime
|
|
}
|
|
|
|
// Query audit logs
|
|
entries, err := s.service.Query(ctx, filters)
|
|
if err != nil {
|
|
s.logger.Error("Failed to query audit logs",
|
|
zap.Error(err),
|
|
)
|
|
return nil, status.Errorf(codes.Internal, "failed to query audit logs: %v", err)
|
|
}
|
|
|
|
// Convert service entries to proto entries
|
|
protoEntries := make([]*auditv1.AuditLogEntry, 0, len(entries))
|
|
for _, entry := range entries {
|
|
protoEntries = append(protoEntries, &auditv1.AuditLogEntry{
|
|
UserId: entry.UserID,
|
|
Action: entry.Action,
|
|
Resource: entry.Resource,
|
|
ResourceId: entry.ResourceID,
|
|
IpAddress: entry.IPAddress,
|
|
UserAgent: entry.UserAgent,
|
|
Metadata: entry.Metadata,
|
|
Timestamp: entry.Timestamp,
|
|
})
|
|
}
|
|
|
|
total := len(protoEntries)
|
|
var totalInt32 int32
|
|
if total > math.MaxInt32 {
|
|
totalInt32 = math.MaxInt32
|
|
} else {
|
|
totalInt32 = int32(total)
|
|
}
|
|
return &auditv1.QueryResponse{
|
|
Entries: protoEntries,
|
|
Total: totalInt32, // Note: This is a simplified total, actual total would require a count query
|
|
}, nil
|
|
}
|