param.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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 interface{}) (err error) {
  44. if err = checkCertFilePath(certFilePath, keyFilePath, pkcs12FilePath); err != nil {
  45. return err
  46. }
  47. cert, err := ioutil.ReadFile(certFilePath.(string))
  48. if err != nil {
  49. return fmt.Errorf("ioutil.ReadFile:%w", err)
  50. }
  51. key, err := ioutil.ReadFile(keyFilePath.(string))
  52. if err != nil {
  53. return fmt.Errorf("ioutil.ReadFile:%w", err)
  54. }
  55. pkcs, err := ioutil.ReadFile(pkcs12FilePath.(string))
  56. if err != nil {
  57. return fmt.Errorf("ioutil.ReadFile:%w", err)
  58. }
  59. certificate, err := tls.X509KeyPair(cert, key)
  60. if err != nil {
  61. return fmt.Errorf("tls.LoadX509KeyPair:%w", err)
  62. }
  63. pkcsPool := x509.NewCertPool()
  64. pkcsPool.AppendCertsFromPEM(pkcs)
  65. w.mu.Lock()
  66. w.certificate = certificate
  67. w.certPool = pkcsPool
  68. w.mu.Unlock()
  69. return nil
  70. }
  71. func (w *Client) addCertConfig(certFilePath, keyFilePath, pkcs12FilePath interface{}) (tlsConfig *tls.Config, err error) {
  72. if certFilePath == nil && keyFilePath == nil && pkcs12FilePath == nil {
  73. w.mu.RLock()
  74. defer w.mu.RUnlock()
  75. if &w.certificate != nil && w.certPool != nil {
  76. tlsConfig = &tls.Config{
  77. Certificates: []tls.Certificate{w.certificate},
  78. RootCAs: w.certPool,
  79. InsecureSkipVerify: true,
  80. }
  81. return tlsConfig, nil
  82. }
  83. }
  84. if certFilePath != nil && keyFilePath != nil && pkcs12FilePath != nil {
  85. cert, err := ioutil.ReadFile(certFilePath.(string))
  86. if err != nil {
  87. return nil, fmt.Errorf("ioutil.ReadFile:%w", err)
  88. }
  89. key, err := ioutil.ReadFile(keyFilePath.(string))
  90. if err != nil {
  91. return nil, fmt.Errorf("ioutil.ReadFile:%w", err)
  92. }
  93. pkcs, err := ioutil.ReadFile(pkcs12FilePath.(string))
  94. if err != nil {
  95. return nil, fmt.Errorf("ioutil.ReadFile:%w", err)
  96. }
  97. pkcsPool := x509.NewCertPool()
  98. pkcsPool.AppendCertsFromPEM(pkcs)
  99. certificate, err := tls.X509KeyPair(cert, key)
  100. if err != nil {
  101. return nil, fmt.Errorf("tls.LoadX509KeyPair:%w", err)
  102. }
  103. tlsConfig = &tls.Config{
  104. Certificates: []tls.Certificate{certificate},
  105. RootCAs: pkcsPool,
  106. InsecureSkipVerify: true}
  107. return tlsConfig, nil
  108. }
  109. return nil, errors.New("cert paths must all nil or all not nil")
  110. }
  111. func checkCertFilePath(certFilePath, keyFilePath, pkcs12FilePath interface{}) error {
  112. if certFilePath != nil && keyFilePath != nil && pkcs12FilePath != nil {
  113. if v, ok := certFilePath.(string); !ok || v == gopay.NULL {
  114. return errors.New("certFilePath not string type or is null string")
  115. }
  116. if v, ok := keyFilePath.(string); !ok || v == gopay.NULL {
  117. return errors.New("keyFilePath not string type or is null string")
  118. }
  119. if v, ok := pkcs12FilePath.(string); !ok || v == gopay.NULL {
  120. return errors.New("pkcs12FilePath not string type or is null string")
  121. }
  122. return nil
  123. }
  124. if !(certFilePath == nil && keyFilePath == nil && pkcs12FilePath == nil) {
  125. return errors.New("cert paths must all nil or all not nil")
  126. }
  127. return nil
  128. }
  129. // 获取微信支付正式环境Sign值
  130. func getReleaseSign(apiKey string, signType string, bm gopay.BodyMap) (sign string) {
  131. var h hash.Hash
  132. if signType == SignType_HMAC_SHA256 {
  133. h = hmac.New(sha256.New, []byte(apiKey))
  134. } else {
  135. h = md5.New()
  136. }
  137. h.Write([]byte(bm.EncodeWeChatSignParams(apiKey)))
  138. return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  139. }
  140. // 获取微信支付沙箱环境Sign值
  141. func getSignBoxSign(mchId, apiKey string, bm gopay.BodyMap) (sign string, err error) {
  142. var (
  143. sandBoxApiKey string
  144. h hash.Hash
  145. )
  146. if sandBoxApiKey, err = getSanBoxKey(mchId, gopay.GetRandomString(32), apiKey, SignType_MD5); err != nil {
  147. return
  148. }
  149. h = md5.New()
  150. h.Write([]byte(bm.EncodeWeChatSignParams(sandBoxApiKey)))
  151. sign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  152. return
  153. }
  154. // 从微信提供的接口获取:SandboxSignKey
  155. func getSanBoxKey(mchId, nonceStr, apiKey, signType string) (key string, err error) {
  156. bm := make(gopay.BodyMap)
  157. bm.Set("mch_id", mchId)
  158. bm.Set("nonce_str", nonceStr)
  159. //沙箱环境:获取沙箱环境ApiKey
  160. if key, err = getSanBoxSignKey(mchId, nonceStr, getReleaseSign(apiKey, signType, bm)); err != nil {
  161. return
  162. }
  163. return
  164. }
  165. // 从微信提供的接口获取:SandboxSignKey
  166. func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) {
  167. reqs := make(gopay.BodyMap)
  168. reqs.Set("mch_id", mchId)
  169. reqs.Set("nonce_str", nonceStr)
  170. reqs.Set("sign", sign)
  171. keyResponse := new(getSignKeyResponse)
  172. _, errs := gopay.NewHttpClient().Type(gopay.TypeXML).Post(sandboxGetSignKey).SendString(generateXml(reqs)).EndStruct(keyResponse)
  173. if len(errs) > 0 {
  174. return gopay.NULL, errs[0]
  175. }
  176. if keyResponse.ReturnCode == "FAIL" {
  177. return gopay.NULL, errors.New(keyResponse.ReturnMsg)
  178. }
  179. return keyResponse.SandboxSignkey, nil
  180. }
  181. // 生成请求XML的Body体
  182. func generateXml(bm gopay.BodyMap) (reqXml string) {
  183. bs, err := xml.Marshal(bm)
  184. if err != nil {
  185. return gopay.NULL
  186. }
  187. return string(bs)
  188. }