feat: api v2 init

api-v2
zijiren233 1 year ago
parent c3b2504157
commit 94cc3637fe

@ -3,8 +3,6 @@ package op
import (
"errors"
"fmt"
"hash/crc32"
"sync/atomic"
"github.com/gorilla/websocket"
"github.com/sirupsen/logrus"
@ -20,7 +18,6 @@ import (
type Room struct {
model.Room
version uint32
current *current
initOnce utils.Once
hub *Hub
@ -73,14 +70,6 @@ func (r *Room) close() {
}
}
func (r *Room) Version() uint32 {
return atomic.LoadUint32(&r.version)
}
func (r *Room) CheckVersion(version uint32) bool {
return atomic.LoadUint32(&r.version) == version
}
func (r *Room) UpdateMovie(movieId string, movie *model.MovieBase) error {
err := r.checkCanModifyMovie(movieId)
if err != nil {
@ -313,7 +302,6 @@ func (r *Room) SetPassword(password string) error {
if err != nil {
return err
}
atomic.StoreUint32(&r.version, crc32.ChecksumIEEE(hashedPassword))
}
r.HashedPassword = hashedPassword
return db.SetRoomHashedPassword(r.ID, hashedPassword)

@ -3,7 +3,6 @@ package op
import (
"errors"
"fmt"
"hash/crc32"
"time"
"github.com/synctv-org/synctv/internal/db"
@ -65,7 +64,6 @@ func LoadOrInitRoom(room *model.Room) (*RoomEntry, error) {
i, _ := roomCache.LoadOrStore(room.ID, &Room{
Room: *room,
version: crc32.ChecksumIEEE(room.HashedPassword),
current: newCurrent(),
movies: &movies{roomID: room.ID},
}, time.Duration(settings.RoomTTL.Get())*time.Hour)

@ -39,10 +39,6 @@ func Init(e *gin.Engine) {
needAuthUserApi := api.Group("", middlewares.AuthUserMiddleware)
needAuthRoomApi := api.Group("", middlewares.AuthRoomMiddleware)
needAuthRoomWithoutGuestApi := api.Group("", middlewares.AuthRoomWithoutGuestMiddleware)
{
public := api.Group("/public")
@ -60,18 +56,18 @@ func Init(e *gin.Engine) {
{
room := api.Group("/room")
needAuthUser := needAuthUserApi.Group("/room")
needAuthRoom := needAuthRoomApi.Group("/room")
needAuthRoomWithoutGuest := needAuthRoomWithoutGuestApi.Group("/room")
needAuthRoom := api.Group("/room/:roomId", middlewares.AuthRoomMiddleware)
needAuthUser := api.Group("/room/:roomId", middlewares.AuthUserMiddleware)
needAuthRoomWithoutGuest := api.Group("/room/:roomId", middlewares.AuthRoomWithoutGuestMiddleware)
initRoom(room, needAuthUser, needAuthRoom, needAuthRoomWithoutGuest)
}
{
movie := api.Group("/movie")
needAuthMovie := needAuthRoomApi.Group("/movie")
{
movie := room.Group("/movie")
needAuthMovie := needAuthRoom.Group("/movie")
initMovie(movie, needAuthMovie)
initMovie(movie, needAuthMovie)
}
}
{
@ -164,8 +160,6 @@ func initAdmin(admin *gin.RouterGroup, root *gin.RouterGroup) {
}
func initRoom(room *gin.RouterGroup, needAuthUser *gin.RouterGroup, needAuthRoom *gin.RouterGroup, needAuthWithoutGuestRoom *gin.RouterGroup) {
room.GET("/ws", NewWebSocketHandler(utils.NewWebSocketServer()))
room.GET("/check", CheckRoom)
room.GET("/hot", RoomHotList)
@ -180,6 +174,8 @@ func initRoom(room *gin.RouterGroup, needAuthUser *gin.RouterGroup, needAuthRoom
needAuthRoom.GET("/me", RoomMe)
needAuthRoom.GET("/ws", NewWebSocketHandler(utils.NewWebSocketServer()))
needAuthWithoutGuestRoom.GET("/settings", RoomPiblicSettings)
needAuthWithoutGuestRoom.GET("/members", RoomMembers)
@ -235,9 +231,9 @@ func initMovie(movie *gin.RouterGroup, needAuthMovie *gin.RouterGroup) {
needAuthMovie.POST("/clear", ClearMovies)
needAuthMovie.HEAD("/proxy/:roomId/:movieId", ProxyMovie)
needAuthMovie.HEAD("/proxy/:movieId", ProxyMovie)
needAuthMovie.GET("/proxy/:roomId/:movieId", ProxyMovie)
needAuthMovie.GET("/proxy/:movieId", ProxyMovie)
{
needAuthLive := needAuthMovie.Group("/live")
@ -250,7 +246,7 @@ func initMovie(movie *gin.RouterGroup, needAuthMovie *gin.RouterGroup) {
needAuthLive.GET("/hls/list/:movieId", JoinHlsLive)
needAuthLive.GET("/hls/data/:roomId/:movieId/:dataId", ServeHlsLive)
needAuthLive.GET("/hls/data/:movieId/:dataId", ServeHlsLive)
}
}

@ -112,16 +112,16 @@ func genMovieInfo(
}
movie = vendorMovie
} else if movie.MovieBase.RtmpSource || movie.MovieBase.Live && movie.MovieBase.Proxy {
movie.MovieBase.Url = fmt.Sprintf("/api/movie/live/hls/list/%s.m3u8?token=%s", movie.ID, userToken)
movie.MovieBase.Url = fmt.Sprintf("/api/room/%s/movie/live/hls/list/%s.m3u8?token=%s", opMovie.RoomID, movie.ID, userToken)
movie.MovieBase.Type = "m3u8"
movie.MoreSources = append(movie.MoreSources, &dbModel.MoreSource{
Name: "flv",
Url: fmt.Sprintf("/api/movie/live/flv/%s.flv?token=%s", movie.ID, userToken),
Url: fmt.Sprintf("/api/room/%s/movie/live/flv/%s.flv?token=%s", opMovie.RoomID, movie.ID, userToken),
Type: "flv",
})
movie.MovieBase.Headers = nil
} else if movie.MovieBase.Proxy {
movie.MovieBase.Url = fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Url = fmt.Sprintf("/api/room/%s/movie/proxy/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Headers = nil
}
if movie.MovieBase.Type == "" && movie.MovieBase.Url != "" {
@ -699,21 +699,11 @@ func ProxyMovie(ctx *gin.Context) {
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp("movie proxy is not enabled"))
return
}
roomId := ctx.Param("roomId")
if roomId == "" {
log.Errorf("room id is empty")
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp("roomId is empty"))
return
}
room, err := op.LoadOrInitRoomByID(roomId)
if err != nil {
log.Errorf("load or init room by id error: %v", err)
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err))
return
}
room := ctx.MustGet("room").(*op.RoomEntry).Value()
// user := ctx.MustGet("user").(*op.UserEntry).Value()
m, err := room.Value().GetMovieByID(ctx.Param("movieId"))
m, err := room.GetMovieByID(ctx.Param("movieId"))
if err != nil {
log.Errorf("get movie by id error: %v", err)
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err))
@ -903,7 +893,7 @@ func JoinLive(ctx *gin.Context) {
if settings.TsDisguisedAsPng.Get() {
ext = "png"
}
return fmt.Sprintf("/api/movie/live/hls/data/%s/%s/%s.%s?token=%s", room.ID, movieId, tsName, ext, token)
return fmt.Sprintf("/api/room/%s/movie/live/hls/data/%s/%s.%s?token=%s", room.ID, movieId, tsName, ext, token)
})
if err != nil {
log.Errorf("join live error: %v", err)
@ -1004,7 +994,7 @@ func JoinHlsLive(ctx *gin.Context) {
if settings.TsDisguisedAsPng.Get() {
ext = "png"
}
return fmt.Sprintf("/api/movie/live/hls/data/%s/%s/%s.%s?token=%s", room.ID, movieId, tsName, ext, token)
return fmt.Sprintf("/api/room/%s/movie/live/hls/data/%s/%s.%s?token=%s", room.ID, movieId, tsName, ext, token)
})
if err != nil {
log.Errorf("join hls live error: %v", err)
@ -1016,16 +1006,11 @@ func JoinHlsLive(ctx *gin.Context) {
func ServeHlsLive(ctx *gin.Context) {
log := ctx.MustGet("log").(*logrus.Entry)
room := ctx.MustGet("room").(*op.RoomEntry).Value()
// user := ctx.MustGet("user").(*op.UserEntry).Value()
ctx.Header("Cache-Control", "no-store")
roomId := ctx.Param("roomId")
roomE, err := op.LoadOrInitRoomByID(roomId)
if err != nil {
log.Errorf("serve hls live error: %v", err)
ctx.AbortWithStatusJSON(http.StatusNotFound, model.NewApiErrorResp(err))
return
}
room := roomE.Value()
movieId := ctx.Param("movieId")
m, err := room.GetMovieByID(movieId)
if err != nil {
@ -1404,7 +1389,7 @@ func proxyVendorMovie(ctx *gin.Context, movie *op.Movie) {
// user is the api requester
func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userAgent, userToken string) (*dbModel.Movie, error) {
movie := *opMovie.Movie
movie := opMovie.Movie.Clone()
var err error
switch movie.MovieBase.VendorInfo.Vendor {
case dbModel.VendorBilibili:
@ -1414,9 +1399,9 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA
bmc := opMovie.BilibiliCache()
if movie.MovieBase.Live {
movie.MovieBase.Url = fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Url = fmt.Sprintf("/api/room/%s/movie/proxy/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Type = "m3u8"
return &movie, nil
return movie, nil
} else {
if !movie.MovieBase.Proxy {
var s string
@ -1436,13 +1421,13 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA
movie.MovieBase.Url = s
} else {
movie.MovieBase.Url = fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Url = fmt.Sprintf("/api/room/%s/movie/proxy/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Type = "mpd"
movie.MovieBase.MoreSources = []*dbModel.MoreSource{
{
Name: "hevc",
Type: "mpd",
Url: fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s&t=hevc", movie.RoomID, movie.ID, userToken),
Url: fmt.Sprintf("/api/room/%s/movie/proxy/%s?token=%s&t=hevc", movie.RoomID, movie.ID, userToken),
},
}
}
@ -1455,11 +1440,11 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA
movie.MovieBase.Subtitles = make(map[string]*dbModel.Subtitle, len(srt))
}
movie.MovieBase.Subtitles[k] = &dbModel.Subtitle{
URL: fmt.Sprintf("/api/movie/proxy/%s/%s?t=subtitle&n=%s&token=%s", movie.RoomID, movie.ID, k, userToken),
URL: fmt.Sprintf("/api/room/%s/movie/proxy/%s?t=subtitle&n=%s&token=%s", movie.RoomID, movie.ID, k, userToken),
Type: "srt",
}
}
return &movie, nil
return movie, nil
}
case dbModel.VendorAlist:
@ -1488,12 +1473,12 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA
switch data.Provider {
case cache.AlistProviderAli:
movie.MovieBase.Url = fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Url = fmt.Sprintf("/api/room/%s/movie/proxy/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Type = "m3u8"
rawStreamUrl := data.URL
if movie.MovieBase.Proxy {
rawStreamUrl = fmt.Sprintf("/api/movie/proxy/%s/%s?t=raw&token=%s", movie.RoomID, movie.ID, userToken)
rawStreamUrl = fmt.Sprintf("/api/room/%s/movie/proxy/%s?t=raw&token=%s", movie.RoomID, movie.ID, userToken)
}
movie.MovieBase.MoreSources = []*dbModel.MoreSource{
{
@ -1508,14 +1493,14 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA
movie.MovieBase.Subtitles = make(map[string]*dbModel.Subtitle, len(data.Subtitles))
}
movie.MovieBase.Subtitles[subt.Name] = &dbModel.Subtitle{
URL: fmt.Sprintf("/api/movie/proxy/%s/%s?t=subtitle&id=%d&token=%s", movie.RoomID, movie.ID, i, userToken),
URL: fmt.Sprintf("/api/room/%s/movie/proxy/%s?t=subtitle&id=%d&token=%s", movie.RoomID, movie.ID, i, userToken),
Type: subt.Type,
}
}
case cache.AlistProvider115:
if movie.MovieBase.Proxy {
movie.MovieBase.Url = fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Url = fmt.Sprintf("/api/room/%s/movie/proxy/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Type = utils.GetUrlExtension(data.URL)
// TODO: proxy subtitle
@ -1541,13 +1526,13 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA
if !movie.MovieBase.Proxy {
movie.MovieBase.Url = data.URL
} else {
movie.MovieBase.Url = fmt.Sprintf("/api/movie/proxy/%s/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Url = fmt.Sprintf("/api/room/%s/movie/proxy/%s?token=%s", movie.RoomID, movie.ID, userToken)
movie.MovieBase.Type = utils.GetUrlExtension(data.URL)
}
}
movie.MovieBase.VendorInfo.Alist.Password = ""
return &movie, nil
return movie, nil
case dbModel.VendorEmby:
u, err := op.LoadOrInitUserByID(movie.CreatorID)
@ -1602,7 +1587,7 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA
}
}
rawPath, err := url.JoinPath("/api/movie/proxy", movie.RoomID, movie.ID)
rawPath, err := url.JoinPath("/api/room", movie.RoomID, "/movie/proxy", movie.ID)
if err != nil {
return nil, err
}
@ -1640,7 +1625,7 @@ func genVendorMovie(ctx context.Context, user *op.User, opMovie *op.Movie, userA
}
}
return &movie, nil
return movie, nil
default:
return nil, fmt.Errorf("vendor not implement gen movie url")

@ -80,16 +80,8 @@ func CreateRoom(ctx *gin.Context) {
return
}
token, err := middlewares.NewAuthRoomToken(user, room.Value())
if err != nil {
log.Errorf("create room failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
ctx.JSON(http.StatusCreated, model.NewApiDataResp(gin.H{
"roomId": room.Value().ID,
"token": token,
}))
}
@ -260,8 +252,13 @@ func genRoomListResp(scopes ...func(db *gorm.DB) *gorm.DB) ([]*model.RoomListRes
func CheckRoom(ctx *gin.Context) {
log := ctx.MustGet("log").(*logrus.Entry)
r, err := db.GetRoomByID(ctx.Query("roomId"))
roomId, err := middlewares.GetRoomIdFromContext(ctx)
if err != nil {
log.Errorf("check room failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err))
return
}
r, err := db.GetRoomByID(roomId)
if err != nil {
log.Errorf("check room failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusNotFound, model.NewApiErrorResp(err))
@ -272,6 +269,8 @@ func CheckRoom(ctx *gin.Context) {
"peopleNum": op.PeopleNum(r.ID),
"needPassword": r.NeedPassword(),
"creator": op.GetUserName(r.CreatorID),
"status": r.Status,
"name": r.Name,
}))
}
@ -305,23 +304,30 @@ func GuestJoinRoom(ctx *gin.Context) {
}
room := roomE.Value()
if !room.CheckPassword(req.Password) {
log.Warn("guest join room failed: password error")
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("password error"))
if !room.NeedPassword() {
log.Warn("guests are not allowed to join rooms that require a password")
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("guests are not allowed to join rooms that require a password"))
return
}
token, err := middlewares.NewAuthRoomToken(user, room)
_, err = room.LoadOrCreateRoomMember(user.ID)
if err != nil {
if errors.Is(err, db.ErrNotFound("")) {
log.Warn("guest join room failed: room was disabled join new user")
ctx.AbortWithStatusJSON(
http.StatusForbidden,
model.NewApiErrorResp(
fmt.Errorf("this room was disabled join new user"),
),
)
return
}
log.Errorf("guest join room failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{
"roomId": room.ID,
"token": token,
}))
ctx.Status(http.StatusNoContent)
}
func LoginRoom(ctx *gin.Context) {
@ -353,17 +359,24 @@ func LoginRoom(ctx *gin.Context) {
return
}
token, err := middlewares.NewAuthRoomToken(user, room)
_, err = room.LoadOrCreateRoomMember(user.ID)
if err != nil {
if errors.Is(err, db.ErrNotFound("")) {
log.Warn("login room failed: room was disabled join new user")
ctx.AbortWithStatusJSON(
http.StatusForbidden,
model.NewApiErrorResp(
fmt.Errorf("this room was disabled join new user"),
),
)
return
}
log.Errorf("login room failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{
"roomId": room.ID,
"token": token,
}))
ctx.Status(http.StatusNoContent)
}
func DeleteRoom(ctx *gin.Context) {
@ -416,17 +429,7 @@ func SetRoomPassword(ctx *gin.Context) {
return
}
token, err := middlewares.NewAuthRoomToken(user, room)
if err != nil {
log.Errorf("set room password failed: %v", err)
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err))
return
}
ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{
"roomId": room.ID,
"token": token,
}))
ctx.Status(http.StatusNoContent)
}
func RoomSetting(ctx *gin.Context) {

@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"io"
"net/http"
"time"
"github.com/gin-gonic/gin"
@ -14,8 +13,6 @@ import (
dbModel "github.com/synctv-org/synctv/internal/model"
"github.com/synctv-org/synctv/internal/op"
pb "github.com/synctv-org/synctv/proto/message"
"github.com/synctv-org/synctv/server/middlewares"
"github.com/synctv-org/synctv/server/model"
"github.com/synctv-org/synctv/utils"
"google.golang.org/protobuf/proto"
)
@ -24,23 +21,11 @@ const maxInterval = 10
func NewWebSocketHandler(wss *utils.WebSocket) gin.HandlerFunc {
return func(ctx *gin.Context) {
token := ctx.GetHeader("Sec-WebSocket-Protocol")
userE, roomE, err := middlewares.AuthRoom(token)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, model.NewApiErrorResp(err))
return
}
user := userE.Value()
room := roomE.Value()
entry := log.WithFields(log.Fields{
"rid": room.ID,
"rnm": room.Name,
"uid": user.ID,
"unm": user.Username,
"uro": user.Role.String(),
})
_ = wss.Server(ctx.Writer, ctx.Request, []string{token}, NewWSMessageHandler(user, room, entry))
token := ctx.MustGet("token").(string)
room := ctx.MustGet("room").(*op.RoomEntry).Value()
user := ctx.MustGet("user").(*op.UserEntry).Value()
log := ctx.MustGet("log").(*logrus.Entry)
_ = wss.Server(ctx.Writer, ctx.Request, []string{token}, NewWSMessageHandler(user, room, log))
}
}

@ -11,8 +11,6 @@ import (
"github.com/golang-jwt/jwt/v5"
"github.com/sirupsen/logrus"
"github.com/synctv-org/synctv/internal/conf"
"github.com/synctv-org/synctv/internal/db"
dbModel "github.com/synctv-org/synctv/internal/model"
"github.com/synctv-org/synctv/internal/op"
"github.com/synctv-org/synctv/server/model"
"github.com/zijiren233/gencontainer/synccache"
@ -30,26 +28,6 @@ type AuthClaims struct {
jwt.RegisteredClaims
}
type AuthRoomClaims struct {
AuthClaims
RoomId string `json:"r"`
RoomVersion uint32 `json:"rv"`
}
func authRoom(Authorization string) (*AuthRoomClaims, error) {
t, err := jwt.ParseWithClaims(strings.TrimPrefix(Authorization, `Bearer `), &AuthRoomClaims{}, func(token *jwt.Token) (any, error) {
return stream.StringToBytes(conf.Conf.Jwt.Secret), nil
})
if err != nil {
return nil, ErrAuthFailed
}
claims, ok := t.Claims.(*AuthRoomClaims)
if !ok || !t.Valid {
return nil, ErrAuthFailed
}
return claims, nil
}
func authUser(Authorization string) (*AuthClaims, error) {
t, err := jwt.ParseWithClaims(strings.TrimPrefix(Authorization, `Bearer `), &AuthClaims{}, func(token *jwt.Token) (any, error) {
return stream.StringToBytes(conf.Conf.Jwt.Secret), nil
@ -64,14 +42,14 @@ func authUser(Authorization string) (*AuthClaims, error) {
return claims, nil
}
func AuthRoom(Authorization string) (*op.UserEntry, *op.RoomEntry, error) {
claims, err := authRoom(Authorization)
if err != nil {
return nil, nil, err
func AuthRoom(Authorization, roomId string) (*op.UserEntry, *op.RoomEntry, error) {
if len(roomId) != 32 {
return nil, nil, ErrAuthFailed
}
if len(claims.RoomId) != 32 {
return nil, nil, ErrAuthFailed
claims, err := authUser(Authorization)
if err != nil {
return nil, nil, err
}
if len(claims.UserId) != 32 {
@ -88,17 +66,31 @@ func AuthRoom(Authorization string) (*op.UserEntry, *op.RoomEntry, error) {
return nil, nil, ErrAuthExpired
}
roomE, err := op.LoadOrInitRoomByID(claims.RoomId)
if user.IsBanned() {
return nil, nil, fmt.Errorf("user is banned")
}
if user.IsPending() {
return nil, nil, fmt.Errorf("user is pending, need admin to approve")
}
roomE, err := op.LoadOrInitRoomByID(roomId)
if err != nil {
return nil, nil, err
}
room := roomE.Value()
if !room.CheckVersion(claims.RoomVersion) {
return nil, nil, ErrAuthExpired
if !room.NeedPassword() && room.IsGuest(user.ID) {
return nil, nil, fmt.Errorf("guests are not allowed to join rooms that require a password")
}
rus, err := room.LoadOrCreateMemberStatus(user.ID)
if room.IsBanned() {
return nil, nil, fmt.Errorf("room is banned")
}
if room.IsPending() {
return nil, nil, fmt.Errorf("room is pending, need admin to approve")
}
rus, err := room.LoadMemberStatus(user.ID)
if err != nil {
return nil, nil, err
}
@ -136,6 +128,13 @@ func AuthUser(Authorization string) (*op.UserEntry, error) {
return nil, ErrAuthExpired
}
if user.IsBanned() {
return nil, errors.New("user is banned")
}
if user.IsPending() {
return nil, errors.New("user is pending, need admin to approve")
}
return userE, nil
}
@ -164,58 +163,6 @@ func NewAuthUserToken(user *op.User) (string, error) {
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(stream.StringToBytes(conf.Conf.Jwt.Secret))
}
func NewAuthRoomToken(user *op.User, room *op.Room) (string, error) {
if user.IsBanned() {
return "", errors.New("user banned")
}
if user.IsPending() {
return "", errors.New("user is pending, need admin to approve")
}
if room.IsBanned() {
return "", errors.New("room banned")
}
if room.IsPending() {
return "", errors.New("room is pending, need admin to approve")
}
member, err := room.LoadOrCreateRoomMember(user.ID)
if err != nil {
if errors.Is(err, db.ErrNotFound("")) {
return "", fmt.Errorf("this room was disabled join new user")
}
return "", fmt.Errorf("load room member failed: %w", err)
}
switch member.Status {
case dbModel.RoomMemberStatusBanned:
return "", fmt.Errorf("user is banned")
case dbModel.RoomMemberStatusPending:
return "", fmt.Errorf("user is pending, need admin to approve")
default:
if member.Status.IsNotActive() {
return "", fmt.Errorf("user is not active")
}
}
t, err := time.ParseDuration(conf.Conf.Jwt.Expire)
if err != nil {
return "", fmt.Errorf("parse jwt expire failed: %w", err)
}
claims := &AuthRoomClaims{
AuthClaims: AuthClaims{
UserId: user.ID,
UserVersion: user.Version(),
RegisteredClaims: jwt.RegisteredClaims{
NotBefore: jwt.NewNumericDate(time.Now()),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(t)),
},
},
RoomId: room.ID,
RoomVersion: room.Version(),
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(stream.StringToBytes(conf.Conf.Jwt.Secret))
}
func AuthUserMiddleware(ctx *gin.Context) {
token, err := GetAuthorizationTokenFromContext(ctx)
if err != nil {
@ -228,14 +175,6 @@ func AuthUserMiddleware(ctx *gin.Context) {
return
}
user := userE.Value()
if user.IsBanned() {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("user banned"))
return
}
if user.IsPending() {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("user is pending, need admin to approve"))
return
}
ctx.Set("user", userE)
log := ctx.MustGet("log").(*logrus.Entry)
@ -253,31 +192,18 @@ func AuthRoomMiddleware(ctx *gin.Context) {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, model.NewApiErrorResp(err))
return
}
userE, roomE, err := AuthRoom(token)
roomId, err := GetRoomIdFromContext(ctx)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, model.NewApiErrorResp(err))
return
}
user := userE.Value()
if user.IsBanned() {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("user banned"))
return
}
if user.IsPending() {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("user is pending, need admin to approve"))
userE, roomE, err := AuthRoom(token, roomId)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, model.NewApiErrorResp(err))
return
}
user := userE.Value()
room := roomE.Value()
if room.IsBanned() {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("room banned"))
return
}
if room.IsPending() {
ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorStringResp("room is pending, need admin to approve"))
return
}
ctx.Set("user", userE)
ctx.Set("room", roomE)
@ -361,16 +287,37 @@ func AuthRootMiddleware(ctx *gin.Context) {
}
}
func GetAuthorizationTokenFromContext(ctx *gin.Context) (string, error) {
Authorization := ctx.GetHeader("Authorization")
func GetAuthorizationTokenFromContext(ctx *gin.Context) (Authorization string, err error) {
Authorization = ctx.GetHeader("Authorization")
defer func() {
if err != nil && Authorization != "" {
ctx.Set("token", Authorization)
}
}()
if Authorization != "" {
ctx.Set("token", Authorization)
return Authorization, nil
}
if ctx.IsWebsocket() {
Authorization = ctx.GetHeader("Sec-WebSocket-Protocol")
if Authorization != "" {
return Authorization, nil
}
}
Authorization = ctx.Query("token")
if Authorization != "" {
ctx.Set("token", Authorization)
return Authorization, nil
}
return "", errors.New("token is empty")
}
func GetRoomIdFromContext(ctx *gin.Context) (string, error) {
roomID := ctx.Param("roomId")
if len(roomID) == 32 {
return roomID, nil
}
roomID = ctx.Query("roomId")
if len(roomID) == 32 {
return roomID, nil
}
return "", errors.New("room id length is not 32")
}

Loading…
Cancel
Save