2025-03-08 00:35:23 +07:00

285 lines
7.4 KiB
Go

package crypto
import (
"fmt"
"strconv"
"time"
"github.com/golang-jwt/jwt"
"golang.org/x/crypto/bcrypt"
"enaklo-pos-be/internal/common/errors"
"enaklo-pos-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
AccessTokenWithdrawSecret() string
AccessTokenWithdrawExpire() 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) GenerateJWTOrderInquiry(inquiry *entity.OrderInquiry) (string, error) {
claims := &entity.JWTOrderClaims{
StandardClaims: jwt.StandardClaims{
Subject: inquiry.ID,
ExpiresAt: c.Config.AccessTokenOrderExpiresDate().Unix(),
IssuedAt: time.Now().Unix(),
NotBefore: time.Now().Unix(),
},
PartnerID: inquiry.PartnerID,
InquiryID: inquiry.ID,
}
token, err := jwt.
NewWithClaims(jwt.SigningMethodHS256, claims).
SignedString([]byte(c.Config.AccessTokenOrderSecret()))
if err != nil {
return "", err
}
return token, nil
}
func (c *CryptoImpl) ValidateJWTOrderInquiry(tokenString string) (int64, string, 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, "", err
}
claims, ok := token.Claims.(*entity.JWTOrderClaims)
if !ok || !token.Valid {
return 0, "", fmt.Errorf("invalid token %v", token.Header["alg"])
}
return claims.PartnerID, claims.InquiryID, 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
}
func (c *CryptoImpl) GenerateJWTWithdraw(req *entity.WalletWithdrawRequest) (string, error) {
claims := &entity.JWTWithdrawClaims{
StandardClaims: jwt.StandardClaims{
Subject: strconv.FormatInt(req.ID, 10),
ExpiresAt: c.Config.AccessTokenWithdrawExpire().Unix(),
IssuedAt: time.Now().Unix(),
NotBefore: time.Now().Unix(),
},
PartnerID: req.PartnerID,
Amount: req.Amount,
Fee: req.Fee,
Total: req.Total,
}
token, err := jwt.
NewWithClaims(jwt.SigningMethodHS256, claims).
SignedString([]byte(c.Config.AccessTokenWithdrawSecret()))
if err != nil {
return "", err
}
return token, nil
}
func (c *CryptoImpl) ValidateJWTWithdraw(tokenString string) (*entity.WalletWithdrawRequest, error) {
token, err := jwt.ParseWithClaims(tokenString, &entity.JWTWithdrawClaims{}, 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.AccessTokenWithdrawSecret()), nil
})
if err != nil {
return nil, err
}
claims, ok := token.Claims.(*entity.JWTWithdrawClaims)
if !ok || !token.Valid {
return nil, fmt.Errorf("invalid token %v", token.Header["alg"])
}
return &entity.WalletWithdrawRequest{
ID: claims.ID,
PartnerID: claims.PartnerID,
Total: claims.Total,
Amount: claims.Amount,
Fee: claims.Fee,
}, nil
}