wireguard-ui/handler/api_v1_users.go

97 lines
2.3 KiB
Go

package handler
import (
"net/http"
"time"
"github.com/labstack/echo/v4"
"github.com/labstack/gommon/log"
"github.com/DigitalTolk/wireguard-ui/store"
)
// APIListUsers returns all users (read-only, managed via SSO)
func APIListUsers(db store.IStore) echo.HandlerFunc {
return func(c echo.Context) error {
users, err := db.GetUsers()
if err != nil {
return apiInternalError(c, "Cannot get user list")
}
return c.JSON(http.StatusOK, users)
}
}
// APIPatchUserAdmin toggles admin status for a user
func APIPatchUserAdmin(db store.IStore) echo.HandlerFunc {
return func(c echo.Context) error {
username := c.Param("username")
if !usernameRegexp.MatchString(username) {
return apiBadRequest(c, "Invalid username")
}
var body struct {
Admin bool `json:"admin"`
}
if err := c.Bind(&body); err != nil {
return apiBadRequest(c, "Invalid request body")
}
user, err := db.GetUserByName(username)
if err != nil {
return apiNotFound(c, "User not found")
}
// prevent demoting yourself
if !body.Admin && username == currentUser(c) {
return apiBadRequest(c, "Cannot remove your own admin role")
}
// prevent removing the last admin
if !body.Admin && user.Admin {
users, err := db.GetUsers()
if err != nil {
return apiInternalError(c, "Cannot verify admin count")
}
adminCount := 0
for _, u := range users {
if u.Admin {
adminCount++
}
}
if adminCount <= 1 {
return apiBadRequest(c, "Cannot remove the last admin")
}
}
user.Admin = body.Admin
user.UpdatedAt = time.Now().UTC()
if err := db.SaveUser(user); err != nil {
return apiInternalError(c, "Cannot update user")
}
action := "user.demote"
if body.Admin {
action = "user.promote"
}
log.Infof("Changed admin status for %s to %v", username, body.Admin)
auditLogEvent(c, action, "user", username, nil)
return c.JSON(http.StatusOK, user)
}
}
// APIGetUser returns a single user by username
func APIGetUser(db store.IStore) echo.HandlerFunc {
return func(c echo.Context) error {
username := c.Param("username")
if !usernameRegexp.MatchString(username) {
return apiBadRequest(c, "Invalid username")
}
user, err := db.GetUserByName(username)
if err != nil {
return apiNotFound(c, "User not found")
}
return c.JSON(http.StatusOK, user)
}
}