Feat: support guess user

pull/134/head
zijiren233 2 years ago
parent cc14366af1
commit 01c087e60e

@ -25,6 +25,10 @@ func Init(d *gorm.DB, t conf.DatabaseType) error {
if err != nil {
return err
}
err = initGuestUser()
if err != nil {
return err
}
return initRootUser()
}
@ -39,6 +43,22 @@ func initRootUser() error {
return err
}
const (
GuestUsername = "guest"
GuestUserID = "00000000000000000000000000000001"
)
func initGuestUser() error {
user := model.User{}
err := db.Where("id = ?", GuestUserID).First(&user).Error
if err == nil || !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
u, err := CreateUser("guest", utils.RandString(32), WithRole(model.RoleUser), WithID(GuestUserID))
log.Infof("init guest user:\nid: %s\nusername: %s", u.ID, u.Username)
return err
}
func DB() *gorm.DB {
return db
}

@ -50,7 +50,7 @@ func FirstOrCreateRoomMemberRelation(roomID, userID string, conf ...CreateRoomMe
return roomMemberRelation, err
}
func GetRoomMemberRelation(roomID, userID string) (*model.RoomMember, error) {
func GetRoomMember(roomID, userID string) (*model.RoomMember, error) {
roomMemberRelation := &model.RoomMember{}
err := db.Where("room_id = ? AND user_id = ?", roomID, userID).First(roomMemberRelation).Error
return roomMemberRelation, HandleNotFound(err, "room or user")

@ -15,6 +15,12 @@ import (
type CreateUserConfig func(u *model.User)
func WithID(id string) CreateUserConfig {
return func(u *model.User) {
u.ID = id
}
}
func WithRole(role model.Role) CreateUserConfig {
return func(u *model.User) {
u.Role = role

@ -77,6 +77,7 @@ type RoomSettings struct {
DisableJoinNewUser bool `gorm:"default:false" json:"disable_join_new_user"`
JoinNeedReview bool `gorm:"default:false" json:"join_need_review"`
UserDefaultPermissions RoomMemberPermission `json:"user_default_permissions"`
DisableGuest bool `gorm:"default:false" json:"disable_guest"`
CanGetMovieList bool `gorm:"default:true" json:"can_get_movie_list"`
CanAddMovie bool `gorm:"default:true" json:"can_add_movie"`
@ -93,6 +94,7 @@ func DefaultRoomSettings() *RoomSettings {
DisableJoinNewUser: false,
JoinNeedReview: false,
UserDefaultPermissions: DefaultPermissions,
DisableGuest: false,
CanGetMovieList: true,
CanAddMovie: true,

@ -7,9 +7,9 @@ import (
"sync/atomic"
"github.com/gorilla/websocket"
log "github.com/sirupsen/logrus"
"github.com/synctv-org/synctv/internal/db"
"github.com/synctv-org/synctv/internal/model"
"github.com/synctv-org/synctv/internal/settings"
"github.com/synctv-org/synctv/utils"
"github.com/zijiren233/gencontainer/rwmap"
rtmps "github.com/zijiren233/livelib/server"
@ -93,10 +93,10 @@ func (r *Room) AddMovies(movies []*model.Movie) error {
}
func (r *Room) UserRole(userID string) (model.RoomMemberRole, error) {
if r.CreatorID == userID {
if r.IsCreator(userID) {
return model.RoomMemberRoleCreator, nil
}
rur, err := r.LoadOrCreateRoomMember(userID)
rur, err := r.LoadRoomMember(userID)
if err != nil {
return model.RoomMemberRoleUnknown, err
}
@ -105,12 +105,8 @@ func (r *Room) UserRole(userID string) (model.RoomMemberRole, error) {
// do not use this value for permission determination
func (r *Room) IsAdmin(userID string) bool {
if r.IsCreator(userID) {
return true
}
role, err := r.UserRole(userID)
if err != nil {
log.Errorf("get user role failed: %s", err.Error())
return false
}
return role.IsAdmin()
@ -120,6 +116,10 @@ func (r *Room) IsCreator(userID string) bool {
return r.CreatorID == userID
}
func (r *Room) IsGuest(userID string) bool {
return userID == db.GuestUserID
}
func (r *Room) HasPermission(userID string, permission model.RoomMemberPermission) bool {
if r.IsCreator(userID) {
return true
@ -162,7 +162,7 @@ func (r *Room) HasAdminPermission(userID string, permission model.RoomAdminPermi
}
func (r *Room) LoadOrCreateMemberStatus(userID string) (model.RoomMemberStatus, error) {
if r.CreatorID == userID {
if r.IsCreator(userID) {
return model.RoomMemberStatusActive, nil
}
rur, err := r.LoadOrCreateRoomMember(userID)
@ -173,7 +173,7 @@ func (r *Room) LoadOrCreateMemberStatus(userID string) (model.RoomMemberStatus,
}
func (r *Room) LoadMemberStatus(userID string) (model.RoomMemberStatus, error) {
if r.CreatorID == userID {
if r.IsCreator(userID) {
return model.RoomMemberStatusActive, nil
}
rur, err := r.LoadRoomMember(userID)
@ -187,12 +187,15 @@ func (r *Room) LoadOrCreateRoomMember(userID string) (*model.RoomMember, error)
if r.Settings.DisableJoinNewUser {
return r.LoadRoomMember(userID)
}
if r.IsGuest(userID) && (r.Settings.DisableGuest || !settings.EnableGuest.Get()) {
return nil, errors.New("guest is disabled")
}
member, ok := r.members.Load(userID)
if ok {
return member, nil
}
var conf []db.CreateRoomMemberRelationConfig
if r.CreatorID == userID {
if r.IsCreator(userID) {
conf = append(
conf,
db.WithRoomMemberStatus(model.RoomMemberStatusActive),
@ -200,6 +203,14 @@ func (r *Room) LoadOrCreateRoomMember(userID string) (*model.RoomMember, error)
db.WithRoomMemberRole(model.RoomMemberRoleCreator),
db.WithRoomMemberAdminPermissions(model.AllAdminPermissions),
)
} else if r.IsGuest(userID) {
conf = append(
conf,
db.WithRoomMemberStatus(model.RoomMemberStatusActive),
db.WithRoomMemberRelationPermissions(model.NoPermission),
db.WithRoomMemberRole(model.RoomMemberRoleMember),
db.WithRoomMemberAdminPermissions(model.NoAdminPermission),
)
} else {
conf = append(
conf,
@ -220,6 +231,11 @@ func (r *Room) LoadOrCreateRoomMember(userID string) (*model.RoomMember, error)
member.Permissions = model.AllPermissions
member.AdminPermissions = model.AllAdminPermissions
member.Status = model.RoomMemberStatusActive
} else if r.IsGuest(userID) {
member.Role = model.RoomMemberRoleMember
member.Permissions = model.NoPermission
member.AdminPermissions = model.NoAdminPermission
member.Status = model.RoomMemberStatusActive
} else if member.Role.IsAdmin() {
member.Permissions = model.AllPermissions
}
@ -228,11 +244,14 @@ func (r *Room) LoadOrCreateRoomMember(userID string) (*model.RoomMember, error)
}
func (r *Room) LoadRoomMember(userID string) (*model.RoomMember, error) {
if r.IsGuest(userID) && (r.Settings.DisableGuest || !settings.EnableGuest.Get()) {
return nil, errors.New("guest is disabled")
}
member, ok := r.members.Load(userID)
if ok {
return member, nil
}
member, err := db.GetRoomMemberRelation(r.ID, userID)
member, err := db.GetRoomMember(r.ID, userID)
if err != nil {
return nil, fmt.Errorf("get room member failed: %w", err)
}
@ -241,6 +260,11 @@ func (r *Room) LoadRoomMember(userID string) (*model.RoomMember, error) {
member.Permissions = model.AllPermissions
member.AdminPermissions = model.AllAdminPermissions
member.Status = model.RoomMemberStatusActive
} else if r.IsGuest(userID) {
member.Role = model.RoomMemberRoleMember
member.Permissions = model.NoPermission
member.AdminPermissions = model.NoAdminPermission
member.Status = model.RoomMemberStatusActive
} else if member.Role.IsAdmin() {
member.Permissions = model.AllPermissions
}

@ -193,6 +193,10 @@ func (u *User) IsPending() bool {
return u.Role == model.RolePending
}
func (u *User) IsGuest() bool {
return u.ID == db.GuestUserID
}
func (u *User) HasRoomPermission(room *Room, permission model.RoomMemberPermission) bool {
if u.IsAdmin() {
return true

@ -19,6 +19,7 @@ var (
DisableUserSignup = NewBoolSetting("disable_user_signup", false, model.SettingGroupUser)
SignupNeedReview = NewBoolSetting("signup_need_review", false, model.SettingGroupUser)
UserMaxRoomCount = NewInt64Setting("user_max_room_count", 3, model.SettingGroupUser)
EnableGuest = NewBoolSetting("enable_guest", true, model.SettingGroupUser)
)
var (

@ -167,6 +167,8 @@ func initRoom(room *gin.RouterGroup, needAuthUser *gin.RouterGroup, needAuthRoom
room.GET("/list", RoomList)
room.POST("/guest", GuestJoinRoom)
needAuthUser.POST("/create", CreateRoom)
needAuthUser.POST("/login", LoginRoom)

@ -276,20 +276,27 @@ func CheckRoom(ctx *gin.Context) {
}))
}
func LoginRoom(ctx *gin.Context) {
user := ctx.MustGet("user").(*op.UserEntry).Value()
func GuestJoinRoom(ctx *gin.Context) {
log := ctx.MustGet("log").(*logrus.Entry)
req := model.LoginRoomReq{}
if err := model.Decode(ctx, &req); err != nil {
log.Errorf("login room failed: %v", err)
log.Errorf("guest join room failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err))
return
}
userE, err := op.LoadOrInitUserByID(db.GuestUserID)
if err != nil {
log.Errorf("guest join room failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
user := userE.Value()
roomE, err := op.LoadOrInitRoomByID(req.RoomId)
if err != nil {
log.Errorf("login room failed: %v", err)
log.Errorf("guest join room failed: %v", err)
if err == op.ErrRoomBanned || err == op.ErrRoomPending {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(err))
return
@ -299,20 +306,49 @@ func LoginRoom(ctx *gin.Context) {
}
room := roomE.Value()
member, err := room.LoadOrCreateRoomMember(user.ID)
if !room.CheckPassword(req.Password) {
log.Warn("guest join room failed: password error")
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("password error"))
return
}
token, err := middlewares.NewAuthRoomToken(user, room)
if err != nil {
log.Errorf("login room failed: %v", err)
log.Errorf("guest join room failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
if member.Status.IsNotActive() {
log.Warn("login room failed: member status not active")
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("member status not active"))
ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{
"roomId": room.ID,
"token": token,
}))
}
func LoginRoom(ctx *gin.Context) {
user := ctx.MustGet("user").(*op.UserEntry).Value()
log := ctx.MustGet("log").(*logrus.Entry)
req := model.LoginRoomReq{}
if err := model.Decode(ctx, &req); err != nil {
log.Errorf("login room failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err))
return
}
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))
return
}
room := roomE.Value()
if !member.Role.IsAdmin() && !room.CheckPassword(req.Password) {
if !user.IsAdmin() && !user.IsRoomAdmin(room) && !room.CheckPassword(req.Password) {
log.Warn("login room failed: password error")
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("password error"))
return

@ -121,16 +121,21 @@ func AuthUser(Authorization string) (*op.UserEntry, error) {
return nil, ErrAuthFailed
}
u, err := op.LoadOrInitUserByID(claims.UserId)
userE, err := op.LoadOrInitUserByID(claims.UserId)
if err != nil {
return nil, err
}
user := userE.Value()
if user.IsGuest() {
return nil, errors.New("user is guest, can not login")
}
if !u.Value().CheckVersion(claims.UserVersion) {
if !user.CheckVersion(claims.UserVersion) {
return nil, ErrAuthExpired
}
return u, nil
return userE, nil
}
func NewAuthUserToken(user *op.User) (string, error) {
@ -140,6 +145,9 @@ func NewAuthUserToken(user *op.User) (string, error) {
if user.IsPending() {
return "", errors.New("user is pending, need admin to approve")
}
if user.IsGuest() {
return "", errors.New("user is guest, can not login")
}
t, err := time.ParseDuration(conf.Conf.Jwt.Expire)
if err != nil {
return "", err

Loading…
Cancel
Save