针对邮乐的修改
This commit is contained in:
parent
a5e5ed2ecc
commit
8ae7a0fa53
|
@ -17,12 +17,13 @@ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certifi
|
|||
COPY --from=builder /src /src
|
||||
|
||||
RUN mkdir "/var/log/supervisor"
|
||||
RUN mkdir "/var/log/queue"
|
||||
WORKDIR /src
|
||||
ADD ./sh/startup.sh /opt/startup.sh
|
||||
RUN sed -i 's/\r//g' /opt/startup.sh
|
||||
ADD ./sh/supervisord.conf /etc/supervisord.conf
|
||||
|
||||
WORKDIR /src
|
||||
EXPOSE 10002
|
||||
EXPOSE 10001
|
||||
|
||||
#CMD ["sh","/opt/startup.sh"]
|
|
@ -10,6 +10,8 @@ type NacosConf struct {
|
|||
NameSpace string
|
||||
TimeOut uint64
|
||||
ServiceName string
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
type RockerMqConfig struct {
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
Name: transfer.rpc
|
||||
ListenOn: 0.0.0.0:8080
|
||||
Etcd:
|
||||
Hosts:
|
||||
- 127.0.0.1:2379
|
||||
Key: transfer.rpc
|
|
@ -2,7 +2,6 @@ package do
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"trasfer_middleware/cmd/rpc/internal/logic/vo"
|
||||
"trasfer_middleware/genModel"
|
||||
|
@ -13,17 +12,11 @@ func MarketKeyDataSet(order *genModel.ServerOrderMarket, resq string, resp strin
|
|||
orderInfoReq map[string]interface{}
|
||||
orderInfoRes map[string]interface{}
|
||||
)
|
||||
if orderInfoRes["code"].(string) != vo.ZLTX_RS_SUCCESS {
|
||||
err = json.Unmarshal([]byte(resp), &orderInfoRes)
|
||||
if orderInfoRes["errCode"].(string) != vo.MARKET_SUCCESS {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal([]byte(resq), &orderInfoReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("订单已存在")
|
||||
}
|
||||
err = json.Unmarshal([]byte(resp), &orderInfoRes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -31,14 +24,14 @@ func MarketKeyDataSet(order *genModel.ServerOrderMarket, resq string, resp strin
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
order.ProductId, err = strconv.ParseInt(orderInfoReq["voucher_id"].(string), 16, 64)
|
||||
order.ProductId = orderInfoReq["voucher_id"].(string)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
order.VoucherNum = orderInfoReq["mem_id"].(string)
|
||||
|
||||
order.OutBizNo = orderInfoReq["req_serial_no"].(string)
|
||||
order.OrderNum = orderInfoReq["voucher_code"].(string)
|
||||
order.OrderNum = orderInfoRes["data"].(map[string]interface{})["voucher_code"].(string)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
"trasfer_middleware/cmd/rpc/etc"
|
||||
"trasfer_middleware/cmd/rpc/internal/logic/po"
|
||||
"trasfer_middleware/cmd/rpc/internal/logic/po/market/types"
|
||||
|
@ -33,14 +32,7 @@ func NewMarket(conf types.MarketConf) *Market {
|
|||
}
|
||||
|
||||
func (r *Market) SetData(c context.Context, data map[string]interface{}, config *etc.RockerMqConfig) *MarketRequest {
|
||||
|
||||
data["timestamp"] = time.Now().Format("20060102150405")
|
||||
private1 := "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC5FGH7Tq5u7pA/eh6AjAS0InykvWDJt095go8yK3w7+TRIhSYDdbRHlTgOQm4nWuMPfz3U2Rs1vJQwyyEYdylcYJ2zFLr7Vb1BdvkJ3Kz/2yJ6sz3BNq6xAHaeCKzA/WZxnc/ypfkGlrmfr2tNqCM9CUHUWryihBjLxwRiWLmo0aKgYpKLKYNixLgyqUYAifD3APncAduv6sSjUPMTyXMOlP1DXgVwX6IaUG/yV8/56Ew72Vdi/y4qZmCKMmXq4PovWrs8ISOEuhxbfLrGWbGCAVYPq7d7XaH+AOY4dhJZm7OZ43UGWw80QKGEPkvU4Oquzu8BqBh12md7Zsd6r0XzAgMBAAECggEAcLgTPKUc437z51UOwqeELdlbJFIaYn/8LTrwz1NgpH4P86L0FeNX2sjsjPK0d8+IvmV2WO2o/r9NWbI9A9N/Iz3MjcawYmZDj11QK0t1KZZil2wWzlfpaO+pTnJmFFvASq4ceeHPms2tW63QokkmvQOoTha9EBV3rJQW/XagDEolty57kkfmB31cQHJuAt+BF5EzBqv3q3jnqhsj8J/ddT0hadyKq65u85VomLH92asu/KKMKYYXC8aHjgX48chAmQUAHGM/HCD2owLHwtei2kPWNDx85ecBsglIX3wy0yhH1dnL+o3eeskVLl89ye3QCJPHJBaNUUfbgucgWT0bsQKBgQD1pPMAe31ZXajl9WlHMtn8qhpAGzi/GiiH6YrrHMQECC2GGuAakBko1Vhc+2HU35gwlPOhwMIOCapB0cCqcZVo3+71AKo78YvZLQ7yMuSsp0/Wn2N79NZ6+++wtHGPP9eHrLuWm23l15W7W0RcQptTaQupbculMQZ8b6cAjh6d1QKBgQDA4c4Xl2ePbQdgMMOuKTPPKF3QI1VhCVtxSV+Gj9MZBZedstz9+ZO3oxHhy8D5S9it1hE6dn6/a+7OWibZ/gBr1S0+11LcwKDb7q30dimr9bQs/srIywpoIIN8wVEkX4P9JLOWgQeAtq53IMba+cElef916aqyJpXuIek9lvUQpwKBgQCD7alNMwWpf3H8v4dhY+BLoRgkIfqiOGxYQogHqhVkjPfWNIzz9zxr/9lLZv+uEsBsJzOKRjpyy6ITY5H0eLhj8REnqMnFE/+mDlsenVLPn7Rzcns90ct3leOvpdnvs7wP9CdzxdqKPPUAAQ5/9o3xiFNpFbzv5Zq0LkslMy8iWQKBgQCiRJWctUxzllcRLpVBTPqAOkaKV195zmR2rzLFQvRmZZUDH7nZlQEYCgF+Q2tqj8uPm7tMwumo4wW55pAu7witr19sMbxNaWUrAeao9kvilkfpXsV9HYv4w/m6l+xKvGyPKDRJ1u1X9Nhb8mA5UsqSW8t2CIoJbHrQJwlRPlGXmwKBgQDg4rcsM2PmShOg8lSrHXPATXiZyyqpPJLpXbV6DRKyt7U6KWjyrplQN7yOoIUgsuD2OC/q67y7w1P3OY7X0RDnMr6MtIV0JyBJHg24eyBTqeLai2DqoHlsBOSvpJDZf+g/DXCjvHMWp1h0wqdj3aLthmU0dHM/CEqr/o7d8GwrGQ=="
|
||||
p := "-----BEGIN RSA PRIVATE KEY-----\n" + private1 + "\n-----END RSA PRIVATE KEY-----"
|
||||
data["app_id"] = "2783278"
|
||||
data["mem_id"] = "2783278"
|
||||
data["pos_id"] = "2783278"
|
||||
|
||||
p := "-----BEGIN RSA PRIVATE KEY-----\n" + data["sign"].(string) + "\n-----END RSA PRIVATE KEY-----"
|
||||
sign, err := common.MarketMakeRsaSign(p, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -81,14 +73,7 @@ func (r *MarketRequest) request(url string) (*request.Response, error) {
|
|||
if err != nil {
|
||||
sysLog.LogSendMq(r.ctx, err)
|
||||
}
|
||||
/*r.Model.Insert(context.Background(), &genModel.ServerMiddleMarketLogs{
|
||||
Url : url,
|
||||
Code :int64()
|
||||
Data :string(reqStr)
|
||||
Resp :resp.Text,
|
||||
CreateTime :time.Now(),
|
||||
})*/
|
||||
return &resp, err
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (r *MarketRequest) KeySend() (*transfer.MarketKeySendRes, error) {
|
||||
|
|
|
@ -11,4 +11,6 @@ const (
|
|||
MARKET_KEY_QUERY = "openApi/v1/market/key/query"
|
||||
|
||||
MARKET_LOG_STATU_DEFAULT = 1
|
||||
|
||||
MARKET_SUCCESS = "00"
|
||||
)
|
||||
|
|
|
@ -181,6 +181,7 @@ func (m *Market) saveMarketOrder(logId int64, resq string, resp string) error {
|
|||
order.LogId = logId
|
||||
order.ReqTime = time.Now()
|
||||
order.CreateTime = time.Now()
|
||||
order.Status = vo.MARKET_LOG_STATU_DEFAULT
|
||||
err := do.MarketKeyDataSet(order, resq, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -129,7 +129,7 @@ message MarketKeySendRes {
|
|||
|
||||
message MarketKeySendReq {
|
||||
string app_id = 1;
|
||||
uint64 sign = 2;
|
||||
string sign = 2;
|
||||
string req_code = 3;
|
||||
string mem_id = 4;
|
||||
string req_serial_no = 5;
|
||||
|
|
|
@ -689,7 +689,7 @@ type MarketKeySendReq struct {
|
|||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AppId string `protobuf:"bytes,1,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"`
|
||||
Sign uint64 `protobuf:"varint,2,opt,name=sign,proto3" json:"sign,omitempty"`
|
||||
Sign string `protobuf:"bytes,2,opt,name=sign,proto3" json:"sign,omitempty"`
|
||||
ReqCode string `protobuf:"bytes,3,opt,name=req_code,json=reqCode,proto3" json:"req_code,omitempty"`
|
||||
MemId string `protobuf:"bytes,4,opt,name=mem_id,json=memId,proto3" json:"mem_id,omitempty"`
|
||||
ReqSerialNo string `protobuf:"bytes,5,opt,name=req_serial_no,json=reqSerialNo,proto3" json:"req_serial_no,omitempty"`
|
||||
|
@ -740,11 +740,11 @@ func (x *MarketKeySendReq) GetAppId() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (x *MarketKeySendReq) GetSign() uint64 {
|
||||
func (x *MarketKeySendReq) GetSign() string {
|
||||
if x != nil {
|
||||
return x.Sign
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MarketKeySendReq) GetReqCode() string {
|
||||
|
@ -2174,7 +2174,7 @@ var file_transfer_proto_rawDesc = []byte{
|
|||
0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, 0x15, 0x0a,
|
||||
0x06, 0x61, 0x70, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61,
|
||||
0x70, 0x70, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x67, 0x6e, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x67, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x5f,
|
||||
0x28, 0x09, 0x52, 0x04, 0x73, 0x69, 0x67, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x5f,
|
||||
0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x71, 0x43,
|
||||
0x6f, 0x64, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x65,
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"trasfer_middleware/until/sysLog"
|
||||
)
|
||||
|
||||
var configFile = flag.String("f", "../../../config/transfer.yaml", "the config file")
|
||||
var configFile = flag.String("f", "../../../config/transfer_local.yaml", "the config file")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
"trasfer_middleware/cmd/rpc/pb/transfer"
|
||||
)
|
||||
|
||||
var configFile = flag.String("f", "../../config/transfer.yaml", "the config file")
|
||||
var configFile = flag.String("f", "../../config/transfer_local.yaml", "the config file")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
@ -51,6 +51,8 @@ func registerNacos(c *config.Config) {
|
|||
NamespaceId: c.Nacos.NameSpace,
|
||||
TimeoutMs: c.Nacos.TimeOut,
|
||||
NotLoadCacheAtStart: true,
|
||||
Username: c.Nacos.Username,
|
||||
Password: c.Nacos.Password,
|
||||
LogDir: "/tmp/nacos/log",
|
||||
CacheDir: "/tmp/nacos/cache",
|
||||
LogLevel: "debug",
|
||||
|
|
|
@ -40,7 +40,7 @@ type (
|
|||
OutBizNo string `db:"out_biz_no"` // 用户侧流水号
|
||||
VoucherNum string `db:"voucher_num"` // 商户号
|
||||
OrderNum string `db:"order_num"` // 系统侧订单号
|
||||
ProductId int64 `db:"product_id"` // 平台提供商品id
|
||||
ProductId string `db:"product_id"` // 平台提供商品id
|
||||
Num int64 `db:"num"` // 购买数量
|
||||
LogId int64 `db:"log_id"` // 对应的日志id
|
||||
ReqTime time.Time `db:"req_time"` // 请求时间
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
{"@timestamp":"2024-07-12T18:11:31.120+08:00","caller":"market/market.go:96","content":"sendMq:[the topic=online_transfer_market route info not found]","level":"info","span":"5139dd7d49f98616","trace":"c1511bea8fd02ac0b3178bab68348d01"}
|
||||
{"@timestamp":"2024-07-12T18:32:40.850+08:00","caller":"market/market.go:96","content":"sendMq:[producer group has been created]","level":"info","span":"49848e601ec056c7","trace":"010c0d971e83368fbfcb7c77bfd0c551"}
|
||||
{"@timestamp":"2024-07-12T18:33:54.829+08:00","caller":"market/market.go:96","content":"sendMq:[the topic=online_transfer_market route info not found]","level":"info","span":"b3e8beb1de670367","trace":"ad085836fc7f1cd2ecf979b48ef9aea0"}
|
||||
{"@timestamp":"2024-07-12T18:34:56.302+08:00","caller":"market/market.go:96","content":"sendMq:[the topic=testx_transfer_market route info not found]","level":"info","span":"1a5d63deb2ec9569","trace":"d59630d3ef3c72069d6e2a77990893d5"}
|
|
@ -0,0 +1 @@
|
|||
{"@timestamp":"2024-07-15T11:34:59.386+08:00","caller":"market/market.go:87","content":"sendMq:[the topic=testx_transfer_market route info not found]","level":"info","span":"59dbedec4cddc60a","trace":"bfce456fdd339411405166a0fd601432"}
|
|
@ -7,8 +7,4 @@ V_REFLECT=""
|
|||
|
||||
|
||||
docker build -t "${IMAGE}" . --no-cache
|
||||
docker stop "${RPC_CONTAINER}"
|
||||
|
||||
docker rm "${RPC_CONTAINER}"
|
||||
|
||||
docker run -it -p "${RPC_PORT}:${RPC_PORT}" --name "$RPC_CONTAINER" "${IMAGE}"
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
IMAGE="transfer_middleware"
|
||||
RPC_CONTAINER="transfer_middleware"
|
||||
RPC_PORT="10001"
|
||||
V_REFLECT=""
|
||||
TAGS_NAME="v1"
|
||||
ADDRESS="registry.cn-chengdu.aliyuncs.com/go_ls/transfer_middleware_produce"
|
||||
|
||||
docker build -t "${IMAGE}:${TAGS_NAME}" . --no-cache
|
||||
|
||||
docker tag "${IMAGE}:${TAGS_NAME}" ${ADDRESS}:${TAGS_NAME}
|
||||
|
||||
docker push ${ADDRESS}:${TAGS_NAME}
|
|
@ -17,7 +17,8 @@ redirect_stderr=false
|
|||
stdout_logfile_maxbytes = 20MB
|
||||
#stdout 日志文件备份数
|
||||
stdout_logfile_backups = 20
|
||||
|
||||
stdout_logfile=/var/log/out.log
|
||||
stderr_logfile=/var/log/err.log
|
||||
|
||||
[program:queue]
|
||||
directory=/src/cmd/rpc/queue
|
||||
|
@ -37,3 +38,5 @@ redirect_stderr=false
|
|||
stdout_logfile_maxbytes = 20MB
|
||||
#stdout 日志文件备份数
|
||||
stdout_logfile_backups = 20
|
||||
stdout_logfile=/var/log/queue/out.log
|
||||
stderr_logfile=/var/log/queue/err.log
|
156
test/encrypt.go
156
test/encrypt.go
|
@ -1,156 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
crand "crypto/rand"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"math/rand"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const lettersString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
// 字符串长度
|
||||
const number = 16
|
||||
|
||||
/*
|
||||
16位码,前15位随机字符串,最后一位通过前15位字符串计算校验生成
|
||||
*/
|
||||
|
||||
func LotteryEncryptEncode() string {
|
||||
b := make([]byte, number)
|
||||
var sum byte
|
||||
for i := 0; i < number-1; i++ {
|
||||
b[i] = lettersString[rand.Int63()%int64(len(lettersString))]
|
||||
sum += b[i]
|
||||
}
|
||||
b[number-1] = lettersString[sum%byte(len(lettersString))]
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
func LotteryEncryptDecode(str string) bool {
|
||||
if len(str) != number {
|
||||
return false
|
||||
}
|
||||
var sum byte
|
||||
for i := 0; i < len(str)-1; i++ {
|
||||
sum += str[i]
|
||||
}
|
||||
if lettersString[sum%byte(len(lettersString))] != str[len(str)-1] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// =================== CBC ======================
|
||||
func AesEncryptCBC(origData []byte, key []byte) (str string) {
|
||||
// 分组秘钥
|
||||
// NewCipher该函数限制了输入k的长度必须为16, 24或者32
|
||||
block, _ := aes.NewCipher(key)
|
||||
blockSize := block.BlockSize() // 获取秘钥块的长度
|
||||
origData = pkcs5Padding(origData, blockSize) // 补全码
|
||||
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) // 加密模式
|
||||
encrypted := make([]byte, len(origData)) // 创建数组
|
||||
blockMode.CryptBlocks(encrypted, origData) // 加密
|
||||
|
||||
return base64.StdEncoding.EncodeToString(encrypted)
|
||||
}
|
||||
func AesDecryptCBC(data string, key []byte) (decrypted []byte) {
|
||||
encrypted, err := base64.StdEncoding.DecodeString(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
block, _ := aes.NewCipher(key) // 分组秘钥
|
||||
blockSize := block.BlockSize() // 获取秘钥块的长度
|
||||
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) // 加密模式
|
||||
decrypted = make([]byte, len(encrypted)) // 创建数组
|
||||
blockMode.CryptBlocks(decrypted, encrypted) // 解密
|
||||
decrypted = pkcs5UnPadding(decrypted) // 去除补全码
|
||||
return decrypted
|
||||
}
|
||||
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
func pkcs5UnPadding(origData []byte) []byte {
|
||||
length := len(origData)
|
||||
unpadding := int(origData[length-1])
|
||||
return origData[:(length - unpadding)]
|
||||
}
|
||||
|
||||
// =================== ECB ======================
|
||||
func AesEncryptECB(origData []byte, key []byte) (encrypted []byte) {
|
||||
cipher, _ := aes.NewCipher(generateKey(key))
|
||||
length := (len(origData) + aes.BlockSize) / aes.BlockSize
|
||||
plain := make([]byte, length*aes.BlockSize)
|
||||
copy(plain, origData)
|
||||
pad := byte(len(plain) - len(origData))
|
||||
for i := len(origData); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
encrypted = make([]byte, len(plain))
|
||||
// 分组分块加密
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(origData); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
|
||||
return encrypted
|
||||
}
|
||||
func AesDecryptECB(encrypted []byte, key []byte) (decrypted []byte) {
|
||||
cipher, _ := aes.NewCipher(generateKey(key))
|
||||
decrypted = make([]byte, len(encrypted))
|
||||
//
|
||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||
}
|
||||
|
||||
trim := 0
|
||||
if len(decrypted) > 0 {
|
||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||
}
|
||||
|
||||
return decrypted[:trim]
|
||||
}
|
||||
func generateKey(key []byte) (genKey []byte) {
|
||||
genKey = make([]byte, 16)
|
||||
copy(genKey, key)
|
||||
for i := 16; i < len(key); {
|
||||
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
|
||||
genKey[j] ^= key[i]
|
||||
}
|
||||
}
|
||||
return genKey
|
||||
}
|
||||
|
||||
// =================== CFB ======================
|
||||
func AesEncryptCFB(origData []byte, key []byte) (encrypted []byte) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
encrypted = make([]byte, aes.BlockSize+len(origData))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(crand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], origData)
|
||||
return encrypted
|
||||
}
|
||||
func AesDecryptCFB(encrypted []byte, key []byte) (decrypted []byte) {
|
||||
block, _ := aes.NewCipher(key)
|
||||
if len(encrypted) < aes.BlockSize {
|
||||
panic("ciphertext too short")
|
||||
}
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
return encrypted
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
package market
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"qteam/config"
|
||||
)
|
||||
|
||||
type MarketClient struct {
|
||||
cfg config.MarketConfig
|
||||
}
|
||||
|
||||
type MarketSendRequest struct {
|
||||
AppId string `json:"app_id"` //APP ID
|
||||
Sign string `json:"sign"` //签名
|
||||
ReqCode string `json:"req_code"` //固定值:voucher.create
|
||||
MemId string `json:"mem_id"` //商户号
|
||||
ReqSerialNo string `json:"req_serial_no"` //请求唯一流水号 最大32位
|
||||
TimeTamp string `json:"timestamp"` //时间戳 yyyyMMddHHmmss
|
||||
PosId string `json:"pos_id"` //商户方平台号
|
||||
VoucherId string `json:"voucher_id"` //制码批次号
|
||||
VoucherNum int `json:"voucher_num"` //请券数量,默认是 1
|
||||
MobileNo string `json:"mobile_no"` //11 手机号,可传空字符串
|
||||
SendMsg string `json:"send_msg"` //是否发送短信:2- 发送 1-不发送
|
||||
}
|
||||
|
||||
type MarketSenResponse struct {
|
||||
VoucherId string `json:"voucher_id"` //制码批次号
|
||||
VoucherCode string `json:"voucher_code"` //券码
|
||||
ShortUrl string `json:"short_url"` //含二维码、条码的短链接
|
||||
VoucherSdate string `json:"voucher_sdate"` //有效期起
|
||||
VoucherEdate string `json:"voucher_edate"` //有效期止
|
||||
CodeType string `json:"code_type"` //码类型: 00- 代金券 01- 满减券
|
||||
}
|
||||
|
||||
type MarketResponse struct {
|
||||
ErrCode string `json:"errCode"` //00-成功 其他:失败
|
||||
Msg string `json:"msg"` //描 述 (失败时必填)
|
||||
Data MarketSenResponse `json:"data"`
|
||||
}
|
||||
|
||||
func (this *MarketSendRequest) toMap() (resultMap map[string]interface{}) {
|
||||
// Marshal the struct to JSON, ignoring omitempty fields.
|
||||
jsonBytes, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Unmarshal the JSON into a map to get the final result.
|
||||
err = json.Unmarshal(jsonBytes, &resultMap)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return resultMap
|
||||
}
|
||||
|
||||
func (this *MarketClient) doPost(url string, jsonBytes []byte) (body []byte, err error) {
|
||||
// 创建POST请求
|
||||
url = this.cfg.Host + url
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置Content-Type头
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// 创建HTTP客户端
|
||||
client := &http.Client{}
|
||||
|
||||
// 发送请求并处理响应
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package market
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"qteam/app/utils/encrypt"
|
||||
"qteam/config"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewMarketClient(cfg config.MarketConfig) *MarketClient {
|
||||
cfg.Sign = "-----BEGIN RSA PRIVATE KEY-----\n" + cfg.Sign + "\n-----END RSA PRIVATE KEY-----"
|
||||
return &MarketClient{
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MarketSend
|
||||
券码生成接口
|
||||
- 请求地址:/openApi/v1/market/key/send
|
||||
- 说明:发券接口应支持使用同一流水号进行重复请求,即:当调用该接口失败时,可 以使用同一流水号进行再次请求,接口需要根据请求的流水号进行判断,若无该流水 号的券码信息则新生成后返回,若有该流水号的券码信息则直接返回该券码的信息
|
||||
orderNo: 订单号
|
||||
VoucherId: 制码批次号
|
||||
MobileNo: 11 手机号,可传空字符串
|
||||
SendMsg: 是否发送短信:2- 发送 1-不发送
|
||||
*/
|
||||
func (this *MarketClient) MarketSend(orderNo, VoucherId, MobileNo, SendMsg string) (res MarketResponse, err error) {
|
||||
url := "/openApi/v1/market/key/send"
|
||||
request := MarketSendRequest{
|
||||
AppId: this.cfg.AppId,
|
||||
ReqCode: this.cfg.ReqCode,
|
||||
MemId: this.cfg.MemId,
|
||||
PosId: this.cfg.PosId,
|
||||
TimeTamp: time.Now().Format("20060102150405"),
|
||||
VoucherId: VoucherId,
|
||||
ReqSerialNo: orderNo,
|
||||
VoucherNum: 1,
|
||||
MobileNo: MobileNo,
|
||||
SendMsg: SendMsg,
|
||||
}
|
||||
|
||||
request.Sign, err = MakeRsaSign(this.cfg.Sign, request.toMap())
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
data, err := this.doPost(url, bytes)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
err = json.Unmarshal(data, &res)
|
||||
// 加密
|
||||
res.Data.ShortUrl = encrypt.AesEncryptCBC([]byte(res.Data.ShortUrl), []byte(this.cfg.SecretKey))
|
||||
return res, err
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package market
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/qit-team/snow-core/kernel/server"
|
||||
"os"
|
||||
"qteam/app/utils"
|
||||
"qteam/config"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMarketSendRequest_Market(t *testing.T) {
|
||||
opts := config.GetOptions()
|
||||
if opts.ShowVersion {
|
||||
fmt.Printf("%s\ncommit %s\nbuilt on %s\n", server.Version, server.BuildCommit, server.BuildDate)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
//加载配置
|
||||
conf, err := config.Load(opts.ConfFile)
|
||||
if err != nil {
|
||||
utils.Log(nil, "err", err.Error())
|
||||
return
|
||||
}
|
||||
client := NewMarketClient(conf.OpenApiMarketConfig)
|
||||
|
||||
data, err := client.MarketSend("123456789111", "1717567048171", "", "2")
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(data)
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
package market
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// getSignString 使用 xx=aa&yy=bb 的字符串拼接
|
||||
func getSignString(data map[string]interface{}) string {
|
||||
keys := make([]string, 0, len(data))
|
||||
for key := range data {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
signString := ""
|
||||
separator := ""
|
||||
for _, key := range keys {
|
||||
value := data[key]
|
||||
if key == "sign" || value == nil {
|
||||
continue
|
||||
}
|
||||
signString += fmt.Sprintf("%s%s=%v", separator, key, value)
|
||||
separator = "&"
|
||||
}
|
||||
return signString
|
||||
}
|
||||
|
||||
// VerifyRsaSign 签名验证
|
||||
func VerifyRsaSign(publicKey string, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
// 对 sign nonce timestamp appId 升序排序
|
||||
// 使用 xx=aa&yy=bb 的字符串拼接
|
||||
// 商户的公钥验签 RSA2验签
|
||||
signString := getSignString(data)
|
||||
|
||||
rsaPubKey, err := parseRSAPublicKeyFromPEM([]byte(publicKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signature, err := base64.StdEncoding.DecodeString(data["sign"].(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hashed := sha256.Sum256([]byte(signString))
|
||||
err = rsa.VerifyPKCS1v15(rsaPubKey, crypto.SHA256, hashed[:], signature)
|
||||
if err != nil {
|
||||
return nil, errors.New("签名验证失败")
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// MakeRsaSign 生成签名
|
||||
func MakeRsaSign(privateKey string, data map[string]interface{}) (string, error) {
|
||||
// 对 sign nonce timestamp appId 升序排序
|
||||
// 使用 xx=aa&yy=bb 的字符串拼接
|
||||
// 营销系统生成的私钥生成签名 RSA2加签
|
||||
signString := getSignString(data)
|
||||
|
||||
privKey, err := parseRSAPrivateKeyFromPEM([]byte(privateKey))
|
||||
if err != nil {
|
||||
return "", errors.New("私钥解析失败")
|
||||
}
|
||||
|
||||
hashed := sha256.Sum256([]byte(signString))
|
||||
signature, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, hashed[:])
|
||||
if err != nil {
|
||||
return "", errors.New("签名失败")
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(signature), nil
|
||||
}
|
||||
|
||||
// ParseRSAPrivateKeyFromPEM 解析私钥
|
||||
func parseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
|
||||
var err error
|
||||
|
||||
// Parse PEM block
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(key); block == nil {
|
||||
return nil, errors.New("私钥解析失败: 无效的PEM格式")
|
||||
}
|
||||
|
||||
var parsedKey interface{}
|
||||
if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
|
||||
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var pkey *rsa.PrivateKey
|
||||
var ok bool
|
||||
if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
|
||||
return nil, errors.New("密钥不是有效的RSA私钥")
|
||||
}
|
||||
|
||||
return pkey, nil
|
||||
}
|
||||
|
||||
// parseRSAPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
|
||||
func parseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
|
||||
var err error
|
||||
|
||||
// Parse PEM block
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(key); block == nil {
|
||||
return nil, errors.New("公钥解析失败: 无效的PEM格式")
|
||||
}
|
||||
|
||||
// Parse the key
|
||||
var parsedKey interface{}
|
||||
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
|
||||
if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
|
||||
parsedKey = cert.PublicKey
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var pkey *rsa.PublicKey
|
||||
var ok bool
|
||||
if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
|
||||
return nil, errors.New("密钥不是有效的RSA公钥")
|
||||
}
|
||||
|
||||
return pkey, nil
|
||||
}
|
Loading…
Reference in New Issue