needed save users that can view channel instead of checking
This commit is contained in:
@@ -9,4 +9,5 @@ const (
|
|||||||
ConnectionDeleted
|
ConnectionDeleted
|
||||||
ConnectionElevated
|
ConnectionElevated
|
||||||
ConnectionDeElevated
|
ConnectionDeElevated
|
||||||
|
HubMessage
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ var (
|
|||||||
MaxRequestWithAvatarBytes uint32 = 1 << 20
|
MaxRequestWithAvatarBytes uint32 = 1 << 20
|
||||||
MaxRequestWithProfileBgBytes uint32 = 4 << 20
|
MaxRequestWithProfileBgBytes uint32 = 4 << 20
|
||||||
FileProcessingPartBytes uint64 = 12 << 20
|
FileProcessingPartBytes uint64 = 12 << 20
|
||||||
FileProcessingThreads uint32 = 3
|
FileProcessingThreads uint = 3
|
||||||
FileDownloadLinkTtl time.Duration = 24 * time.Hour
|
FileDownloadLinkTtl time.Duration = 24 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ type configFile struct {
|
|||||||
MaxRequestWithAvatarBytes uint32 `toml:"max_request_with_avatar_bytes"`
|
MaxRequestWithAvatarBytes uint32 `toml:"max_request_with_avatar_bytes"`
|
||||||
MaxRequestWithProfileBgBytes uint32 `toml:"max_request_with_profile_bg_bytes"`
|
MaxRequestWithProfileBgBytes uint32 `toml:"max_request_with_profile_bg_bytes"`
|
||||||
FileProcessingPartBytes uint64 `toml:"file_processing_part_bytes"`
|
FileProcessingPartBytes uint64 `toml:"file_processing_part_bytes"`
|
||||||
FileProcessingThreads uint32 `toml:"file_processing_threads"`
|
FileProcessingThreads uint `toml:"file_processing_threads"`
|
||||||
FileDownloadLinkTtl time.Duration `toml:"file_download_link_ttl"`
|
FileDownloadLinkTtl time.Duration `toml:"file_download_link_ttl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func HandleAttachmentFileUpload(response http.ResponseWriter, request *http.Requ
|
|||||||
key := minio.GetKey(minio.GetKeyOptions{
|
key := minio.GetKey(minio.GetKeyOptions{
|
||||||
ConnectionId: conn.Id,
|
ConnectionId: conn.Id,
|
||||||
MimeType: contentType,
|
MimeType: contentType,
|
||||||
UploadType: minio.File,
|
UploadType: minio.ConnectionFile,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{
|
if err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package httpRequest
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"go-socket/packages/convertions"
|
"go-socket/packages/convertions"
|
||||||
@@ -57,13 +58,11 @@ func getHubByIdStr(ctx context.Context, hubId string) (*types.Hub, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hub, ok := cache.GetHubById(hubUuid)
|
hub, ok := cache.GetHubById(hubUuid)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
hub = types.CreateHub()
|
return nil, errors.New("hub not found")
|
||||||
hub.Id = hubUuid
|
|
||||||
if err := postgresql.GetWholeHub(ctx, hub); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hub, nil
|
return hub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,3 +90,39 @@ func getHubUserIfValidWithResponseOnFail(ctx context.Context, response http.Resp
|
|||||||
|
|
||||||
return user, hubUser, hub, nil
|
return user, hubUser, hub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getHubChannelIfValidWithResponseOnFail(ctx context.Context, response http.ResponseWriter, hub *types.Hub, hubUser *types.HubUser, channelId string) (
|
||||||
|
*types.HubChannel, error) {
|
||||||
|
channelUuid, err := convertions.StringToUuid(channelId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid channelid", http.StatusBadRequest)
|
||||||
|
return nil, errors.New("invalid channelid")
|
||||||
|
}
|
||||||
|
channel, ok := hub.Channels[channelUuid]
|
||||||
|
if !ok {
|
||||||
|
http.Error(response, "invalid channelid", http.StatusUnauthorized)
|
||||||
|
return nil, errors.New("invalid channelid")
|
||||||
|
}
|
||||||
|
|
||||||
|
group := hub.Groups[channel.ParentId]
|
||||||
|
if group == nil {
|
||||||
|
slog.Warn("hub channel has no parent group", "Hub", hub.Id, "Channel", channel.Id)
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return nil, errors.New("internal server error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !group.RolesCanView.HasSameId(hubUser.Roles) {
|
||||||
|
http.Error(response, "invalid channelid", http.StatusUnauthorized)
|
||||||
|
return nil, errors.New("invalid channelid")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !channel.RolesCanView.HasSameId(hubUser.Roles) {
|
||||||
|
http.Error(response, "invalid channelid", http.StatusUnauthorized)
|
||||||
|
return nil, errors.New("invalid channelid")
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO cache on roles or channels needed for quick lookup
|
||||||
|
func getHubChannelReadHistorayAndViewChannel(hub *types.Hub, channel *types.HubChannel) []*types.HubUser
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go-socket/packages/convertions"
|
||||||
"go-socket/packages/types"
|
"go-socket/packages/types"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func canHubUserMessage(channel)
|
||||||
|
|
||||||
func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
||||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||||
return
|
return
|
||||||
@@ -21,7 +24,7 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hubName := request.Header.Get("hubname")
|
hubName := request.FormValue("hubname")
|
||||||
if hubName == "" {
|
if hubName == "" {
|
||||||
http.Error(response, "hub name is required", http.StatusBadRequest)
|
http.Error(response, "hub name is required", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -35,9 +38,9 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
hub.CreatedAt = time.Now()
|
hub.CreatedAt = time.Now()
|
||||||
|
|
||||||
creator := types.NewHubUser()
|
creator := types.NewHubUser()
|
||||||
creator.Name = user.Name
|
|
||||||
creator.OriginalId = user.Id
|
creator.OriginalId = user.Id
|
||||||
creator.CreatedAt = hub.CreatedAt
|
creator.CreatedAt = hub.CreatedAt
|
||||||
|
hub.Users[creator.OriginalId] = creator
|
||||||
|
|
||||||
rootRole := &types.HubRole{
|
rootRole := &types.HubRole{
|
||||||
Id: uint8(0),
|
Id: uint8(0),
|
||||||
@@ -50,7 +53,7 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
creator.Roles.Add(rootRole.Id)
|
creator.Roles.Add(rootRole.Id)
|
||||||
|
|
||||||
memberRole := &types.HubRole{
|
memberRole := &types.HubRole{
|
||||||
Id: uint8(255),
|
Id: types.BoundRolesMax,
|
||||||
Name: "member",
|
Name: "member",
|
||||||
Color: types.Rgba{}.GetRandom(),
|
Color: types.Rgba{}.GetRandom(),
|
||||||
CreatedAt: hub.CreatedAt,
|
CreatedAt: hub.CreatedAt,
|
||||||
@@ -63,6 +66,8 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
rootGroup.Id = uint8(1)
|
rootGroup.Id = uint8(1)
|
||||||
rootGroup.Color = types.Rgba{}.GetRandom()
|
rootGroup.Color = types.Rgba{}.GetRandom()
|
||||||
rootGroup.CreatedAt = hub.CreatedAt
|
rootGroup.CreatedAt = hub.CreatedAt
|
||||||
|
rootGroup.RolesCanView.Add(rootRole.Id)
|
||||||
|
rootGroup.RolesCanView.Add(memberRole.Id)
|
||||||
hub.Groups[rootGroup.Id] = rootGroup
|
hub.Groups[rootGroup.Id] = rootGroup
|
||||||
|
|
||||||
channel := types.NewHubChannel()
|
channel := types.NewHubChannel()
|
||||||
@@ -71,5 +76,49 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
channel.Id = uuid.New()
|
channel.Id = uuid.New()
|
||||||
channel.ParentId = rootGroup.Id
|
channel.ParentId = rootGroup.Id
|
||||||
channel.Description = "The fist channel!"
|
channel.Description = "The fist channel!"
|
||||||
|
channel.CreatedAt = hub.CreatedAt
|
||||||
|
channel.RolesCanMessage.Add(rootGroup.Id)
|
||||||
|
channel.RolesCanMessage.Add(memberRole.Id)
|
||||||
|
channel.RolesCanView.Add(rootGroup.Id)
|
||||||
|
channel.RolesCanView.Add(memberRole.Id)
|
||||||
|
channel.RolesCanReadHistory.Add(rootGroup.Id)
|
||||||
|
channel.RolesCanReadHistory.Add(memberRole.Id)
|
||||||
hub.Channels[channel.Id] = channel
|
hub.Channels[channel.Id] = channel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleChannelSendMessage(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
user, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
channelId, err := convertions.StringToUuid(request.FormValue("channelid"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid channelid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msgContent := request.FormValue("msgContent")
|
||||||
|
attachedFile := request.FormValue("attachedFile")
|
||||||
|
|
||||||
|
if msgContent == "" && attachedFile == "" {
|
||||||
|
http.Error(response, "empty msgContent", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add check in future
|
||||||
|
// if attachedFile != "" && !strings.HasPrefix(attachedFile, conn.Id.String()+"/") {
|
||||||
|
// http.Error(response, "invalid attachedFile", http.StatusBadRequest)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
channel, err := getHubChannelIfValidWithResponseOnFail(ctx, response, hub, hubUser, request.FormValue("hubid"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
+10
-5
@@ -20,7 +20,8 @@ var minClient *minio.Client
|
|||||||
type DataType uint8
|
type DataType uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
File DataType = iota
|
ConnectionFile DataType = iota
|
||||||
|
HubChannelFile
|
||||||
UserAvatar
|
UserAvatar
|
||||||
UserProfileBg
|
UserProfileBg
|
||||||
)
|
)
|
||||||
@@ -28,14 +29,16 @@ const (
|
|||||||
type DataTypePrefix string
|
type DataTypePrefix string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FilePrefix DataTypePrefix = "upload/"
|
ConnectionFilePrefix DataTypePrefix = "connection/"
|
||||||
UserAvatarPrefix DataTypePrefix = "userAvatar/"
|
HubChannelFilePrefix DataTypePrefix = "hub/"
|
||||||
UserProfileBgPrefix DataTypePrefix = "userProfileBg/"
|
UserAvatarPrefix DataTypePrefix = "userAvatar/"
|
||||||
|
UserProfileBgPrefix DataTypePrefix = "userProfileBg/"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GetKeyOptions struct {
|
type GetKeyOptions struct {
|
||||||
UserId uuid.UUID
|
UserId uuid.UUID
|
||||||
ConnectionId uuid.UUID
|
ConnectionId uuid.UUID
|
||||||
|
ChannelId uuid.UUID
|
||||||
MimeType string
|
MimeType string
|
||||||
UploadType DataType
|
UploadType DataType
|
||||||
}
|
}
|
||||||
@@ -49,12 +52,14 @@ func GetKey(opts GetKeyOptions) string {
|
|||||||
key := "/" + strconv.FormatInt(time.Now().UnixMilli(), 10) + extensions[0]
|
key := "/" + strconv.FormatInt(time.Now().UnixMilli(), 10) + extensions[0]
|
||||||
|
|
||||||
switch opts.UploadType {
|
switch opts.UploadType {
|
||||||
|
case HubChannelFile:
|
||||||
|
return string(HubChannelFilePrefix) + opts.ChannelId.String() + key
|
||||||
case UserAvatar:
|
case UserAvatar:
|
||||||
return string(UserAvatarPrefix) + opts.UserId.String() + key
|
return string(UserAvatarPrefix) + opts.UserId.String() + key
|
||||||
case UserProfileBg:
|
case UserProfileBg:
|
||||||
return string(UserProfileBgPrefix) + opts.UserId.String() + key
|
return string(UserProfileBgPrefix) + opts.UserId.String() + key
|
||||||
default:
|
default:
|
||||||
return string(FilePrefix) + opts.ConnectionId.String() + key
|
return string(ConnectionFilePrefix) + opts.ConnectionId.String() + key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-23
@@ -187,23 +187,22 @@ func PermissionAll() Permissions {
|
|||||||
return math.MaxUint32
|
return math.MaxUint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type BoundRoles uint64
|
type BoundRoles [3]uint64
|
||||||
|
|
||||||
func (b *BoundRoles) Add(id uint8) {
|
const BoundRolesMax uint8 = 191
|
||||||
*b |= 1 << id
|
|
||||||
}
|
func (r *BoundRoles) Add(bit uint8) { r[bit>>6] |= 1 << (bit & 63) }
|
||||||
func (b *BoundRoles) Remove(id uint8) {
|
func (r *BoundRoles) Remove(bit uint8) { r[bit>>6] &^= 1 << (bit & 63) }
|
||||||
*b &^= 1 << id
|
func (r *BoundRoles) Has(bit uint8) bool { return r[bit>>6]>>(bit&63)&1 == 1 }
|
||||||
}
|
func (r *BoundRoles) HasSameId(against BoundRoles) bool {
|
||||||
func (b *BoundRoles) Has(id uint8) bool {
|
return against[0]&r[0] != 0 || against[1]&r[1] != 0 || against[2]&r[2] != 0
|
||||||
return *b&(1<<id) != 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Hub struct {
|
type Hub struct {
|
||||||
Mu sync.RWMutex `json:"-"`
|
Mu sync.RWMutex `json:"-"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
Roles [256]*HubRole `json:"-"`
|
Roles [256]*HubRole `json:"-"`
|
||||||
Users [256]*HubUser `json:"-"`
|
Users map[uuid.UUID]*HubUser `json:"-"`
|
||||||
Groups [256]*HubGroup `json:"-"`
|
Groups [256]*HubGroup `json:"-"`
|
||||||
Channels map[uuid.UUID]*HubChannel `json:"-"`
|
Channels map[uuid.UUID]*HubChannel `json:"-"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -218,6 +217,7 @@ type Hub struct {
|
|||||||
|
|
||||||
func NewHub() *Hub {
|
func NewHub() *Hub {
|
||||||
return &Hub{
|
return &Hub{
|
||||||
|
Users: make(map[uuid.UUID]*HubUser),
|
||||||
Channels: make(map[uuid.UUID]*HubChannel),
|
Channels: make(map[uuid.UUID]*HubChannel),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,6 +241,19 @@ func (h *HubRole) HasPermission(r Permissions) bool {
|
|||||||
return h.Permissions&r != 0
|
return h.Permissions&r != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HubUser struct {
|
||||||
|
Mu sync.RWMutex `json:"mu"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
Roles BoundRoles `json:"-"`
|
||||||
|
Name string `json:"name"` // Name empty = original name
|
||||||
|
OriginalId uuid.UUID `json:"originalId"`
|
||||||
|
IsMuted bool `json:"isMuted"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHubUser() *HubUser {
|
||||||
|
return &HubUser{}
|
||||||
|
}
|
||||||
|
|
||||||
type HubGroup struct {
|
type HubGroup struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
@@ -253,19 +266,6 @@ func NewHubGroup() *HubGroup {
|
|||||||
return &HubGroup{}
|
return &HubGroup{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type HubUser struct {
|
|
||||||
Mu sync.RWMutex `json:"mu"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
Roles BoundRoles `json:"-"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
OriginalId uuid.UUID `json:"originalId"`
|
|
||||||
IsMuted bool `json:"isMuted"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHubUser() *HubUser {
|
|
||||||
return &HubUser{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type HubChannel struct {
|
type HubChannel struct {
|
||||||
Mu sync.RWMutex `json:"-"`
|
Mu sync.RWMutex `json:"-"`
|
||||||
MessagesBuff []*Message `json:"-"`
|
MessagesBuff []*Message `json:"-"`
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
when user not ws connected collect count of unread messages for each conn (add db table in future)
|
when user not ws connected collect count of unread messages for each conn (add db table in future)
|
||||||
|
|
||||||
add hubs
|
add hubs
|
||||||
|
setting avatar and profilebg
|
||||||
check when mutex needed
|
check when mutex needed
|
||||||
|
|
||||||
user banners
|
user banners
|
||||||
|
|||||||
Reference in New Issue
Block a user