callback.go 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package qiyuesuosdk
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/sha256"
  6. "encoding/base64"
  7. "encoding/hex"
  8. "encoding/json"
  9. "fmt"
  10. )
  11. type callbackMeta struct {
  12. CallbackType string `json:"callbackType"`
  13. CallbackTime string `json:"callbackTime"`
  14. CallbackBizType string `json:"callbackBizType"`
  15. }
  16. // ParseCallback 解密、验签并解析契约锁回调。
  17. func (c *Client) ParseCallback(req CallbackRequest) (CallbackEvent, error) {
  18. plain, err := c.decryptCallback(req.Encrypted, c.cfg.CallbackToken, c.cfg.CallbackAESKey)
  19. if err != nil {
  20. return CallbackEvent{}, err
  21. }
  22. hash := sha256.Sum256([]byte(plain + req.Timestamp + req.Nonce + c.cfg.CallbackToken))
  23. if hex.EncodeToString(hash[:]) != req.Signature {
  24. return CallbackEvent{}, fmt.Errorf("qiyuesuo: callback signature mismatch")
  25. }
  26. return parseCallbackPayload(plain)
  27. }
  28. func parseCallbackPayload(plain string) (CallbackEvent, error) {
  29. raw := []byte(plain)
  30. var meta callbackMeta
  31. if err := json.Unmarshal(raw, &meta); err != nil {
  32. return CallbackEvent{}, err
  33. }
  34. switch EventType(meta.CallbackType) {
  35. case EventCompanyAuthSuccess:
  36. var data CompanyCertificationData
  37. if err := json.Unmarshal(raw, &data); err != nil {
  38. return CallbackEvent{}, err
  39. }
  40. data.CallbackTime = meta.CallbackTime
  41. return CallbackEvent{Type: EventCompanyAuthSuccess, Data: data}, nil
  42. case EventCompanySealAuthSuccess:
  43. var data CompanySealAuthData
  44. if err := json.Unmarshal(raw, &data); err != nil {
  45. return CallbackEvent{}, err
  46. }
  47. data.CallbackTime = meta.CallbackTime
  48. return CallbackEvent{Type: EventCompanySealAuthSuccess, Data: data}, nil
  49. case EventPersonalSealAuthSuccess:
  50. var data PersonalSealAuthData
  51. if err := json.Unmarshal(raw, &data); err != nil {
  52. return CallbackEvent{}, err
  53. }
  54. data.CallbackTime = meta.CallbackTime
  55. return CallbackEvent{Type: EventPersonalSealAuthSuccess, Data: data}, nil
  56. case EventCallbackCheck:
  57. return CallbackEvent{Type: EventCallbackCheck, Data: nil}, nil
  58. default:
  59. return CallbackEvent{}, fmt.Errorf("qiyuesuo: unknown callback type %q", meta.CallbackType)
  60. }
  61. }
  62. func (c *Client) decryptCallback(encrypted, token, aesKey string) (string, error) {
  63. ciphertext, err := base64.StdEncoding.DecodeString(encrypted)
  64. if err != nil {
  65. return "", fmt.Errorf("qiyuesuo: base64 decode: %w", err)
  66. }
  67. key := []byte(aesKey)
  68. if len(key) < 16 {
  69. return "", fmt.Errorf("qiyuesuo: aes key too short")
  70. }
  71. key = key[:16]
  72. block, err := aes.NewCipher(key)
  73. if err != nil {
  74. return "", err
  75. }
  76. ivHash := sha256.Sum256([]byte(token))
  77. iv := ivHash[:aes.BlockSize]
  78. if len(ciphertext)%aes.BlockSize != 0 {
  79. return "", fmt.Errorf("qiyuesuo: invalid ciphertext block size")
  80. }
  81. mode := cipher.NewCBCDecrypter(block, iv)
  82. plain := make([]byte, len(ciphertext))
  83. mode.CryptBlocks(plain, ciphertext)
  84. if len(plain) == 0 {
  85. return "", fmt.Errorf("qiyuesuo: empty plaintext")
  86. }
  87. padding := int(plain[len(plain)-1])
  88. if padding <= 0 || padding > len(plain) {
  89. return "", fmt.Errorf("qiyuesuo: invalid pkcs padding")
  90. }
  91. return string(plain[:len(plain)-padding]), nil
  92. }