Use separate variables with explicit else branches to make type conversions safe and satisfy gosec integer overflow checks.
146 lines
3.6 KiB
Go
146 lines
3.6 KiB
Go
// Package grpc provides gRPC client implementations for service clients.
|
|
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"math"
|
|
|
|
auditv1 "git.dcentral.systems/toolz/goplt/api/proto/generated/audit/v1"
|
|
"git.dcentral.systems/toolz/goplt/pkg/registry"
|
|
"git.dcentral.systems/toolz/goplt/pkg/services"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
)
|
|
|
|
// AuditClient implements AuditServiceClient using gRPC.
|
|
type AuditClient struct {
|
|
registry registry.ServiceRegistry
|
|
conn *grpc.ClientConn
|
|
client auditv1.AuditServiceClient
|
|
}
|
|
|
|
// NewAuditClient creates a new gRPC client for the Audit Service.
|
|
func NewAuditClient(reg registry.ServiceRegistry) (services.AuditServiceClient, error) {
|
|
client := &AuditClient{
|
|
registry: reg,
|
|
}
|
|
return client, nil
|
|
}
|
|
|
|
// connect connects to the Audit Service.
|
|
func (c *AuditClient) connect(ctx context.Context) error {
|
|
if c.conn != nil {
|
|
return nil
|
|
}
|
|
|
|
instances, err := c.registry.Discover(ctx, "audit-service")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to discover audit service: %w", err)
|
|
}
|
|
|
|
if len(instances) == 0 {
|
|
return fmt.Errorf("no instances found for audit-service")
|
|
}
|
|
|
|
instance := instances[0]
|
|
address := fmt.Sprintf("%s:%d", instance.Address, instance.Port)
|
|
|
|
conn, err := grpc.NewClient(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to connect to audit-service at %s: %w", address, err)
|
|
}
|
|
|
|
c.conn = conn
|
|
c.client = auditv1.NewAuditServiceClient(conn)
|
|
return nil
|
|
}
|
|
|
|
// Record records an audit log entry.
|
|
func (c *AuditClient) Record(ctx context.Context, entry *services.AuditLogEntry) error {
|
|
if err := c.connect(ctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err := c.client.Record(ctx, &auditv1.RecordRequest{
|
|
Entry: &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,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("record audit log failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Query queries audit logs based on filters.
|
|
func (c *AuditClient) Query(ctx context.Context, filters *services.AuditLogFilters) ([]services.AuditLogEntry, error) {
|
|
if err := c.connect(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var limitInt32, offsetInt32 int32
|
|
if filters.Limit > math.MaxInt32 {
|
|
limitInt32 = math.MaxInt32
|
|
} else {
|
|
limitInt32 = int32(filters.Limit)
|
|
}
|
|
if filters.Offset > math.MaxInt32 {
|
|
offsetInt32 = math.MaxInt32
|
|
} else {
|
|
offsetInt32 = int32(filters.Offset)
|
|
}
|
|
req := &auditv1.QueryRequest{
|
|
Limit: limitInt32,
|
|
Offset: offsetInt32,
|
|
}
|
|
|
|
if filters.UserID != nil {
|
|
req.UserId = filters.UserID
|
|
}
|
|
if filters.Action != nil {
|
|
req.Action = filters.Action
|
|
}
|
|
if filters.Resource != nil {
|
|
req.Resource = filters.Resource
|
|
}
|
|
if filters.ResourceID != nil {
|
|
req.ResourceId = filters.ResourceID
|
|
}
|
|
if filters.StartTime != nil {
|
|
req.StartTime = filters.StartTime
|
|
}
|
|
if filters.EndTime != nil {
|
|
req.EndTime = filters.EndTime
|
|
}
|
|
|
|
resp, err := c.client.Query(ctx, req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("query audit logs failed: %w", err)
|
|
}
|
|
|
|
entries := make([]services.AuditLogEntry, 0, len(resp.Entries))
|
|
for _, e := range resp.Entries {
|
|
entries = append(entries, services.AuditLogEntry{
|
|
UserID: e.UserId,
|
|
Action: e.Action,
|
|
Resource: e.Resource,
|
|
ResourceID: e.ResourceId,
|
|
IPAddress: e.IpAddress,
|
|
UserAgent: e.UserAgent,
|
|
Metadata: e.Metadata,
|
|
Timestamp: e.Timestamp,
|
|
})
|
|
}
|
|
|
|
return entries, nil
|
|
}
|