✨ New ticket ways
This commit is contained in:
@ -6,7 +6,6 @@ import (
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/security"
|
||||
"github.com/google/uuid"
|
||||
"github.com/samber/lo"
|
||||
"gorm.io/gorm"
|
||||
@ -23,14 +22,14 @@ func GetAccount(id uint) (models.Account, error) {
|
||||
return account, nil
|
||||
}
|
||||
|
||||
func LookupAccount(id string) (models.Account, error) {
|
||||
func LookupAccount(probe string) (models.Account, error) {
|
||||
var account models.Account
|
||||
if err := database.C.Where(models.Account{Name: id}).First(&account).Error; err == nil {
|
||||
if err := database.C.Where(models.Account{Name: probe}).First(&account).Error; err == nil {
|
||||
return account, nil
|
||||
}
|
||||
|
||||
var contact models.AccountContact
|
||||
if err := database.C.Where(models.AccountContact{Content: id}).First(&contact).Error; err == nil {
|
||||
if err := database.C.Where(models.AccountContact{Content: probe}).First(&contact).Error; err == nil {
|
||||
if err := database.C.
|
||||
Where(models.Account{
|
||||
BaseModel: models.BaseModel{ID: contact.AccountID},
|
||||
@ -52,7 +51,7 @@ func CreateAccount(name, nick, email, password string) (models.Account, error) {
|
||||
Factors: []models.AuthFactor{
|
||||
{
|
||||
Type: models.PasswordAuthFactor,
|
||||
Secret: security.HashPassword(password),
|
||||
Secret: HashPassword(password),
|
||||
},
|
||||
{
|
||||
Type: models.EmailPasswordFactor,
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/security"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/rs/zerolog/log"
|
||||
@ -16,12 +15,12 @@ import (
|
||||
const authContextBucket = "AuthContext"
|
||||
|
||||
func Authenticate(access, refresh string, depth int) (user models.Account, newAccess, newRefresh string, err error) {
|
||||
var claims security.PayloadClaims
|
||||
claims, err = security.DecodeJwt(access)
|
||||
var claims PayloadClaims
|
||||
claims, err = DecodeJwt(access)
|
||||
if err != nil {
|
||||
if len(refresh) > 0 && depth < 1 {
|
||||
// Auto refresh and retry
|
||||
newAccess, newRefresh, err = security.RefreshToken(refresh)
|
||||
newAccess, newRefresh, err = RefreshToken(refresh)
|
||||
if err == nil {
|
||||
return Authenticate(newAccess, newRefresh, depth+1)
|
||||
}
|
||||
@ -74,7 +73,7 @@ func GetAuthContext(jti string) (models.AuthContext, error) {
|
||||
})
|
||||
|
||||
if err == nil && time.Now().Unix() >= ctx.ExpiredAt.Unix() {
|
||||
RevokeAuthContext(jti)
|
||||
_ = RevokeAuthContext(jti)
|
||||
|
||||
return ctx, fmt.Errorf("auth context has been expired")
|
||||
}
|
||||
@ -86,7 +85,7 @@ func GrantAuthContext(jti string) (models.AuthContext, error) {
|
||||
var ctx models.AuthContext
|
||||
|
||||
// Query data from primary database
|
||||
session, err := LookupSessionWithToken(jti)
|
||||
session, err := GetTicketWithToken(jti)
|
||||
if err != nil {
|
||||
return ctx, fmt.Errorf("invalid auth session: %v", err)
|
||||
} else if err := session.IsAvailable(); err != nil {
|
||||
@ -101,7 +100,7 @@ func GrantAuthContext(jti string) (models.AuthContext, error) {
|
||||
// Every context should expires in some while
|
||||
// Once user update their account info, this will have delay to update
|
||||
ctx = models.AuthContext{
|
||||
Session: session,
|
||||
Ticket: session,
|
||||
Account: user,
|
||||
ExpiredAt: time.Now().Add(5 * time.Minute),
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
)
|
||||
|
||||
func LookupChallenge(id uint) (models.AuthChallenge, error) {
|
||||
var challenge models.AuthChallenge
|
||||
err := database.C.Where(models.AuthChallenge{
|
||||
BaseModel: models.BaseModel{ID: id},
|
||||
}).First(&challenge).Error
|
||||
|
||||
return challenge, err
|
||||
}
|
||||
|
||||
func LookupChallengeWithFingerprint(id uint, ip string, ua string) (models.AuthChallenge, error) {
|
||||
var challenge models.AuthChallenge
|
||||
err := database.C.Where(models.AuthChallenge{
|
||||
BaseModel: models.BaseModel{ID: id},
|
||||
IpAddress: ip,
|
||||
UserAgent: ua,
|
||||
}).First(&challenge).Error
|
||||
|
||||
return challenge, err
|
||||
}
|
12
pkg/services/encryptor.go
Normal file
12
pkg/services/encryptor.go
Normal file
@ -0,0 +1,12 @@
|
||||
package services
|
||||
|
||||
import "golang.org/x/crypto/bcrypt"
|
||||
|
||||
func HashPassword(raw string) string {
|
||||
data, _ := bcrypt.GenerateFromPassword([]byte(raw), 12)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func VerifyPassword(text string, password string) bool {
|
||||
return bcrypt.CompareHashAndPassword([]byte(password), []byte(text)) == nil
|
||||
}
|
@ -2,6 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/samber/lo"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
@ -24,7 +25,17 @@ Thank you for your cooperation in helping us maintain the security of your accou
|
||||
Best regards,
|
||||
%s`
|
||||
|
||||
func LookupFactor(id uint) (models.AuthFactor, error) {
|
||||
func GetPasswordFactor(userId uint) (models.AuthFactor, error) {
|
||||
var factor models.AuthFactor
|
||||
err := database.C.Where(models.AuthFactor{
|
||||
Type: models.PasswordAuthFactor,
|
||||
AccountID: userId,
|
||||
}).First(&factor).Error
|
||||
|
||||
return factor, err
|
||||
}
|
||||
|
||||
func GetFactor(id uint) (models.AuthFactor, error) {
|
||||
var factor models.AuthFactor
|
||||
err := database.C.Where(models.AuthFactor{
|
||||
BaseModel: models.BaseModel{ID: id},
|
||||
@ -33,10 +44,10 @@ func LookupFactor(id uint) (models.AuthFactor, error) {
|
||||
return factor, err
|
||||
}
|
||||
|
||||
func LookupFactorsByUser(uid uint) ([]models.AuthFactor, error) {
|
||||
func ListUserFactor(userId uint) ([]models.AuthFactor, error) {
|
||||
var factors []models.AuthFactor
|
||||
err := database.C.Where(models.AuthFactor{
|
||||
AccountID: uid,
|
||||
AccountID: userId,
|
||||
}).Find(&factors).Error
|
||||
|
||||
return factors, err
|
||||
@ -68,3 +79,22 @@ func GetFactorCode(factor models.AuthFactor) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
func CheckFactor(factor models.AuthFactor, code string) error {
|
||||
switch factor.Type {
|
||||
case models.PasswordAuthFactor:
|
||||
return lo.Ternary(
|
||||
VerifyPassword(code, factor.Secret),
|
||||
nil,
|
||||
fmt.Errorf("invalid password"),
|
||||
)
|
||||
case models.EmailPasswordFactor:
|
||||
return lo.Ternary(
|
||||
code == factor.Secret,
|
||||
nil,
|
||||
fmt.Errorf("invalid verification code"),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
81
pkg/services/jwt.go
Normal file
81
pkg/services/jwt.go
Normal file
@ -0,0 +1,81 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var CookieAccessKey = "passport_auth_key"
|
||||
var CookieRefreshKey = "passport_refresh_key"
|
||||
|
||||
type PayloadClaims struct {
|
||||
jwt.RegisteredClaims
|
||||
|
||||
SessionID string `json:"sed"`
|
||||
Type string `json:"typ"`
|
||||
}
|
||||
|
||||
const (
|
||||
JwtAccessType = "access"
|
||||
JwtRefreshType = "refresh"
|
||||
)
|
||||
|
||||
func EncodeJwt(id string, typ, sub, sed string, aud []string, exp time.Time) (string, error) {
|
||||
tk := jwt.NewWithClaims(jwt.SigningMethodHS512, PayloadClaims{
|
||||
jwt.RegisteredClaims{
|
||||
Subject: sub,
|
||||
Audience: aud,
|
||||
Issuer: fmt.Sprintf("https://%s", viper.GetString("domain")),
|
||||
ExpiresAt: jwt.NewNumericDate(exp),
|
||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ID: id,
|
||||
},
|
||||
sed,
|
||||
typ,
|
||||
})
|
||||
|
||||
return tk.SignedString([]byte(viper.GetString("secret")))
|
||||
}
|
||||
|
||||
func DecodeJwt(str string) (PayloadClaims, error) {
|
||||
var claims PayloadClaims
|
||||
tk, err := jwt.ParseWithClaims(str, &claims, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return []byte(viper.GetString("secret")), nil
|
||||
})
|
||||
if err != nil {
|
||||
return claims, err
|
||||
}
|
||||
|
||||
if data, ok := tk.Claims.(*PayloadClaims); ok {
|
||||
return *data, nil
|
||||
} else {
|
||||
return claims, fmt.Errorf("unexpected token payload: not payload claims type")
|
||||
}
|
||||
}
|
||||
|
||||
func SetJwtCookieSet(c *fiber.Ctx, access, refresh string) {
|
||||
c.Cookie(&fiber.Cookie{
|
||||
Name: CookieAccessKey,
|
||||
Value: access,
|
||||
Domain: viper.GetString("security.cookie_domain"),
|
||||
SameSite: viper.GetString("security.cookie_samesite"),
|
||||
Expires: time.Now().Add(60 * time.Minute),
|
||||
Path: "/",
|
||||
})
|
||||
c.Cookie(&fiber.Cookie{
|
||||
Name: CookieRefreshKey,
|
||||
Value: refresh,
|
||||
Domain: viper.GetString("security.cookie_domain"),
|
||||
SameSite: viper.GetString("security.cookie_samesite"),
|
||||
Expires: time.Now().Add(24 * 30 * time.Hour),
|
||||
Path: "/",
|
||||
})
|
||||
}
|
@ -1,28 +1,15 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/viper"
|
||||
"go.etcd.io/bbolt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func LookupSessionWithToken(tokenId string) (models.AuthSession, error) {
|
||||
var session models.AuthSession
|
||||
if err := database.C.
|
||||
Where(models.AuthSession{AccessToken: tokenId}).
|
||||
Or(models.AuthSession{RefreshToken: tokenId}).
|
||||
First(&session).Error; err != nil {
|
||||
return session, err
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func DoAutoSignoff() {
|
||||
duration := time.Duration(viper.GetInt64("security.auto_signoff_duration")) * time.Second
|
||||
divider := time.Now().Add(-duration)
|
||||
@ -31,7 +18,7 @@ func DoAutoSignoff() {
|
||||
|
||||
if tx := database.C.
|
||||
Where("last_grant_at < ?", divider).
|
||||
Delete(&models.AuthSession{}); tx.Error != nil {
|
||||
Delete(&models.AuthTicket{}); tx.Error != nil {
|
||||
log.Error().Err(tx.Error).Msg("An error occurred when running auto sign off...")
|
||||
} else {
|
||||
log.Debug().Int64("affected", tx.RowsAffected).Msg("Auto sign off accomplished.")
|
136
pkg/services/ticket.go
Normal file
136
pkg/services/ticket.go
Normal file
@ -0,0 +1,136 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func DetectRisk(user models.Account, ip, ua string) bool {
|
||||
var secureFactor int64
|
||||
if err := database.C.Where(models.AuthTicket{
|
||||
AccountID: user.ID,
|
||||
IpAddress: ip,
|
||||
}).Model(models.AuthTicket{}).Count(&secureFactor).Error; err == nil {
|
||||
if secureFactor >= 1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func NewTicket(user models.Account, ip, ua string) (models.AuthTicket, error) {
|
||||
var ticket models.AuthTicket
|
||||
if err := database.C.Where(models.AuthTicket{
|
||||
AccountID: user.ID,
|
||||
}).First(&ticket).Error; err == nil {
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
ticket = models.AuthTicket{
|
||||
Claims: []string{"*"},
|
||||
Audiences: []string{"passport"},
|
||||
IpAddress: ip,
|
||||
UserAgent: ua,
|
||||
RequireMFA: DetectRisk(user, ip, ua),
|
||||
ExpiredAt: lo.ToPtr(time.Now().Add(2 * time.Hour)),
|
||||
AvailableAt: nil,
|
||||
AccountID: user.ID,
|
||||
}
|
||||
|
||||
err := database.C.Save(&ticket).Error
|
||||
|
||||
return ticket, err
|
||||
}
|
||||
|
||||
func NewOauthTicket(
|
||||
user models.Account,
|
||||
client models.ThirdClient,
|
||||
claims, audiences []string,
|
||||
ip, ua string,
|
||||
) (models.AuthTicket, error) {
|
||||
ticket := models.AuthTicket{
|
||||
Claims: claims,
|
||||
Audiences: audiences,
|
||||
IpAddress: ip,
|
||||
UserAgent: ua,
|
||||
RequireMFA: DetectRisk(user, ip, ua),
|
||||
GrantToken: lo.ToPtr(uuid.NewString()),
|
||||
AccessToken: lo.ToPtr(uuid.NewString()),
|
||||
RefreshToken: lo.ToPtr(uuid.NewString()),
|
||||
AvailableAt: lo.ToPtr(time.Now()),
|
||||
ExpiredAt: lo.ToPtr(time.Now()),
|
||||
ClientID: &client.ID,
|
||||
AccountID: user.ID,
|
||||
}
|
||||
|
||||
if err := database.C.Save(&ticket).Error; err != nil {
|
||||
return ticket, err
|
||||
}
|
||||
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
func ActiveTicketWithPassword(ticket models.AuthTicket, password string) (models.AuthTicket, error) {
|
||||
if ticket.AvailableAt != nil {
|
||||
return ticket, nil
|
||||
} else if !ticket.RequireAuthenticate {
|
||||
return ticket, fmt.Errorf("detected risk, multi factor authentication required")
|
||||
}
|
||||
|
||||
if factor, err := GetPasswordFactor(ticket.AccountID); err != nil {
|
||||
return ticket, fmt.Errorf("unable to active ticket: %v", err)
|
||||
} else if err = CheckFactor(factor, password); err != nil {
|
||||
return ticket, err
|
||||
}
|
||||
|
||||
ticket.AvailableAt = lo.ToPtr(time.Now())
|
||||
|
||||
if !ticket.RequireAuthenticate && !ticket.RequireMFA {
|
||||
ticket.AvailableAt = lo.ToPtr(time.Now())
|
||||
}
|
||||
|
||||
if err := database.C.Save(&ticket).Error; err != nil {
|
||||
return ticket, err
|
||||
}
|
||||
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
func ActiveTicketWithMFA(ticket models.AuthTicket, factor models.AuthFactor, code string) (models.AuthTicket, error) {
|
||||
if ticket.AvailableAt != nil {
|
||||
return ticket, nil
|
||||
} else if !ticket.RequireMFA {
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
if err := CheckFactor(factor, code); err != nil {
|
||||
return ticket, fmt.Errorf("invalid code: %v", err)
|
||||
}
|
||||
|
||||
ticket.RequireMFA = false
|
||||
|
||||
if !ticket.RequireAuthenticate && !ticket.RequireMFA {
|
||||
ticket.AvailableAt = lo.ToPtr(time.Now())
|
||||
}
|
||||
|
||||
if err := database.C.Save(&ticket).Error; err != nil {
|
||||
return ticket, err
|
||||
}
|
||||
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
func RegenSession(session models.AuthTicket) (models.AuthTicket, error) {
|
||||
session.GrantToken = lo.ToPtr(uuid.NewString())
|
||||
session.AccessToken = lo.ToPtr(uuid.NewString())
|
||||
session.RefreshToken = lo.ToPtr(uuid.NewString())
|
||||
err := database.C.Save(&session).Error
|
||||
return session, err
|
||||
}
|
29
pkg/services/ticket_queries.go
Normal file
29
pkg/services/ticket_queries.go
Normal file
@ -0,0 +1,29 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
)
|
||||
|
||||
func GetTicket(id uint) (models.AuthTicket, error) {
|
||||
var ticket models.AuthTicket
|
||||
if err := database.C.
|
||||
Where(&models.AuthTicket{BaseModel: models.BaseModel{ID: id}}).
|
||||
First(&ticket).Error; err != nil {
|
||||
return ticket, err
|
||||
}
|
||||
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
func GetTicketWithToken(tokenId string) (models.AuthTicket, error) {
|
||||
var ticket models.AuthTicket
|
||||
if err := database.C.
|
||||
Where(models.AuthTicket{AccessToken: &tokenId}).
|
||||
Or(models.AuthTicket{RefreshToken: &tokenId}).
|
||||
First(&ticket).Error; err != nil {
|
||||
return ticket, err
|
||||
}
|
||||
|
||||
return ticket, nil
|
||||
}
|
98
pkg/services/ticket_token.go
Normal file
98
pkg/services/ticket_token.go
Normal file
@ -0,0 +1,98 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetToken(ticket models.AuthTicket) (string, string, error) {
|
||||
var refresh, access string
|
||||
if err := ticket.IsAvailable(); err != nil {
|
||||
return refresh, access, err
|
||||
}
|
||||
if ticket.AccessToken == nil || ticket.RefreshToken == nil {
|
||||
return refresh, access, fmt.Errorf("unable to encode token, access or refresh token id missing")
|
||||
}
|
||||
|
||||
accessDuration := time.Duration(viper.GetInt64("access_token_duration")) * time.Second
|
||||
refreshDuration := time.Duration(viper.GetInt64("refresh_token_duration")) * time.Second
|
||||
|
||||
var err error
|
||||
sub := strconv.Itoa(int(ticket.AccountID))
|
||||
sed := strconv.Itoa(int(ticket.ID))
|
||||
access, err = EncodeJwt(*ticket.AccessToken, JwtAccessType, sub, sed, ticket.Audiences, time.Now().Add(accessDuration))
|
||||
if err != nil {
|
||||
return refresh, access, err
|
||||
}
|
||||
refresh, err = EncodeJwt(*ticket.RefreshToken, JwtRefreshType, sub, sed, ticket.Audiences, time.Now().Add(refreshDuration))
|
||||
if err != nil {
|
||||
return refresh, access, err
|
||||
}
|
||||
|
||||
ticket.LastGrantAt = lo.ToPtr(time.Now())
|
||||
database.C.Save(&ticket)
|
||||
|
||||
return access, refresh, nil
|
||||
}
|
||||
|
||||
func ExchangeToken(token string) (string, string, error) {
|
||||
var ticket models.AuthTicket
|
||||
if err := database.C.Where(models.AuthTicket{GrantToken: &token}).First(&ticket).Error; err != nil {
|
||||
return "", "", err
|
||||
} else if ticket.LastGrantAt != nil {
|
||||
return "", "", fmt.Errorf("ticket was granted the first token, use refresh token instead")
|
||||
} else if len(ticket.Audiences) > 1 {
|
||||
return "", "", fmt.Errorf("should use authorization code grant type")
|
||||
}
|
||||
|
||||
return GetToken(ticket)
|
||||
}
|
||||
|
||||
func ExchangeOauthToken(clientId, clientSecret, redirectUri, token string) (string, string, error) {
|
||||
var client models.ThirdClient
|
||||
if err := database.C.Where(models.ThirdClient{Alias: clientId}).First(&client).Error; err != nil {
|
||||
return "", "", err
|
||||
} else if client.Secret != clientSecret {
|
||||
return "", "", fmt.Errorf("invalid client secret")
|
||||
} else if !client.IsDraft && !lo.Contains(client.Callbacks, redirectUri) {
|
||||
return "", "", fmt.Errorf("invalid redirect uri")
|
||||
}
|
||||
|
||||
var ticket models.AuthTicket
|
||||
if err := database.C.Where(models.AuthTicket{GrantToken: &token}).First(&ticket).Error; err != nil {
|
||||
return "", "", err
|
||||
} else if ticket.LastGrantAt != nil {
|
||||
return "", "", fmt.Errorf("ticket was granted the first token, use refresh token instead")
|
||||
}
|
||||
|
||||
return GetToken(ticket)
|
||||
}
|
||||
|
||||
func RefreshToken(token string) (string, string, error) {
|
||||
parseInt := func(str string) int {
|
||||
val, _ := strconv.Atoi(str)
|
||||
return val
|
||||
}
|
||||
|
||||
var ticket models.AuthTicket
|
||||
if claims, err := DecodeJwt(token); err != nil {
|
||||
return "404", "403", err
|
||||
} else if claims.Type != JwtRefreshType {
|
||||
return "404", "403", fmt.Errorf("invalid token type, expected refresh token")
|
||||
} else if err := database.C.Where(models.AuthTicket{
|
||||
BaseModel: models.BaseModel{ID: uint(parseInt(claims.SessionID))},
|
||||
}).First(&ticket).Error; err != nil {
|
||||
return "404", "403", err
|
||||
}
|
||||
|
||||
if ticket, err := RegenSession(ticket); err != nil {
|
||||
return "404", "403", err
|
||||
} else {
|
||||
return GetToken(ticket)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user