增加taptap支付
This commit is contained in:
101
package/pay/taptap/sign.go
Normal file
101
package/pay/taptap/sign.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package taptap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/grand"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type pTapTap struct {
|
||||
Secret string `json:"secret" dc:"秘钥"`
|
||||
OrderId string `json:"order_id" dc:"订单唯一 ID"`
|
||||
ClientId string `json:"client_id" dc:"应用的 Client ID"`
|
||||
}
|
||||
|
||||
func New(orderId string) *pTapTap {
|
||||
return &pTapTap{
|
||||
Secret: "5AFEWnadBA0NgJK2mxeBLQEde0qyIefxLSc4XKHsx9AwkQRhxzkQ9DixsOkK6gcV",
|
||||
ClientId: "mox88lbz43edfukdgk",
|
||||
OrderId: orderId,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pTapTap) Sign(url string, body []byte) (sign string, ts int64, nonce string, err error) {
|
||||
//nolint:gosec
|
||||
secret := p.Secret
|
||||
//body := gjson.MustEncode(g.Map{})
|
||||
//body := []byte(`{"event_type":"charge.succeeded","order":{"order_id":"1790288650833465345","purchase_token":"rT2Et9p0cfzq4fwjrTsGSacq0jQExFDqf5gTy1alp+Y=","client_id":"o6nD4iNavjQj75zPQk","open_id":"4+Axcl2RFgXbt6MZwdh++w==","user_region":"US","goods_open_id":"com.goods.open_id","goods_name":"TestGoodsName","status":"charge.succeeded","amount":"19000000000","currency":"USD","create_time":"1716168000","pay_time":"1716168000","extra":"1111111111111111111"}}`)
|
||||
//url := "https://example.com/my-service/v1/my-method"
|
||||
ts = gtime.Now().Unix()
|
||||
nonce = grand.S(5)
|
||||
method := "POST"
|
||||
header := http.Header{
|
||||
"Content-Type": {"Content-Type: application/json; charset=utf-8"},
|
||||
"X-Tap-Ts": {strconv.FormatInt(ts, 10)},
|
||||
"X-Tap-Nonce": {nonce},
|
||||
}
|
||||
ctx := context.Background()
|
||||
req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewBuffer(body))
|
||||
req.Header = header
|
||||
sign, err = Sign(req, secret)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
req.Header.Set("X-Tap-Sign", sign)
|
||||
return
|
||||
}
|
||||
|
||||
// Sign signs the request.
|
||||
func Sign(req *http.Request, secret string) (string, error) {
|
||||
methodPart := req.Method
|
||||
urlPathAndQueryPart := req.URL.RequestURI()
|
||||
headersPart, err := getHeadersPart(req.Header)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bodyPart, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signParts := methodPart + "\n" + urlPathAndQueryPart + "\n" + headersPart + "\n" + string(bodyPart) + "\n"
|
||||
fmt.Println(signParts)
|
||||
h := hmac.New(sha256.New, []byte(secret))
|
||||
h.Write([]byte(signParts))
|
||||
rawSign := h.Sum(nil)
|
||||
sign := base64.StdEncoding.EncodeToString(rawSign)
|
||||
return sign, nil
|
||||
}
|
||||
|
||||
// getHeadersPart returns the headers part of the request.
|
||||
func getHeadersPart(header http.Header) (string, error) {
|
||||
var headerKeys []string
|
||||
for k, v := range header {
|
||||
k = strings.ToLower(k)
|
||||
if !strings.HasPrefix(k, "x-tap-") {
|
||||
continue
|
||||
}
|
||||
if k == "x-tap-sign" {
|
||||
continue
|
||||
}
|
||||
if len(v) > 1 {
|
||||
return "", fmt.Errorf("invalid header, %q has multiple values", k)
|
||||
}
|
||||
headerKeys = append(headerKeys, k)
|
||||
}
|
||||
sort.Strings(headerKeys)
|
||||
headers := make([]string, 0, len(headerKeys))
|
||||
for _, k := range headerKeys {
|
||||
headers = append(headers, fmt.Sprintf("%s:%s", k, header.Get(k)))
|
||||
}
|
||||
return strings.Join(headers, "\n"), nil
|
||||
}
|
||||
Reference in New Issue
Block a user