feat: check joined and err handler

pull/242/head
zijiren233 1 year ago
parent 03a88d3aea
commit 2b5fb20675

@ -584,7 +584,7 @@ func (r *Room) RemoveMemberPermissions(userID string, permissions model.RoomMemb
func (r *Room) ApprovePendingMember(userID string) error {
if r.IsCreator(userID) {
return errors.New("you are creator, cannot approve")
return errors.New("creator cannot be approved as a pending member")
}
defer r.members.Delete(userID)
return db.RoomApprovePendingMember(r.ID, userID)
@ -592,7 +592,7 @@ func (r *Room) ApprovePendingMember(userID string) error {
func (r *Room) BanMember(userID string) error {
if r.IsCreator(userID) {
return errors.New("you are creator, cannot ban")
return errors.New("creator cannot be banned")
}
if r.IsGuest(userID) {
return errors.New("please set whether to disable guest users in the room settings")
@ -606,7 +606,7 @@ func (r *Room) BanMember(userID string) error {
func (r *Room) UnbanMember(userID string) error {
if r.IsCreator(userID) {
return errors.New("you are creator, cannot unban")
return errors.New("creator cannot be unbanned")
}
if r.IsGuest(userID) {
return errors.New("please set whether to enable guest users in the room settings")
@ -617,7 +617,7 @@ func (r *Room) UnbanMember(userID string) error {
func (r *Room) DeleteMember(userID string) error {
if r.IsCreator(userID) {
return errors.New("you are creator, cannot delete")
return errors.New("creator cannot be deleted")
}
defer func() {
r.members.Delete(userID)
@ -632,7 +632,7 @@ func (r *Room) ResetAdminPermissions(userID string) error {
func (r *Room) SetAdminPermissions(userID string, permissions model.RoomAdminPermission) error {
if r.IsCreator(userID) {
return errors.New("you are creator, cannot set admin permissions")
return errors.New("creator cannot set admin permissions")
}
if r.IsGuest(userID) {
return errors.New("cannot set admin permissions to guest")
@ -648,7 +648,7 @@ func (r *Room) SetAdminPermissions(userID string, permissions model.RoomAdminPer
func (r *Room) AddAdminPermissions(userID string, permissions model.RoomAdminPermission) error {
if r.IsCreator(userID) {
return errors.New("you are creator, cannot add admin permissions")
return errors.New("creator cannot add admin permissions")
}
if r.IsGuest(userID) {
return errors.New("cannot add admin permissions to guest")
@ -664,7 +664,7 @@ func (r *Room) AddAdminPermissions(userID string, permissions model.RoomAdminPer
func (r *Room) RemoveAdminPermissions(userID string, permissions model.RoomAdminPermission) error {
if r.IsCreator(userID) {
return errors.New("you are creator, cannot remove admin permissions")
return errors.New("creator cannot remove admin permissions")
}
if r.IsGuest(userID) {
return errors.New("cannot remove admin permissions from guest")
@ -680,7 +680,7 @@ func (r *Room) RemoveAdminPermissions(userID string, permissions model.RoomAdmin
func (r *Room) SetAdmin(userID string, permissions model.RoomAdminPermission) error {
if r.IsCreator(userID) {
return errors.New("you are creator, cannot set admin")
return errors.New("creator cannot set admin")
}
if r.IsGuest(userID) {
return errors.New("cannot set guest as admin")
@ -691,7 +691,7 @@ func (r *Room) SetAdmin(userID string, permissions model.RoomAdminPermission) er
func (r *Room) SetMember(userID string, permissions model.RoomMemberPermission) error {
if r.IsCreator(userID) {
return errors.New("you are creator, cannot set member")
return errors.New("creator cannot set member")
}
defer r.members.Delete(userID)
return db.RoomSetMember(r.ID, userID, permissions)

@ -13,12 +13,10 @@ import (
var (
roomCache *synccache.SyncCache[string, *Room]
ErrRoomPending = errors.New("room pending, please wait for admin to approve")
ErrRoomBanned = errors.New("room banned")
ErrRoomCreatorBanned = errors.New("room creator banned")
ErrRoomCreatorPending = errors.New("room creator pending, please wait for admin to approve")
ErrInvalidRoomID = errors.New("room id is not 32 bit")
ErrRoomNotInCache = errors.New("room is not in cache")
ErrRoomCreatorBanned = errors.New("room creator is banned")
ErrRoomCreatorPending = errors.New("room creator is pending approval, please wait for admin to review")
ErrInvalidRoomID = errors.New("invalid room ID: must be 32 characters long")
ErrRoomNotInCache = errors.New("room not found in cache")
)
type RoomEntry = synccache.Entry[*Room]

@ -16,8 +16,8 @@ var userCache *synccache.SyncCache[string, *User]
type UserEntry = synccache.Entry[*User]
var (
ErrUserBanned = errors.New("user banned")
ErrUserPending = errors.New("user pending, please wait for admin to approve")
ErrUserBanned = errors.New("user account has been banned")
ErrUserPending = errors.New("user account is pending approval, please wait for administrator review")
)
func LoadOrInitUser(u *model.User) (*UserEntry, error) {

@ -69,6 +69,7 @@ func RoomInfo(ctx *gin.Context) {
"name": room.Name,
"needPassword": room.NeedPassword(),
"creator": op.GetUserName(room.CreatorID),
"creatorId": room.CreatorID,
"createdAt": room.CreatedAt.UnixMilli(),
"status": room.Status,
"enabledGuest": room.EnabledGuest(),
@ -128,9 +129,10 @@ var roomHotCache = refreshcache0.NewRefreshCache[[]*model.RoomListResp](func(con
rooms = append(rooms, &model.RoomListResp{
RoomId: v.ID,
RoomName: v.Name,
PeopleNum: v.ViewerCount(),
ViewerCount: v.ViewerCount(),
NeedPassword: v.NeedPassword(),
Creator: op.GetUserName(v.CreatorID),
CreatorID: v.CreatorID,
CreatedAt: v.CreatedAt.UnixMilli(),
})
}
@ -138,7 +140,7 @@ var roomHotCache = refreshcache0.NewRefreshCache[[]*model.RoomListResp](func(con
})
slices.SortStableFunc(rooms, func(a, b *model.RoomListResp) int {
if a.PeopleNum == b.PeopleNum {
if a.ViewerCount == b.ViewerCount {
if a.RoomName == b.RoomName {
return 0
}
@ -147,7 +149,7 @@ var roomHotCache = refreshcache0.NewRefreshCache[[]*model.RoomListResp](func(con
} else {
return 1
}
} else if a.PeopleNum > b.PeopleNum {
} else if a.ViewerCount > b.ViewerCount {
return -1
} else {
return 1
@ -274,7 +276,7 @@ func genRoomListResp(scopes ...func(db *gorm.DB) *gorm.DB) ([]*model.RoomListRes
resp[i] = &model.RoomListResp{
RoomId: r.ID,
RoomName: r.Name,
PeopleNum: op.ViewerCount(r.ID),
ViewerCount: op.ViewerCount(r.ID),
NeedPassword: len(r.HashedPassword) != 0,
CreatorID: r.CreatorID,
Creator: op.GetUserName(r.CreatorID),
@ -299,7 +301,7 @@ func genJoinedRoomListResp(scopes ...func(db *gorm.DB) *gorm.DB) ([]*model.Joine
RoomListResp: model.RoomListResp{
RoomId: r.ID,
RoomName: r.Name,
PeopleNum: op.ViewerCount(r.ID),
ViewerCount: op.ViewerCount(r.ID),
NeedPassword: len(r.HashedPassword) != 0,
CreatorID: r.CreatorID,
Creator: op.GetUserName(r.CreatorID),
@ -330,14 +332,14 @@ func CheckRoom(ctx *gin.Context) {
}
room := roomE.Value()
ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{
"name": room.Name,
"status": room.Status,
"peopleNum": op.ViewerCount(room.ID),
"needPassword": room.NeedPassword(),
"creatorId": room.CreatorID,
"creator": op.GetUserName(room.CreatorID),
"enabledGuest": room.EnabledGuest(),
ctx.JSON(http.StatusOK, model.NewApiDataResp(&model.CheckRoomResp{
Name: room.Name,
Status: room.Status,
CreatorID: room.CreatorID,
Creator: op.GetUserName(room.CreatorID),
NeedPassword: room.NeedPassword(),
ViewerCount: op.ViewerCount(room.ID),
EnabledGuest: room.EnabledGuest(),
}))
}
@ -355,15 +357,23 @@ func LoginRoom(ctx *gin.Context) {
roomE, err := op.LoadOrInitRoomByID(req.RoomId)
if err != nil {
log.Errorf("login room failed: %v", err)
if err == op.ErrRoomBanned || err == op.ErrRoomPending {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(err))
return
}
ctx.AbortWithStatusJSON(http.StatusNotFound, model.NewApiErrorResp(err))
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err))
return
}
room := roomE.Value()
if room.IsBanned() {
log.Warn("login room failed: room is banned")
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("room is banned"))
return
}
if room.IsPending() {
log.Warn("login room failed: room is pending, please wait for admin to approve")
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("room is pending, please wait for admin to approve"))
return
}
if member, err := room.LoadMember(user.ID); err == nil {
ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{
"status": member.Status,

@ -305,6 +305,15 @@ func UserCheckJoinedRoom(ctx *gin.Context) {
ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{
"joined": status != dbModel.RoomMemberStatusNotJoined,
"status": status,
"room": &model.CheckRoomResp{
Name: room.Name,
Status: room.Status,
CreatorID: room.CreatorID,
Creator: op.GetUserName(room.CreatorID),
NeedPassword: room.NeedPassword(),
ViewerCount: op.ViewerCount(room.ID),
EnabledGuest: room.EnabledGuest(),
},
}))
}

@ -2,7 +2,6 @@ package middlewares
import (
"errors"
"fmt"
"net/http"
"strings"
"time"
@ -20,8 +19,20 @@ import (
)
var (
ErrAuthFailed = errors.New("auth failed")
ErrAuthExpired = errors.New("auth expired")
ErrAuthFailed = errors.New("authentication failed")
ErrAuthExpired = errors.New("authentication token expired")
ErrUserBanned = errors.New("user account has been banned")
ErrUserPending = errors.New("user account is pending approval")
ErrUserGuest = errors.New("guests are not allowed to perform this action")
ErrRoomBanned = errors.New("room has been banned")
ErrRoomPending = errors.New("room is pending approval")
ErrUserBannedFromRoom = errors.New("user has been banned from this room")
ErrInvalidRoomID = errors.New("invalid room ID")
ErrEmptyToken = errors.New("authentication token is empty")
ErrNotRoomAdmin = errors.New("user is not a room administrator")
ErrNotRoomCreator = errors.New("user is not the room creator")
ErrNotAdmin = errors.New("user is not an administrator")
ErrNotRoot = errors.New("user is not a root user")
)
type AuthClaims struct {
@ -46,7 +57,7 @@ func authUser(authorization string) (*AuthClaims, error) {
func AuthRoom(authorization, roomId string) (*op.UserEntry, *op.RoomEntry, error) {
if len(roomId) != 32 {
return nil, nil, ErrAuthFailed
return nil, nil, ErrInvalidRoomID
}
userE, err := authenticateUserOrGuest(authorization)
@ -95,23 +106,23 @@ func authenticateUser(Authorization string) (*op.UserEntry, error) {
func authenticateGuest() (*op.UserEntry, error) {
if !settings.EnableGuest.Get() {
return nil, fmt.Errorf("guests are disabled")
return nil, ErrUserGuest
}
return op.LoadOrInitGuestUser()
}
func validateUser(user *op.User, userVersion uint32) error {
if user.IsGuest() {
return fmt.Errorf("guests are not allowed to join rooms by token")
return ErrUserGuest
}
if !user.CheckVersion(userVersion) {
return ErrAuthExpired
}
if user.IsBanned() {
return fmt.Errorf("user is banned")
return ErrUserBanned
}
if user.IsPending() {
return fmt.Errorf("user is pending, need admin to approve")
return ErrUserPending
}
return nil
}
@ -133,18 +144,18 @@ func authenticateRoomAccess(roomId string, user *op.User) (*op.RoomEntry, error)
func validateRoomAccess(room *op.Room, user *op.User) error {
if room.IsGuest(user.ID) {
if room.Settings.DisableGuest {
return fmt.Errorf("guests are not allowed to join rooms")
return ErrUserGuest
}
if room.NeedPassword() {
return fmt.Errorf("guests are not allowed to join rooms that require a password")
return ErrUserGuest
}
}
if room.IsBanned() {
return fmt.Errorf("room is banned")
return ErrRoomBanned
}
if room.IsPending() {
return fmt.Errorf("room is pending, need admin to approve")
return ErrRoomPending
}
var status dbModel.RoomMemberStatus
@ -159,10 +170,10 @@ func validateRoomAccess(room *op.Room, user *op.User) error {
}
if status.IsBanned() {
return fmt.Errorf("user is banned from room")
return ErrUserBannedFromRoom
}
if status.IsPending() {
return fmt.Errorf("user is pending, need admin to approve")
return ErrUserPending
}
return nil
@ -193,16 +204,16 @@ func AuthUser(authorization string) (*op.UserEntry, error) {
func validateAuthUser(user *op.User, userVersion uint32) error {
if user.IsGuest() {
return errors.New("user is guest, cannot login")
return ErrUserGuest
}
if !user.CheckVersion(userVersion) {
return ErrAuthExpired
}
if user.IsBanned() {
return errors.New("user is banned")
return ErrUserBanned
}
if user.IsPending() {
return errors.New("user is pending, need admin to approve")
return ErrUserPending
}
return nil
}
@ -228,12 +239,6 @@ func NewAuthUserToken(user *op.User) (string, error) {
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(stream.StringToBytes(conf.Conf.Jwt.Secret))
}
var (
ErrUserBanned = errors.New("user banned")
ErrUserPending = errors.New("user is pending, need admin to approve")
ErrUserGuest = errors.New("user is guest, cannot login")
)
func validateNewAuthUserToken(user *op.User) error {
if user.IsBanned() {
return ErrUserBanned
@ -250,7 +255,7 @@ func validateNewAuthUserToken(user *op.User) error {
func AuthUserMiddleware(ctx *gin.Context) {
token := GetAuthorizationTokenFromContext(ctx)
if token == "" {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, model.NewApiErrorStringResp("token is empty"))
ctx.AbortWithStatusJSON(http.StatusUnauthorized, model.NewApiErrorResp(ErrEmptyToken))
return
}
userE, err := AuthUser(token)
@ -291,7 +296,7 @@ func AuthRoomWithoutGuestMiddleware(ctx *gin.Context) {
user := ctx.MustGet("user").(*synccache.Entry[*op.User]).Value()
if user.IsGuest() {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("guest has no permission"))
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(ErrUserGuest))
return
}
}
@ -306,7 +311,7 @@ func AuthRoomAdminMiddleware(ctx *gin.Context) {
user := ctx.MustGet("user").(*synccache.Entry[*op.User]).Value()
if !user.IsRoomAdmin(room) {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("user has no permission"))
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(ErrNotRoomAdmin))
return
}
}
@ -321,7 +326,7 @@ func AuthRoomCreatorMiddleware(ctx *gin.Context) {
user := ctx.MustGet("user").(*synccache.Entry[*op.User]).Value()
if room.CreatorID != user.ID {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("user is not creator"))
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(ErrNotRoomCreator))
return
}
}
@ -334,7 +339,7 @@ func AuthAdminMiddleware(ctx *gin.Context) {
userE := ctx.MustGet("user").(*synccache.Entry[*op.User])
if !userE.Value().IsAdmin() {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("user is not admin"))
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(ErrNotAdmin))
return
}
}
@ -347,7 +352,7 @@ func AuthRootMiddleware(ctx *gin.Context) {
userE := ctx.MustGet("user").(*synccache.Entry[*op.User])
if !userE.Value().IsRoot() {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("user is not root"))
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(ErrNotRoot))
return
}
}
@ -392,11 +397,11 @@ func GetRoomIdFromContext(ctx *gin.Context) (string, error) {
return roomId, nil
}
ctx.Set("roomId", "")
return "", errors.New("room id length is not 32")
return "", ErrInvalidRoomID
}
ctx.Set("roomId", "")
return "", errors.New("room id is empty")
return "", ErrInvalidRoomID
}
func setLogFields(ctx *gin.Context, user *op.User, room *op.Room) {

@ -61,7 +61,7 @@ func (c *CreateRoomReq) Validate() error {
type RoomListResp struct {
RoomId string `json:"roomId"`
RoomName string `json:"roomName"`
PeopleNum int64 `json:"peopleNum"`
ViewerCount int64 `json:"viewerCount"`
NeedPassword bool `json:"needPassword"`
CreatorID string `json:"creatorId"`
Creator string `json:"creator"`
@ -150,3 +150,13 @@ func (c *CheckRoomPasswordReq) Decode(ctx *gin.Context) error {
func (c *CheckRoomPasswordReq) Validate() error {
return nil
}
type CheckRoomResp struct {
Name string `json:"name"`
Status model.RoomStatus `json:"status"`
CreatorID string `json:"creatorId"`
Creator string `json:"creator"`
NeedPassword bool `json:"needPassword"`
ViewerCount int64 `json:"viewerCount"`
EnabledGuest bool `json:"enabledGuest"`
}

Loading…
Cancel
Save