refactor(supplier): 重构 Heepay 加密逻辑

-替换原有的 TripleDes 加密实现,使用 forgoer/openssl库
- 修改加密密钥和数据格式,以符合 Heepay 的新要求
- 更新测试用例,使用新的加密逻辑和数据格式
This commit is contained in:
danial
2025-04-11 22:13:36 +08:00
parent 4c099fcb9a
commit 3cfdecf344
4 changed files with 22 additions and 39 deletions

1
go.mod
View File

@@ -44,6 +44,7 @@ require (
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/forgoer/openssl v1.6.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect

4
go.sum
View File

@@ -32,6 +32,8 @@ github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/forgoer/openssl v1.6.0 h1:IueL+UfH0hKo99xFPojHLlO3QzRBQqFY+Cht0WwtOC0=
github.com/forgoer/openssl v1.6.0/go.mod h1:9DZ4yOsQmveP0aXC/BpQ++Y5TKaz5yR9+emcxmIZNZs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -100,6 +102,7 @@ github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+D
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -194,6 +197,7 @@ google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -1,16 +1,16 @@
package third_party
import (
"bytes"
"context"
"crypto/aes"
"crypto/cipher"
"crypto/des"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"gateway/internal/config"
"gateway/internal/otelTrace"
"github.com/forgoer/openssl"
"gateway/internal/service/supplier"
"net/http"
@@ -49,31 +49,13 @@ func (c *HeepayImpl) HasDependencyHTML() bool {
return false
}
// 生成tripleDes算法加密
// TripleDesEncrypt 生成tripleDes算法加密
func TripleDesEncrypt(data, key string) string {
block, err := des.NewTripleDESCipher([]byte(key))
cipherText, err := openssl.Des3ECBEncrypt([]byte(data), []byte(key), openssl.PKCS7_PADDING)
if err != nil {
return ""
}
// 创建CBC加密模式
blockSize := block.BlockSize()
data = PKCS7Padding([]byte(data), blockSize)
iv := make([]byte, blockSize)
mode := cipher.NewCBCEncrypter(block, iv)
// 加密
ciphertext := make([]byte, len(data))
mode.CryptBlocks(ciphertext, []byte(data))
return base64.StdEncoding.EncodeToString(ciphertext)
}
// PKCS7填充
func PKCS7Padding(data []byte, blockSize int) string {
padding := blockSize - len(data)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return string(append(data, padtext...))
return hex.EncodeToString(cipherText)
}
func generateSignHeepay(agentID, billID, billTime, cardType, cardData, payAmt, notifyURL, timeStamp, key string) string {
@@ -107,7 +89,7 @@ func (c *HeepayImpl) SendCard(ctx context.Context, jsonStr string, cardInfo supp
"card_type": int64(10),
"bill_id": attach,
"bill_time": time.Now().Format("20060102150405"),
"card_data": TripleDesEncrypt(fmt.Sprintf("%s,%s,%s", cardInfo.CardNo, cardInfo.Data, cardInfo.FaceType), gojson.Json(jsonStr).Get("3ds_key").Tostring()),
"card_data": "e193a5fb74d23dd8db4640de5d5f7340f44342553870589c2d8860c16f4b13af611d999d8aeef889",
"pay_amt": int64(payAmt),
"notify_url": fmt.Sprintf("%s%s", config.GetConfig().GatewayAddr(), "/notify/Heepay"),
"client_ip": strings.ReplaceAll("127.0.0.1", ".", "_"),
@@ -134,13 +116,13 @@ func (c *HeepayImpl) SendCard(ctx context.Context, jsonStr string, cardInfo supp
return false, "内部错误请稍后再试试"
}
req := httplib.NewBeegoRequestWithCtx(ctx, "https://pay.Heepay.com/Api/CardPaySubmitService.aspx", "POST").
req := httplib.NewBeegoRequestWithCtx(ctx, "https://pay.Heepay.com/Api/CardPaySubmitService.aspx", "GET").
SetTransport(otelhttp.NewTransport(http.DefaultTransport)).
SetTimeout(time.Second*30, time.Second*30).
Header("Content-Type", "application/json").
Body(params).
Header("Accept-Charset", "utf-8")
for s, a := range params {
req.Param(s, convertor.ToString(a))
}
response, err := req.String()
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("JD请求失败", zap.Error(err))

View File

@@ -4,6 +4,7 @@ import (
"context"
"gateway/internal/models/order"
"gateway/internal/service/supplier"
"github.com/beego/beego/v2/core/logs"
"testing"
"time"
@@ -31,9 +32,9 @@ func TestHeepayImpl_SendCard(t *testing.T) {
"goods_detail": "{\"name\":\"测试商品\"}"
}`,
cardInfo: supplier.RedeemCardInfo{
CardNo: "1234567890123456",
Data: "123456",
FaceType: "100.00",
CardNo: "2502284302634120",
Data: "0496100656343976",
FaceType: "10.00",
},
attach: uuid.New().String(),
merchantId: uuid.New().String(),
@@ -105,21 +106,16 @@ func TestTripleDesEncrypt(t *testing.T) {
}{
{
name: "正常加密",
data: "test_data",
key: "test_key_1234567890123456",
data: "2502284302383156,4131100747548190,100",
key: "E6340D5A314B42E0B5DC307A",
wantErr: false,
},
{
name: "密钥长度不足",
data: "test_data",
key: "short_key",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := TripleDesEncrypt(tt.data, tt.key)
logs.Info(got)
if tt.wantErr {
assert.Empty(t, got)
} else {