// // login.go // Copyright (C) 2025 veypi // 2025-05-12 17:35 // Distributed under terms of the MIT license. // package user import ( "encoding/base64" "time" "github.com/golang-jwt/jwt/v5" "github.com/veypi/OneAuth/cfg" "github.com/veypi/OneAuth/libs/auth" "github.com/veypi/OneAuth/libs/utils" "github.com/veypi/OneAuth/models" "github.com/vyes/vigo" "github.com/vyes/vigo/contrib/limiter" "github.com/vyes/vigo/logv" ) var publicLimits = limiter.NewAdvancedRequestLimiter(limiter.LimiterConfig{ Window: time.Minute * 5, MaxRequests: 20, MinInterval: time.Second * 3, }).Limit var _ = Router.Post("/login", vigo.SkipBefore, publicLimits, userLogin) type loginOpts struct { UserName string `json:"username" parse:"json"` Code string `json:"code" parse:"json"` Phone *string `json:"phone" parse:"json"` Email *string `json:"email" parse:"json"` Type *string `json:"type" parse:"json"` AppID *string `json:"app_id" parse:"json"` Device *string `json:"device" parse:"json"` } func userLogin(x *vigo.X) (any, error) { // Implement login logic here // For example, validate user credentials and return a token opts := &loginOpts{} err := x.Parse(opts) if err != nil { return nil, err } user := &models.User{} query := cfg.DB() typ := "" if opts.Type != nil { typ = *opts.Type } switch typ { case "phone": query = query.Where("phone = ?", opts.Phone) case "email": query = query.Where("email = ?", opts.Email) default: query = query.Where("username = ?", opts.UserName) } err = query.First(user).Error if err != nil { return nil, vigo.ErrNotFound } logv.Info().Str("user", user.ID).Msg("login") code, err := base64.URLEncoding.DecodeString(opts.Code) if err != nil { return nil, vigo.ErrArgInvalid.WithArgs("code") } logv.Warn().Msgf("code: %s", code) ncode, err := utils.AesDecrypt([]byte(user.Code), utils.PKCS7Padding(code, 32), []byte(user.Salt)) logv.Warn().Msgf("id: %s\n%s", ncode, user.ID) if err != nil || string(ncode) != user.ID { return nil, vigo.ErrNotAuthorized } aid := cfg.Config.ID if opts.AppID != nil && *opts.AppID != "" { aid = *opts.AppID } data := &models.Token{} data.UserID = user.ID data.AppID = aid data.ExpiredAt = time.Now().Add(time.Hour * 72) if opts.Device != nil { data.Device = *opts.Device } data.Ip = x.GetRemoteIp() logv.AssertError(cfg.DB().Create(data).Error) claim := &auth.Claims{} claim.IssuedAt = jwt.NewNumericDate(time.Now()) claim.Issuer = cfg.Config.ID claim.ID = data.ID claim.AID = aid claim.UID = user.ID claim.Name = user.Username claim.Icon = user.Icon claim.ExpiresAt = jwt.NewNumericDate(data.ExpiredAt) if user.Nickname != "" { claim.Name = user.Nickname } return auth.GenJwt(claim) }