package auth import ( "context" "net/http" ) type roleKey struct{} type Role int const ( RoleReader Role = iota RoleWriter RoleAdmin ) func ParseRole(s string) Role { switch s { case "admin": return RoleAdmin case "writer": return RoleWriter default: return RoleReader } } func (r Role) CanRead() bool { return true } func (r Role) CanWrite() bool { return r >= RoleWriter } func (r Role) CanDDL() bool { return r >= RoleAdmin } type Handler struct { role Role } func New(roleStr string) *Handler { return &Handler{role: ParseRole(roleStr)} } func (h *Handler) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := context.WithValue(r.Context(), roleKey{}, h.role) next.ServeHTTP(w, r.WithContext(ctx)) }) } func RoleFromContext(ctx context.Context) Role { if r, ok := ctx.Value(roleKey{}).(Role); ok { return r } return RoleReader } func RequireWrite(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !RoleFromContext(r.Context()).CanWrite() { http.Error(w, `{"error":"forbidden: write access required"}`, http.StatusForbidden) return } next(w, r) } } func RequireDDL(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !RoleFromContext(r.Context()).CanDDL() { http.Error(w, `{"error":"forbidden: admin access required"}`, http.StatusForbidden) return } next(w, r) } } func RequireWriteMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !RoleFromContext(r.Context()).CanWrite() { http.Error(w, `{"error":"forbidden: write access required"}`, http.StatusForbidden) return } next.ServeHTTP(w, r) }) }