package crypto import ( "fmt" "strconv" "time" "github.com/golang-jwt/jwt" "golang.org/x/crypto/bcrypt" "furtuna-be/internal/common/errors" "furtuna-be/internal/entity" ) func NewCrypto(config CryptoConfig) *CryptoImpl { return &CryptoImpl{ Config: config, } } type CryptoConfig interface { AccessTokenSecret() string AccessTokenOrderSecret() string AccessTokenOrderExpiresDate() time.Time AccessTokenExpiresDate() time.Time AccessTokenResetPasswordSecret() string AccessTokenResetPasswordExpire() time.Time } type CryptoImpl struct { Config CryptoConfig } func (c *CryptoImpl) CompareHashAndPassword(hash string, password string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } func (c *CryptoImpl) ValidateWT(tokenString string) (*jwt.Token, error) { token, err := jwt.Parse(tokenString, 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(c.Config.AccessTokenSecret()), nil }) return token, err } func (c *CryptoImpl) GenerateJWT(user *entity.User) (string, error) { partnerID := int64(0) if user.PartnerID != nil { partnerID = *user.PartnerID } siteID := int64(0) if user.SiteID != nil { siteID = *user.SiteID } claims := &entity.JWTAuthClaims{ StandardClaims: jwt.StandardClaims{ Subject: strconv.FormatInt(user.ID, 10), ExpiresAt: c.Config.AccessTokenExpiresDate().Unix(), IssuedAt: time.Now().Unix(), NotBefore: time.Now().Unix(), }, UserID: user.ID, Name: user.Name, Email: user.Email, Role: int(user.RoleID), PartnerID: partnerID, SiteID: siteID, SiteName: user.SiteName, } token, err := jwt. NewWithClaims(jwt.SigningMethodHS256, claims). SignedString([]byte(c.Config.AccessTokenSecret())) if err != nil { return "", err } return token, nil } func (c *CryptoImpl) GenerateJWTReseetPassword(user *entity.User) (string, error) { claims := &entity.JWTAuthClaims{ StandardClaims: jwt.StandardClaims{ Subject: strconv.FormatInt(user.ID, 10), ExpiresAt: c.Config.AccessTokenResetPasswordExpire().Unix(), IssuedAt: time.Now().Unix(), NotBefore: time.Now().Unix(), }, UserID: user.ID, Name: user.Name, Email: user.Email, } token, err := jwt. NewWithClaims(jwt.SigningMethodHS256, claims). SignedString([]byte(c.Config.AccessTokenResetPasswordSecret())) if err != nil { return "", err } return token, nil } func (c *CryptoImpl) ParseAndValidateJWT(tokenString string) (*entity.JWTAuthClaims, error) { token, err := jwt.ParseWithClaims(tokenString, &entity.JWTAuthClaims{}, func(token *jwt.Token) (interface{}, error) { return []byte(c.Config.AccessTokenSecret()), nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*entity.JWTAuthClaims); ok && token.Valid { return claims, nil } else { return nil, errors.ErrorUnauthorized } } func (c *CryptoImpl) GenerateJWTOrder(order *entity.Order) (string, error) { claims := &entity.JWTOrderClaims{ StandardClaims: jwt.StandardClaims{ Subject: strconv.FormatInt(order.ID, 10), ExpiresAt: c.Config.AccessTokenOrderExpiresDate().Unix(), IssuedAt: time.Now().Unix(), NotBefore: time.Now().Unix(), }, PartnerID: order.PartnerID, OrderID: order.ID, } token, err := jwt. NewWithClaims(jwt.SigningMethodHS256, claims). SignedString([]byte(c.Config.AccessTokenOrderSecret())) if err != nil { return "", err } return token, nil } func (c *CryptoImpl) ValidateJWTOrder(tokenString string) (int64, int64, error) { token, err := jwt.ParseWithClaims(tokenString, &entity.JWTOrderClaims{}, 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(c.Config.AccessTokenOrderSecret()), nil }) if err != nil { return 0, 0, err } claims, ok := token.Claims.(*entity.JWTOrderClaims) if !ok || !token.Valid { return 0, 0, fmt.Errorf("invalid token %v", token.Header["alg"]) } return claims.PartnerID, claims.OrderID, nil } func (c *CryptoImpl) ValidateResetPassword(tokenString string) (int64, error) { token, err := jwt.ParseWithClaims(tokenString, &entity.JWTOrderClaims{}, 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(c.Config.AccessTokenResetPasswordSecret()), nil }) if err != nil { return 0, err } claims, ok := token.Claims.(*entity.JWTAuthClaims) if !ok || !token.Valid { return 0, fmt.Errorf("invalid token %v", token.Header["alg"]) } return claims.UserID, nil }