mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-04 12:52:27 +08:00
fix some bugs (#277)
* fix payRequset xml marshal: root element should be xml * support HMAC-SHA256 for unifiedorder api * support HMAC-SHA256 for PaidVerifySign * fix SignType is nil * fix code style * constantize SignType * add comments * fix code style
This commit is contained in:
2
go.sum
2
go.sum
@@ -14,6 +14,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJ
|
|||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
@@ -21,6 +22,7 @@ github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
|||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
|
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
|
||||||
|
|||||||
@@ -85,8 +85,15 @@ func (notify *Notify) PaidVerifySign(notifyRes PaidResult) bool {
|
|||||||
// STEP3, 在键值对的最后加上key=API_KEY
|
// STEP3, 在键值对的最后加上key=API_KEY
|
||||||
signStrings = signStrings + "key=" + notify.Key
|
signStrings = signStrings + "key=" + notify.Key
|
||||||
|
|
||||||
// STEP4, 进行MD5签名并且将所有字符转为大写.
|
// STEP4, 根据SignType计算出签名
|
||||||
sign := util.MD5Sum(signStrings)
|
var signType string
|
||||||
|
if notifyRes.SignType != nil {
|
||||||
|
signType = *notifyRes.SignType
|
||||||
|
}
|
||||||
|
sign, err := util.CalculateSign(signStrings, signType, notify.Key)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if sign != *notifyRes.Sign {
|
if sign != *notifyRes.Sign {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
package order
|
package order
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/md5"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"hash"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -96,13 +91,14 @@ type payRequest struct {
|
|||||||
LimitPay string `xml:"limit_pay,omitempty"` //
|
LimitPay string `xml:"limit_pay,omitempty"` //
|
||||||
OpenID string `xml:"openid,omitempty"` // 用户标识
|
OpenID string `xml:"openid,omitempty"` // 用户标识
|
||||||
SceneInfo string `xml:"scene_info,omitempty"` // 场景信息
|
SceneInfo string `xml:"scene_info,omitempty"` // 场景信息
|
||||||
|
|
||||||
|
XMLName struct{} `xml:"xml"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BridgeConfig get js bridge config
|
// BridgeConfig get js bridge config
|
||||||
func (o *Order) BridgeConfig(p *Params) (cfg Config, err error) {
|
func (o *Order) BridgeConfig(p *Params) (cfg Config, err error) {
|
||||||
var (
|
var (
|
||||||
buffer strings.Builder
|
buffer strings.Builder
|
||||||
h hash.Hash
|
|
||||||
timestamp = strconv.FormatInt(time.Now().Unix(), 10)
|
timestamp = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
)
|
)
|
||||||
order, err := o.PrePayOrder(p)
|
order, err := o.PrePayOrder(p)
|
||||||
@@ -121,14 +117,13 @@ func (o *Order) BridgeConfig(p *Params) (cfg Config, err error) {
|
|||||||
buffer.WriteString(timestamp)
|
buffer.WriteString(timestamp)
|
||||||
buffer.WriteString("&key=")
|
buffer.WriteString("&key=")
|
||||||
buffer.WriteString(o.Key)
|
buffer.WriteString(o.Key)
|
||||||
if p.SignType == "MD5" {
|
|
||||||
h = md5.New()
|
sign, err := util.CalculateSign(buffer.String(), p.SignType, o.Key)
|
||||||
} else {
|
if err != nil {
|
||||||
h = hmac.New(sha256.New, []byte(o.Key))
|
return
|
||||||
}
|
}
|
||||||
h.Write([]byte(buffer.String()))
|
|
||||||
// 签名
|
// 签名
|
||||||
cfg.PaySign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
|
cfg.PaySign = sign
|
||||||
cfg.NonceStr = order.NonceStr
|
cfg.NonceStr = order.NonceStr
|
||||||
cfg.Timestamp = timestamp
|
cfg.Timestamp = timestamp
|
||||||
cfg.PrePayID = order.PrePayID
|
cfg.PrePayID = order.PrePayID
|
||||||
@@ -143,13 +138,13 @@ func (o *Order) PrePayOrder(p *Params) (payOrder PreOrder, err error) {
|
|||||||
notifyURL := o.NotifyURL
|
notifyURL := o.NotifyURL
|
||||||
// 签名类型
|
// 签名类型
|
||||||
if p.SignType == "" {
|
if p.SignType == "" {
|
||||||
p.SignType = "MD5"
|
p.SignType = util.SignTypeMD5
|
||||||
}
|
}
|
||||||
// 通知地址
|
// 通知地址
|
||||||
if p.NotifyURL != "" {
|
if p.NotifyURL != "" {
|
||||||
notifyURL = p.NotifyURL
|
notifyURL = p.NotifyURL
|
||||||
}
|
}
|
||||||
param := make(map[string]interface{})
|
param := make(map[string]string)
|
||||||
param["appid"] = o.AppID
|
param["appid"] = o.AppID
|
||||||
param["body"] = p.Body
|
param["body"] = p.Body
|
||||||
param["mch_id"] = o.MchID
|
param["mch_id"] = o.MchID
|
||||||
@@ -165,9 +160,10 @@ func (o *Order) PrePayOrder(p *Params) (payOrder PreOrder, err error) {
|
|||||||
param["goods_tag"] = p.GoodsTag
|
param["goods_tag"] = p.GoodsTag
|
||||||
param["notify_url"] = notifyURL
|
param["notify_url"] = notifyURL
|
||||||
|
|
||||||
bizKey := "&key=" + o.Key
|
sign, err := util.ParamSign(param, o.Key)
|
||||||
str := util.OrderParam(param, bizKey)
|
if err != nil {
|
||||||
sign := util.MD5Sum(str)
|
return
|
||||||
|
}
|
||||||
request := payRequest{
|
request := payRequest{
|
||||||
AppID: o.AppID,
|
AppID: o.AppID,
|
||||||
MchID: o.MchID,
|
MchID: o.MchID,
|
||||||
@@ -202,7 +198,7 @@ func (o *Order) PrePayOrder(p *Params) (payOrder PreOrder, err error) {
|
|||||||
err = errors.New(payOrder.ErrCode + payOrder.ErrCodeDes)
|
err = errors.New(payOrder.ErrCode + payOrder.ErrCodeDes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = errors.New("[msg : xmlUnmarshalError] [rawReturn : " + string(rawRet) + "] [params : " + str + "] [sign : " + sign + "]")
|
err = errors.New("[msg : xmlUnmarshalError] [rawReturn : " + string(rawRet) + "] [sign : " + sign + "]")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ type Response struct {
|
|||||||
//Refund 退款申请
|
//Refund 退款申请
|
||||||
func (refund *Refund) Refund(p *Params) (rsp Response, err error) {
|
func (refund *Refund) Refund(p *Params) (rsp Response, err error) {
|
||||||
nonceStr := util.RandomStr(32)
|
nonceStr := util.RandomStr(32)
|
||||||
param := make(map[string]interface{})
|
param := make(map[string]string)
|
||||||
param["appid"] = refund.AppID
|
param["appid"] = refund.AppID
|
||||||
param["mch_id"] = refund.MchID
|
param["mch_id"] = refund.MchID
|
||||||
param["nonce_str"] = nonceStr
|
param["nonce_str"] = nonceStr
|
||||||
@@ -81,18 +81,20 @@ func (refund *Refund) Refund(p *Params) (rsp Response, err error) {
|
|||||||
param["refund_desc"] = p.RefundDesc
|
param["refund_desc"] = p.RefundDesc
|
||||||
param["refund_fee"] = p.RefundFee
|
param["refund_fee"] = p.RefundFee
|
||||||
param["total_fee"] = p.TotalFee
|
param["total_fee"] = p.TotalFee
|
||||||
param["sign_type"] = "MD5"
|
param["sign_type"] = util.SignTypeMD5
|
||||||
param["transaction_id"] = p.TransactionID
|
param["transaction_id"] = p.TransactionID
|
||||||
|
|
||||||
bizKey := "&key=" + refund.Key
|
sign, err := util.ParamSign(param, refund.Key)
|
||||||
str := util.OrderParam(param, bizKey)
|
if err != nil {
|
||||||
sign := util.MD5Sum(str)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
request := request{
|
request := request{
|
||||||
AppID: refund.AppID,
|
AppID: refund.AppID,
|
||||||
MchID: refund.MchID,
|
MchID: refund.MchID,
|
||||||
NonceStr: nonceStr,
|
NonceStr: nonceStr,
|
||||||
Sign: sign,
|
Sign: sign,
|
||||||
SignType: "MD5",
|
SignType: util.SignTypeMD5,
|
||||||
TransactionID: p.TransactionID,
|
TransactionID: p.TransactionID,
|
||||||
OutRefundNo: p.OutRefundNo,
|
OutRefundNo: p.OutRefundNo,
|
||||||
TotalFee: p.TotalFee,
|
TotalFee: p.TotalFee,
|
||||||
@@ -115,7 +117,6 @@ func (refund *Refund) Refund(p *Params) (rsp Response, err error) {
|
|||||||
err = fmt.Errorf("refund error, errcode=%s,errmsg=%s", rsp.ErrCode, rsp.ErrCodeDes)
|
err = fmt.Errorf("refund error, errcode=%s,errmsg=%s", rsp.ErrCode, rsp.ErrCodeDes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = fmt.Errorf("[msg : xmlUnmarshalError] [rawReturn : %s] [params : %s] [sign : %s]",
|
err = fmt.Errorf("[msg : xmlUnmarshalError] [rawReturn : %s] [sign : %s]", string(rawRet), sign)
|
||||||
string(rawRet), str, sign)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/hmac"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"hash"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 微信签名算法方式
|
||||||
|
const (
|
||||||
|
SignTypeMD5 = `MD5`
|
||||||
|
SignTypeHMACSHA256 = `HMAC-SHA256`
|
||||||
)
|
)
|
||||||
|
|
||||||
//EncryptMsg 加密消息
|
//EncryptMsg 加密消息
|
||||||
@@ -186,14 +195,35 @@ func decodeNetworkByteOrder(orderBytes []byte) (n uint32) {
|
|||||||
uint32(orderBytes[3])
|
uint32(orderBytes[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
// MD5Sum 计算 32 位长度的 MD5 sum
|
// CalculateSign 计算签名
|
||||||
func MD5Sum(txt string) (sum string) {
|
func CalculateSign(content, signType, key string) (string, error) {
|
||||||
h := md5.New()
|
var h hash.Hash
|
||||||
buf := bufio.NewWriterSize(h, 128)
|
if signType == SignTypeMD5 {
|
||||||
buf.WriteString(txt)
|
h = md5.New()
|
||||||
buf.Flush()
|
} else {
|
||||||
sign := make([]byte, hex.EncodedLen(h.Size()))
|
h = hmac.New(sha256.New, []byte(key))
|
||||||
hex.Encode(sign, h.Sum(nil))
|
}
|
||||||
sum = string(bytes.ToUpper(sign))
|
|
||||||
return
|
if _, err := h.Write([]byte(content)); err != nil {
|
||||||
|
return ``, err
|
||||||
|
}
|
||||||
|
return strings.ToUpper(hex.EncodeToString(h.Sum(nil))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParamSign 计算所传参数的签名
|
||||||
|
func ParamSign(p map[string]string, key string) (string, error) {
|
||||||
|
bizKey := "&key=" + key
|
||||||
|
str := OrderParam(p, bizKey)
|
||||||
|
|
||||||
|
var signType string
|
||||||
|
switch p["sign_type"] {
|
||||||
|
case SignTypeMD5, SignTypeHMACSHA256:
|
||||||
|
signType = p["sign_type"]
|
||||||
|
case ``:
|
||||||
|
signType = SignTypeMD5
|
||||||
|
default:
|
||||||
|
return ``, errors.New(`invalid sign_type`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return CalculateSign(str, signType, key)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,12 @@ package util
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// OrderParam order params
|
// OrderParam order params
|
||||||
func OrderParam(source interface{}, bizKey string) (returnStr string) {
|
func OrderParam(p map[string]string, bizKey string) (returnStr string) {
|
||||||
switch v := source.(type) {
|
keys := make([]string, 0, len(p))
|
||||||
case map[string]string:
|
for k := range p {
|
||||||
keys := make([]string, 0, len(v))
|
|
||||||
for k := range v {
|
|
||||||
if k == "sign" {
|
if k == "sign" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -20,7 +17,7 @@ func OrderParam(source interface{}, bizKey string) (returnStr string) {
|
|||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if v[k] == "" {
|
if p[k] == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if buf.Len() > 0 {
|
if buf.Len() > 0 {
|
||||||
@@ -28,40 +25,9 @@ func OrderParam(source interface{}, bizKey string) (returnStr string) {
|
|||||||
}
|
}
|
||||||
buf.WriteString(k)
|
buf.WriteString(k)
|
||||||
buf.WriteByte('=')
|
buf.WriteByte('=')
|
||||||
buf.WriteString(v[k])
|
buf.WriteString(p[k])
|
||||||
}
|
}
|
||||||
buf.WriteString(bizKey)
|
buf.WriteString(bizKey)
|
||||||
returnStr = buf.String()
|
returnStr = buf.String()
|
||||||
case map[string]interface{}:
|
|
||||||
keys := make([]string, 0, len(v))
|
|
||||||
for k := range v {
|
|
||||||
if k == "sign" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for _, k := range keys {
|
|
||||||
if v[k] == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if buf.Len() > 0 {
|
|
||||||
buf.WriteByte('&')
|
|
||||||
}
|
|
||||||
buf.WriteString(k)
|
|
||||||
buf.WriteByte('=')
|
|
||||||
switch vv := v[k].(type) {
|
|
||||||
case string:
|
|
||||||
buf.WriteString(vv)
|
|
||||||
case int:
|
|
||||||
buf.WriteString(strconv.FormatInt(int64(vv), 10))
|
|
||||||
default:
|
|
||||||
panic("params type not supported")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.WriteString(bizKey)
|
|
||||||
returnStr = buf.String()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user