97 lines
2.5 KiB
Go
97 lines
2.5 KiB
Go
package rbac
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"git.haelnorr.com/h/golib/hws"
|
|
"git.haelnorr.com/h/oslstats/internal/contexts"
|
|
"git.haelnorr.com/h/oslstats/internal/db"
|
|
"github.com/pkg/errors"
|
|
"github.com/uptrace/bun"
|
|
)
|
|
|
|
// LoadPreviewRoleMiddleware loads the preview role from the session cookie if present
|
|
// and adds it to the request context. This must run after authentication but before
|
|
// the RBAC cache middleware.
|
|
func LoadPreviewRoleMiddleware(s *hws.Server, conn *bun.DB) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// Check if there's a preview role in the cookie
|
|
roleID := getPreviewRoleCookie(r)
|
|
if roleID == 0 {
|
|
// No preview role, continue normally
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
// Load the preview role from the database
|
|
var previewRole *db.Role
|
|
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
|
|
var err error
|
|
previewRole, err = db.GetRoleByID(ctx, tx, roleID)
|
|
if err != nil {
|
|
return false, errors.Wrap(err, "db.GetRoleByID")
|
|
}
|
|
if previewRole == nil {
|
|
// Role doesn't exist anymore, clear the cookie
|
|
ClearPreviewRoleCookie(w)
|
|
return true, nil
|
|
}
|
|
return true, nil
|
|
}); !ok {
|
|
return
|
|
}
|
|
|
|
// If role was found, add it to context
|
|
if previewRole != nil {
|
|
ctx := contexts.WithPreviewRole(r.Context(), previewRole)
|
|
r = r.WithContext(ctx)
|
|
}
|
|
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|
|
|
|
// SetPreviewRoleCookie sets the preview role ID in a session cookie
|
|
func SetPreviewRoleCookie(w http.ResponseWriter, roleID int, ssl bool) {
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: "preview_role",
|
|
Value: strconv.Itoa(roleID),
|
|
Path: "/",
|
|
MaxAge: 0, // Session cookie - expires when browser closes or session times out
|
|
HttpOnly: true,
|
|
Secure: ssl,
|
|
SameSite: http.SameSiteLaxMode,
|
|
})
|
|
}
|
|
|
|
// getPreviewRoleCookie retrieves the preview role ID from the cookie
|
|
// Returns 0 if not present or invalid
|
|
func getPreviewRoleCookie(r *http.Request) int {
|
|
if r == nil {
|
|
return 0
|
|
}
|
|
cookie, err := r.Cookie("preview_role")
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
roleID, err := strconv.Atoi(cookie.Value)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return roleID
|
|
}
|
|
|
|
// ClearPreviewRoleCookie removes the preview role cookie
|
|
func ClearPreviewRoleCookie(w http.ResponseWriter) {
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: "preview_role",
|
|
Value: "",
|
|
Path: "/",
|
|
MaxAge: -1,
|
|
})
|
|
}
|