Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加微信v3 的掌纹支付相关接口 #433

Merged
merged 4 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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