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(`abc`)); err == nil { t.Fatal("xml envelope should fail with a clear hint") } }