CI / backend (push) Canceled after 0s
- 丢弃支付模块自带的 PAYMENT_SECRET_KEY/JWT_SECRET 派生双密钥体系, EncryptSecret/DecryptSecret 直接走 internal/secretbox(OPSLIC_MASTER_KEY) - 全站只有一把主密钥:Waffo 私钥、节点 shared_key、支付 APIv3 密钥/应用私钥同格式同前缀 - 测试改由 TestMain 装载 secretbox 主密钥,密文前缀统一引用 secretbox.Prefix - .env.example 移除 PAYMENT_SECRET_KEY,改为说明复用 OPSLIC_MASTER_KEY
115 lines
3.4 KiB
Go
115 lines
3.4 KiB
Go
package payment
|
||
|
||
import (
|
||
"backend/internal/secretbox"
|
||
"os"
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
// TestMain 固定测试用加密主密钥并装载信封加密(全站共用 OPSLIC_MASTER_KEY) // Logan.Li
|
||
func TestMain(m *testing.M) {
|
||
os.Setenv(EnvPaymentMasterKey, "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||
os.Setenv("PAYMENT_CERT_DIR", os.TempDir()+"/opsx-licence-test-certs")
|
||
if err := secretbox.LoadMasterKey(); err != nil {
|
||
panic(err)
|
||
}
|
||
os.Exit(m.Run())
|
||
}
|
||
|
||
// TestEncryptDecryptRoundTrip 验证 AES-GCM 加解密与密文格式 // Logan.Li
|
||
func TestEncryptDecryptRoundTrip(t *testing.T) {
|
||
plain := "wx-api-v3-key-32-bytes-example!!"
|
||
enc, err := EncryptSecret(plain)
|
||
if err != nil {
|
||
t.Fatalf("加密失败: %v", err)
|
||
}
|
||
if !strings.HasPrefix(enc, secretbox.Prefix) {
|
||
t.Fatalf("密文缺少前缀: %s", enc)
|
||
}
|
||
if strings.Contains(enc, plain) {
|
||
t.Fatalf("密文中出现了明文")
|
||
}
|
||
got, err := DecryptSecret(enc)
|
||
if err != nil {
|
||
t.Fatalf("解密失败: %v", err)
|
||
}
|
||
if got != plain {
|
||
t.Fatalf("解密结果不一致: %q", got)
|
||
}
|
||
|
||
// 同一明文两次加密应产生不同密文(随机 nonce) // Logan.Li
|
||
enc2, _ := EncryptSecret(plain)
|
||
if enc == enc2 {
|
||
t.Fatalf("两次加密结果相同,nonce 未随机化")
|
||
}
|
||
}
|
||
|
||
// TestEncryptSecretEmpty 空值不应产生密文 // Logan.Li
|
||
func TestEncryptSecretEmpty(t *testing.T) {
|
||
enc, err := EncryptSecret(" ")
|
||
if err != nil || enc != "" {
|
||
t.Fatalf("空值加密应返回空串,得到 %q err=%v", enc, err)
|
||
}
|
||
if v, err := DecryptSecret(""); err != nil || v != "" {
|
||
t.Fatalf("空密文应返回空串,得到 %q err=%v", v, err)
|
||
}
|
||
}
|
||
|
||
// TestDecryptTampered 篡改密文必须解密失败 // Logan.Li
|
||
func TestDecryptTampered(t *testing.T) {
|
||
enc, _ := EncryptSecret("secret-value")
|
||
tampered := enc[:len(enc)-4] + "AAAA"
|
||
if _, err := DecryptSecret(tampered); err == nil {
|
||
t.Fatalf("篡改后的密文不应解密成功")
|
||
}
|
||
}
|
||
|
||
// TestMaskTail 脱敏仅保留末位 // Logan.Li
|
||
func TestMaskTail(t *testing.T) {
|
||
masked := MaskTail("0123456789abcdef0123456789abcdef", 4, 32)
|
||
if !strings.HasSuffix(masked, "cdef") {
|
||
t.Fatalf("脱敏结果应保留后 4 位: %s", masked)
|
||
}
|
||
if len([]rune(masked)) != 32 {
|
||
t.Fatalf("脱敏长度应为 32: %d", len([]rune(masked)))
|
||
}
|
||
if MaskTail("", 4, 32) != "" {
|
||
t.Fatalf("空值脱敏应为空串")
|
||
}
|
||
}
|
||
|
||
// TestPayMethods 支付方式校验/去重与展示解析 // Logan.Li
|
||
func TestPayMethods(t *testing.T) {
|
||
got, err := normalizePayMethods([]string{"native", " h5 ", "native", "JSAPI"})
|
||
if err != nil {
|
||
t.Fatalf("合法支付方式不应报错: %v", err)
|
||
}
|
||
want := []string{"native", "h5", "jsapi"}
|
||
if len(got) != len(want) {
|
||
t.Fatalf("解析结果数量不符: %v", got)
|
||
}
|
||
for i := range want {
|
||
if got[i] != want[i] {
|
||
t.Fatalf("解析结果不符: %v", got)
|
||
}
|
||
}
|
||
if _, err := normalizePayMethods([]string{"alipay"}); err == nil {
|
||
t.Fatalf("非法支付方式应报错")
|
||
}
|
||
if _, err := normalizePayMethods(nil); err == nil {
|
||
t.Fatalf("空支付方式应报错")
|
||
}
|
||
if def := splitPayMethods(""); len(def) != 1 || def[0] != "native" {
|
||
t.Fatalf("空串展示应回退 native: %v", def)
|
||
}
|
||
}
|
||
|
||
// TestNormalizePEM 裸 base64 自动补 PEM 头 // Logan.Li
|
||
func TestNormalizePEM(t *testing.T) {
|
||
out := NormalizePEM("QUJDREVGRw==", "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----")
|
||
if !strings.HasPrefix(out, "-----BEGIN PUBLIC KEY-----") || !strings.Contains(out, "QUJDREVGRw==") {
|
||
t.Fatalf("PEM 补全失败: %s", out)
|
||
}
|
||
}
|