Skip to content

Commit

Permalink
增加微信v3 的掌纹支付相关接口 (#433)
Browse files Browse the repository at this point in the history
* map to smap
* 增加掌纹支付预授权查询接口
  • Loading branch information
iGoogle-ink authored Dec 2, 2024
1 parent 6042c74 commit 9940221
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 37 deletions.
5 changes: 0 additions & 5 deletions body_map_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gopay

import (
"container/list"
"encoding/json"
"encoding/xml"
"testing"
Expand Down Expand Up @@ -173,7 +172,3 @@ func TestOutSlice(t *testing.T) {
xlog.Debugf("%s", bm.GetString(""))
xlog.Debugf("%s", bm.JsonBody())
}

func TestLruCache(t *testing.T) {
list.New()
}
2 changes: 1 addition & 1 deletion constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const (
OK = "OK"
DebugOff = 0
DebugOn = 1
Version = "v1.5.106"
Version = "v1.5.107"
)

type DebugSwitch int8
3 changes: 3 additions & 0 deletions doc/wechat_v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,9 @@ wechat.V3DecryptCombineNotifyCipherText()
* 查询省份列表:`client.V3BankSearchProvinceList()`
* 查询城市列表:`client.V3BankSearchCityList()`
* 查询支行列表:`client.V3BankSearchBranchList()`
* <font color='#07C160' size='4'>掌纹支付</font>
* 用户自主录掌&预授权:`client.V3PalmServicePreAuthorize()`
* 预授权状态查询:`client.V3PalmServiceOpenidQuery()`


### 微信v3公共 API
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ go 1.21

require (
github.com/go-pay/crypto v0.0.1
github.com/go-pay/errgroup v0.0.2
github.com/go-pay/errgroup v0.0.3
github.com/go-pay/smap v0.0.2
github.com/go-pay/util v0.0.4
github.com/go-pay/xlog v0.0.3
github.com/go-pay/xtime v0.0.2
golang.org/x/crypto v0.28.0
golang.org/x/crypto v0.29.0
)
10 changes: 6 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
github.com/go-pay/crypto v0.0.1 h1:B6InT8CLfSLc6nGRVx9VMJRBBazFMjr293+jl0lLXUY=
github.com/go-pay/crypto v0.0.1/go.mod h1:41oEIvHMKbNcYlWUlRWtsnC6+ASgh7u29z0gJXe5bes=
github.com/go-pay/errgroup v0.0.2 h1:5mZMdm0TDClDm2S3G0/sm0f8AuQRtz0dOrTHDR9R8Cc=
github.com/go-pay/errgroup v0.0.2/go.mod h1:0+4b8mvFMS71MIzsaC+gVvB4x37I93lRb2dqrwuU8x8=
github.com/go-pay/errgroup v0.0.3 h1:DB4s8e8oWYDyETKQ1y1riMJ7y29zE1uIsMCSjEOFSbU=
github.com/go-pay/errgroup v0.0.3/go.mod h1:0+4b8mvFMS71MIzsaC+gVvB4x37I93lRb2dqrwuU8x8=
github.com/go-pay/smap v0.0.2 h1:kKflYor5T5FgZltPFBMTFfjJvqYMHr5VnIFSEyhVTcA=
github.com/go-pay/smap v0.0.2/go.mod h1:HW9oAo0okuyDYsbpbj5fJFxnNj/BZorRGFw26SxrNWw=
github.com/go-pay/util v0.0.4 h1:TuwSU9o3Qd7m9v1PbzFuIA/8uO9FJnA6P7neG/NwPyk=
github.com/go-pay/util v0.0.4/go.mod h1:Tsdhs8Ib9J9b4+NKNO1PHh5hWHhlg98PthsX0ckq6PM=
github.com/go-pay/xlog v0.0.3 h1:avyMhCL/JgBHreoGx/am/kHxfs1udDOAeVqbmzP/Yes=
github.com/go-pay/xlog v0.0.3/go.mod h1:mH47xbobrdsSHWsmFtSF5agWbMHFP+tK0ZbVCk5OAEw=
github.com/go-pay/xtime v0.0.2 h1:7YR4/iuELsEHpJ6LUO0SVK80hQxDO9MLCfuVYIiTCRM=
github.com/go-pay/xtime v0.0.2/go.mod h1:W1yRbJaSt4CSBcdAtLBQ8xajiN/Pl5hquGczUcUE9xE=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
4 changes: 4 additions & 0 deletions release_note.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
版本号:v1.5.107
修改记录:
(1) 微信V3:新增掌纹支付相关接口。

版本号:v1.5.106
修改记录:
(1) 支付宝:支付宝支持V3接口,接口还在完善中,欢迎提PR一起建设。
Expand Down
17 changes: 8 additions & 9 deletions wechat/v3/cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,11 @@ func (c *ClientV3) WxPublicKey() (wxPublicKey *rsa.PublicKey) {
// 获取 微信平台证书 Map(readonly)
// wxPublicKeyMap: key:SerialNo, value:WxPublicKey
func (c *ClientV3) WxPublicKeyMap() (wxPublicKeyMap map[string]*rsa.PublicKey) {
wxPublicKeyMap = make(map[string]*rsa.PublicKey, len(c.SnCertMap))
for k, v := range c.SnCertMap {
wxPublicKeyMap = make(map[string]*rsa.PublicKey)
c.SnCertMap.Range(func(k string, v *rsa.PublicKey) bool {
wxPublicKeyMap[k] = v
}
return true
})
return wxPublicKeyMap
}

Expand Down Expand Up @@ -328,19 +329,17 @@ func (c *ClientV3) autoCheckCertProc() {
if err != nil {
return err
}
snPkMap := make(map[string]*rsa.PublicKey)
for sn, cert := range snCertMap {
pubKey, err := xpem.DecodePublicKey([]byte(cert))
if err != nil {
return err
}
snPkMap[sn] = pubKey
c.SnCertMap.Store(sn, pubKey)
if sn == serialNo {
c.wxPublicKey = pubKey
}
}
c.rwMu.Lock()
c.SnCertMap = snPkMap
c.WxSerialNo = serialNo
c.wxPublicKey = snPkMap[serialNo]
c.rwMu.Unlock()
return nil
}, 3, time.Second)
if err != nil {
Expand Down
17 changes: 7 additions & 10 deletions wechat/v3/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/go-pay/crypto/xpem"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/pkg/xhttp"
"github.com/go-pay/smap"
"github.com/go-pay/xlog"
)

Expand All @@ -27,7 +28,7 @@ type ClientV3 struct {
DebugSwitch gopay.DebugSwitch
requestIdFunc xhttp.RequestIdHandler
logger xlog.XLogger
SnCertMap map[string]*rsa.PublicKey // key: serial_no
SnCertMap smap.Map[string, *rsa.PublicKey] // key: serial_no
}

// NewClientV3 初始化微信客户端 V3
Expand Down Expand Up @@ -72,19 +73,18 @@ func (c *ClientV3) AutoVerifySign(autoRefresh ...bool) (err error) {
if err != nil {
return err
}
if len(c.SnCertMap) <= 0 {
c.SnCertMap = make(map[string]*rsa.PublicKey)
}
for sn, cert := range certMap {
// decode cert
pubKey, err := xpem.DecodePublicKey([]byte(cert))
if err != nil {
return err
}
c.SnCertMap[sn] = pubKey
c.SnCertMap.Store(sn, pubKey)
if sn == wxSerialNo {
c.wxPublicKey = pubKey
}
}
c.WxSerialNo = wxSerialNo
c.wxPublicKey = c.SnCertMap[wxSerialNo]
if len(autoRefresh) == 1 && !autoRefresh[0] {
return nil
}
Expand All @@ -103,10 +103,7 @@ func (c *ClientV3) AutoVerifySignByCert(wxPublicKeyContent []byte, wxPublicKeyID
if pubKey == nil {
return errors.New("xpem.DecodePublicKey() failed, pubKey is nil")
}
if len(c.SnCertMap) <= 0 {
c.SnCertMap = make(map[string]*rsa.PublicKey)
}
c.SnCertMap[wxPublicKeyID] = pubKey
c.SnCertMap.Store(wxPublicKeyID, pubKey)
c.wxPublicKey = pubKey
c.WxSerialNo = wxPublicKeyID
c.autoSign = true
Expand Down
4 changes: 4 additions & 0 deletions wechat/v3/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,10 @@ const (
// 扣款服务-直连模式(其他相关接口在v2接口中)
v3EntrustPayNotify = "/v3/papay/contracts/%s/notify" // contract_id 预扣费通知 POST

// 刷掌支付
v3PalmServicePreAuthorize = "/v3/palmservice/authorization/preauthorize" // 用户自主录掌&预授权 POST
v3PalmServiceOpenidQuery = "/v3/palmservice/authorization/openid/%s" // organization_id 预授权状态查询 GET

// 特约商户进件申请单状态
ApplyStateEditing = "APPLYMENT_STATE_EDITTING" // 编辑中
ApplyStateAuditing = "APPLYMENT_STATE_AUDITING" // 审核中
Expand Down
25 changes: 25 additions & 0 deletions wechat/v3/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ type EntrustPayNotifyRsp struct {
Error string `json:"-"`
}

type PalmServicePreAuthorizeRsp struct {
Code int `json:"-"`
SignInfo *SignInfo `json:"-"`
Response *PalmServicePreAuthorize `json:"response,omitempty"`
Error string `json:"-"`
}

type PalmServiceOpenidQueryRsp struct {
Code int `json:"-"`
SignInfo *SignInfo `json:"-"`
Response *PalmServiceOpenidQuery `json:"response,omitempty"`
Error string `json:"-"`
}

// =========================================================分割=========================================================

type JSAPIPayParams struct {
Expand Down Expand Up @@ -299,3 +313,14 @@ type WithdrawStatus struct {
AccountBank string `json:"account_bank"` // 服务商提现入账的开户银行
BankName string `json:"bank_name"` // 服务商提现入账的开户银行全称(含支行)
}

type PalmServicePreAuthorize struct {
PermissionToken string `json:"permission_token"` // 预授权token,跳转小程序使用
}

type PalmServiceOpenidQuery struct {
OrganizationId string `json:"organization_id"`
Openid string `json:"openid"`
State string `json:"state"`
AuthorizeTime string `json:"authorize_time"`
}
49 changes: 49 additions & 0 deletions wechat/v3/palm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package wechat

import (
"context"
"net/http"

"github.com/go-pay/gopay"
)

// 用户自主录掌&预授权
// Code = 0 is success
func (c *ClientV3) V3PalmServicePreAuthorize(ctx context.Context, bm gopay.BodyMap) (wxRsp *PalmServicePreAuthorizeRsp, err error) {
authorization, err := c.authorization(MethodPost, v3PalmServicePreAuthorize, bm)
if err != nil {
return nil, err
}
res, si, bs, err := c.doProdPost(ctx, bm, v3PalmServicePreAuthorize, authorization)
if err != nil {
return nil, err
}
wxRsp = &PalmServicePreAuthorizeRsp{Code: Success, SignInfo: si}
if res.StatusCode != http.StatusOK {
wxRsp.Code = res.StatusCode
wxRsp.Error = string(bs)
return wxRsp, nil
}
return wxRsp, c.verifySyncSign(si)
}

// 预授权状态查询
// Code = 0 is success
func (c *ClientV3) V3PalmServiceOpenidQuery(ctx context.Context, bm gopay.BodyMap) (wxRsp *PalmServiceOpenidQueryRsp, err error) {
uri := v3PalmServiceOpenidQuery + "?" + bm.EncodeURLParams()
authorization, err := c.authorization(MethodGet, uri, nil)
if err != nil {
return nil, err
}
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
if err != nil {
return nil, err
}
wxRsp = &PalmServiceOpenidQueryRsp{Code: Success, SignInfo: si}
if res.StatusCode != http.StatusOK {
wxRsp.Code = res.StatusCode
wxRsp.Error = string(bs)
return wxRsp, nil
}
return wxRsp, c.verifySyncSign(si)
}
9 changes: 3 additions & 6 deletions wechat/v3/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,17 +268,14 @@ func (c *ClientV3) verifySyncSign(si *SignInfo) (err error) {
if si == nil {
return errors.New("auto verify sign, but SignInfo is nil")
}
c.rwMu.RLock()
wxPublicKey, exist := c.SnCertMap[si.HeaderSerial]
c.rwMu.RUnlock()

wxPublicKey, exist := c.SnCertMap.Load(si.HeaderSerial)
if !exist {
err = c.AutoVerifySign(false)
if err != nil {
return fmt.Errorf("[get all public key err]: %v", err)
}
c.rwMu.RLock()
wxPublicKey, exist = c.SnCertMap[si.HeaderSerial]
c.rwMu.RUnlock()
wxPublicKey, exist = c.SnCertMap.Load(si.HeaderSerial)
if !exist {
return errors.New("auto verify sign, but public key not found")
}
Expand Down

0 comments on commit 9940221

Please sign in to comment.