only lower id roles can be modfified, add new hub endpoints
This commit is contained in:
@@ -73,3 +73,7 @@ func StringToUuidSlice(uuidStr string) ([]uuid.UUID, error) {
|
||||
func StringToTimestamp(str string) (time.Time, error) {
|
||||
return time.Parse(time.RFC3339, str)
|
||||
}
|
||||
|
||||
func StringToBool(str string) bool {
|
||||
return strings.ToLower(str) == "true"
|
||||
}
|
||||
|
||||
+187
-52
@@ -3,13 +3,14 @@ package httpRequest
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"go-socket/packages/convertions"
|
||||
"maps"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go-socket/packages/convertions"
|
||||
|
||||
"go-socket/packages/cache"
|
||||
"go-socket/packages/types"
|
||||
"go-socket/packages/wsServer"
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func haveHubUserPermission(u *types.HubUser, h *types.Hub, needed types.Permissions) bool {
|
||||
func haveHubUserPermission(u *types.HubUser, h *types.Hub, needed types.Permissions) (id uint8, has bool) {
|
||||
h.Mu.Lock()
|
||||
defer h.Mu.Unlock()
|
||||
for _, role := range h.Roles {
|
||||
@@ -27,11 +28,30 @@ func haveHubUserPermission(u *types.HubUser, h *types.Hub, needed types.Permissi
|
||||
if !u.Roles.Has(role.Id) {
|
||||
continue
|
||||
}
|
||||
if (needed & role.Permissions) == needed {
|
||||
return true
|
||||
if (needed&role.Permissions) == needed && role.Id > id {
|
||||
id = role.Id
|
||||
has = true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return id, has
|
||||
}
|
||||
|
||||
func hubUserHighestRoleId(u *types.HubUser, h *types.Hub) (id uint8) {
|
||||
h.Mu.Lock()
|
||||
defer h.Mu.Unlock()
|
||||
|
||||
for _, role := range h.Roles {
|
||||
if role == nil {
|
||||
continue
|
||||
}
|
||||
if !u.Roles.Has(role.Id) {
|
||||
continue
|
||||
}
|
||||
if role.Id > id {
|
||||
id = role.Id
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
func haveHubUserCachedPermissions(needed types.CachedUserPermissions, user *types.HubUser, channel *types.HubChannel) bool {
|
||||
@@ -222,24 +242,27 @@ func HandleGetHubs(response http.ResponseWriter, request *http.Request) {
|
||||
response.Write(converted)
|
||||
}
|
||||
|
||||
func hubPermissionContext(response http.ResponseWriter, request *http.Request, rt bodyLimit, needed types.Permissions) (*types.HubUser, *types.Hub, context.Context, bool) {
|
||||
func hubPermissionContext(response http.ResponseWriter, request *http.Request, rt bodyLimit, needed types.Permissions) (*types.HubUser, *types.Hub, context.Context, uint8, bool) {
|
||||
if !validCheckWithResponseOnFail(response, request, rt) {
|
||||
return nil, nil, nil, false
|
||||
return nil, nil, nil, 0, false
|
||||
}
|
||||
ctx := request.Context()
|
||||
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false
|
||||
return nil, nil, nil, 0, false
|
||||
}
|
||||
if !haveHubUserPermission(hubUser, hub, needed) {
|
||||
|
||||
roleId, ok := haveHubUserPermission(hubUser, hub, needed)
|
||||
|
||||
if !ok {
|
||||
http.Error(response, "", http.StatusForbidden)
|
||||
return nil, nil, nil, false
|
||||
return nil, nil, nil, 0, false
|
||||
}
|
||||
return hubUser, hub, ctx, true
|
||||
return hubUser, hub, ctx, roleId, true
|
||||
}
|
||||
|
||||
func HandleHubSetName(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubName)
|
||||
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubName)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -253,7 +276,7 @@ func HandleHubSetName(response http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
func HandleHubSetColor(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubColor)
|
||||
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubColor)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -267,7 +290,7 @@ func HandleHubSetColor(response http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
func HandleHubRemove(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveHub)
|
||||
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveHub)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -276,7 +299,7 @@ func HandleHubRemove(response http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
func HandleHubToggleUserColorAllowed(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetUserColorAllowed)
|
||||
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetUserColorAllowed)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -285,7 +308,7 @@ func HandleHubToggleUserColorAllowed(response http.ResponseWriter, request *http
|
||||
}
|
||||
|
||||
func HandleHubUserRemove(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveUser)
|
||||
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveUser)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -294,19 +317,27 @@ func HandleHubUserRemove(response http.ResponseWriter, request *http.Request) {
|
||||
http.Error(response, "bad targetid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
hub.Mu.Lock()
|
||||
if _, exists := hub.Users[targetId]; !exists {
|
||||
hub.Mu.RLock()
|
||||
target, exists := hub.Users[targetId]
|
||||
if !exists {
|
||||
hub.Mu.Unlock()
|
||||
http.Error(response, "user not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
hub.Mu.RUnlock()
|
||||
|
||||
if usedRoleId <= hubUserHighestRoleId(target, hub) {
|
||||
http.Error(response, "target higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
hub.Mu.Lock()
|
||||
delete(hub.Users, targetId)
|
||||
hub.Mu.Unlock()
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandleHubRenameUser(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionRenameUser)
|
||||
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionRenameUser)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -317,10 +348,16 @@ func HandleHubRenameUser(response http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
hub.Mu.RLock()
|
||||
target, ok := hub.Users[targetId]
|
||||
target, exists := hub.Users[targetId]
|
||||
if !exists {
|
||||
hub.Mu.Unlock()
|
||||
http.Error(response, "user not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
hub.Mu.RUnlock()
|
||||
if !ok {
|
||||
http.Error(response, "no users found", http.StatusNotFound)
|
||||
|
||||
if usedRoleId <= hubUserHighestRoleId(target, hub) {
|
||||
http.Error(response, "target higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
target.Name = newName
|
||||
@@ -329,16 +366,16 @@ func HandleHubRenameUser(response http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
func HandleHubRenameSelf(response http.ResponseWriter, request *http.Request) {
|
||||
hubUser, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSelfRename)
|
||||
requestor, _, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSelfRename)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
hubUser.Name = request.FormValue("newname")
|
||||
requestor.Name = request.FormValue("newname")
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandleHubToggleMuteUser(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionMuteUser)
|
||||
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionMuteUser)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -348,18 +385,25 @@ func HandleHubToggleMuteUser(response http.ResponseWriter, request *http.Request
|
||||
return
|
||||
}
|
||||
hub.Mu.RLock()
|
||||
target, ok := hub.Users[targetId]
|
||||
hub.Mu.RUnlock()
|
||||
if !ok {
|
||||
target, exists := hub.Users[targetId]
|
||||
if !exists {
|
||||
hub.Mu.Unlock()
|
||||
http.Error(response, "user not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
hub.Mu.RUnlock()
|
||||
|
||||
if usedRoleId <= hubUserHighestRoleId(target, hub) {
|
||||
http.Error(response, "target higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
hub.Mu.RLock()
|
||||
target.IsMuted = !target.IsMuted
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandleHubUserAddRole(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionUserAddRole)
|
||||
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionUserAddRole)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -373,6 +417,11 @@ func HandleHubUserAddRole(response http.ResponseWriter, request *http.Request) {
|
||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if roleId > usedRoleId {
|
||||
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
hub.Mu.RLock()
|
||||
target, ok := hub.Users[targetId]
|
||||
role := hub.Roles[roleId]
|
||||
@@ -390,7 +439,7 @@ func HandleHubUserAddRole(response http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
func HandleHubUserRemoveRole(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionUserRemoveRole)
|
||||
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionUserRemoveRole)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -404,6 +453,11 @@ func HandleHubUserRemoveRole(response http.ResponseWriter, request *http.Request
|
||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if roleId > usedRoleId {
|
||||
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
hub.Mu.RLock()
|
||||
target, ok := hub.Users[targetId]
|
||||
hub.Mu.RUnlock()
|
||||
@@ -416,7 +470,7 @@ func HandleHubUserRemoveRole(response http.ResponseWriter, request *http.Request
|
||||
}
|
||||
|
||||
func HandleHubCreateRole(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionCreateRole)
|
||||
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionCreateRole)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -429,7 +483,7 @@ func HandleHubCreateRole(response http.ResponseWriter, request *http.Request) {
|
||||
var freeId uint8
|
||||
found := false
|
||||
for i := uint8(1); i < types.HubBoundRolesMax; i++ {
|
||||
if hub.Roles[i] == nil {
|
||||
if hub.Roles[i] == nil && usedRoleId > i {
|
||||
freeId = i
|
||||
found = true
|
||||
break
|
||||
@@ -451,32 +505,37 @@ func HandleHubCreateRole(response http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
func HandleHubRemoveRole(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveRole)
|
||||
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveRole)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
roleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
||||
targetRoleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
||||
if err != nil {
|
||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if roleId == 0 || roleId == types.HubBoundRolesMax {
|
||||
http.Error(response, "cannot remove system role", http.StatusForbidden)
|
||||
if targetRoleId == 0 {
|
||||
http.Error(response, "cannot remove root role", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
if targetRoleId > usedRoleId {
|
||||
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
hub.Mu.Lock()
|
||||
if hub.Roles[roleId] == nil {
|
||||
if hub.Roles[targetRoleId] == nil {
|
||||
hub.Mu.Unlock()
|
||||
http.Error(response, "role not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
hub.Roles[roleId] = nil
|
||||
hub.Roles[targetRoleId] = nil
|
||||
hub.Mu.Unlock()
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandleHubSelfRoleRemove(response http.ResponseWriter, request *http.Request) {
|
||||
hubUser, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSelfRoleRemove)
|
||||
func HandlePermissionSetRoleName(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionSetRoleName)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -485,18 +544,8 @@ func HandleHubSelfRoleRemove(response http.ResponseWriter, request *http.Request
|
||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
hubUser.Roles.Remove(roleId)
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func PermissionSetRoleName(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetRoleName)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
roleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
||||
if err != nil {
|
||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
||||
if roleId > usedRoleId {
|
||||
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
newName := request.FormValue("newname")
|
||||
@@ -515,3 +564,89 @@ func PermissionSetRoleName(response http.ResponseWriter, request *http.Request)
|
||||
hub.Mu.Unlock()
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandlePermissionSetRoleColor(response http.ResponseWriter, request *http.Request) {
|
||||
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionSetRoleColor)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
roleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
||||
if err != nil {
|
||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if roleId > usedRoleId {
|
||||
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
color, err := convertions.StringToRgba(request.FormValue("newcolor"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid newcolor", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
hub.Mu.Lock()
|
||||
role := hub.Roles[roleId]
|
||||
if role == nil {
|
||||
http.Error(response, "no such role", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
role.Color = color
|
||||
hub.Mu.Unlock()
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandlePermissionSetRolePermissions(response http.ResponseWriter, request *http.Request) {
|
||||
requestor, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionSetRolePermissions)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
targetRoleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
||||
if err != nil {
|
||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if targetRoleId > usedRoleId {
|
||||
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
hub.Mu.Lock()
|
||||
targetRole := hub.Roles[targetRoleId]
|
||||
hub.Mu.Unlock()
|
||||
if targetRole == nil {
|
||||
http.Error(response, "no such role", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
query := request.URL.Query()
|
||||
for key, values := range query {
|
||||
permission, ok := types.PermissionLookup(key)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
permRoleId, ok := haveHubUserPermission(requestor, hub, permission)
|
||||
if !ok {
|
||||
http.Error(response, "permission needed: "+key, http.StatusNotFound)
|
||||
}
|
||||
if permRoleId <= targetRoleId {
|
||||
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
if convertions.StringToBool(values[0]) {
|
||||
targetRole.Permissions.Grant(permission)
|
||||
} else {
|
||||
targetRole.Permissions.Revoke(permission)
|
||||
}
|
||||
}
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandlePermissionSelfRoleRemove(response http.ResponseWriter, request *http.Request) {
|
||||
requestor, _, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionUserSelfRoleRemove)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
requestor.Roles.Remove(usedRoleId)
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
+35
-3
@@ -157,6 +157,7 @@ const (
|
||||
PermissionMuteUser
|
||||
PermissionUserAddRole
|
||||
PermissionUserRemoveRole
|
||||
PermissionUserSelfRoleRemove
|
||||
|
||||
// Role permissions
|
||||
PermissionCreateRole
|
||||
@@ -165,9 +166,6 @@ const (
|
||||
PermissionSetRoleColor
|
||||
PermissionSetRolePermissions
|
||||
|
||||
PermissionSelfRoleRemove
|
||||
PermissionOnlySelfRoleRemove
|
||||
|
||||
// Channel permissions
|
||||
PermissionAddChannel
|
||||
PermissionRemoveChannel
|
||||
@@ -178,6 +176,40 @@ const (
|
||||
PermissionSetChannelPermittedReadHistoryRoles
|
||||
)
|
||||
|
||||
var permissionRegistry = map[string]Permissions{
|
||||
"set_hub_name": PermissionSetHubName,
|
||||
"set_hub_icon": PermissionSetHubIcon,
|
||||
"set_hub_bg": PermissionSetHubBg,
|
||||
"set_hub_color": PermissionSetHubColor,
|
||||
"remove_hub": PermissionRemoveHub,
|
||||
"set_user_color_allowed": PermissionSetUserColorAllowed,
|
||||
"invite_user": PermissionInviteUser,
|
||||
"remove_user": PermissionRemoveUser,
|
||||
"rename_user": PermissionRenameUser,
|
||||
"self_rename": PermissionSelfRename,
|
||||
"mute_user": PermissionMuteUser,
|
||||
"user_add_role": PermissionUserAddRole,
|
||||
"user_remove_role": PermissionUserRemoveRole,
|
||||
"create_role": PermissionCreateRole,
|
||||
"remove_role": PermissionRemoveRole,
|
||||
"set_role_name": PermissionSetRoleName,
|
||||
"set_role_color": PermissionSetRoleColor,
|
||||
"set_role_permissions": PermissionSetRolePermissions,
|
||||
"self_role_remove": PermissionUserSelfRoleRemove,
|
||||
"add_channel": PermissionAddChannel,
|
||||
"remove_channel": PermissionRemoveChannel,
|
||||
"set_channel_name": PermissionSetChannelName,
|
||||
"set_channel_icon": PermissionSetChannelIcon,
|
||||
"set_channel_permitted_visible": PermissionSetChannelPermittedVisibleRoles,
|
||||
"set_channel_permitted_send": PermissionSetChannelPermittedSendMessageRoles,
|
||||
"set_channel_permitted_read": PermissionSetChannelPermittedReadHistoryRoles,
|
||||
}
|
||||
|
||||
func PermissionLookup(permission string) (Permissions, bool) {
|
||||
p, ok := permissionRegistry[permission]
|
||||
return p, ok
|
||||
}
|
||||
|
||||
func (p *Permissions) Grant(permissions Permissions) {
|
||||
*p |= permissions
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user