bugfix:支付
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// testEncodingAESKey 由固定 32 字节密钥生成合法的 43 位 EncodingAESKey。
|
||||
func testEncodingAESKey() string {
|
||||
key := []byte("0123456789abcdef0123456789abcdef")
|
||||
return strings.TrimRight(base64.StdEncoding.EncodeToString(key), "=")
|
||||
}
|
||||
|
||||
// TestSortedSHA1HexOfficialVectors 用官方文档示例校验签名算法:
|
||||
// 参与项按字典序(字节序)排序后拼接,取 sha1 小写 hex。
|
||||
// 官方「安全模式接收 msg_signature」示例中的 Encrypt 是占位符而非真实密文,无法复现,故不纳入。
|
||||
func TestSortedSHA1HexOfficialVectors(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
parts []string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "GET URL 验证 signature",
|
||||
parts: []string{"AAAAA", "1514711492", "1714036504"},
|
||||
want: "f464b24fc39322e44b38aa78f5edd27bd1441696",
|
||||
},
|
||||
{
|
||||
name: "明文模式接收 signature",
|
||||
parts: []string{"AAAAA", "1714037059", "486452656"},
|
||||
want: "899cf89e464efb63f54ddac96b0a0a235f53aa78",
|
||||
},
|
||||
{
|
||||
name: "安全模式回包 MsgSignature",
|
||||
parts: []string{
|
||||
"AAAAA", "1713424427", "415670741",
|
||||
"ELGduP2YcVatjqIS+eZbp80MNLoAUWvzzyJxgGzxZO/5sAvd070Bs6qrLARC9nVHm48Y4hyRbtzve1L32tmxSQ==",
|
||||
},
|
||||
want: "1b9339964ed2e271e7c7b6ff2b0ef902fc94dea1",
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := sortedSHA1Hex(c.parts...); got != c.want {
|
||||
t.Fatalf("%s: got %s, want %s", c.name, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestVirtualPayMsgCryptRoundTrip 校验安全模式加解密闭环:明文 → 加密 → 解密应完全还原,
|
||||
// 且密文中携带的 appid 可被正确切出(用于防伪造校验)。
|
||||
func TestVirtualPayMsgCryptRoundTrip(t *testing.T) {
|
||||
key, err := decodeEncodingAESKey(testEncodingAESKey())
|
||||
if err != nil {
|
||||
t.Fatalf("decodeEncodingAESKey: %v", err)
|
||||
}
|
||||
c := &virtualPayClient{token: "test-token", aesKey: key, appID: "wxfc03c59fc1bb4de5"}
|
||||
|
||||
const plain = `{"ErrCode":0,"ErrMsg":"success"}`
|
||||
encrypt, err := c.encrypt(plain)
|
||||
if err != nil {
|
||||
t.Fatalf("encrypt: %v", err)
|
||||
}
|
||||
msg, appID, err := c.decrypt(encrypt)
|
||||
if err != nil {
|
||||
t.Fatalf("decrypt: %v", err)
|
||||
}
|
||||
if msg != plain {
|
||||
t.Fatalf("round trip msg = %q, want %q", msg, plain)
|
||||
}
|
||||
if appID != c.appID {
|
||||
t.Fatalf("round trip appid = %q, want %q", appID, c.appID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestVirtualPayMsgCryptSignature 校验接收签名:只有 token/timestamp/nonce/encrypt 全对才通过。
|
||||
func TestVirtualPayMsgCryptSignature(t *testing.T) {
|
||||
c := &virtualPayClient{token: "test-token"}
|
||||
const (
|
||||
timestamp = "1714112445"
|
||||
nonce = "415670741"
|
||||
encrypt = "abc123"
|
||||
)
|
||||
good := sortedSHA1Hex(c.token, timestamp, nonce, encrypt)
|
||||
if !c.checkMsgSignature(timestamp, nonce, encrypt, good) {
|
||||
t.Fatal("valid msg_signature should pass")
|
||||
}
|
||||
if c.checkMsgSignature(timestamp, nonce, encrypt, "deadbeef") {
|
||||
t.Fatal("wrong msg_signature should fail")
|
||||
}
|
||||
if c.checkMsgSignature(timestamp, nonce, "tampered", good) {
|
||||
t.Fatal("tampered encrypt should fail")
|
||||
}
|
||||
if c.checkMsgSignature(timestamp, nonce, encrypt, "") {
|
||||
t.Fatal("empty msg_signature should fail")
|
||||
}
|
||||
}
|
||||
|
||||
// TestDecodeEncodingAESKey 校验密钥解码:空值=明文模式,长度非法报错,合法值解出 32 字节。
|
||||
func TestDecodeEncodingAESKey(t *testing.T) {
|
||||
if key, err := decodeEncodingAESKey(""); err != nil || key != nil {
|
||||
t.Fatalf("empty key: key=%v err=%v, want nil/nil", key, err)
|
||||
}
|
||||
if _, err := decodeEncodingAESKey("tooshort"); err == nil {
|
||||
t.Fatal("short key should fail")
|
||||
}
|
||||
key, err := decodeEncodingAESKey(testEncodingAESKey())
|
||||
if err != nil || len(key) != 32 {
|
||||
t.Fatalf("valid key: len=%d err=%v, want 32/nil", len(key), err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestExtractEncryptField 校验安全模式信封解析与 XML 明确提示。
|
||||
func TestExtractEncryptField(t *testing.T) {
|
||||
if _, err := extractEncryptField([]byte(`{"ToUserName":"gh_x","Encrypt":"abc"}`)); err != nil {
|
||||
t.Fatalf("json envelope: %v", err)
|
||||
}
|
||||
if _, err := extractEncryptField([]byte(`{"ToUserName":"gh_x"}`)); err == nil {
|
||||
t.Fatal("missing Encrypt should fail")
|
||||
}
|
||||
if _, err := extractEncryptField([]byte(`<xml><Encrypt>abc</Encrypt></xml>`)); err == nil {
|
||||
t.Fatal("xml envelope should fail with a clear hint")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user