diff --git a/alipay/client.go b/alipay/client.go index 6d1c5058..399fb444 100644 --- a/alipay/client.go +++ b/alipay/client.go @@ -3,8 +3,12 @@ package alipay import ( "context" "crypto/rsa" + "crypto/sha1" + "crypto/sha256" "encoding/json" "fmt" + "hash" + "sync" "time" "github.com/go-pay/gopay" @@ -32,6 +36,10 @@ type Client struct { autoSign bool DebugSwitch gopay.DebugSwitch location *time.Location + hc *xhttp.Client + sha1Hash hash.Hash + sha256Hash hash.Hash + mu sync.Mutex } // 初始化支付宝客户端 @@ -55,6 +63,9 @@ func NewClient(appid, privateKey string, isProd bool) (client *Client, err error IsProd: isProd, privateKey: priKey, DebugSwitch: gopay.DebugOff, + hc: xhttp.NewClient(), + sha1Hash: sha1.New(), + sha256Hash: sha256.New(), } return client, nil } @@ -76,7 +87,7 @@ func (a *Client) AutoVerifySign(alipayPublicKeyContent []byte) { // SetBodySize 设置http response body size(MB) func (a *Client) SetBodySize(sizeMB int) { if sizeMB > 0 { - a.bodySize = sizeMB + a.hc.SetBodySize(sizeMB) } } @@ -123,7 +134,7 @@ func (a *Client) RequestParam(bm gopay.BodyMap, method string) (string, error) { // check sign if bm.GetString("sign") == "" { - sign, err = a.getRsaSign(bm, bm.GetString("sign_type"), a.privateKey) + sign, err = a.getRsaSign(bm, bm.GetString("sign_type")) if err != nil { return "", fmt.Errorf("GetRsaSign Error: %w", err) } @@ -136,229 +147,6 @@ func (a *Client) RequestParam(bm gopay.BodyMap, method string) (string, error) { return bm.EncodeURLParams(), nil } -// PostAliPayAPISelfV2 支付宝接口自行实现方法 -// 注意:biz_content 需要自行通过bm.SetBodyMap()设置,不设置则没有此参数 -// 示例:请参考 client_test.go 的 TestClient_PostAliPayAPISelfV2() 方法 -func (a *Client) PostAliPayAPISelfV2(ctx context.Context, bm gopay.BodyMap, method string, aliRsp any) (err error) { - var ( - bs, bodyBs []byte - ) - // check if there is biz_content - bz := bm.GetInterface("biz_content") - if bzBody, ok := bz.(gopay.BodyMap); ok { - if bodyBs, err = json.Marshal(bzBody); err != nil { - return fmt.Errorf("json.Marshal(%v):%w", bzBody, err) - } - bm.Set("biz_content", string(bodyBs)) - } - - if bs, err = a.doAliPaySelf(ctx, bm, method); err != nil { - return err - } - if err = json.Unmarshal(bs, aliRsp); err != nil { - return err - } - return nil -} - -// 向支付宝发送自定义请求 -func (a *Client) doAliPaySelf(ctx context.Context, bm gopay.BodyMap, method string) (bs []byte, err error) { - var ( - url, sign string - ) - bm.Set("method", method) - // check public parameter - a.checkPublicParam(bm) - // check sign - if bm.GetString("sign") == "" { - sign, err = a.getRsaSign(bm, bm.GetString("sign_type"), a.privateKey) - if err != nil { - return nil, fmt.Errorf("GetRsaSign Error: %w", err) - } - bm.Set("sign", sign) - } - if a.DebugSwitch == gopay.DebugOn { - xlog.Debugf("Alipay_Request: %s", bm.JsonBody()) - } - - httpClient := xhttp.NewClient() - if a.bodySize > 0 { - httpClient.SetBodySize(a.bodySize) - } - if a.IsProd { - url = baseUrlUtf8 - } else { - url = sandboxBaseUrlUtf8 - } - res, bs, err := httpClient.Type(xhttp.TypeForm).Post(url).SendString(bm.EncodeURLParams()).EndBytes(ctx) - if err != nil { - return nil, err - } - if a.DebugSwitch == gopay.DebugOn { - xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs)) - } - if res.StatusCode != 200 { - return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode) - } - return bs, nil -} - -// 向支付宝发送请求 -func (a *Client) doAliPay(ctx context.Context, bm gopay.BodyMap, method string, authToken ...string) (bs []byte, err error) { - var ( - bizContent, url string - bodyBs []byte - ) - if bm != nil { - _, has := appAuthTokenInBizContent[method] - if has { - if bodyBs, err = json.Marshal(bm); err != nil { - return nil, fmt.Errorf("json.Marshal:%w", err) - } - bizContent = string(bodyBs) - bm.Remove("app_auth_token") - } else { - aat := bm.GetString("app_auth_token") - bm.Remove("app_auth_token") - if bodyBs, err = json.Marshal(bm); err != nil { - return nil, fmt.Errorf("json.Marshal:%w", err) - } - bizContent = string(bodyBs) - bm.Set("app_auth_token", aat) - } - } - // 处理公共参数 - param, err := a.pubParamsHandle(bm, method, bizContent, authToken...) - if err != nil { - return nil, err - } - switch method { - case "alipay.trade.app.pay", "alipay.fund.auth.order.app.freeze": - return []byte(param), nil - case "alipay.trade.wap.pay", "alipay.trade.page.pay", "alipay.user.certify.open.certify": - if !a.IsProd { - return []byte(sandboxBaseUrl + "?" + param), nil - } - return []byte(baseUrl + "?" + param), nil - default: - httpClient := xhttp.NewClient() - if a.bodySize > 0 { - httpClient.SetBodySize(a.bodySize) - } - url = baseUrlUtf8 - if !a.IsProd { - url = sandboxBaseUrlUtf8 - } - res, bs, err := httpClient.Type(xhttp.TypeForm).Post(url).SendString(param).EndBytes(ctx) - if err != nil { - return nil, err - } - if a.DebugSwitch == gopay.DebugOn { - xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs)) - } - if res.StatusCode != 200 { - return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode) - } - return bs, nil - } -} - -// 向支付宝发送请求 -func (a *Client) DoAliPay(ctx context.Context, bm gopay.BodyMap, method string, authToken ...string) (bs []byte, err error) { - var ( - bizContent, url string - bodyBs []byte - ) - if bm != nil { - _, has := appAuthTokenInBizContent[method] - if has { - if bodyBs, err = json.Marshal(bm); err != nil { - return nil, fmt.Errorf("json.Marshal:%w", err) - } - bizContent = string(bodyBs) - bm.Remove("app_auth_token") - } else { - aat := bm.GetString("app_auth_token") - bm.Remove("app_auth_token") - if bodyBs, err = json.Marshal(bm); err != nil { - return nil, fmt.Errorf("json.Marshal:%w", err) - } - bizContent = string(bodyBs) - bm.Set("app_auth_token", aat) - } - } - // 处理公共参数 - param, err := a.pubParamsHandle(bm, method, bizContent, authToken...) - if err != nil { - return nil, err - } - switch method { - case "alipay.trade.app.pay", "alipay.fund.auth.order.app.freeze": - return []byte(param), nil - case "alipay.trade.wap.pay", "alipay.trade.page.pay", "alipay.user.certify.open.certify": - if !a.IsProd { - return []byte(sandboxBaseUrl + "?" + param), nil - } - return []byte(baseUrl + "?" + param), nil - default: - httpClient := xhttp.NewClient() - if a.bodySize > 0 { - httpClient.SetBodySize(a.bodySize) - } - url = baseUrlUtf8 - if !a.IsProd { - url = sandboxBaseUrlUtf8 - } - res, bs, err := httpClient.Type(xhttp.TypeForm).Post(url).SendString(param).EndBytes(ctx) - if err != nil { - return nil, err - } - if a.DebugSwitch == gopay.DebugOn { - xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs)) - } - if res.StatusCode != 200 { - return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode) - } - return bs, nil - } -} - -// 保持和官方 SDK 命名方式一致 -func (a *Client) PageExecute(ctx context.Context, bm gopay.BodyMap, method string, authToken ...string) (url string, err error) { - var ( - bizContent string - bodyBs []byte - ) - if bm != nil { - _, has := appAuthTokenInBizContent[method] - if has { - if bodyBs, err = json.Marshal(bm); err != nil { - return "", fmt.Errorf("json.Marshal:%w", err) - } - bizContent = string(bodyBs) - bm.Remove("app_auth_token") - } else { - aat := bm.GetString("app_auth_token") - bm.Remove("app_auth_token") - if bodyBs, err = json.Marshal(bm); err != nil { - return "", fmt.Errorf("json.Marshal:%w", err) - } - bizContent = string(bodyBs) - bm.Set("app_auth_token", aat) - } - } - // 处理公共参数 - param, err := a.pubParamsHandle(bm, method, bizContent, authToken...) - if err != nil { - return "", err - } - - if !a.IsProd { - return sandboxBaseUrl + "?" + param, nil - } - return baseUrl + "?" + param, nil -} - // 公共参数处理 func (a *Client) pubParamsHandle(bm gopay.BodyMap, method, bizContent string, authToken ...string) (param string, err error) { pubBody := make(gopay.BodyMap) @@ -412,7 +200,7 @@ func (a *Client) pubParamsHandle(bm gopay.BodyMap, method, bizContent string, au pubBody.Set("biz_content", bizContent) } // sign - sign, err := a.getRsaSign(pubBody, pubBody.GetString("sign_type"), a.privateKey) + sign, err := a.getRsaSign(pubBody, pubBody.GetString("sign_type")) if err != nil { return "", fmt.Errorf("GetRsaSign Error: %w", err) } @@ -454,82 +242,3 @@ func (a *Client) checkPublicParam(bm gopay.BodyMap) { bm.Set("app_auth_token", a.AppAuthToken) } } - -// 文件上传 -func (a *Client) FileRequest(ctx context.Context, bm gopay.BodyMap, file *util.File, method string) (bs []byte, err error) { - var ( - bodyStr string - bodyBs []byte - aat string - ) - if bm != nil { - aat = bm.GetString("app_auth_token") - bm.Remove("app_auth_token") - if bodyBs, err = json.Marshal(bm); err != nil { - return nil, fmt.Errorf("json.Marshal:%w", err) - } - bodyStr = string(bodyBs) - } - pubBody := make(gopay.BodyMap) - pubBody.Set("app_id", a.AppId). - Set("method", method). - Set("format", "JSON"). - Set("charset", a.Charset). - Set("sign_type", a.SignType). - Set("version", "1.0"). - Set("scene", "SYNC_ORDER"). - Set("timestamp", time.Now().Format(util.TimeLayout)) - - if a.AppCertSN != util.NULL { - pubBody.Set("app_cert_sn", a.AppCertSN) - } - if a.AliPayRootCertSN != util.NULL { - pubBody.Set("alipay_root_cert_sn", a.AliPayRootCertSN) - } - if a.ReturnUrl != util.NULL { - pubBody.Set("return_url", a.ReturnUrl) - } - if a.location != nil { - pubBody.Set("timestamp", time.Now().In(a.location).Format(util.TimeLayout)) - } - if a.NotifyUrl != util.NULL { //如果返回url为空,传过来的返回url不为空 - //fmt.Println("url不为空?", a.NotifyUrl) - pubBody.Set("notify_url", a.NotifyUrl) - } - //fmt.Println("notify,", pubBody.JsonBody()) - if a.AppAuthToken != util.NULL { - pubBody.Set("app_auth_token", a.AppAuthToken) - } - if aat != util.NULL { - pubBody.Set("app_auth_token", aat) - } - if bodyStr != util.NULL { - pubBody.Set("biz_content", bodyStr) - } - sign, err := a.getRsaSign(pubBody, pubBody.GetString("sign_type"), a.privateKey) - if err != nil { - return nil, fmt.Errorf("GetRsaSign Error: %w", err) - } - //pubBody.Set("file_content", file.Content) - pubBody.Set("sign", sign) - if a.DebugSwitch == gopay.DebugOn { - xlog.Debugf("Alipay_Request: %s", pubBody.JsonBody()) - } - param := pubBody.EncodeURLParams() - url := baseUrlUtf8 + "&" + param - bm.Reset() - bm.SetFormFile("file_content", file) - httpClient := xhttp.NewClient() - res, bs, err := httpClient.Type(xhttp.TypeMultipartFormData).Post(url). - SendMultipartBodyMap(bm).EndBytes(ctx) - if err != nil { - return nil, err - } - if a.DebugSwitch == gopay.DebugOn { - xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs)) - } - if res.StatusCode != 200 { - return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode) - } - return bs, nil -} diff --git a/alipay/common_api.go b/alipay/common_api.go index 70564543..d435f302 100644 --- a/alipay/common_api.go +++ b/alipay/common_api.go @@ -180,7 +180,7 @@ func systemOauthToken(ctx context.Context, appId string, privateKey *rsa.Private if !isProd { baseUrl = sandboxBaseUrlUtf8 } - _, bs, err = xhttp.NewClient().Type(xhttp.TypeForm).Post(baseUrl).SendString(bm.EncodeURLParams()).EndBytes(ctx) + _, bs, err = xhttp.NewClient().Req(xhttp.TypeForm).Post(baseUrl).SendString(bm.EncodeURLParams()).EndBytes(ctx) if err != nil { return nil, err } @@ -220,7 +220,7 @@ func MonitorHeartbeatSyn(ctx context.Context, appId string, privateKey, signType } bm.Set("sign", sign) - _, bs, err = xhttp.NewClient().Type(xhttp.TypeForm).Post(baseUrlUtf8).SendString(bm.EncodeURLParams()).EndBytes(ctx) + _, bs, err = xhttp.NewClient().Req(xhttp.TypeForm).Post(baseUrlUtf8).SendString(bm.EncodeURLParams()).EndBytes(ctx) if err != nil { return nil, err } diff --git a/alipay/customs.go b/alipay/customs.go index 679221b8..7cfcdf65 100644 --- a/alipay/customs.go +++ b/alipay/customs.go @@ -69,7 +69,7 @@ func (a *Client) doAliPayCustoms(ctx context.Context, bm gopay.BodyMap, service bm.Remove("sign_type") bm.Remove("sign") - sign, err := a.getRsaSign(bm, RSA, a.privateKey) + sign, err := a.getRsaSign(bm, RSA) if err != nil { return nil, fmt.Errorf("GetRsaSign Error: %v", err) } @@ -79,8 +79,7 @@ func (a *Client) doAliPayCustoms(ctx context.Context, bm gopay.BodyMap, service xlog.Debugf("Alipay_Request: %s", bm.JsonBody()) } // request - httpClient := xhttp.NewClient() - res, bs, err := httpClient.Type(xhttp.TypeForm).Post("https://mapi.alipay.com/gateway.do").SendString(bm.EncodeURLParams()).EndBytes(ctx) + res, bs, err := a.hc.Req(xhttp.TypeForm).Post("https://mapi.alipay.com/gateway.do").SendString(bm.EncodeURLParams()).EndBytes(ctx) if err != nil { return nil, err } diff --git a/alipay/request.go b/alipay/request.go new file mode 100644 index 00000000..a19b40f5 --- /dev/null +++ b/alipay/request.go @@ -0,0 +1,301 @@ +package alipay + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/go-pay/gopay" + "github.com/go-pay/gopay/pkg/util" + "github.com/go-pay/gopay/pkg/xhttp" + "github.com/go-pay/gopay/pkg/xlog" +) + +// PostAliPayAPISelfV2 支付宝接口自行实现方法 +// 注意:biz_content 需要自行通过bm.SetBodyMap()设置,不设置则没有此参数 +// 示例:请参考 client_test.go 的 TestClient_PostAliPayAPISelfV2() 方法 +func (a *Client) PostAliPayAPISelfV2(ctx context.Context, bm gopay.BodyMap, method string, aliRsp any) (err error) { + var ( + bs, bodyBs []byte + ) + // check if there is biz_content + bz := bm.GetInterface("biz_content") + if bzBody, ok := bz.(gopay.BodyMap); ok { + if bodyBs, err = json.Marshal(bzBody); err != nil { + return fmt.Errorf("json.Marshal(%v):%w", bzBody, err) + } + bm.Set("biz_content", string(bodyBs)) + } + + if bs, err = a.doAliPaySelf(ctx, bm, method); err != nil { + return err + } + if err = json.Unmarshal(bs, aliRsp); err != nil { + return err + } + return nil +} + +// 向支付宝发送自定义请求 +func (a *Client) doAliPaySelf(ctx context.Context, bm gopay.BodyMap, method string) (bs []byte, err error) { + var ( + url, sign string + ) + bm.Set("method", method) + // check public parameter + a.checkPublicParam(bm) + // check sign + if bm.GetString("sign") == "" { + sign, err = a.getRsaSign(bm, bm.GetString("sign_type")) + if err != nil { + return nil, fmt.Errorf("GetRsaSign Error: %w", err) + } + bm.Set("sign", sign) + } + if a.DebugSwitch == gopay.DebugOn { + xlog.Debugf("Alipay_Request: %s", bm.JsonBody()) + } + if a.IsProd { + url = baseUrlUtf8 + } else { + url = sandboxBaseUrlUtf8 + } + res, bs, err := a.hc.Req(xhttp.TypeForm).Post(url).SendString(bm.EncodeURLParams()).EndBytes(ctx) + if err != nil { + return nil, err + } + if a.DebugSwitch == gopay.DebugOn { + xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs)) + } + if res.StatusCode != 200 { + return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode) + } + return bs, nil +} + +// 向支付宝发送请求 +func (a *Client) doAliPay(ctx context.Context, bm gopay.BodyMap, method string, authToken ...string) (bs []byte, err error) { + var ( + bizContent, url string + bodyBs []byte + ) + if bm != nil { + _, has := appAuthTokenInBizContent[method] + if has { + if bodyBs, err = json.Marshal(bm); err != nil { + return nil, fmt.Errorf("json.Marshal:%w", err) + } + bizContent = string(bodyBs) + bm.Remove("app_auth_token") + } else { + aat := bm.GetString("app_auth_token") + bm.Remove("app_auth_token") + if bodyBs, err = json.Marshal(bm); err != nil { + return nil, fmt.Errorf("json.Marshal:%w", err) + } + bizContent = string(bodyBs) + bm.Set("app_auth_token", aat) + } + } + // 处理公共参数 + param, err := a.pubParamsHandle(bm, method, bizContent, authToken...) + if err != nil { + return nil, err + } + switch method { + case "alipay.trade.app.pay", "alipay.fund.auth.order.app.freeze": + return []byte(param), nil + case "alipay.trade.wap.pay", "alipay.trade.page.pay", "alipay.user.certify.open.certify": + if !a.IsProd { + return []byte(sandboxBaseUrl + "?" + param), nil + } + return []byte(baseUrl + "?" + param), nil + default: + url = baseUrlUtf8 + if !a.IsProd { + url = sandboxBaseUrlUtf8 + } + res, bs, err := a.hc.Req(xhttp.TypeForm).Post(url).SendString(param).EndBytes(ctx) + if err != nil { + return nil, err + } + if a.DebugSwitch == gopay.DebugOn { + xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs)) + } + if res.StatusCode != 200 { + return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode) + } + return bs, nil + } +} + +// 向支付宝发送请求 +func (a *Client) DoAliPay(ctx context.Context, bm gopay.BodyMap, method string, authToken ...string) (bs []byte, err error) { + var ( + bizContent, url string + bodyBs []byte + ) + if bm != nil { + _, has := appAuthTokenInBizContent[method] + if has { + if bodyBs, err = json.Marshal(bm); err != nil { + return nil, fmt.Errorf("json.Marshal:%w", err) + } + bizContent = string(bodyBs) + bm.Remove("app_auth_token") + } else { + aat := bm.GetString("app_auth_token") + bm.Remove("app_auth_token") + if bodyBs, err = json.Marshal(bm); err != nil { + return nil, fmt.Errorf("json.Marshal:%w", err) + } + bizContent = string(bodyBs) + bm.Set("app_auth_token", aat) + } + } + // 处理公共参数 + param, err := a.pubParamsHandle(bm, method, bizContent, authToken...) + if err != nil { + return nil, err + } + switch method { + case "alipay.trade.app.pay", "alipay.fund.auth.order.app.freeze": + return []byte(param), nil + case "alipay.trade.wap.pay", "alipay.trade.page.pay", "alipay.user.certify.open.certify": + if !a.IsProd { + return []byte(sandboxBaseUrl + "?" + param), nil + } + return []byte(baseUrl + "?" + param), nil + default: + url = baseUrlUtf8 + if !a.IsProd { + url = sandboxBaseUrlUtf8 + } + res, bs, err := a.hc.Req(xhttp.TypeForm).Post(url).SendString(param).EndBytes(ctx) + if err != nil { + return nil, err + } + if a.DebugSwitch == gopay.DebugOn { + xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs)) + } + if res.StatusCode != 200 { + return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode) + } + return bs, nil + } +} + +// 保持和官方 SDK 命名方式一致 +func (a *Client) PageExecute(ctx context.Context, bm gopay.BodyMap, method string, authToken ...string) (url string, err error) { + var ( + bizContent string + bodyBs []byte + ) + if bm != nil { + _, has := appAuthTokenInBizContent[method] + if has { + if bodyBs, err = json.Marshal(bm); err != nil { + return "", fmt.Errorf("json.Marshal:%w", err) + } + bizContent = string(bodyBs) + bm.Remove("app_auth_token") + } else { + aat := bm.GetString("app_auth_token") + bm.Remove("app_auth_token") + if bodyBs, err = json.Marshal(bm); err != nil { + return "", fmt.Errorf("json.Marshal:%w", err) + } + bizContent = string(bodyBs) + bm.Set("app_auth_token", aat) + } + } + // 处理公共参数 + param, err := a.pubParamsHandle(bm, method, bizContent, authToken...) + if err != nil { + return "", err + } + + if !a.IsProd { + return sandboxBaseUrl + "?" + param, nil + } + return baseUrl + "?" + param, nil +} + +// 文件上传 +func (a *Client) FileRequest(ctx context.Context, bm gopay.BodyMap, file *util.File, method string) (bs []byte, err error) { + var ( + bodyStr string + bodyBs []byte + aat string + ) + if bm != nil { + aat = bm.GetString("app_auth_token") + bm.Remove("app_auth_token") + if bodyBs, err = json.Marshal(bm); err != nil { + return nil, fmt.Errorf("json.Marshal:%w", err) + } + bodyStr = string(bodyBs) + } + pubBody := make(gopay.BodyMap) + pubBody.Set("app_id", a.AppId). + Set("method", method). + Set("format", "JSON"). + Set("charset", a.Charset). + Set("sign_type", a.SignType). + Set("version", "1.0"). + Set("scene", "SYNC_ORDER"). + Set("timestamp", time.Now().Format(util.TimeLayout)) + + if a.AppCertSN != util.NULL { + pubBody.Set("app_cert_sn", a.AppCertSN) + } + if a.AliPayRootCertSN != util.NULL { + pubBody.Set("alipay_root_cert_sn", a.AliPayRootCertSN) + } + if a.ReturnUrl != util.NULL { + pubBody.Set("return_url", a.ReturnUrl) + } + if a.location != nil { + pubBody.Set("timestamp", time.Now().In(a.location).Format(util.TimeLayout)) + } + if a.NotifyUrl != util.NULL { //如果返回url为空,传过来的返回url不为空 + //fmt.Println("url不为空?", a.NotifyUrl) + pubBody.Set("notify_url", a.NotifyUrl) + } + //fmt.Println("notify,", pubBody.JsonBody()) + if a.AppAuthToken != util.NULL { + pubBody.Set("app_auth_token", a.AppAuthToken) + } + if aat != util.NULL { + pubBody.Set("app_auth_token", aat) + } + if bodyStr != util.NULL { + pubBody.Set("biz_content", bodyStr) + } + sign, err := a.getRsaSign(pubBody, pubBody.GetString("sign_type")) + if err != nil { + return nil, fmt.Errorf("GetRsaSign Error: %w", err) + } + //pubBody.Set("file_content", file.Content) + pubBody.Set("sign", sign) + if a.DebugSwitch == gopay.DebugOn { + xlog.Debugf("Alipay_Request: %s", pubBody.JsonBody()) + } + param := pubBody.EncodeURLParams() + url := baseUrlUtf8 + "&" + param + bm.Reset() + bm.SetFormFile("file_content", file) + res, bs, err := a.hc.Req(xhttp.TypeMultipartFormData).Post(url). + SendMultipartBodyMap(bm).EndBytes(ctx) + if err != nil { + return nil, err + } + if a.DebugSwitch == gopay.DebugOn { + xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs)) + } + if res.StatusCode != 200 { + return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode) + } + return bs, nil +} diff --git a/alipay/sign.go b/alipay/sign.go index 1bc5e8bf..dba8d1b2 100644 --- a/alipay/sign.go +++ b/alipay/sign.go @@ -173,7 +173,7 @@ func GetRsaSign(bm gopay.BodyMap, signType string, privateKey *rsa.PrivateKey) ( return } -func (a *Client) getRsaSign(bm gopay.BodyMap, signType string, privateKey *rsa.PrivateKey) (sign string, err error) { +func (a *Client) getRsaSign(bm gopay.BodyMap, signType string) (sign string, err error) { var ( h hash.Hash hashs crypto.Hash @@ -182,23 +182,26 @@ func (a *Client) getRsaSign(bm gopay.BodyMap, signType string, privateKey *rsa.P switch signType { case RSA: - h = sha1.New() + h = a.sha1Hash hashs = crypto.SHA1 case RSA2: - h = sha256.New() + h = a.sha256Hash hashs = crypto.SHA256 default: - h = sha256.New() + h = a.sha256Hash hashs = crypto.SHA256 } signParams := bm.EncodeAliPaySignParams() if a.DebugSwitch == gopay.DebugOn { xlog.Debugf("Alipay_Request_SignStr: %s", signParams) } - if _, err = h.Write([]byte(signParams)); err != nil { - return - } - if encryptedBytes, err = rsa.SignPKCS1v15(rand.Reader, privateKey, hashs, h.Sum(nil)); err != nil { + a.mu.Lock() + defer func() { + h.Reset() + a.mu.Unlock() + }() + h.Write([]byte(signParams)) + if encryptedBytes, err = rsa.SignPKCS1v15(rand.Reader, a.privateKey, hashs, h.Sum(nil)); err != nil { return util.NULL, fmt.Errorf("[%w]: %+v", gopay.SignatureErr, err) } sign = base64.StdEncoding.EncodeToString(encryptedBytes) diff --git a/allinpay/client.go b/allinpay/client.go index 695bc32d..82a9e36e 100644 --- a/allinpay/client.go +++ b/allinpay/client.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "hash" + "sync" "github.com/go-pay/gopay" "github.com/go-pay/gopay/pkg/util" @@ -26,6 +27,9 @@ type Client struct { isProd bool // 是否正式环境 privateKey *rsa.PrivateKey // 商户的RSA私钥 publicKey *rsa.PublicKey // 通联的公钥 + hc *xhttp.Client + mu sync.Mutex + sha1Hash hash.Hash } // NewClient 初始化通联客户端 @@ -50,6 +54,8 @@ func NewClient(cusId, appId, privateKey, publicKey string, isProd bool) (*Client isProd: isProd, privateKey: prk, publicKey: puk, + hc: xhttp.NewClient(), + sha1Hash: sha1.New(), }, nil } @@ -62,25 +68,25 @@ func (c *Client) SetOrgId(id string) *Client { // getRsaSign 获取签名字符串 func (c *Client) getRsaSign(bm gopay.BodyMap, signType string, privateKey *rsa.PrivateKey) (sign string, err error) { var ( - h hash.Hash hashs crypto.Hash encryptedBytes []byte ) switch signType { case RSA: - h = sha1.New() hashs = crypto.SHA1 case SM2: return "", errors.New("暂不支持SM2加密") default: - h = sha1.New() hashs = crypto.SHA1 } signParams := bm.EncodeAliPaySignParams() - if _, err = h.Write([]byte(signParams)); err != nil { - return - } - if encryptedBytes, err = rsa.SignPKCS1v15(rand.Reader, privateKey, hashs, h.Sum(nil)); err != nil { + c.mu.Lock() + defer func() { + c.sha1Hash.Reset() + c.mu.Unlock() + }() + c.sha1Hash.Write([]byte(signParams)) + if encryptedBytes, err = rsa.SignPKCS1v15(rand.Reader, privateKey, hashs, c.sha1Hash.Sum(nil)); err != nil { return util.NULL, fmt.Errorf("[%w]: %+v", gopay.SignatureErr, err) } sign = base64.StdEncoding.EncodeToString(encryptedBytes) @@ -117,12 +123,11 @@ func (c *Client) doPost(ctx context.Context, path string, bm gopay.BodyMap) (bs if err != nil { return nil, err } - httpClient := xhttp.NewClient() url := baseUrl if !c.isProd { url = sandboxBaseUrl } - res, bs, err := httpClient.Type(xhttp.TypeForm).Post(url + path).SendString(param).EndBytes(ctx) + res, bs, err := c.hc.Req(xhttp.TypeForm).Post(url + path).SendString(param).EndBytes(ctx) if err != nil { return nil, err } diff --git a/allinpay/sign.go b/allinpay/sign.go index 9117eb6b..f715f2cc 100644 --- a/allinpay/sign.go +++ b/allinpay/sign.go @@ -13,7 +13,7 @@ import ( // verifySign 验证响应签名 func (c *Client) verifySign(bs []byte) (err error) { bm := gopay.BodyMap{} - if err := json.Unmarshal(bs, &bm); err != nil { + if err = json.Unmarshal(bs, &bm); err != nil { return err } sign := bm.Get("sign") @@ -21,9 +21,13 @@ func (c *Client) verifySign(bs []byte) (err error) { signData := bm.EncodeAliPaySignParams() signBytes, _ := base64.StdEncoding.DecodeString(sign) hashs := crypto.SHA1 - h := hashs.New() - h.Write([]byte(signData)) - if err = rsa.VerifyPKCS1v15(c.publicKey, hashs, h.Sum(nil), signBytes); err != nil { + c.mu.Lock() + defer func() { + c.sha1Hash.Reset() + c.mu.Unlock() + }() + c.sha1Hash.Write([]byte(signData)) + if err = rsa.VerifyPKCS1v15(c.publicKey, hashs, c.sha1Hash.Sum(nil), signBytes); err != nil { return fmt.Errorf("[%w]: %v", gopay.VerifySignatureErr, err) } return nil diff --git a/apple/client.go b/apple/client.go index 4740a845..15a894f4 100644 --- a/apple/client.go +++ b/apple/client.go @@ -17,6 +17,7 @@ type Client struct { kid string // Your private key ID from App Store Connect (Ex: 2X9R4HXF34) isProd bool // 是否是正式环境 privateKey *ecdsa.PrivateKey + hc *xhttp.Client } // NewClient 初始化Apple客户端 @@ -43,6 +44,7 @@ func NewClient(iss, bid, kid, privateKey string, isProd bool) (client *Client, e kid: kid, privateKey: ecPrivateKey, isProd: isProd, + hc: xhttp.NewClient(), } return client, nil } @@ -56,9 +58,9 @@ func (c *Client) doRequestGet(ctx context.Context, path string) (res *http.Respo if err != nil { return nil, nil, err } - cli := xhttp.NewClient() - cli.Header.Set("Authorization", "Bearer "+token) - res, bs, err = cli.Type(xhttp.TypeJSON).Get(uri).EndBytes(ctx) + req := c.hc.Req() + req.Header.Set("Authorization", "Bearer "+token) + res, bs, err = req.Get(uri).EndBytes(ctx) if err != nil { return nil, nil, err } @@ -74,9 +76,9 @@ func (c *Client) doRequestPost(ctx context.Context, path string, bm gopay.BodyMa if err != nil { return nil, nil, err } - cli := xhttp.NewClient() - cli.Header.Set("Authorization", "Bearer "+token) - res, bs, err = cli.Type(xhttp.TypeJSON).Post(uri).SendBodyMap(bm).EndBytes(ctx) + req := c.hc.Req() + req.Header.Set("Authorization", "Bearer "+token) + res, bs, err = req.Post(uri).SendBodyMap(bm).EndBytes(ctx) if err != nil { return nil, nil, err } @@ -92,9 +94,9 @@ func (c *Client) doRequestPut(ctx context.Context, path string, bm gopay.BodyMap if err != nil { return nil, nil, err } - cli := xhttp.NewClient() - cli.Header.Set("Authorization", "Bearer "+token) - res, bs, err = cli.Type(xhttp.TypeJSON).Put(uri).SendBodyMap(bm).EndBytes(ctx) + req := c.hc.Req() + req.Header.Set("Authorization", "Bearer "+token) + res, bs, err = req.Put(uri).SendBodyMap(bm).EndBytes(ctx) if err != nil { return nil, nil, err } diff --git a/apple/verify.go b/apple/verify.go index 1787b8ca..c7e45311 100644 --- a/apple/verify.go +++ b/apple/verify.go @@ -20,7 +20,7 @@ const ( func VerifyReceipt(ctx context.Context, url, pwd, receipt string) (rsp *VerifyResponse, err error) { req := &VerifyRequest{Receipt: receipt, Password: pwd} rsp = new(VerifyResponse) - _, err = xhttp.NewClient().Type(xhttp.TypeJSON).Post(url).SendStruct(req).EndStruct(ctx, rsp) + _, err = xhttp.NewClient().Req(xhttp.TypeJSON).Post(url).SendStruct(req).EndStruct(ctx, rsp) if err != nil { return nil, err } diff --git a/apple/verify_model.go b/apple/verify_model.go index 9b3eb49a..7673ebda 100644 --- a/apple/verify_model.go +++ b/apple/verify_model.go @@ -7,7 +7,7 @@ type VerifyRequest struct { Receipt string `json:"receipt-data"` // Password App的秘钥 - Password string `json:"password"` + Password string `json:"password,omitempty"` // ExcludeOldTranscations Set this value to true for the response to include only the latest renewal transaction for any subscriptions. Use this field only for app receipts that contain auto-renewable subscriptions. ExcludeOldTranscations bool `json:"exclude-old-transactions"` diff --git a/lakala/client.go b/lakala/client.go index d2b5d421..cb8c3681 100644 --- a/lakala/client.go +++ b/lakala/client.go @@ -26,6 +26,7 @@ type Client struct { DebugSwitch gopay.DebugSwitch // 调试开关,是否打印日志 hc *xhttp.Client sha256Hash hash.Hash + mu sync.Mutex } // NewClient 初始化lakala户端 @@ -88,16 +89,15 @@ func (c *Client) getRsaSign(bm gopay.BodyMap) (sign string, err error) { ts = bm.Get("time") nonceStr = bm.Get("nonce_str") credentialCode = c.credentialCode - mu sync.Mutex ) if ts == "" || nonceStr == "" { return "", fmt.Errorf("签名缺少必要的参数") } validStr := fmt.Sprintf("%v&%v&%v&%v", partnerCode, ts, nonceStr, credentialCode) - mu.Lock() + c.mu.Lock() defer func() { c.sha256Hash.Reset() - mu.Unlock() + c.mu.Unlock() }() c.sha256Hash.Write([]byte(validStr)) sign = strings.ToLower(hex.EncodeToString(c.sha256Hash.Sum(nil))) diff --git a/qq/param.go b/qq/param.go index 62c0b7c1..27ccbce7 100644 --- a/qq/param.go +++ b/qq/param.go @@ -113,16 +113,16 @@ func (q *Client) getReleaseSign(apiKey string, signType string, bm gopay.BodyMap xlog.Debugf("QQ_Request_SignStr: %s", signParams) } var h hash.Hash - q.mu.Lock() - defer func() { - h.Reset() - q.mu.Unlock() - }() if signType == SignType_HMAC_SHA256 { h = q.sha256Hash } else { h = q.md5Hash } + q.mu.Lock() + defer func() { + h.Reset() + q.mu.Unlock() + }() h.Write([]byte(signParams)) return strings.ToUpper(hex.EncodeToString(h.Sum(nil))) } diff --git a/wechat/param.go b/wechat/param.go index d70ca7c0..9d406c5a 100644 --- a/wechat/param.go +++ b/wechat/param.go @@ -198,16 +198,16 @@ func (w *Client) getReleaseSign(apiKey string, signType string, bm gopay.BodyMap xlog.Debugf("Wechat_Request_SignStr: %s", signParams) } var h hash.Hash - w.mu.Lock() - defer func() { - h.Reset() - w.mu.Unlock() - }() if signType == SignType_HMAC_SHA256 { h = w.sha256Hash } else { h = w.md5Hash } + w.mu.Lock() + defer func() { + h.Reset() + w.mu.Unlock() + }() h.Write([]byte(signParams)) return strings.ToUpper(hex.EncodeToString(h.Sum(nil))) }