110 lines
2.6 KiB
Go
110 lines
2.6 KiB
Go
package pay
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
)
|
|
|
|
type NotifyRequest struct {
|
|
ID string `json:"id"`
|
|
CreateTime string `json:"create_time"`
|
|
EventType string `json:"event_type"`
|
|
ResourceType string `json:"resource_type"`
|
|
Summary string `json:"summary"`
|
|
Resource NotifyResource `json:"resource"`
|
|
}
|
|
|
|
type NotifyResource struct {
|
|
Algorithm string `json:"algorithm"`
|
|
Ciphertext string `json:"ciphertext"`
|
|
AssociatedData string `json:"associated_data"`
|
|
Nonce string `json:"nonce"`
|
|
OriginalType string `json:"original_type"`
|
|
}
|
|
|
|
type TransactionNotify struct {
|
|
AppID string `json:"appid"`
|
|
MchID string `json:"mchid"`
|
|
OutTradeNo string `json:"out_trade_no"`
|
|
TransactionID string `json:"transaction_id"`
|
|
TradeType string `json:"trade_type"`
|
|
TradeState string `json:"trade_state"`
|
|
TradeStateDesc string `json:"trade_state_desc"`
|
|
BankType string `json:"bank_type"`
|
|
Attach string `json:"attach"`
|
|
SuccessTime string `json:"success_time"`
|
|
Payer struct {
|
|
OpenID string `json:"openid"`
|
|
} `json:"payer"`
|
|
Amount struct {
|
|
Total int64 `json:"total"`
|
|
PayerTotal int64 `json:"payer_total"`
|
|
Currency string `json:"currency"`
|
|
PayerCurrency string `json:"payer_currency"`
|
|
} `json:"amount"`
|
|
}
|
|
|
|
func (c *Client) ParseNotify(r *http.Request) (*NotifyRequest, error) {
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := c.validateResponse(r.Header, body); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var notify NotifyRequest
|
|
if err := json.Unmarshal(body, ¬ify); err != nil {
|
|
return nil, err
|
|
}
|
|
return ¬ify, nil
|
|
}
|
|
|
|
func (c *Client) DecryptNotify(notify *NotifyRequest) (*TransactionNotify, error) {
|
|
if c.APIv3Key == "" {
|
|
return nil, fmt.Errorf("apiv3 key is required for notify decryption")
|
|
}
|
|
|
|
plaintext, err := decryptAES256GCM(
|
|
c.APIv3Key,
|
|
notify.Resource.AssociatedData,
|
|
notify.Resource.Nonce,
|
|
notify.Resource.Ciphertext,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var tx TransactionNotify
|
|
if err := json.Unmarshal(plaintext, &tx); err != nil {
|
|
return nil, err
|
|
}
|
|
return &tx, nil
|
|
}
|
|
|
|
func decryptAES256GCM(apiV3Key, associatedData, nonce, ciphertext string) ([]byte, error) {
|
|
key := []byte(apiV3Key)
|
|
cipherBytes, err := base64.StdEncoding.DecodeString(ciphertext)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
gcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return gcm.Open(nil, []byte(nonce), cipherBytes, []byte(associatedData))
|
|
}
|