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 }