add hub menagment functions

This commit is contained in:
gitGnome
2026-04-29 14:46:22 +02:00
parent 221fb47495
commit 6378966267
19 changed files with 780 additions and 62 deletions
@@ -13,4 +13,5 @@ const (
UserAvatarChange
UserProfileBgChange
HubMessage
ConnectionElevatePending
)
+14 -1
View File
@@ -13,6 +13,7 @@ import (
"go-socket/packages/cache"
"go-socket/packages/config"
"go-socket/packages/convertions"
"go-socket/packages/minio"
"go-socket/packages/postgresql"
"go-socket/packages/types"
"go-socket/packages/wsServer"
@@ -45,7 +46,7 @@ func HandleDm(response http.ResponseWriter, request *http.Request) {
return
}
if attachedFile != "" && !strings.HasPrefix(attachedFile, conn.Id.String()+"/") {
if attachedFile != "" && !strings.HasPrefix(attachedFile, string(minio.ConnectionFilePrefix)+conn.Id.String()+"/") {
http.Error(response, "invalid attachedFile", http.StatusBadRequest)
return
}
@@ -346,6 +347,18 @@ func HandleUserElevateConnection(response http.ResponseWriter, request *http.Req
}
conn.UserWantingToElevate = user.Id
user2, err := getUserById(ctx, conn.GetSecondUser(user.Id))
if err == nil {
wsServer.WsSendMessageCloseIfTimeout(user2, types.WsEventMessage{
Type: WsEventType.ConnectionElevatePending,
Event: types.ConnectionElevatePendingData{
Id: conn.Id,
UserWantingToElevate: user.Id,
},
})
}
response.Write([]byte("waiting for second user to elevate"))
}
+1 -1
View File
@@ -326,7 +326,7 @@ func HandleAttachmentFileDownload(response http.ResponseWriter, request *http.Re
}
key := request.URL.Query().Get("key")
if !strings.HasPrefix(key, conn.Id.String()+"/") {
if !strings.HasPrefix(key, string(minio.ConnectionFilePrefix)+conn.Id.String()+"/") {
http.Error(response, "no such file", http.StatusUnauthorized)
return
}
+241 -2
View File
@@ -2,6 +2,7 @@ package httpRequest
import (
"encoding/json"
"go-socket/packages/convertions"
"maps"
"net/http"
"slices"
@@ -15,16 +16,37 @@ import (
"github.com/google/uuid"
)
func haveHubUserPermissionsOnChannel(permissions types.CachedUserPermissions, user *types.HubUser, channel *types.HubChannel) bool {
func haveHubUserPermissionsOnChannel(needed types.CachedUserPermissions, user *types.HubUser, channel *types.HubChannel) bool {
channel.Mu.RLock()
checkAgainst, ok := channel.UsersCachedPermissions[user.OriginalId]
channel.Mu.RUnlock()
if !ok || (permissions&checkAgainst) != permissions {
if !ok || (needed&checkAgainst) != needed {
return false
}
return true
}
func haveUserPermissions(needed types.Permissions, scope uint8, hu *types.HubUser, h *types.Hub) bool {
h.Mu.RLock()
defer h.Mu.RUnlock()
for _, role := range h.Roles {
if role == nil {
continue
}
if scope != 0 && role.BoundedGroup != scope {
continue
}
if !hu.Roles.Has(role.Id) {
continue
}
if (needed & role.Permissions) != needed {
return true
}
}
return true
}
func addHubUserToPermissionCache(hub *types.Hub, user *types.HubUser) {
user.Mu.RLock()
roles := user.Roles
@@ -177,6 +199,10 @@ func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
return
}
if hubUser.IsGlobalMuted {
http.Error(response, "muted", http.StatusForbidden)
}
msgContent := request.FormValue("msgContent")
attachedFile := request.FormValue("attachedFile")
@@ -242,3 +268,216 @@ func HandleGetHubs(response http.ResponseWriter, request *http.Request) {
response.WriteHeader(http.StatusOK)
response.Write(converted)
}
func HandleHubSetName(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(&response, request, normal) {
return
}
ctx := request.Context()
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
if err != nil {
return
}
newName := request.FormValue("name")
if newName == "" {
http.Error(response, "empty name", http.StatusBadRequest)
return
}
if !haveUserPermissions(types.PermissionSetHubName, 0, hubUser, hub) {
http.Error(response, "no permission", http.StatusForbidden)
return
}
hub.Name = newName
response.WriteHeader(http.StatusAccepted)
}
func HandleHubSetColor(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(&response, request, normal) {
return
}
ctx := request.Context()
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
if err != nil {
return
}
newColor, err := convertions.StringToRgba(request.FormValue("color"))
if err != nil {
http.Error(response, "bad color", http.StatusBadRequest)
return
}
if !haveUserPermissions(types.PermissionSetHubColor, 0, hubUser, hub) {
http.Error(response, "no permission", http.StatusForbidden)
return
}
hub.Color = newColor
response.WriteHeader(http.StatusAccepted)
}
func HandleHubRemove(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(&response, request, normal) {
return
}
ctx := request.Context()
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
if err != nil {
return
}
if !haveUserPermissions(types.PermissionRemoveHub, 0, hubUser, hub) {
http.Error(response, "no permission", http.StatusForbidden)
return
}
cache.DeleteHub(hub)
}
func HandleHubSetAllowUserColor(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(&response, request, normal) {
return
}
ctx := request.Context()
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
if err != nil {
return
}
if !haveUserPermissions(types.PermissionSetUserColorAllowed, 0, hubUser, hub) {
http.Error(response, "no permission", http.StatusForbidden)
return
}
cache.DeleteHub(hub)
}
func HandleHubRemoveUser(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(&response, request, normal) {
return
}
ctx := request.Context()
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
if err != nil {
return
}
targetId, err := convertions.StringToUuid(request.FormValue("target"))
if err != nil {
http.Error(response, "invalid targetid", http.StatusBadRequest)
return
}
hub.Mu.RLock()
_, ok := hub.Users[targetId]
if !ok {
http.Error(response, "target not found", http.StatusNotFound)
return
}
if !haveUserPermissions(types.PermissionRemoveUser, 0, hubUser, hub) {
http.Error(response, "no permission", http.StatusForbidden)
return
}
hub.Mu.Lock()
delete(hub.Users, targetId)
hub.Mu.Unlock()
response.WriteHeader(http.StatusAccepted)
}
func HandleHubMuteUserToggle(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(&response, request, normal) {
return
}
ctx := request.Context()
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
if err != nil {
return
}
targetId, err := convertions.StringToUuid(request.FormValue("target"))
if err != nil {
http.Error(response, "invalid targetid", http.StatusBadRequest)
return
}
scope, err := convertions.StringToUint32(request.FormValue("scope"))
if err != nil {
http.Error(response, "invalid scope (set 0 for no scope)", http.StatusBadRequest)
return
}
hub.Mu.RLock()
target, ok := hub.Users[targetId]
hub.Mu.RUnlock()
if !ok {
http.Error(response, "target not found", http.StatusNotFound)
return
}
if !haveUserPermissions(types.PermissionMuteUser, uint8(scope), hubUser, hub) {
http.Error(response, "no permission", http.StatusForbidden)
return
}
if scope == 0 {
target.IsGlobalMuted = !target.IsGlobalMuted
} else {
hub.Mu.Lock()
users := hub.Groups[scope].MutedUsers
_, ok = users[targetId]
if ok {
delete(users, targetId)
} else {
users[targetId] = struct{}{}
}
}
}
func HandleHubMuteUserToggle(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(&response, request, normal) {
return
}
ctx := request.Context()
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
if err != nil {
return
}
targetId, err := convertions.StringToUuid(request.FormValue("target"))
if err != nil {
http.Error(response, "invalid targetid", http.StatusBadRequest)
return
}
scope, err := convertions.StringToUint32(request.FormValue("scope"))
if err != nil {
http.Error(response, "invalid scope (set 0 for no scope)", http.StatusBadRequest)
return
}
hub.Mu.RLock()
target, ok := hub.Users[targetId]
hub.Mu.RUnlock()
if !ok {
http.Error(response, "target not found", http.StatusNotFound)
return
}
if !haveUserPermissions(types.PermissionMuteUser, uint8(scope), hubUser, hub) {
http.Error(response, "no permission", http.StatusForbidden)
return
}
if scope == 0 {
target.IsGlobalMuted = !target.IsGlobalMuted
} else {
hub.Mu.Lock()
users := hub.Groups[scope].MutedUsers
_, ok = users[targetId]
if ok {
delete(users, targetId)
} else {
users[targetId] = struct{}{}
}
}
}
+13 -7
View File
@@ -108,6 +108,11 @@ type ConnectionStatusSetData struct {
NewState ConnectionState.ConnectionState `json:"newState"`
}
type ConnectionElevatePendingData struct {
Id uuid.UUID `json:"id"`
UserWantingToElevate uuid.UUID `json:"userWantingToElevate"`
}
type Message struct {
Id uuid.UUID `json:"id"`
AttachedFile string `json:"attachedFile"`
@@ -272,12 +277,12 @@ func (h *HubRole) HasPermission(r Permissions) bool {
}
type HubUser struct {
Mu sync.RWMutex `json:"mu"`
CreatedAt time.Time `json:"createdAt"`
Roles HubBoundRoles `json:"-"`
Name string `json:"name"` // Name empty = original name
OriginalId uuid.UUID `json:"originalId"`
IsMuted bool `json:"isMuted"`
Mu sync.RWMutex `json:"mu"`
CreatedAt time.Time `json:"createdAt"`
Roles HubBoundRoles `json:"-"`
Name string `json:"name"` // Name empty = original name
OriginalId uuid.UUID `json:"originalId"`
IsGlobalMuted bool `json:"isGlobalMuted"`
}
func NewHubUser() *HubUser {
@@ -290,7 +295,8 @@ type HubGroup struct {
Color Rgba `json:"color"`
RolesCanView HubBoundRoles `json:"rolesCanView"`
UsersCachedPermissions map[uuid.UUID]CachedUserPermissions `json:"-"`
Channels map[uuid.UUID]*HubChannel `json:"channels"`
Channels map[uuid.UUID]*HubChannel `json:"-"`
MutedUsers map[uuid.UUID]struct{} `json:"-"`
Id uint8 `json:"id"` // Id 0 for unused
}