|
|
|
package middlewares
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
"github.com/synctv-org/synctv/internal/conf"
|
|
|
|
"github.com/synctv-org/synctv/room"
|
|
|
|
"github.com/synctv-org/synctv/server/model"
|
|
|
|
"github.com/zijiren233/stream"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrAuthFailed = errors.New("auth failed")
|
|
|
|
ErrAuthExpired = errors.New("auth expired")
|
|
|
|
)
|
|
|
|
|
|
|
|
type AuthClaims struct {
|
|
|
|
RoomId string `json:"id"`
|
|
|
|
Version uint64 `json:"v"`
|
|
|
|
Username string `json:"un"`
|
|
|
|
UserVersion uint64 `json:"uv"`
|
|
|
|
jwt.RegisteredClaims
|
|
|
|
}
|
|
|
|
|
|
|
|
func auth(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
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrAuthFailed
|
|
|
|
}
|
|
|
|
claims, ok := t.Claims.(*AuthClaims)
|
|
|
|
if !ok || !t.Valid {
|
|
|
|
return nil, ErrAuthFailed
|
|
|
|
}
|
|
|
|
return claims, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func Auth(Authorization string, rooms *room.Rooms) (*room.User, error) {
|
|
|
|
claims, err := auth(Authorization)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
r, err := rooms.GetRoom(claims.RoomId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !r.CheckVersion(claims.Version) {
|
|
|
|
return nil, ErrAuthExpired
|
|
|
|
}
|
|
|
|
|
|
|
|
user, err := r.GetUser(claims.Username)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !user.CheckVersion(claims.UserVersion) {
|
|
|
|
return nil, ErrAuthExpired
|
|
|
|
}
|
|
|
|
|
|
|
|
return user, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func AuthWithPassword(roomId, roomPassword, username, password string, rooms *room.Rooms) (*room.User, error) {
|
|
|
|
room, err := rooms.GetRoom(roomId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if !room.CheckPassword(roomPassword) {
|
|
|
|
return nil, ErrAuthFailed
|
|
|
|
}
|
|
|
|
user, err := room.GetUser(username)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if !user.CheckPassword(password) {
|
|
|
|
return nil, ErrAuthFailed
|
|
|
|
}
|
|
|
|
return user, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func AuthOrNewWithPassword(roomId, roomPassword, username, password string, rooms *room.Rooms) (*room.User, error) {
|
|
|
|
room, err := rooms.GetRoom(roomId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if !room.CheckPassword(roomPassword) {
|
|
|
|
return nil, ErrAuthFailed
|
|
|
|
}
|
|
|
|
user, err := room.GetOrNewUser(username, password)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if !user.CheckPassword(password) {
|
|
|
|
return nil, ErrAuthFailed
|
|
|
|
}
|
|
|
|
return user, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func AuthRoom(ctx *gin.Context) {
|
|
|
|
rooms := ctx.Value("rooms").(*room.Rooms)
|
|
|
|
user, err := Auth(ctx.GetHeader("Authorization"), rooms)
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatusJSON(401, model.NewApiErrorResp(err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Set("user", user)
|
|
|
|
ctx.Next()
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewAuthToken(user *room.User) (string, error) {
|
|
|
|
claims := &AuthClaims{
|
|
|
|
RoomId: user.Room().Id(),
|
|
|
|
Version: user.Room().Version(),
|
|
|
|
Username: user.Name(),
|
|
|
|
UserVersion: user.Version(),
|
|
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
|
|
|
NotBefore: jwt.NewNumericDate(time.Now()),
|
|
|
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(conf.Conf.Jwt.Expire))),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(stream.StringToBytes(conf.Conf.Jwt.Secret))
|
|
|
|
}
|