蛋蛋星球-制度模式
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

182 linhas
4.6 KiB

  1. package qq
  2. import (
  3. "crypto/hmac"
  4. "crypto/md5"
  5. "crypto/sha256"
  6. "crypto/tls"
  7. "encoding/hex"
  8. "encoding/pem"
  9. "encoding/xml"
  10. "errors"
  11. "fmt"
  12. "hash"
  13. "os"
  14. "strings"
  15. "github.com/go-pay/gopay"
  16. "github.com/go-pay/xlog"
  17. "golang.org/x/crypto/pkcs12"
  18. )
  19. // 添加QQ证书 Path 路径
  20. // certFilePath:apiclient_cert.pem 路径
  21. // keyFilePath:apiclient_key.pem 路径
  22. // pkcs12FilePath:apiclient_cert.p12 路径
  23. // 返回err
  24. func (q *Client) AddCertFilePath(certFilePath, keyFilePath, pkcs12FilePath any) (err error) {
  25. if err = checkCertFilePathOrContent(certFilePath, keyFilePath, pkcs12FilePath); err != nil {
  26. return err
  27. }
  28. config, err := q.addCertConfig(certFilePath, keyFilePath, pkcs12FilePath)
  29. if err != nil {
  30. return
  31. }
  32. q.tlsHc.SetTLSConfig(config)
  33. return nil
  34. }
  35. // 添加QQ证书内容
  36. // certFileContent:apiclient_cert.pem 内容
  37. // keyFileContent:apiclient_key.pem 内容
  38. // pkcs12FileContent:apiclient_cert.p12 内容
  39. // 返回err
  40. func (q *Client) AddCertFileContent(certFileContent, keyFileContent, pkcs12FileContent []byte) (err error) {
  41. return q.AddCertFilePath(certFileContent, keyFileContent, pkcs12FileContent)
  42. }
  43. func checkCertFilePathOrContent(certFile, keyFile, pkcs12File any) error {
  44. if certFile == nil && keyFile == nil && pkcs12File == nil {
  45. return nil
  46. }
  47. if certFile != nil && keyFile != nil {
  48. files := map[string]any{"certFile": certFile, "keyFile": keyFile}
  49. for varName, v := range files {
  50. switch v := v.(type) {
  51. case string:
  52. if v == gopay.NULL {
  53. return fmt.Errorf("%s is empty", varName)
  54. }
  55. case []byte:
  56. if len(v) == 0 {
  57. return fmt.Errorf("%s is empty", varName)
  58. }
  59. default:
  60. return fmt.Errorf("%s type error", varName)
  61. }
  62. }
  63. return nil
  64. } else if pkcs12File != nil {
  65. switch pkcs12File := pkcs12File.(type) {
  66. case string:
  67. if pkcs12File == gopay.NULL {
  68. return errors.New("pkcs12File is empty")
  69. }
  70. case []byte:
  71. if len(pkcs12File) == 0 {
  72. return errors.New("pkcs12File is empty")
  73. }
  74. default:
  75. return errors.New("pkcs12File type error")
  76. }
  77. return nil
  78. } else {
  79. return errors.New("certFile keyFile must all nil or all not nil")
  80. }
  81. }
  82. // 生成请求XML的Body体
  83. func GenerateXml(bm gopay.BodyMap) (reqXml string) {
  84. bs, err := xml.Marshal(bm)
  85. if err != nil {
  86. return gopay.NULL
  87. }
  88. return string(bs)
  89. }
  90. // 获取QQ支付正式环境Sign值
  91. func GetReleaseSign(apiKey string, signType string, bm gopay.BodyMap) (sign string) {
  92. var h hash.Hash
  93. if signType == SignType_HMAC_SHA256 {
  94. h = hmac.New(sha256.New, []byte(apiKey))
  95. } else {
  96. h = md5.New()
  97. }
  98. h.Write([]byte(bm.EncodeWeChatSignParams(apiKey)))
  99. return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  100. }
  101. func (q *Client) getReleaseSign(apiKey string, signType string, bm gopay.BodyMap) (sign string) {
  102. signParams := bm.EncodeWeChatSignParams(apiKey)
  103. if q.DebugSwitch == gopay.DebugOn {
  104. xlog.Debugf("QQ_Request_SignStr: %s", signParams)
  105. }
  106. var h hash.Hash
  107. if signType == SignType_HMAC_SHA256 {
  108. h = q.sha256Hash
  109. } else {
  110. h = q.md5Hash
  111. }
  112. q.mu.Lock()
  113. defer func() {
  114. h.Reset()
  115. q.mu.Unlock()
  116. }()
  117. h.Write([]byte(signParams))
  118. return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  119. }
  120. func (q *Client) addCertConfig(certFile, keyFile, pkcs12File any) (tlsConfig *tls.Config, err error) {
  121. if certFile == nil && keyFile == nil && pkcs12File == nil {
  122. return nil, errors.New("cert parse failed")
  123. }
  124. var (
  125. certPem, keyPem []byte
  126. certificate tls.Certificate
  127. )
  128. if certFile != nil && keyFile != nil {
  129. if _, ok := certFile.([]byte); ok {
  130. certPem = certFile.([]byte)
  131. } else {
  132. certPem, err = os.ReadFile(certFile.(string))
  133. }
  134. if _, ok := keyFile.([]byte); ok {
  135. keyPem = keyFile.([]byte)
  136. } else {
  137. keyPem, err = os.ReadFile(keyFile.(string))
  138. }
  139. if err != nil {
  140. return nil, fmt.Errorf("os.ReadFile:%w", err)
  141. }
  142. } else if pkcs12File != nil {
  143. var pfxData []byte
  144. if _, ok := pkcs12File.([]byte); ok {
  145. pfxData = pkcs12File.([]byte)
  146. } else {
  147. if pfxData, err = os.ReadFile(pkcs12File.(string)); err != nil {
  148. return nil, fmt.Errorf("os.ReadFile:%w", err)
  149. }
  150. }
  151. blocks, err := pkcs12.ToPEM(pfxData, q.MchId)
  152. if err != nil {
  153. return nil, fmt.Errorf("pkcs12.ToPEM:%w", err)
  154. }
  155. for _, b := range blocks {
  156. keyPem = append(keyPem, pem.EncodeToMemory(b)...)
  157. }
  158. certPem = keyPem
  159. }
  160. if certPem != nil && keyPem != nil {
  161. if certificate, err = tls.X509KeyPair(certPem, keyPem); err != nil {
  162. return nil, fmt.Errorf("tls.LoadX509KeyPair:%w", err)
  163. }
  164. tlsConfig = &tls.Config{
  165. Certificates: []tls.Certificate{certificate},
  166. InsecureSkipVerify: true,
  167. }
  168. return tlsConfig, nil
  169. }
  170. return nil, errors.New("cert files must all nil or all not nil")
  171. }