teldrive/services/auth.service.go

177 lines
4.8 KiB
Go
Raw Normal View History

2023-08-12 19:21:42 +08:00
package services
import (
"bytes"
2023-08-13 04:15:19 +08:00
"context"
2023-08-12 19:21:42 +08:00
"encoding/base64"
"encoding/binary"
"encoding/hex"
"errors"
"math/big"
"net"
"net/http"
2023-08-13 04:15:19 +08:00
"strconv"
2023-08-12 19:21:42 +08:00
"time"
2023-08-14 04:58:06 +08:00
"github.com/divyam234/teldrive-go/models"
"github.com/divyam234/teldrive-go/schemas"
2023-08-12 19:21:42 +08:00
"github.com/divyam234/teldrive-go/types"
2023-08-13 04:15:19 +08:00
"github.com/divyam234/teldrive-go/utils"
2023-08-12 19:21:42 +08:00
"github.com/divyam234/teldrive-go/utils/auth"
"github.com/gin-gonic/gin"
"github.com/go-jose/go-jose/v3/jwt"
2023-08-14 04:58:06 +08:00
"gorm.io/gorm"
"gorm.io/gorm/clause"
2023-08-12 19:21:42 +08:00
)
type AuthService struct {
2023-08-14 04:58:06 +08:00
Db *gorm.DB
2023-08-12 19:21:42 +08:00
SessionMaxAge int
}
func IP4toInt(IPv4Address net.IP) int64 {
IPv4Int := big.NewInt(0)
IPv4Int.SetBytes(IPv4Address.To4())
return IPv4Int.Int64()
}
func Pack32BinaryIP4(ip4Address string) []byte {
ipv4Decimal := IP4toInt(net.ParseIP(ip4Address))
buf := new(bytes.Buffer)
binary.Write(buf, binary.BigEndian, uint32(ipv4Decimal))
return buf.Bytes()
}
2023-08-13 04:15:19 +08:00
func generateTgSession(dcID int, serverAddress string, authKey []byte, port int) string {
2023-08-12 19:21:42 +08:00
dcIDByte := byte(dcID)
serverAddressBytes := Pack32BinaryIP4(serverAddress)
portByte := make([]byte, 2)
binary.BigEndian.PutUint16(portByte, uint16(port))
packet := make([]byte, 0)
packet = append(packet, dcIDByte)
packet = append(packet, serverAddressBytes...)
packet = append(packet, portByte...)
packet = append(packet, authKey...)
base64Encoded := base64.URLEncoding.EncodeToString(packet)
return "1" + base64Encoded
}
func GetUserSessionCookieName(c *gin.Context) string {
isHttps := c.Request.URL.Scheme == "https"
var cookieName string
if isHttps {
cookieName = "__Secure-user-session"
} else {
cookieName = "user-session"
}
return cookieName
}
2023-08-14 04:58:06 +08:00
func (as *AuthService) LogIn(c *gin.Context) (*schemas.Message, *types.AppError) {
2023-08-12 19:21:42 +08:00
dcMaps := map[int]string{
1: "149.154.175.53",
2: "149.154.167.51",
3: "149.154.175.100",
4: "149.154.167.91",
5: "91.108.56.130",
}
var session types.TgSession
if err := c.ShouldBindJSON(&session); err != nil {
2023-08-14 04:58:06 +08:00
return nil, &types.AppError{Error: errors.New("invalid request payload"), Code: http.StatusBadRequest}
2023-08-12 19:21:42 +08:00
}
now := time.Now().UTC()
authBytes, _ := hex.DecodeString(session.AuthKey)
2023-08-13 04:15:19 +08:00
sessionData := generateTgSession(session.DcID, dcMaps[session.DcID], authBytes, 443)
2023-08-12 19:21:42 +08:00
jwtClaims := &types.JWTClaims{Claims: jwt.Claims{
Subject: session.UserID,
IssuedAt: jwt.NewNumericDate(now),
Expiry: jwt.NewNumericDate(now.Add(time.Duration(as.SessionMaxAge) * time.Second)),
}, TgSession: sessionData, Name: session.Name, UserName: session.UserName, Bot: session.Bot, IsPremium: session.IsPremium}
jweToken, err := auth.Encode(jwtClaims)
if err != nil {
2023-08-14 04:58:06 +08:00
return nil, &types.AppError{Error: err, Code: http.StatusBadRequest}
2023-08-12 19:21:42 +08:00
}
2023-08-14 04:58:06 +08:00
userId, _ := strconv.Atoi(session.UserID)
user := models.User{
UserId: userId,
Name: session.Name,
UserName: session.UserName,
IsPremium: session.IsPremium,
TgSession: sessionData,
}
if err := as.Db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "user_id"}},
DoUpdates: clause.Assignments(map[string]interface{}{"tg_session": sessionData}),
}).Create(&user).Error; err != nil {
return nil, &types.AppError{Error: errors.New("failed to create or update user"), Code: http.StatusInternalServerError}
}
2023-08-12 19:21:42 +08:00
c.SetCookie(GetUserSessionCookieName(c), jweToken, as.SessionMaxAge, "/", c.Request.Host, false, false)
2023-08-14 04:58:06 +08:00
return &schemas.Message{Status: true, Message: "login success"}, nil
2023-08-12 19:21:42 +08:00
}
func (as *AuthService) GetSession(c *gin.Context) *types.Session {
cookie, err := c.Request.Cookie(GetUserSessionCookieName(c))
if err != nil {
return nil
}
jwePayload, err := auth.Decode(cookie.Value)
if err != nil {
return nil
}
now := time.Now().UTC()
newExpires := now.Add(time.Duration(as.SessionMaxAge) * time.Second)
session := &types.Session{Name: jwePayload.Name, UserName: jwePayload.UserName, Expires: newExpires.Format(time.RFC3339)}
jwePayload.IssuedAt = jwt.NewNumericDate(now)
jwePayload.Expiry = jwt.NewNumericDate(newExpires)
jweToken, err := auth.Encode(jwePayload)
if err != nil {
return nil
}
c.SetCookie(GetUserSessionCookieName(c), jweToken, as.SessionMaxAge, "/", c.Request.Host, false, false)
return session
}
2023-08-13 04:15:19 +08:00
2023-08-14 04:58:06 +08:00
func (as *AuthService) Logout(c *gin.Context) (*schemas.Message, *types.AppError) {
2023-08-13 04:15:19 +08:00
val, _ := c.Get("jwtUser")
jwtUser := val.(*types.JWTClaims)
userId, _ := strconv.Atoi(jwtUser.Subject)
tgClient, err, stop := utils.GetAuthClient(jwtUser.TgSession, userId)
if err != nil {
2023-08-14 04:58:06 +08:00
return nil, &types.AppError{Error: err, Code: http.StatusInternalServerError}
2023-08-13 04:15:19 +08:00
}
_, err = tgClient.Tg.API().AuthLogOut(context.Background())
if err != nil {
2023-08-14 04:58:06 +08:00
return nil, &types.AppError{Error: err, Code: http.StatusInternalServerError}
2023-08-13 04:15:19 +08:00
}
utils.StopClient(stop, userId)
c.SetCookie(GetUserSessionCookieName(c), "", -1, "/", c.Request.Host, false, false)
2023-08-14 04:58:06 +08:00
return &schemas.Message{Status: true, Message: "logout success"}, nil
2023-08-13 04:15:19 +08:00
}