param.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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"
  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 = baseUrlCh
  26. case China2:
  27. w.BaseURL = baseUrlCh2
  28. case SoutheastAsia:
  29. w.BaseURL = baseUrlHk
  30. case Other:
  31. w.BaseURL = baseUrlUs
  32. default:
  33. w.BaseURL = baseUrlCh
  34. }
  35. w.mu.Unlock()
  36. return w
  37. }
  38. // 添加微信证书 Path 路径
  39. // certFilePath:apiclient_cert.pem 路径
  40. // keyFilePath:apiclient_key.pem 路径
  41. // pkcs12FilePath:apiclient_cert.p12 路径
  42. // 返回err
  43. func (w *Client) AddCertFilePath(certFilePath, keyFilePath, pkcs12FilePath string) (err error) {
  44. cert, err := ioutil.ReadFile(certFilePath)
  45. if err != nil {
  46. return fmt.Errorf("ioutil.ReadFile:%w", err)
  47. }
  48. key, err := ioutil.ReadFile(keyFilePath)
  49. if err != nil {
  50. return fmt.Errorf("ioutil.ReadFile:%w", err)
  51. }
  52. pkcs, err := ioutil.ReadFile(pkcs12FilePath)
  53. if err != nil {
  54. return fmt.Errorf("ioutil.ReadFile:%w", err)
  55. }
  56. certificate, err := tls.X509KeyPair(cert, key)
  57. if err != nil {
  58. return fmt.Errorf("tls.LoadX509KeyPair:%w", err)
  59. }
  60. pkcsPool := x509.NewCertPool()
  61. pkcsPool.AppendCertsFromPEM(pkcs)
  62. w.mu.Lock()
  63. w.certificate = certificate
  64. w.certPool = pkcsPool
  65. w.mu.Unlock()
  66. return nil
  67. }
  68. func (w *Client) addCertConfig(certFilePath, keyFilePath, pkcs12FilePath string) (tlsConfig *tls.Config, err error) {
  69. if certFilePath == gopay.NULL && keyFilePath == gopay.NULL && pkcs12FilePath == gopay.NULL {
  70. w.mu.RLock()
  71. defer w.mu.RUnlock()
  72. if &w.certificate != nil && w.certPool != nil {
  73. tlsConfig = &tls.Config{
  74. Certificates: []tls.Certificate{w.certificate},
  75. RootCAs: w.certPool,
  76. InsecureSkipVerify: true,
  77. }
  78. return tlsConfig, nil
  79. }
  80. }
  81. if certFilePath != gopay.NULL && keyFilePath != gopay.NULL && pkcs12FilePath != gopay.NULL {
  82. cert, err := ioutil.ReadFile(certFilePath)
  83. if err != nil {
  84. return nil, fmt.Errorf("ioutil.ReadFile:%w", err)
  85. }
  86. key, err := ioutil.ReadFile(keyFilePath)
  87. if err != nil {
  88. return nil, fmt.Errorf("ioutil.ReadFile:%w", err)
  89. }
  90. pkcs, err := ioutil.ReadFile(pkcs12FilePath)
  91. if err != nil {
  92. return nil, fmt.Errorf("ioutil.ReadFile:%w", err)
  93. }
  94. pkcsPool := x509.NewCertPool()
  95. pkcsPool.AppendCertsFromPEM(pkcs)
  96. certificate, err := tls.X509KeyPair(cert, key)
  97. if err != nil {
  98. return nil, fmt.Errorf("tls.LoadX509KeyPair:%w", err)
  99. }
  100. tlsConfig = &tls.Config{
  101. Certificates: []tls.Certificate{certificate},
  102. RootCAs: pkcsPool,
  103. InsecureSkipVerify: true}
  104. return tlsConfig, nil
  105. }
  106. return nil, errors.New("certificate file path must be all input or all input null")
  107. }
  108. // 获取微信支付正式环境Sign值
  109. func getReleaseSign(apiKey string, signType string, bm gopay.BodyMap) (sign string) {
  110. var h hash.Hash
  111. if signType == SignType_HMAC_SHA256 {
  112. h = hmac.New(sha256.New, []byte(apiKey))
  113. } else {
  114. h = md5.New()
  115. }
  116. h.Write([]byte(bm.EncodeWeChatSignParams(apiKey)))
  117. return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  118. }
  119. // 获取微信支付沙箱环境Sign值
  120. func getSignBoxSign(mchId, apiKey string, bm gopay.BodyMap) (sign string, err error) {
  121. var (
  122. sandBoxApiKey string
  123. h hash.Hash
  124. )
  125. if sandBoxApiKey, err = getSanBoxKey(mchId, gopay.GetRandomString(32), apiKey, SignType_MD5); err != nil {
  126. return
  127. }
  128. h = md5.New()
  129. h.Write([]byte(bm.EncodeWeChatSignParams(sandBoxApiKey)))
  130. sign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  131. return
  132. }
  133. // 从微信提供的接口获取:SandboxSignKey
  134. func getSanBoxKey(mchId, nonceStr, apiKey, signType string) (key string, err error) {
  135. bm := make(gopay.BodyMap)
  136. bm.Set("mch_id", mchId)
  137. bm.Set("nonce_str", nonceStr)
  138. //沙箱环境:获取沙箱环境ApiKey
  139. if key, err = getSanBoxSignKey(mchId, nonceStr, getReleaseSign(apiKey, signType, bm)); err != nil {
  140. return
  141. }
  142. return
  143. }
  144. // 从微信提供的接口获取:SandboxSignKey
  145. func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) {
  146. reqs := make(gopay.BodyMap)
  147. reqs.Set("mch_id", mchId)
  148. reqs.Set("nonce_str", nonceStr)
  149. reqs.Set("sign", sign)
  150. keyResponse := new(getSignKeyResponse)
  151. _, errs := gopay.NewHttpClient().Type(gopay.TypeXML).Post(sandboxGetSignKey).SendString(generateXml(reqs)).EndStruct(keyResponse)
  152. if len(errs) > 0 {
  153. return gopay.NULL, errs[0]
  154. }
  155. if keyResponse.ReturnCode == "FAIL" {
  156. return gopay.NULL, errors.New(keyResponse.ReturnMsg)
  157. }
  158. return keyResponse.SandboxSignkey, nil
  159. }
  160. // 生成请求XML的Body体
  161. func generateXml(bm gopay.BodyMap) (reqXml string) {
  162. bs, err := xml.Marshal(bm)
  163. if err != nil {
  164. return gopay.NULL
  165. }
  166. return string(bs)
  167. }