hotime/vendor/github.com/go-pay/gopay/wechat/v3/sign.go
2022-05-24 13:49:25 +08:00

170 lines
4.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package wechat
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"time"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/pkg/util"
"github.com/go-pay/gopay/pkg/xlog"
"github.com/go-pay/gopay/pkg/xpem"
)
// Deprecated
// 推荐使用 wechat.V3VerifySignByPK()
func V3VerifySign(timestamp, nonce, signBody, sign, wxPubKeyContent string) (err error) {
publicKey, err := xpem.DecodePublicKey([]byte(wxPubKeyContent))
if err != nil {
return err
}
str := timestamp + "\n" + nonce + "\n" + signBody + "\n"
signBytes, _ := base64.StdEncoding.DecodeString(sign)
h := sha256.New()
h.Write([]byte(str))
if err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, h.Sum(nil), signBytes); err != nil {
return fmt.Errorf("[%w]: %v", gopay.VerifySignatureErr, err)
}
return nil
}
// 微信V3 版本验签(同步/异步)
// wxPublicKey微信平台证书公钥内容通过 client.WxPublicKey() 获取
func V3VerifySignByPK(timestamp, nonce, signBody, sign string, wxPublicKey *rsa.PublicKey) (err error) {
str := timestamp + "\n" + nonce + "\n" + signBody + "\n"
signBytes, _ := base64.StdEncoding.DecodeString(sign)
h := sha256.New()
h.Write([]byte(str))
if err = rsa.VerifyPKCS1v15(wxPublicKey, crypto.SHA256, h.Sum(nil), signBytes); err != nil {
return fmt.Errorf("[%w]: %v", gopay.VerifySignatureErr, err)
}
return nil
}
// PaySignOfJSAPI 获取 JSAPI paySign
// 文档https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml
func (c *ClientV3) PaySignOfJSAPI(appid, prepayid string) (jsapi *JSAPIPayParams, err error) {
ts := util.Int642String(time.Now().Unix())
nonceStr := util.RandomString(32)
pkg := "prepay_id=" + prepayid
_str := appid + "\n" + ts + "\n" + nonceStr + "\n" + pkg + "\n"
sign, err := c.rsaSign(_str)
if err != nil {
return nil, err
}
jsapi = &JSAPIPayParams{
AppId: appid,
TimeStamp: ts,
NonceStr: nonceStr,
Package: pkg,
SignType: SignTypeRSA,
PaySign: sign,
}
return jsapi, nil
}
// PaySignOfApp 获取 App sign
// 文档https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml
func (c *ClientV3) PaySignOfApp(appid, prepayid string) (app *AppPayParams, err error) {
ts := util.Int642String(time.Now().Unix())
nonceStr := util.RandomString(32)
_str := appid + "\n" + ts + "\n" + nonceStr + "\n" + prepayid + "\n"
sign, err := c.rsaSign(_str)
if err != nil {
return nil, err
}
app = &AppPayParams{
Appid: appid,
Partnerid: c.Mchid,
Prepayid: prepayid,
Package: "Sign=WXPay",
Noncestr: nonceStr,
Timestamp: ts,
Sign: sign,
}
return app, nil
}
// PaySignOfApplet 获取 小程序 paySign
// 文档https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml
func (c *ClientV3) PaySignOfApplet(appid, prepayid string) (applet *AppletParams, err error) {
jsapi, err := c.PaySignOfJSAPI(appid, prepayid)
if err != nil {
return nil, err
}
applet = &AppletParams{
AppId: jsapi.AppId,
TimeStamp: jsapi.TimeStamp,
NonceStr: jsapi.NonceStr,
Package: jsapi.Package,
SignType: jsapi.SignType,
PaySign: jsapi.PaySign,
}
return applet, nil
}
// v3 鉴权请求Header
func (c *ClientV3) authorization(method, path string, bm gopay.BodyMap) (string, error) {
var (
jb = ""
timestamp = time.Now().Unix()
nonceStr = util.RandomString(32)
)
if bm != nil {
jb = bm.JsonBody()
}
ts := util.Int642String(timestamp)
_str := method + "\n" + path + "\n" + ts + "\n" + nonceStr + "\n" + jb + "\n"
if c.DebugSwitch == gopay.DebugOn {
xlog.Debugf("Wechat_V3_SignString:\n%s", _str)
}
sign, err := c.rsaSign(_str)
if err != nil {
return "", err
}
return Authorization + ` mchid="` + c.Mchid + `",nonce_str="` + nonceStr + `",timestamp="` + ts + `",serial_no="` + c.SerialNo + `",signature="` + sign + `"`, nil
}
func (c *ClientV3) rsaSign(str string) (string, error) {
if c.privateKey == nil {
return "", errors.New("privateKey can't be nil")
}
h := sha256.New()
h.Write([]byte(str))
result, err := rsa.SignPKCS1v15(rand.Reader, c.privateKey, crypto.SHA256, h.Sum(nil))
if err != nil {
return util.NULL, fmt.Errorf("[%w]: %+v", gopay.SignatureErr, err)
}
return base64.StdEncoding.EncodeToString(result), nil
}
// 自动同步请求验签
func (c *ClientV3) verifySyncSign(si *SignInfo) (err error) {
if c.autoSign && c.wxPublicKey != nil {
if si != nil {
str := si.HeaderTimestamp + "\n" + si.HeaderNonce + "\n" + si.SignBody + "\n"
signBytes, _ := base64.StdEncoding.DecodeString(si.HeaderSignature)
h := sha256.New()
h.Write([]byte(str))
if err = rsa.VerifyPKCS1v15(c.wxPublicKey, crypto.SHA256, h.Sum(nil), signBytes); err != nil {
return fmt.Errorf("[%w]: %v", gopay.VerifySignatureErr, err)
}
return nil
}
return errors.New("auto verify sign, bug SignInfo is nil")
}
return nil
}