Files
sub2api-cn-relay-manager/internal/store/sqlite/user_key_audit_events_repo.go
phamnazage-jpg 5b59ad7490
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
feat(vnext2): close user key self-service on real host
2026-06-05 19:58:02 +08:00

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
}