param.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package wechat
  2. import (
  3. "crypto/hmac"
  4. "crypto/md5"
  5. "crypto/sha256"
  6. "crypto/tls"
  7. "crypto/x509"
  8. "encoding/hex"
  9. "encoding/xml"
  10. "errors"
  11. "fmt"
  12. "hash"
  13. "io/ioutil"
  14. "strings"
  15. "github.com/iGoogle-ink/gopay/v2"
  16. )
  17. type Country int
  18. // 设置支付国家(默认:中国国内)
  19. // 根据支付地区情况设置国家
  20. // country:<China:中国国内,China2:中国国内(冗灾方案),SoutheastAsia:东南亚,Other:其他国家>
  21. func (w *Client) SetCountry(country Country) (client *Client) {
  22. w.mu.Lock()
  23. switch country {
  24. case China:
  25. w.BaseURL = wxBaseUrlCh
  26. case China2:
  27. w.BaseURL = wxBaseUrlCh2
  28. case SoutheastAsia:
  29. w.BaseURL = wxBaseUrlHk
  30. case Other:
  31. w.BaseURL = wxBaseUrlUs
  32. default:
  33. w.BaseURL = wxBaseUrlCh
  34. }
  35. w.mu.Unlock()
  36. return w
  37. }
  38. // 添加微信证书 Byte 数组
  39. // certFile:apiclient_cert.pem byte数组
  40. // keyFile:apiclient_key.pem byte数组
  41. // pkcs12File:apiclient_cert.p12 byte数组
  42. func (w *Client) AddCertFileByte(certFile, keyFile, pkcs12File []byte) {
  43. w.mu.Lock()
  44. w.CertFile = certFile
  45. w.KeyFile = keyFile
  46. w.Pkcs12File = pkcs12File
  47. w.mu.Unlock()
  48. }
  49. // 添加微信证书 Path 路径
  50. // certFilePath:apiclient_cert.pem 路径
  51. // keyFilePath:apiclient_key.pem 路径
  52. // pkcs12FilePath:apiclient_cert.p12 路径
  53. // 返回err
  54. func (w *Client) AddCertFilePath(certFilePath, keyFilePath, pkcs12FilePath string) (err error) {
  55. cert, err := ioutil.ReadFile(certFilePath)
  56. if err != nil {
  57. return err
  58. }
  59. key, err := ioutil.ReadFile(keyFilePath)
  60. if err != nil {
  61. return err
  62. }
  63. pkcs, err := ioutil.ReadFile(pkcs12FilePath)
  64. if err != nil {
  65. return err
  66. }
  67. w.mu.Lock()
  68. w.CertFile = cert
  69. w.KeyFile = key
  70. w.Pkcs12File = pkcs
  71. w.mu.Unlock()
  72. return nil
  73. }
  74. func (w *Client) addCertConfig(certFilePath, keyFilePath, pkcs12FilePath string) (tlsConfig *tls.Config, err error) {
  75. var (
  76. pkcs []byte
  77. certificate tls.Certificate
  78. pkcsPool = x509.NewCertPool()
  79. )
  80. if certFilePath == gopay.NULL && keyFilePath == gopay.NULL && pkcs12FilePath == gopay.NULL {
  81. w.mu.RLock()
  82. pkcsPool.AppendCertsFromPEM(w.Pkcs12File)
  83. certificate, err = tls.X509KeyPair(w.CertFile, w.KeyFile)
  84. w.mu.RUnlock()
  85. if err != nil {
  86. return nil, fmt.Errorf("tls.X509KeyPair:%s", err.Error())
  87. }
  88. tlsConfig = &tls.Config{
  89. Certificates: []tls.Certificate{certificate},
  90. RootCAs: pkcsPool,
  91. InsecureSkipVerify: true}
  92. return tlsConfig, nil
  93. }
  94. if certFilePath != gopay.NULL && keyFilePath != gopay.NULL && pkcs12FilePath != gopay.NULL {
  95. if pkcs, err = ioutil.ReadFile(pkcs12FilePath); err != nil {
  96. return nil, fmt.Errorf("ioutil.ReadFile:%s", err.Error())
  97. }
  98. pkcsPool.AppendCertsFromPEM(pkcs)
  99. if certificate, err = tls.LoadX509KeyPair(certFilePath, keyFilePath); err != nil {
  100. return nil, fmt.Errorf("tls.LoadX509KeyPair:%s", err.Error())
  101. }
  102. tlsConfig = &tls.Config{
  103. Certificates: []tls.Certificate{certificate},
  104. RootCAs: pkcsPool,
  105. InsecureSkipVerify: true}
  106. return tlsConfig, nil
  107. }
  108. return nil, errors.New("certificate file path must be all input or all input null")
  109. }
  110. // 获取微信支付正式环境Sign值
  111. func getReleaseSign(apiKey string, signType string, bm gopay.BodyMap) (sign string) {
  112. var h hash.Hash
  113. if signType == SignType_HMAC_SHA256 {
  114. h = hmac.New(sha256.New, []byte(apiKey))
  115. } else {
  116. h = md5.New()
  117. }
  118. h.Write([]byte(bm.EncodeWeChatSignParams(apiKey)))
  119. return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  120. }
  121. // 获取微信支付沙箱环境Sign值
  122. func getSignBoxSign(mchId, apiKey string, bm gopay.BodyMap) (sign string, err error) {
  123. var (
  124. sandBoxApiKey string
  125. h hash.Hash
  126. )
  127. if sandBoxApiKey, err = getSanBoxKey(mchId, gopay.GetRandomString(32), apiKey, SignType_MD5); err != nil {
  128. return
  129. }
  130. h = md5.New()
  131. h.Write([]byte(bm.EncodeWeChatSignParams(sandBoxApiKey)))
  132. sign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  133. return
  134. }
  135. // 从微信提供的接口获取:SandboxSignKey
  136. func getSanBoxKey(mchId, nonceStr, apiKey, signType string) (key string, err error) {
  137. bm := make(gopay.BodyMap)
  138. bm.Set("mch_id", mchId)
  139. bm.Set("nonce_str", nonceStr)
  140. //沙箱环境:获取沙箱环境ApiKey
  141. if key, err = getSanBoxSignKey(mchId, nonceStr, getReleaseSign(apiKey, signType, bm)); err != nil {
  142. return
  143. }
  144. return
  145. }
  146. // 从微信提供的接口获取:SandboxSignKey
  147. func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) {
  148. reqs := make(gopay.BodyMap)
  149. reqs.Set("mch_id", mchId)
  150. reqs.Set("nonce_str", nonceStr)
  151. reqs.Set("sign", sign)
  152. keyResponse := new(getSignKeyResponse)
  153. _, errs := gopay.NewHttpClient().Type(gopay.TypeXML).Post(wxSandboxGetsignkey).SendString(generateXml(reqs)).EndStruct(keyResponse)
  154. if len(errs) > 0 {
  155. return gopay.NULL, errs[0]
  156. }
  157. if keyResponse.ReturnCode == "FAIL" {
  158. return gopay.NULL, errors.New(keyResponse.ReturnMsg)
  159. }
  160. return keyResponse.SandboxSignkey, nil
  161. }
  162. // 生成请求XML的Body体
  163. func generateXml(bm gopay.BodyMap) (reqXml string) {
  164. bs, err := xml.Marshal(bm)
  165. if err != nil {
  166. return gopay.NULL
  167. }
  168. return string(bs)
  169. }