package middleware import ( "net/http" "haixun-backend/internal/library/authctx" app "haixun-backend/internal/library/errors" "haixun-backend/internal/library/errors/code" "haixun-backend/internal/library/permmatch" memberdomain "haixun-backend/internal/model/member/domain/usecase" permissiondomain "haixun-backend/internal/model/permission/domain/usecase" "haixun-backend/internal/response" ) // PermissionRBACMiddleware enforces catalog permissions for authenticated members. // Mount after AuthJWT or MemberAuth so actor is present in context. type PermissionRBACMiddleware struct { members memberdomain.UseCase permissions permissiondomain.UseCase } func NewPermissionRBACMiddleware( members memberdomain.UseCase, permissions permissiondomain.UseCase, ) *PermissionRBACMiddleware { return &PermissionRBACMiddleware{members: members, permissions: permissions} } func (m *PermissionRBACMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { actor, ok := authctx.ActorFromContext(r.Context()) if !ok { response.Write(r.Context(), w, nil, app.For(code.Auth).AuthUnauthorized("missing actor")) return } if m.members == nil || m.permissions == nil { response.Write(r.Context(), w, nil, app.For(code.Permission).SysNotImplemented("permission rbac is not configured")) return } member, err := m.members.GetByUID(r.Context(), actor.TenantID, actor.UID) if err != nil { response.Write(r.Context(), w, nil, err) return } me, err := m.permissions.Me(r.Context(), member, false) if err != nil { response.Write(r.Context(), w, nil, err) return } if !permmatch.RequestAllowed(me.Permissions, r.Method, r.URL.Path) { response.Write(r.Context(), w, nil, app.For(code.Permission).AuthForbidden("permission denied")) return } next(w, r) } }