102 lines
3.8 KiB
Go
102 lines
3.8 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type UserKeyAuditEvent struct {
|
|
ID int64 `json:"-"`
|
|
EventID string `json:"event_id"`
|
|
ActorSubjectID string `json:"actor_subject_id"`
|
|
ActorRole string `json:"actor_role"`
|
|
TargetKeyID string `json:"target_key_id"`
|
|
Action string `json:"action"`
|
|
Result string `json:"result"`
|
|
Reason string `json:"reason,omitempty"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
type UserKeyAuditEventsRepo struct {
|
|
db execQuerier
|
|
}
|
|
|
|
func newUserKeyAuditEventsRepo(db execQuerier) *UserKeyAuditEventsRepo {
|
|
return &UserKeyAuditEventsRepo{db: db}
|
|
}
|
|
|
|
func (r *UserKeyAuditEventsRepo) Create(ctx context.Context, row UserKeyAuditEvent) (int64, error) {
|
|
row, err := normalizeUserKeyAuditEvent(row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
result, err := r.db.ExecContext(ctx, `INSERT INTO user_key_audit_events (
|
|
event_id, actor_subject_id, actor_role, target_key_id, action, result, reason
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
row.EventID, row.ActorSubjectID, row.ActorRole, row.TargetKeyID, row.Action, row.Result, row.Reason,
|
|
)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("insert user key audit event %q: %w", row.EventID, err)
|
|
}
|
|
id, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, fmt.Errorf("read inserted user key audit event id for %q: %w", row.EventID, err)
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func (r *UserKeyAuditEventsRepo) ListByTargetKeyID(ctx context.Context, keyID string, limit int) ([]UserKeyAuditEvent, error) {
|
|
keyID = strings.TrimSpace(keyID)
|
|
if keyID == "" {
|
|
return nil, fmt.Errorf("target_key_id is required")
|
|
}
|
|
if limit <= 0 || limit > 100 {
|
|
limit = 20
|
|
}
|
|
rows, err := r.db.QueryContext(ctx, `SELECT id, event_id, actor_subject_id, actor_role, target_key_id, action, result, reason, created_at
|
|
FROM user_key_audit_events WHERE target_key_id = ? ORDER BY id DESC LIMIT ?`, keyID, limit)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list user key audit events for %q: %w", keyID, err)
|
|
}
|
|
defer rows.Close()
|
|
items := make([]UserKeyAuditEvent, 0)
|
|
for rows.Next() {
|
|
var item UserKeyAuditEvent
|
|
if err := rows.Scan(&item.ID, &item.EventID, &item.ActorSubjectID, &item.ActorRole, &item.TargetKeyID, &item.Action, &item.Result, &item.Reason, &item.CreatedAt); err != nil {
|
|
return nil, fmt.Errorf("scan user key audit event: %w", err)
|
|
}
|
|
items = append(items, item)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("iterate user key audit events: %w", err)
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
func normalizeUserKeyAuditEvent(row UserKeyAuditEvent) (UserKeyAuditEvent, error) {
|
|
row.EventID = strings.TrimSpace(row.EventID)
|
|
row.ActorSubjectID = strings.TrimSpace(row.ActorSubjectID)
|
|
row.ActorRole = strings.ToLower(strings.TrimSpace(row.ActorRole))
|
|
row.TargetKeyID = strings.TrimSpace(row.TargetKeyID)
|
|
row.Action = strings.ToLower(strings.TrimSpace(row.Action))
|
|
row.Result = strings.ToLower(strings.TrimSpace(row.Result))
|
|
row.Reason = strings.TrimSpace(row.Reason)
|
|
|
|
switch {
|
|
case row.EventID == "":
|
|
return UserKeyAuditEvent{}, fmt.Errorf("event_id is required")
|
|
case row.ActorSubjectID == "":
|
|
return UserKeyAuditEvent{}, fmt.Errorf("actor_subject_id is required")
|
|
case row.ActorRole != "admin" && row.ActorRole != "user" && row.ActorRole != "system":
|
|
return UserKeyAuditEvent{}, fmt.Errorf("invalid actor_role: %s", row.ActorRole)
|
|
case row.TargetKeyID == "":
|
|
return UserKeyAuditEvent{}, fmt.Errorf("target_key_id is required")
|
|
case row.Action != "create" && row.Action != "reset" && row.Action != "pause" && row.Action != "resume" && row.Action != "delete":
|
|
return UserKeyAuditEvent{}, fmt.Errorf("invalid action: %s", row.Action)
|
|
case row.Result != "success" && row.Result != "denied" && row.Result != "failed":
|
|
return UserKeyAuditEvent{}, fmt.Errorf("invalid result: %s", row.Result)
|
|
}
|
|
return row, nil
|
|
}
|