针对邮乐的修改
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