Implement dashboard and audit log templates, add paginated audit log support
- Added `web/templates/{dashboard,audit,base,accounts,account_detail}.html` for a consistent UI.
- Implemented new audit log endpoint (`GET /v1/audit`) with filtering and pagination via `ListAuditEventsPaged`.
- Extended `AuditQueryParams`, added `AuditEventView` for joined actor/target usernames.
- Updated configuration (`goimports` preference), linting rules, and E2E tests.
- No logic changes to existing APIs.
This commit is contained in:
@@ -38,8 +38,17 @@ const (
|
||||
|
||||
// ClaimsFromContext retrieves the validated JWT claims from the request context.
|
||||
// Returns nil if no claims are present (unauthenticated request).
|
||||
//
|
||||
// Security: The type assertion uses the ok form so a context value of the wrong
|
||||
// type (e.g. from a different package's context injection) returns nil rather
|
||||
// than panicking.
|
||||
func ClaimsFromContext(ctx context.Context) *token.Claims {
|
||||
c, _ := ctx.Value(claimsKey).(*token.Claims)
|
||||
// ok is intentionally checked: if the value is absent or the wrong type,
|
||||
// c is nil (zero value for *token.Claims), which is the correct "no auth" result.
|
||||
c, ok := ctx.Value(claimsKey).(*token.Claims)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -152,18 +161,18 @@ func RequireRole(role string) func(http.Handler) http.Handler {
|
||||
|
||||
// rateLimitEntry holds the token bucket state for a single IP.
|
||||
type rateLimitEntry struct {
|
||||
tokens float64
|
||||
lastSeen time.Time
|
||||
tokens float64
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// ipRateLimiter implements a per-IP token bucket rate limiter.
|
||||
type ipRateLimiter struct {
|
||||
rps float64 // refill rate: tokens per second
|
||||
burst float64 // bucket capacity
|
||||
ttl time.Duration // how long to keep idle entries
|
||||
mu sync.Mutex
|
||||
ips map[string]*rateLimitEntry
|
||||
rps float64
|
||||
burst float64
|
||||
ttl time.Duration
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// RateLimit returns middleware implementing a per-IP token bucket.
|
||||
|
||||
@@ -314,14 +314,14 @@ func TestExtractBearerToken(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
header string
|
||||
wantErr bool
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid", "Bearer mytoken123", false, "mytoken123"},
|
||||
{"missing header", "", true, ""},
|
||||
{"no bearer prefix", "Token mytoken123", true, ""},
|
||||
{"empty token", "Bearer ", true, ""},
|
||||
{"case insensitive", "bearer mytoken123", false, "mytoken123"},
|
||||
{"valid", "Bearer mytoken123", "mytoken123", false},
|
||||
{"missing header", "", "", true},
|
||||
{"no bearer prefix", "Token mytoken123", "", true},
|
||||
{"empty token", "Bearer ", "", true},
|
||||
{"case insensitive", "bearer mytoken123", "mytoken123", false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
|
||||
Reference in New Issue
Block a user