implemented NATS event bus, websocket hub upgrade, and audit log
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
"github.com/forgeo/forgebucket/internal/events"
|
||||
"github.com/forgeo/forgebucket/internal/models"
|
||||
)
|
||||
|
||||
// statusRecorder wraps ResponseWriter to capture the written status code.
|
||||
type statusRecorder struct {
|
||||
http.ResponseWriter
|
||||
status int
|
||||
}
|
||||
|
||||
func (r *statusRecorder) WriteHeader(code int) {
|
||||
r.status = code
|
||||
r.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
// AuditLog middleware records every state-mutating request (POST/PUT/PATCH/DELETE)
|
||||
// to the audit_log table and publishes an audit.event to the event bus.
|
||||
// It runs after auth middleware so the actor is available in context.
|
||||
func AuditLog(db *xorm.Engine, bus events.EventBus) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet, http.MethodHead, http.MethodOptions, http.MethodTrace:
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
rec := &statusRecorder{ResponseWriter: w, status: http.StatusOK}
|
||||
next.ServeHTTP(rec, r)
|
||||
|
||||
actorID, _ := UserIDFromContext(r.Context())
|
||||
actorName, _ := r.Context().Value(ContextKeyUsername).(string)
|
||||
|
||||
entry := &models.AuditLog{
|
||||
ActorID: actorID,
|
||||
ActorName: actorName,
|
||||
Method: r.Method,
|
||||
Path: r.URL.Path,
|
||||
StatusCode: rec.status,
|
||||
IPAddress: r.RemoteAddr,
|
||||
UserAgent: r.UserAgent(),
|
||||
OccurredAt: time.Now().UTC(),
|
||||
}
|
||||
|
||||
go func() {
|
||||
db.Insert(entry) //nolint:errcheck
|
||||
bus.Publish(events.SubjectAuditEvent, events.AuditEvent{ //nolint:errcheck
|
||||
ActorID: entry.ActorID,
|
||||
ActorName: entry.ActorName,
|
||||
Action: entry.Method + " " + entry.Path,
|
||||
ResourcePath: entry.Path,
|
||||
IPAddress: entry.IPAddress,
|
||||
StatusCode: entry.StatusCode,
|
||||
At: entry.OccurredAt,
|
||||
})
|
||||
}()
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user