api_certificates_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. package certificates_test
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/rsa"
  6. "crypto/x509"
  7. "fmt"
  8. "io/ioutil"
  9. "net/http"
  10. "reflect"
  11. "strconv"
  12. "strings"
  13. "testing"
  14. "time"
  15. "git.nanodreamtech.com/sg/wechatpay-go/core"
  16. "git.nanodreamtech.com/sg/wechatpay-go/core/consts"
  17. "git.nanodreamtech.com/sg/wechatpay-go/core/option"
  18. "git.nanodreamtech.com/sg/wechatpay-go/services/certificates"
  19. "git.nanodreamtech.com/sg/wechatpay-go/utils"
  20. "github.com/agiledragon/gomonkey"
  21. "github.com/stretchr/testify/assert"
  22. "github.com/stretchr/testify/require"
  23. )
  24. const (
  25. mockWechatPayPrivateKeyStr = `-----BEGIN TESTING KEY-----
  26. MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZUJN33V+dSfvd
  27. fL0Mu+39XrZNXFFMQSy1V15FpncHeV47SmV0TzTqZc7hHB0ddqAdDi8Z5k3TKqb7
  28. 6sOwYr5TcAfuR6PIPaleyE0/0KrljBum2Isa2Nyq7Dgc3ElBQ6YN4l/a+DpvKaz1
  29. FSKmKrhLNskqokWVSlu4g8OlKlbPXQ9ibII14MZRQrrkTmHYHzfi7GXXM0thAKuR
  30. 0HNvyhTHBh4/lrYM3GaMvmWwkwvsMavnOex6+eioZHBOb1/EIZ/LzC6zuHArPpyW
  31. 3daGaZ1rtQB1vVzTyERAVVFsXXgBHvfFud3w3ShsJYk8JvMwK2RpJ5/gV0QSARcm
  32. LDRUAlPzAgMBAAECggEBAMc7rDeUaXiWv6bMGbZ3BTXpg1FhdddnWUnYE8HfX/km
  33. OFI7XtBHXcgYFpcjYz4D5787pcsk7ezPidAj58zqenuclmjKnUmT3pfbI5eCA2v4
  34. C9HnbYDrmUPK1ZcADtka4D6ScDccpNYNa1g2TFHzkIrEa6H+q7S3O2fqxY/DRVtN
  35. 0JIXalBb8daaqL5QVzSmM2BMVnHy+YITJWIkP2a3pKs9C0W65JGDsnG0wVrHinHF
  36. +cnhFZIbaPEI//DAFMc9NkrWOKVRTEgcCUxCFaHOZVNxDWZD7A2ZfJB2rK6eg//y
  37. gEiFDR2h6mTaDowMB4YF2n2dsIO4/dCG8vPHI20jn4ECgYEA/ZGu6lEMlO0XZnam
  38. AZGtiNgLcCfM/C2ZERZE7QTRPZH1WdK92Al9ndldsswFw4baJrJLCmghjF/iG4zi
  39. hhBvLnOLksnZUfjdumxoHDWXo2QBWbI5QsWIE7AuTiWgWj1I7X4fCXSQf6i+M/y2
  40. 6TogQ7d0ANpZFyOkTNMn/tiJvLECgYEA22XqlamG/yfAGWery5KNH2DGlTIyd6xJ
  41. WtJ9j3jU99lZ0bCQ5xhiBbU9ImxCi3zgTsoqLWgA/p00HhNFNoUcTl9ofc0G3zwT
  42. D1y0ZzcnVKxGJdZ6ohW52V0hJStAigtjYAsUgjm7//FH7PiQDBDP1Wa6xSRkDQU/
  43. aSbQxvEE8+MCgYEA3bb8krW7opyM0XL9RHH0oqsFlVO30Oit5lrqebS0oHl3Zsr2
  44. ZGgoBlWBsEzk3UqUhTFwm/DhJLTSJ/TQPRkxnhQ5/mewNhS9C7yua7wQkzVmWN+V
  45. YeUGTvDGDF6qDz12/vJAgSwDDRym8x4NcXD5tTw7mmNRcwIfL22SkysThIECgYAV
  46. BgccoEoXWS/HP2/u6fQr9ZIR6eV8Ij5FPbZacTG3LlS1Cz5XZra95UgebFFUHHtC
  47. EY1JHJY7z8SWvTH8r3Su7eWNaIAoFBGffzqqSVazfm6aYZsOvRY6BfqPHT3p/H1h
  48. Tq6AbBffxrcltgvXnCTORjHPglU0CjSxVs7awW3AEQKBgB5WtaC8VLROM7rkfVIq
  49. +RXqE5vtJfa3e3N7W3RqxKp4zHFAPfr82FK5CX2bppEaxY7SEZVvVInKDc5gKdG/
  50. jWNRBmvvftZhY59PILHO2X5vO4FXh7suEjy6VIh0gsnK36mmRboYIBGsNuDHjXLe
  51. BDa+8mDLkWu5nHEhOxy2JJZl
  52. -----END TESTING KEY-----`
  53. mockWechatPayCertificateStr = `-----BEGIN CERTIFICATE-----
  54. MIIDVzCCAj+gAwIBAgIJANfOWdH1ItcBMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV
  55. BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
  56. Q29tcGFueSBMdGQwHhcNMjEwNDI3MDg1NTIzWhcNMzEwNDI1MDg1NTIzWjBCMQsw
  57. CQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZh
  58. dWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
  59. 2VCTd91fnUn73Xy9DLvt/V62TVxRTEEstVdeRaZ3B3leO0pldE806mXO4RwdHXag
  60. HQ4vGeZN0yqm++rDsGK+U3AH7kejyD2pXshNP9Cq5YwbptiLGtjcquw4HNxJQUOm
  61. DeJf2vg6byms9RUipiq4SzbJKqJFlUpbuIPDpSpWz10PYmyCNeDGUUK65E5h2B83
  62. 4uxl1zNLYQCrkdBzb8oUxwYeP5a2DNxmjL5lsJML7DGr5znsevnoqGRwTm9fxCGf
  63. y8wus7hwKz6clt3Whmmda7UAdb1c08hEQFVRbF14AR73xbnd8N0obCWJPCbzMCtk
  64. aSef4FdEEgEXJiw0VAJT8wIDAQABo1AwTjAdBgNVHQ4EFgQUT1c7nd/SUO76HSoZ
  65. umNUJv1R5PwwHwYDVR0jBBgwFoAUT1c7nd/SUO76HSoZumNUJv1R5PwwDAYDVR0T
  66. BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAfTjxKRQMzNB/U6ZoCUS+BSNfa2Oh
  67. 0plMN6ZuzwiVVZwg1jywvv5yv04koS7Pd4i9E4gt9ZBUQXlpq+A3oOCEEHNRR6b2
  68. kyazGRM7s0OP5X21WrbpSmKmU6K7hkfx30yYs08LVs/Q8DIhvaj1FCFeJzUCzYn/
  69. fHMq4tsbKO0dKAeydPM/nrUZBmaYQVKMVOORGLFjFKVO7JV6Kq/R86ouhjEPgJOe
  70. 2xulNBUcjicqtZlBdEh/PWCYP2SpGVDclKm8jeo175T3EVAkdKzzmfpxtMmnMlmq
  71. cTJOU9TxuGvNASMtjj7pYIerTx+xgZDXEVBWFW9PjJ0TV06tCRsgSHItgg==
  72. -----END CERTIFICATE-----`
  73. mockAPIv3Key = "mockAPIv3Key1234"
  74. mockMchID = "1234567890"
  75. mockMchCertificateSerial = "BE6DCDA7A5931FA0"
  76. mockMchPrivateKey = `-----BEGIN TESTING KEY-----
  77. MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/KuDQhHMw9Rkv
  78. IUvXrBgCNTqhWAxdu1O4pdSzeaJJYeUQPPP3KLlm6jjvjZg8nOS2zv0hZRGHNviS
  79. Am70+HKsRlZThbB6Kz08c/jPN01CoLJ1bLGFEX4tvcmalM5RGyRZrhXYSWtO/aDr
  80. ezC1HRTRrKCvGq0utVb8wJz3NykX2U5PN3g7VliADFJvAjcLH9ctNwl/DU6+uNVd
  81. 3ch/REZIhM/8K3UKYULTBpg3Hx2oKmFdRfay5Fy7Q1snrz3ziIciNKfynu6dWQ0R
  82. f2pvkulTLASDDbQD2k1z/oStV29O/VcnYTuwVhQmOM0v8v6jWNhnqxzlMG8QY4uR
  83. K2UrmvIpAgMBAAECggEBAJmmWgne20MXTMWfynivnqBvrg8uWMohnZoE15/lfLXk
  84. lBroEuKt/c6lJVwNf7YAGKiCV9w2gs8eNM4OXKZS5sBmzE3XX0/iXxau0+WhOlz6
  85. ElXlJg2hULxtFZREVEvGOAJItNAhurlDi8qZOj3oAOrCCGiVVWr8X81I9yCQWlwK
  86. a46UoWixU8E0W4jFFt4AFLbrMPa+7TsKr9gilYcwcNHvKDqYhuqKdGRmO+QtKlPw
  87. 4AdlfhwUh1L+TCUcDVb6Zcby+HWUpcx7hBcKRd8sLxPeWcS8imeR8OlVO/8bRJYD
  88. WhFlBRqvIuJqycW5/v01ka3zRe1yO/bl+sxJ6QHPrA0CgYEA+/7+97lmNeKIfFYS
  89. 4JD8jiAZeCl9C6CZFj3gCpXE3ChT9wGsHdkw2QZRZkKYDFMhF7KVtiijvexSeWaB
  90. uXelk+3yHhmVUC8DH1aXh2CXGgJhhxE08YzBtFp7oqn8dd2SXQAf37FGjjlhCcnw
  91. JqgE212qdFzY1nrTCjS6ymTdv5sCgYEAwjR1pAXW5mR/PXMH/8i+Wr3ZeZawHByN
  92. /H4wtw5F/mR7xzJup1y6XA0q7BEH+zp5ts0nKzOwIr6uZsBJl2xUuntD/pZCwsN+
  93. 6P+mC1JGWKYhXTZ8PASVU834wqUjaCDBxXZqFqkIZAnjQZhpC7meSJ1ANAt6f5zq
  94. /DhoyI8My4sCgYAkxkW3KRs9ad25J2aB1ybEJvMQkh1pgPpWQJldchXUex4lwdy4
  95. TmXOhhmC7tz5j3gY2Tr35l5e7QnsJYVw54EGYYcf1WPw26t8+0oJu5LRfN92spAj
  96. YAM0qq+4QU5SdQ9S+x2rq1c8kisTHqEpQwPSb4zchmAujKYXqzJHLwkdWQKBgCV9
  97. EPR/uBMzdSh8ix/CNZS4r0F8aDSVAoeqKGc91x8bcJVsU9X03XilhhKZ2wuRJyu1
  98. gIkjai3a1zm4hrw3SkfRQbfkc7C7IkWCDCCFWlUEhM5ElUjUrarGyO1yCVqxcBZZ
  99. HHORX7BIBFmGPUjpJPfpexpQ2O3HcckMbpXAn3yvAoGAPxQSNSa8JKGgdD8pZQIC
  100. eQU9Br/ZPXtI1EZdxfMwdwFov+6DtPaq5kt01wACK9ozTHONLFH3diW+HIl+49r6
  101. 0q+pf03FucCa+chixggyeyvV5Zi2KrV5CRH+tRVDy75Erf6YgjTzoXrPfZZ1FIzM
  102. wvAZNrxhvtBilUC8adsqhSY=
  103. -----END TESTING KEY-----`
  104. mockNonce = "mockNonce1234"
  105. data = "{\"data\":[{\"effective_time\":\"2021-04-27T16:55:23+08:00\",\"encrypt_certificate\":{" +
  106. "\"algorithm\":\"AEAD_AES_256_GCM\"," +
  107. "\"associated_data\":\"certificate\"," +
  108. "\"ciphertext\":\"QHBP2NGCmcEhGWa1f+t5AeImEdkS+XyUx1nB50LLGTgfDdb+EELcl9/GRJR0m9SFcTSlsS67QKemf2DuvPGTFEn" +
  109. "EIhZ/I26zym7Ift1YJt7ftiVqoU4lv9aopCWD7IrzQBLT7XeYKh0CFHj0fUeqnNrGC+3EMj+NHbDY6zGfW4SfhvzLxO6tvpQ3xbFyT2C" +
  110. "gxHmiKiVTxkewiSDuaimy3X/SN/Nq901lhEtqBVMFyFOyT1MvTL0RUWpU+l4Wdyz9xGTrrv0pd7regqfXwklx+Y94ULUd7lhSyb77h9j" +
  111. "8golVvxYUwrUrxWj5ri6APPd8qedWuxkBjOPUAho/q1ETpjYJqK0eXuVWf5EPBS63jvqEE4IfopXOwltPLEME++6u7H4qjhAfzdUvfLQ" +
  112. "awUe/zPPwWS5GOWRxov7qnuK3aV0+ybZM33hmPwP5LsPNQlDdaQxcNgqbnmpVWjxCPdiiZ52z19AxcB4Ry9LN5IBAEbTnm9WnCp4cOqN" +
  113. "OXBr2/l+FRLSqZnNTIFbOzXWKw5AngHbciLEvTYEsFNpT/u1SBCU2xQ3Y+Q8OHIn6kmE3AO/gUmXjciLv05ZGo+DCAnqGOVdr2yCLv2j" +
  114. "maBSIcrComs1WzliuNfFJ5+On7i+rOAbKMaZLdTcB//Lpa4mfkhULhslQYUT5H4XbQqsi5IPGplYvvNh2+ktahI6lYWnCprFeFthyEfy" +
  115. "LNc9MGtsO1rdsZqoI6ed+KLzMJDOGAhgEQqSJIOzz546/pyn5DnINlxjMSpq6+Zdan+iuiz3Un2idaLf6iPSx1FtdNPi94EjlI+bQSEi" +
  116. "hKKm4Em2xVgauajO3mK6+JTPNQMVrbtEV9wIGHvPLVm6Uw3OAuLWL0UCn3P6wuxF7+4X+S8s1EKN/3q/w++U93NKdfnpOKe7Vxg7Pg3f" +
  117. "96WQzJTvRJ7C1Xm4W7GvS09hGjCNGCvbcGXla14X/Y35o6Uf37NlnmnDe2rdcnmYsXE5qooS0ThLdOKdKNybg+ih9iFPcxdTJ67WfvVP" +
  118. "vaOhLrRm8cDgTYjfVYAj7lxztRYnZE65PTeWUE/mLZTd52g3WEE8ty79KLcqnzARGq7sjdptcZQ4Vw11hHA3PbrxQdyvuyXbONZzjrMR" +
  119. "0RsOmJPfyQTYPQuh6xdbcLP8bQiibREl+iOop0PLYRu9GtQ+r2uEI4VIuuNW1DwFzJRkWdxPm8kjC+g7XLDWqBYImFfep9Dfxj6Jam/w" +
  120. "ILKWVg3JjfuZe6nTwK7xqwDsY4Ylj8rnjnf+Cw3XQh94IU2E3uq3wqhoR1NCM7Qky+a6JIMGCALiqlj2DMnUgPKWEwFJ7bigRCdC+0s+" +
  121. "QQaeIEQ04Rm8jeuHaNvEsfloqLNrWx0D3ZHeIKB6hEegNnpSllfPJ/lF1U3ZnhMYd6oUef5HuV4wcu4oPf0nCEBi/CGlyRhmRKaondms" +
  122. "puRv5C4/zqQrqaVfJrkL0XO6EnhaxI0Yh6t5piA6vw73LtNH5fI55d1S2KWu0zUVbfyijzFohSfVZ5Zryo8uSggAgE96O+jiYzXfuS0d" +
  123. "vCVhXW/lw0ekQnKMx0Xh6U7XIckIvLgb4QQ6Oqv4/GZBo4dV7s78pNj/KvcCI6ya6qfrWgy1+pWmOLO+wcTmfzYOae4IyZnmuDXwyPng=\"," +
  124. "\"nonce\":\"3a584b49ed9b\"}," +
  125. "\"expire_time\":\"2031-04-25T16:55:23+08:00\",\"serial_no\":\"D7CE59D1F522D701\"}]}"
  126. )
  127. func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
  128. var mockWechatPayPrivateKey *rsa.PrivateKey
  129. var mockWechatPayCertificate *x509.Certificate
  130. func init() {
  131. var err error
  132. if mockWechatPayPrivateKey, err = utils.LoadPrivateKey(testingKey(mockWechatPayPrivateKeyStr)); err != nil {
  133. panic("mockWechatPayPrivateKeyStr is invalid")
  134. }
  135. if mockWechatPayCertificate, err = utils.LoadCertificate(mockWechatPayCertificateStr); err != nil {
  136. panic("mockWechatPayCertificateStr is invalid")
  137. }
  138. }
  139. func mockDownloadServer(t *testing.T) *gomonkey.Patches {
  140. patches := gomonkey.NewPatches()
  141. patches.ApplyMethod(
  142. reflect.TypeOf(&http.Client{}), "Do", func(_ *http.Client, req *http.Request) (*http.Response, error) {
  143. resp := http.Response{
  144. Status: "200 OK",
  145. StatusCode: 200,
  146. Proto: "HTTP/1.1",
  147. ProtoMajor: 1,
  148. ProtoMinor: 1,
  149. Header: http.Header{},
  150. Body: ioutil.NopCloser(bytes.NewBufferString(data)),
  151. ContentLength: int64(len(data)),
  152. Request: req,
  153. }
  154. resp.Header.Set(consts.ContentLength, strconv.Itoa(len(data)))
  155. resp.Header.Set(consts.ContentType, "application/json; charset=utf-8")
  156. resp.Header.Set(consts.RequestID, "mock-request-id")
  157. resp.Header.Set(consts.WechatPaySerial, utils.GetCertificateSerialNumber(*mockWechatPayCertificate))
  158. resp.Header.Set(consts.WechatPayNonce, mockNonce)
  159. timestamp := strconv.FormatInt(time.Now().Unix(), 10)
  160. resp.Header.Set(consts.WechatPayTimestamp, timestamp)
  161. signature, err := utils.SignSHA256WithRSA(
  162. fmt.Sprintf("%s\n%s\n%s\n", timestamp, mockNonce, data), mockWechatPayPrivateKey,
  163. )
  164. require.NoError(t, err)
  165. resp.Header.Set(consts.WechatPaySignature, signature)
  166. return &resp, nil
  167. },
  168. )
  169. return patches
  170. }
  171. func TestCertificatesApiService_DownloadCertificates_WithoutValidator(t *testing.T) {
  172. patches := mockDownloadServer(t)
  173. defer patches.Reset()
  174. ctx := context.Background()
  175. privateKey, err := utils.LoadPrivateKey(testingKey(mockMchPrivateKey))
  176. require.NoError(t, err)
  177. opts := []core.ClientOption{
  178. option.WithMerchantCredential(mockMchID, mockMchCertificateSerial, privateKey),
  179. option.WithoutValidator(),
  180. }
  181. client, err := core.NewClient(ctx, opts...)
  182. require.NoError(t, err)
  183. svc := certificates.CertificatesApiService{Client: client}
  184. resp, result, err := svc.DownloadCertificates(ctx)
  185. require.NoError(t, err)
  186. assert.Nil(t, result.Request.Body)
  187. require.Len(t, resp.Data, 1)
  188. assert.Equal(t, "D7CE59D1F522D701", *resp.Data[0].SerialNo)
  189. assert.Equal(t, "AEAD_AES_256_GCM", *resp.Data[0].EncryptCertificate.Algorithm)
  190. assert.Equal(t, "certificate", *resp.Data[0].EncryptCertificate.AssociatedData)
  191. assert.Equal(t, "3a584b49ed9b", *resp.Data[0].EncryptCertificate.Nonce)
  192. effectiveTime, err := time.Parse(time.RFC3339, "2021-04-27T16:55:23+08:00")
  193. require.NoError(t, err)
  194. assert.Equal(t, effectiveTime, *resp.Data[0].EffectiveTime)
  195. expireTime, err := time.Parse(time.RFC3339, "2031-04-25T16:55:23+08:00")
  196. require.NoError(t, err)
  197. assert.Equal(t, expireTime, *resp.Data[0].ExpireTime)
  198. }
  199. func TestCertificatesApiService_DownloadCertificates_WithValidator(t *testing.T) {
  200. patches := mockDownloadServer(t)
  201. defer patches.Reset()
  202. ctx := context.Background()
  203. privateKey, err := utils.LoadPrivateKey(testingKey(mockMchPrivateKey))
  204. require.NoError(t, err)
  205. wechatPayCert, err := utils.LoadCertificate(mockWechatPayCertificateStr)
  206. require.NoError(t, err)
  207. opts := []core.ClientOption{
  208. option.WithMerchantCredential(mockMchID, mockMchCertificateSerial, privateKey),
  209. option.WithWechatPayCertificate([]*x509.Certificate{wechatPayCert}),
  210. }
  211. client, err := core.NewClient(ctx, opts...)
  212. require.NoError(t, err)
  213. svc := certificates.CertificatesApiService{Client: client}
  214. resp, result, err := svc.DownloadCertificates(ctx)
  215. require.NoError(t, err)
  216. assert.Nil(t, result.Request.Body)
  217. require.Len(t, resp.Data, 1)
  218. assert.Equal(t, "D7CE59D1F522D701", *resp.Data[0].SerialNo)
  219. assert.Equal(t, "AEAD_AES_256_GCM", *resp.Data[0].EncryptCertificate.Algorithm)
  220. assert.Equal(t, "certificate", *resp.Data[0].EncryptCertificate.AssociatedData)
  221. assert.Equal(t, "3a584b49ed9b", *resp.Data[0].EncryptCertificate.Nonce)
  222. effectiveTime, err := time.Parse(time.RFC3339, "2021-04-27T16:55:23+08:00")
  223. require.NoError(t, err)
  224. assert.Equal(t, effectiveTime, *resp.Data[0].EffectiveTime)
  225. expireTime, err := time.Parse(time.RFC3339, "2031-04-25T16:55:23+08:00")
  226. require.NoError(t, err)
  227. assert.Equal(t, expireTime, *resp.Data[0].ExpireTime)
  228. }