Replaced one-pager with multiple pages and fixed security bugs
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
@@ -17,7 +16,7 @@ func registerUserRoutes(mux *http.ServeMux) {
|
||||
}
|
||||
|
||||
func handleListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
rows, err := db.Query("SELECT id,username,display_name,language,is_system_admin FROM users ORDER BY username")
|
||||
rows, err := db.Query("SELECT id,username,display_name,language,is_system_admin,must_change_password FROM users ORDER BY username")
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "db_error")
|
||||
return
|
||||
@@ -26,9 +25,10 @@ func handleListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
out := []User{}
|
||||
for rows.Next() {
|
||||
var u User
|
||||
var admin int
|
||||
rows.Scan(&u.ID, &u.Username, &u.DisplayName, &u.Language, &admin)
|
||||
var admin, mustChange int
|
||||
rows.Scan(&u.ID, &u.Username, &u.DisplayName, &u.Language, &admin, &mustChange)
|
||||
u.IsSystemAdmin = admin == 1
|
||||
u.MustChangePassword = mustChange == 1
|
||||
out = append(out, u)
|
||||
}
|
||||
writeJSON(w, http.StatusOK, out)
|
||||
@@ -47,11 +47,16 @@ func handleCreateUser(w http.ResponseWriter, r *http.Request) {
|
||||
writeError(w, http.StatusBadRequest, "invalid_body")
|
||||
return
|
||||
}
|
||||
req.Username = strings.TrimSpace(req.Username)
|
||||
req.Username = normalizeUsername(req.Username)
|
||||
if req.Username == "" || req.Password == "" {
|
||||
writeError(w, http.StatusBadRequest, "missing_fields")
|
||||
return
|
||||
}
|
||||
if len(req.Username) > maxUsernameLen || len(req.Password) > maxPasswordLen ||
|
||||
len(req.DisplayName) > maxDisplayNameLen {
|
||||
writeError(w, http.StatusBadRequest, "too_long")
|
||||
return
|
||||
}
|
||||
if req.IsSystemAdmin && !actor.IsSystemAdmin {
|
||||
writeError(w, http.StatusForbidden, "forbidden")
|
||||
return
|
||||
@@ -114,18 +119,39 @@ func handleAdminUpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
var req struct {
|
||||
DisplayName *string `json:"display_name"`
|
||||
Password *string `json:"password"`
|
||||
IsSystemAdmin *bool `json:"is_system_admin"`
|
||||
Username *string `json:"username"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
Password *string `json:"password"`
|
||||
IsSystemAdmin *bool `json:"is_system_admin"`
|
||||
MustChangePassword *bool `json:"must_change_password"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid_body")
|
||||
return
|
||||
}
|
||||
if req.Username != nil {
|
||||
newName := normalizeUsername(*req.Username)
|
||||
if newName == "" || len(newName) > maxUsernameLen {
|
||||
writeError(w, http.StatusBadRequest, "invalid_username")
|
||||
return
|
||||
}
|
||||
if _, err := db.Exec("UPDATE users SET username=? WHERE id=?", newName, id); err != nil {
|
||||
writeError(w, http.StatusConflict, "username_taken")
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.DisplayName != nil {
|
||||
if len(*req.DisplayName) > maxDisplayNameLen {
|
||||
writeError(w, http.StatusBadRequest, "too_long")
|
||||
return
|
||||
}
|
||||
db.Exec("UPDATE users SET display_name=? WHERE id=?", *req.DisplayName, id)
|
||||
}
|
||||
if req.Password != nil && *req.Password != "" {
|
||||
if len(*req.Password) > maxPasswordLen {
|
||||
writeError(w, http.StatusBadRequest, "too_long")
|
||||
return
|
||||
}
|
||||
hash, _ := bcrypt.GenerateFromPassword([]byte(*req.Password), bcrypt.DefaultCost)
|
||||
db.Exec("UPDATE users SET password_hash=? WHERE id=?", string(hash), id)
|
||||
}
|
||||
@@ -136,6 +162,13 @@ func handleAdminUpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
db.Exec("UPDATE users SET is_system_admin=? WHERE id=?", v, id)
|
||||
}
|
||||
if req.MustChangePassword != nil {
|
||||
v := 0
|
||||
if *req.MustChangePassword {
|
||||
v = 1
|
||||
}
|
||||
db.Exec("UPDATE users SET must_change_password=? WHERE id=?", v, id)
|
||||
}
|
||||
u, _ := loadUser(id)
|
||||
writeJSON(w, http.StatusOK, u)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user