Skip to content

Commit

Permalink
Develop (#66)
Browse files Browse the repository at this point in the history
* feat(miniprogram): add customer service, risk control, service markert struct (#60)

* refactor(mini-program): update all request params struct (#62)

* fix(payment): add tls http client

* refactor(payment): 修改requestSendRedPack 结构体增加json tag 

* fix(payment): add tls http client

* fix(payment): update v2 md5 sign

* feat(payment): update Wxappid to WxappID

* refactor(go.mod): remove local replace

Co-authored-by: Walle <[email protected]>
Co-authored-by: Matrix-X <[email protected]>
Co-authored-by: Alvin <[email protected]>
  • Loading branch information
4 people authored Oct 24, 2021
1 parent e9eef5a commit 6c18ad6
Show file tree
Hide file tree
Showing 44 changed files with 606 additions and 295 deletions.
17 changes: 5 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
test: test-aes test-rsa test-signer

test-aes:
# go test -v src/kernel/Encryptor.go src/kernel/Encryptor_test.go
go test -v src/kernel/support/aes.go src/kernel/support/aes_test.go

test-rsa:
go test -v src/kernel/support/rsa_oaep.go src/kernel/support/rsa_oaep_test.go

test-signer:
go test -v src/kernel/support/signer.go src/kernel/support/signer_test.go
test: test-kernel-support

test-message:
go test -v test/featureUnit/main_test.go test/featureUnit/work_message_test.go
Expand All @@ -34,7 +24,10 @@ test-payment:
go test -v test/featureUnit/main_test.go test/featureUnit/payment_redpack_test.go

test-kernel-support:
go test -v src/kernel/support/str.go src/kernel/support/str_test.go
go test -v src/kernel/support/aes.go src/kernel/support/aes_test.go
go test -v src/kernel/support/helper.go src/kernel/support/helper_test.go
go test -v src/kernel/support/rsa_oaep.go src/kernel/support/rsa_oaep_test.go
go test -v src/kernel/support/signer.go src/kernel/support/signer_test.go

build:
go build
7 changes: 2 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ module github.com/ArtisanCloud/PowerWeChat

go 1.16

//replace github.com/ArtisanCloud/PowerLibs => ../PowerLibs
//replace github.com/ArtisanCloud/PowerSocialite => ../PowerSocialite

require (
github.com/ArtisanCloud/PowerLibs v1.1.6
github.com/ArtisanCloud/PowerSocialite v1.0.10
github.com/ArtisanCloud/PowerLibs v1.2.0
github.com/ArtisanCloud/PowerSocialite v1.2.0
github.com/gin-gonic/gin v1.7.2
github.com/go-playground/assert/v2 v2.0.1
github.com/go-playground/validator/v10 v10.6.1 // indirect
Expand Down
7 changes: 4 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
github.com/ArtisanCloud/PowerLibs v1.1.6 h1:LVudscMtD8wO6+GFt5sH5OHheiuHA7ElbJFd/n2yspA=
github.com/ArtisanCloud/PowerLibs v1.1.6/go.mod h1:WFX9eqXpXjLk67xRKFCIY/fALwtoASj9y/FWbHbG+d4=
github.com/ArtisanCloud/PowerSocialite v1.0.10 h1:wM9OWqt2zDAjDuXPMjDLkfhMBYeD04xV16ziAThjlpc=
github.com/ArtisanCloud/PowerSocialite v1.0.10/go.mod h1:WQ2tsvi+vY7xe11CRFFCNexUEpw7cYQkRgDIXGfVOIs=
github.com/ArtisanCloud/PowerLibs v1.2.0 h1:UlPsaX76wh0IgtHy8Z6aWND+671KbI7N07V5d2xhgHg=
github.com/ArtisanCloud/PowerLibs v1.2.0/go.mod h1:WFX9eqXpXjLk67xRKFCIY/fALwtoASj9y/FWbHbG+d4=
github.com/ArtisanCloud/PowerSocialite v1.2.0 h1:Gnit7aBbyFxdJI0C7AJzvhFyGCMvNdsfYGYznoXeZ0o=
github.com/ArtisanCloud/PowerSocialite v1.2.0/go.mod h1:WQ2tsvi+vY7xe11CRFFCNexUEpw7cYQkRgDIXGfVOIs=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
75 changes: 32 additions & 43 deletions src/kernel/support/helper.go
Original file line number Diff line number Diff line change
@@ -1,54 +1,43 @@
package support

import (
"context"
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/ArtisanCloud/PowerLibs/object"
"time"
"github.com/ArtisanCloud/PowerWeChat/src/kernel/power"
"sort"
"strings"
)

type GenerateSigner struct {
Method string // 接口提交方法。"GET", "POST"等
CanonicalURL string // 微信支付接口路径。 例如: /v3/pay/transactions/jsapi
SignBody string // 提交的body字符串。 例如; {"amount":{"total":1},"appid":"ww16143ea0101327c7","attach":"自定义数据说明","description":"Image形象店-深圳腾大-QQ公仔","mchid":"1611854986","notify_url":"https://pay.wangchaoyi.com/wx/notify","out_trade_no":"5519778939773395659222199361","payer":{"openid":"oAuaP0TRUMwP169nQfg7XCEAw3HQ"}}
timestamp int64 // 单元测试传入的固定时间戳
nonce string // 单元测试传入的固定随机数
}

func GenerateSign(signer *SHA256WithRSASigner, gs GenerateSigner) (authorization string, err error) {

timestamp := time.Now().Unix()
nonce := object.QuickRandom(32)

// Under ci mode, go fixed value
// 在ci模式下面,走固定值
if gs.timestamp != 0 && gs.nonce != "" {
timestamp = gs.timestamp
nonce = gs.nonce
func PaymentV2ParamsJoin(params *power.StringMap, key string) string {
var arr []string
for k, v := range *params {
if v == "" {
continue
}
arr = append(arr, k)
}

// Splice the string to be signed
// 拼接出需要签名的字符串
message := fmt.Sprintf(SignatureMessageFormat, gs.Method, gs.CanonicalURL, fmt.Sprintf("%d", timestamp), nonce, gs.SignBody)

signatureResult, err := signer.Sign(context.TODO(), message)
if err != nil {
return "", err
sort.Strings(arr)
for i, k := range arr {
arr[i] = fmt.Sprintf("%s=%s", k, (*params)[k])
}
return fmt.Sprintf("%s&key=%s", strings.Join(arr, "&"), key)
}

authorization = fmt.Sprintf(
HeaderAuthorizationFormat,
signer.GetAuthorizationType(),
signatureResult.MchID,
nonce,
timestamp,
signatureResult.CertificateSerialNo,
signatureResult.Signature,
)

return authorization, err
// GenerateSignMD5 适用于微信支付V2 MD5签名算法
// https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3
func GenerateSignMD5(params *power.StringMap, key string) string {
sign := fmt.Sprintf("%x", md5.Sum([]byte(PaymentV2ParamsJoin(params, key))))
return strings.ToUpper(sign)
}

func GetEncryptMethod(signType string, secretKey string) string {
return ""
// GenerateSignHmacSHA256 适用于微信支付V2 HMAC-SHA256签名算法
// https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3
func GenerateSignHmacSHA256(params *power.StringMap, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(PaymentV2ParamsJoin(params, key)))

sign := hex.EncodeToString(h.Sum(nil))
return strings.ToUpper(sign)
}
81 changes: 62 additions & 19 deletions src/kernel/support/helper_test.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,77 @@
package support

import (
"github.com/ArtisanCloud/PowerWeChat/src/kernel/power"
"github.com/go-playground/assert/v2"
"log"
"testing"
)

// Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1611854986",nonce_str="sacfXg6R9YwKqo3sfPoOVJQd4jPb0KOe",timestamp="1626623583",serial_no="2655A2CD634B06C2A86B28780228A997D047B01C",signature="dvB2r+z5v8JOsKw0goAmXNNTdLtpwmCkZHzuVdAi63kBZIvFugQuYx1nCUiZQckIV7ebq0JkK5/3N2gkmX70RJSnEa/Rjq7n2K//0OahXPGI+2qgFr5qUZ586en66QZjuQVeqoW6aYsaAwHPnszva56uJmopvHnuPPdUzKTTWf8sDNdIph/y+BpDXGTIvgifYR3RnJc2qh5n9eOo1Tqr4Ei6y6HhdPhMWMrr9RXY4bOCjtDkZhQ+mUXEP6aHLPau+5Th2cGlb5dyUY3o/MzgfjvvXjv4JDXhHFuo9BZAwp4XQcs/6jh/XAakf9lHx7ESvoQyT406Sfn30An3Y+p4wg=="
func TestGetEncryptMethod(t *testing.T) {
signer := &SHA256WithRSASigner{
MchID: "161186666",
CertificateSerialNo: "2355A2CD634B06C2A86B28780228A997D017B011",
PrivateKey: getPrivateKey(),
}
//func TestGetEncryptMethod(t *testing.T) {
// signer := &SHA256WithRSASigner{
// MchID: "161186666",
// CertificateSerialNo: "2355A2CD634B06C2A86B28780228A997D017B011",
// PrivateKey: getPrivateKey(),
// }
//
// signBody := "{\"amount\":{\"total\":1},\"appid\":\"ww16143ea0101327c7\",\"attach\":\"自定义数据说明\",\"description\":\"Image形象店-深圳腾大-QQ公仔\",\"mchid\":\"1611854986\",\"notify_url\":\"https://pay.wangchaoyi.com/power/notify\",\"out_trade_no\":\"5519778939773395659222199361\",\"payer\":{\"openid\":\"oAuaP0TRUMwP169nQfg7XCEAw3HQ\"}}"
//
// authorization, err := GenerateSign(signer, GenerateSigner{
// Method: "POST",
// CanonicalURL: "/v3/pay/transactions/jsapi",
// SignBody: signBody,
// timestamp: 1626747079,
// nonce: "W2XLk2c8KYM1aRNBzwmeGBnVqZ3QbvHS",
// })
//
// if err != nil {
// log.Fatalln(err)
// }
//
// expectAuthorization := "WECHATPAY2-SHA256-RSA2048 mchid=\"161186666\",nonce_str=\"W2XLk2c8KYM1aRNBzwmeGBnVqZ3QbvHS\",timestamp=\"1626747079\",serial_no=\"2355A2CD634B06C2A86B28780228A997D017B011\",signature=\"eUF/u5p9UjRtflGwOIk5jXUzD2Aduaj/NLhlwWwkliFPpF2I9jtTtM7gARrMHYuX2tQNS6OfY5Jf350D6OsJ4YKaKK4C8HOQ62maQ90DASJUrcqRI/EA4uyCrkqbUWnl+Xm2dE5wuVpfTSbRaMzOdXQwFB376uZgfUQtnD8C5PUfyqJ07qjxvh6NGi+R1vNCyG2rHhWityYtd66CZX4lBTOG5bJocn4GpOZOnyJO5/paQVQ8rKmQn+Wm7XCSCFL+4QLIa7ATyra/JMy0SLswq8ORfjCV0wFsHNR3h0u0vJo9JFRcqhhr/L6uQRc5x0vAC/wciOiDejAWYWBY90LEnA==\""
//
// assert.Equal(t, authorization, expectAuthorization)
//}

signBody := "{\"amount\":{\"total\":1},\"appid\":\"ww16143ea0101327c7\",\"attach\":\"自定义数据说明\",\"description\":\"Image形象店-深圳腾大-QQ公仔\",\"mchid\":\"1611854986\",\"notify_url\":\"https://pay.wangchaoyi.com/power/notify\",\"out_trade_no\":\"5519778939773395659222199361\",\"payer\":{\"openid\":\"oAuaP0TRUMwP169nQfg7XCEAw3HQ\"}}"
func TestPaymentV2ParamsJoin(t *testing.T) {
params := &power.StringMap{
"appid": "f323",
"c": "12",
"d": "34",
"mch_id": "2323532",
}
key := "HelloPowerWeChat"
expectText := "appid=f323&c=12&d=34&mch_id=2323532&key=HelloPowerWeChat"
text := PaymentV2ParamsJoin(params, key)

authorization, err := GenerateSign(signer, GenerateSigner{
Method: "POST",
CanonicalURL: "/v3/pay/transactions/jsapi",
SignBody: signBody,
timestamp: 1626747079,
nonce: "W2XLk2c8KYM1aRNBzwmeGBnVqZ3QbvHS",
})
assert.Equal(t, expectText, text)
}

if err != nil {
log.Fatalln(err)
func TestGenerateSignMD5(t *testing.T) {
params := &power.StringMap{
"appid": "f323",
"c": "12",
"d": "34",
"mch_id": "2323532",
}
key := "HelloPowerWeChat"
expectSignMD5 := "D18B5A9F4D01EB18CDEFFA39C78EB0F5"
signMD5 := GenerateSignMD5(params, key)

expectAuthorization := "WECHATPAY2-SHA256-RSA2048 mchid=\"161186666\",nonce_str=\"W2XLk2c8KYM1aRNBzwmeGBnVqZ3QbvHS\",timestamp=\"1626747079\",serial_no=\"2355A2CD634B06C2A86B28780228A997D017B011\",signature=\"eUF/u5p9UjRtflGwOIk5jXUzD2Aduaj/NLhlwWwkliFPpF2I9jtTtM7gARrMHYuX2tQNS6OfY5Jf350D6OsJ4YKaKK4C8HOQ62maQ90DASJUrcqRI/EA4uyCrkqbUWnl+Xm2dE5wuVpfTSbRaMzOdXQwFB376uZgfUQtnD8C5PUfyqJ07qjxvh6NGi+R1vNCyG2rHhWityYtd66CZX4lBTOG5bJocn4GpOZOnyJO5/paQVQ8rKmQn+Wm7XCSCFL+4QLIa7ATyra/JMy0SLswq8ORfjCV0wFsHNR3h0u0vJo9JFRcqhhr/L6uQRc5x0vAC/wciOiDejAWYWBY90LEnA==\""
assert.Equal(t, expectSignMD5, signMD5)
}

assert.Equal(t, authorization, expectAuthorization)
func TestGenerateSignHmacSHA256(t *testing.T) {
params := &power.StringMap{
"appid": "f323",
"c": "12",
"d": "34",
"mch_id": "2323532",
}
key := "HelloPowerWeChat"
expectSignHmacSHA256 := "CF3C3C7B038A12682967DC5ABADDAD56CE612FEE9B0E0A885B3B41E9E72B9A10"
signHmacSHA256 := GenerateSignHmacSHA256(params, key)

assert.Equal(t, expectSignHmacSHA256, signHmacSHA256)
}

11 changes: 3 additions & 8 deletions src/miniProgram/base/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package base
import (
"github.com/ArtisanCloud/PowerLibs/object"
"github.com/ArtisanCloud/PowerWeChat/src/kernel"
"github.com/ArtisanCloud/PowerWeChat/src/miniProgram/base/request"
"github.com/ArtisanCloud/PowerWeChat/src/miniProgram/base/response"
)

Expand All @@ -11,17 +12,11 @@ type Client struct {
}

// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/user-info/auth.getPaidUnionId.html
func (comp *Client) GetPaidUnionID(openID string, option *object.StringMap) (*response.ResponseAuthGetPaidUnionID, error) {
func (comp *Client) GetPaidUnionID(options *request.RequestGetPaidUnionID) (*response.ResponseAuthGetPaidUnionID, error) {

result := &response.ResponseAuthGetPaidUnionID{}

params := &object.StringMap{
"openid": openID,
}

params = object.MergeStringMap(params, option)

_, err := comp.HttpGet("wxa/getpaidunionid", params, nil, result)
_, err := comp.HttpGet("wxa/getpaidunionid", options, nil, result)

return result, err
}
Expand Down
8 changes: 8 additions & 0 deletions src/miniProgram/base/request/GetPaidUnionID.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package request

type RequestGetPaidUnionID struct {
OpenID string `json:"openid"` // 支付用户唯一标识
TransactionID string `json:"transaction_id,omitempty"` // 微信支付订单号
MchID string `json:"mch_id,omitempty"` // 微信支付分配的商户号,和商户订单号配合使用
OutTradeNo string `json:"out_trade_no,omitempty"`
}
20 changes: 17 additions & 3 deletions src/miniProgram/customerServiceMessage/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/ArtisanCloud/PowerWeChat/src/kernel"
"github.com/ArtisanCloud/PowerWeChat/src/kernel/power"
response2 "github.com/ArtisanCloud/PowerWeChat/src/kernel/response"
"github.com/ArtisanCloud/PowerWeChat/src/miniProgram/customerServiceMessage/request"
"github.com/ArtisanCloud/PowerWeChat/src/miniProgram/customerServiceMessage/response"
response4 "github.com/ArtisanCloud/PowerWeChat/src/work/media/response"
"net/http"
Expand Down Expand Up @@ -37,20 +38,33 @@ func (comp *Client) GetTempMedia(mediaID string) (*http.Response, error) {

// 发送客服消息给用户
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/customer-message/customerServiceMessage.send.html
func (comp *Client) Send(toUser string, msgType string, text *power.HashMap) (*response2.ResponseMiniProgram, error) {
func (comp *Client) Send(toUser string, msgType string, msg interface{}) (*response2.ResponseMiniProgram, error) {

result := &response2.ResponseMiniProgram{}

data := &object.HashMap{
"touser": toUser,
"msgtype": msgType,
"text": text,
msgType: msg,
}

_, err := comp.HttpPostJson("cgi-bin/message/custom/send", data, nil, nil, result)

return result, err
}
func (comp *Client) SendText(toUser string, msg *request.CustomerServiceMsgText) (*response2.ResponseMiniProgram, error) {
return comp.Send(toUser, "text", msg)
}
func (comp *Client) SendImage(toUser string, msg *request.CustomerServiceMsgImage) (*response2.ResponseMiniProgram, error) {
return comp.Send(toUser, "image", msg)
}
func (comp *Client) SendLink(toUser string, msg *request.CustomerServiceMsgLink) (*response2.ResponseMiniProgram, error) {
return comp.Send(toUser, "link", msg)
}
func (comp *Client) SendMiniProgramPage(toUser string, msg *request.CustomerServiceMsgMpPage) (*response2.ResponseMiniProgram, error) {
return comp.Send(toUser, "miniprogrampage", msg)
}


// 下发客服当前输入状态给用户
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/customer-message/customerServiceMessage.setTyping.html
Expand Down Expand Up @@ -84,7 +98,7 @@ func (comp *Client) UploadTempMedia(mediaType string, path string, form *power.H
var formData *object.HashMap
if form != nil {
formData = &object.HashMap{
"name": (*form)["name"],
"name": (*form)["name"],
"value": (*form)["value"],
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package request

type CustomerServiceMsgText struct {
Content string `json:"content"`
}

type CustomerServiceMsgImage struct {
MediaID string `json:"media_id"`
}

type CustomerServiceMsgLink struct {
Title string `json:"title"`
Description string `json:"description"`
Url string `json:"url"`
ThumbUrl string `json:"thumb_url"`
}

type CustomerServiceMsgMpPage struct {
Title string `json:"title"`
PagePath string `json:"pagepath"`
ThumbMediaID string `json:"thumb_media_id"`
}
4 changes: 2 additions & 2 deletions src/miniProgram/dataCube/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package dataCube
import (
"github.com/ArtisanCloud/PowerLibs/object"
"github.com/ArtisanCloud/PowerWeChat/src/kernel"
"github.com/ArtisanCloud/PowerWeChat/src/kernel/power"
"github.com/ArtisanCloud/PowerWeChat/src/miniProgram/dataCube/request"
"github.com/ArtisanCloud/PowerWeChat/src/miniProgram/dataCube/response"
)

Expand All @@ -24,7 +24,7 @@ func (comp *Client) GetDailySummary(from string, to string) (*response.ResponseD

// 获取小程序启动性能,运行性能等数据
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/data-analysis/analysis.getPerformanceData.html
func (comp *Client) GetPerformanceData(options *power.HashMap) (*response.ResponseDataCubeGetPerformanceData, error) {
func (comp *Client) GetPerformanceData(options *request.RequestGetPerformanceData) (*response.ResponseDataCubeGetPerformanceData, error) {

result := &response.ResponseDataCubeGetPerformanceData{}

Expand Down
18 changes: 18 additions & 0 deletions src/miniProgram/dataCube/request/performanceData.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package request

type RequestGetPerformanceData struct {
Time *GetPerformanceDataTime `json:"time"`
Module string `json:"module"`
Params []*GetPerformanceDataParams `json:"params"`
}

type GetPerformanceDataTime struct {
// int64类型: time.Now().Unix()
BeginTimestamp int64 `json:"begin_timestamp"`
EndTimestamp int64 `json:"end_timestamp"`
}

type GetPerformanceDataParams struct {
Field string `json:"field"`
Value string `json:"value"`
}
Loading

0 comments on commit 6c18ad6

Please sign in to comment.