feat: add user status and path permissions

This commit is contained in:
OpenClaw Agent
2026-09-22 01:30:30 +08:00
parent eafc6c6499
commit 71757ec0fa
5 changed files with 163 additions and 16 deletions
+35 -7
View File
@@ -110,7 +110,7 @@ func account(r *http.Request, s *Server) *auth.Account {
if err != nil {
return s.Auth.Guest
}
if a, ok := s.Auth.Accounts[username]; ok {
if a, ok := s.Auth.Accounts[username]; ok && (a.Enabled || a.PasswordHash == "") {
return a
}
return s.Auth.Guest
@@ -465,7 +465,7 @@ func (s *Server) me(w http.ResponseWriter, r *http.Request) {
writeJSONError(w, http.StatusUnauthorized, "not authenticated")
return
}
writeJSON(w, map[string]any{"username": a.Username, "home": a.Home, "admin": a.Admin, "mask": permString(a.MaskFor(a.Home)), "managed": a.PasswordHash != ""})
writeJSON(w, map[string]any{"username": a.Username, "home": a.Home, "admin": a.Admin, "mask": permString(a.MaskFor(a.Home)), "managed": a.PasswordHash != "", "enabled": a.Enabled})
}
func (s *Server) password(w http.ResponseWriter, r *http.Request) {
@@ -502,6 +502,21 @@ func (s *Server) password(w http.ResponseWriter, r *http.Request) {
writeJSON(w, map[string]any{"ok": true})
}
type userRuleJSON struct {
Dir string `json:"dir"`
Mask string `json:"mask"`
Deny bool `json:"deny,omitempty"`
ChildrenOnly bool `json:"childrenOnly,omitempty"`
}
func userRulesJSON(rules []auth.PathRule) []userRuleJSON {
out := make([]userRuleJSON, 0, len(rules))
for _, r := range rules {
out = append(out, userRuleJSON{Dir: r.Dir, Mask: permString(r.Mask), Deny: r.Deny, ChildrenOnly: r.ChildrenOnly})
}
return out
}
func (s *Server) users(w http.ResponseWriter, r *http.Request) {
a := account(r, s)
if a == nil || !a.Admin {
@@ -519,7 +534,7 @@ func (s *Server) users(w http.ResponseWriter, r *http.Request) {
if u.Username == "" || u == s.Auth.Guest {
continue
}
out = append(out, map[string]any{"username": u.Username, "home": u.Home, "admin": u.Admin, "managed": u.PasswordHash != ""})
out = append(out, map[string]any{"username": u.Username, "home": u.Home, "admin": u.Admin, "managed": u.PasswordHash != "", "enabled": u.Enabled, "rules": userRulesJSON(u.Rules)})
}
writeJSON(w, map[string]any{"users": out})
case http.MethodPost:
@@ -550,8 +565,10 @@ func (s *Server) users(w http.ResponseWriter, r *http.Request) {
writeJSON(w, map[string]any{"username": u.Username, "home": u.Home})
case http.MethodPut:
var req struct {
Username string `json:"username"`
Password string `json:"password"`
Username string `json:"username"`
Password string `json:"password"`
Enabled *bool `json:"enabled"`
Rules []userRuleJSON `json:"rules"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSONError(w, http.StatusBadRequest, "invalid json")
@@ -561,11 +578,22 @@ func (s *Server) users(w http.ResponseWriter, r *http.Request) {
writeJSONError(w, http.StatusBadRequest, "invalid username")
return
}
if err := s.UserStore.UpdatePassword(s.Auth, req.Username, req.Password); err != nil {
var rules []auth.PathRule
if req.Rules != nil {
for _, rr := range req.Rules {
dir := strings.Trim(strings.ReplaceAll(rr.Dir, "\\", "/"), "/")
if dir == "" || unsafePath(dir) {
writeJSONError(w, http.StatusBadRequest, "invalid rule path")
return
}
rules = append(rules, auth.PathRule{Dir: dir, Mask: auth.ParseMask(rr.Mask), Deny: rr.Deny, ChildrenOnly: rr.ChildrenOnly})
}
}
if err := s.UserStore.Update(s.Auth, req.Username, req.Password, req.Enabled, rules); err != nil {
writeJSONError(w, http.StatusBadRequest, err.Error())
return
}
s.logOp(r, fmt.Sprintf("reset password for '%s'", req.Username))
s.logOp(r, fmt.Sprintf("updated user '%s'", req.Username))
writeJSON(w, map[string]any{"ok": true})
case http.MethodDelete:
username := r.URL.Query().Get("username")