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
107 lines
2.8 KiB
Go
107 lines
2.8 KiB
Go
package payment
|
||
|
||
import (
|
||
"backend/internal/secretbox"
|
||
"crypto/sha256"
|
||
"encoding/hex"
|
||
"strings"
|
||
)
|
||
|
||
// 支付配置敏感字段的加密出口:统一走项目级信封加密(internal/secretbox,AES-256-GCM)。
|
||
//
|
||
// 这样全站只有一把主密钥(环境变量 OPSLIC_MASTER_KEY,启动时 fail-fast 装载),
|
||
// 支付配置不再自带第二套密钥体系:微信 APIv3 密钥、支付宝应用私钥/公钥
|
||
// 与 Waffo 私钥、节点 shared_key 共用同一套密文格式(enc:v1: 前缀)。 // Logan.Li
|
||
|
||
const (
|
||
// EnvPaymentMasterKey 主密钥环境变量名(与 secretbox 一致,保留常量供文档/提示引用) // Logan.Li
|
||
EnvPaymentMasterKey = "OPSLIC_MASTER_KEY"
|
||
)
|
||
|
||
// PaymentMasterKeyOrigin 返回加密主密钥来源,供后台页面提示 // Logan.Li
|
||
func PaymentMasterKeyOrigin() string {
|
||
if secretbox.Ready() {
|
||
return "env"
|
||
}
|
||
return "none"
|
||
}
|
||
|
||
// EncryptSecret 加密敏感字段;空串直接返回空串 // Logan.Li
|
||
func EncryptSecret(plain string) (string, error) {
|
||
if strings.TrimSpace(plain) == "" {
|
||
return "", nil
|
||
}
|
||
return secretbox.Encrypt(plain)
|
||
}
|
||
|
||
// DecryptSecret 解密敏感字段;无前缀视为历史明文直接返回 // Logan.Li
|
||
func DecryptSecret(stored string) (string, error) {
|
||
raw := strings.TrimSpace(stored)
|
||
if raw == "" {
|
||
return "", nil
|
||
}
|
||
return secretbox.Decrypt(raw)
|
||
}
|
||
|
||
// MaskTail 脱敏展示:仅保留末尾 keep 位,其余用掩码填充到 total 位 // Logan.Li
|
||
func MaskTail(secret string, keep, total int) string {
|
||
s := strings.TrimSpace(secret)
|
||
if s == "" {
|
||
return ""
|
||
}
|
||
if total <= 0 {
|
||
total = len(s)
|
||
}
|
||
if total < keep {
|
||
total = keep
|
||
}
|
||
if len(s) <= keep {
|
||
return strings.Repeat("•", total-len(s)) + s
|
||
}
|
||
return strings.Repeat("•", total-keep) + s[len(s)-keep:]
|
||
}
|
||
|
||
// FingerprintSHA256 计算内容指纹,用于「已配置但不回显」字段 // Logan.Li
|
||
func FingerprintSHA256(data []byte) string {
|
||
if len(data) == 0 {
|
||
return ""
|
||
}
|
||
sum := sha256.Sum256(data)
|
||
return hex.EncodeToString(sum[:])
|
||
}
|
||
|
||
// ShortFingerprint 指纹取前 16 位做展示 // Logan.Li
|
||
func ShortFingerprint(fp string) string {
|
||
if len(fp) <= 16 {
|
||
return fp
|
||
}
|
||
return fp[:16]
|
||
}
|
||
|
||
// NormalizePEM 把可能是裸 base64 的密钥补全成 PEM 块 // Logan.Li
|
||
func NormalizePEM(raw, begin, end string) string {
|
||
s := strings.TrimSpace(raw)
|
||
if s == "" {
|
||
return ""
|
||
}
|
||
// 已含 PEM 头则原样(统一换行)
|
||
if strings.Contains(s, "-----BEGIN") {
|
||
return strings.ReplaceAll(s, "\r\n", "\n")
|
||
}
|
||
body := strings.Join(strings.Fields(s), "")
|
||
var b strings.Builder
|
||
b.WriteString(begin)
|
||
b.WriteString("\n")
|
||
for i := 0; i < len(body); i += 64 {
|
||
j := i + 64
|
||
if j > len(body) {
|
||
j = len(body)
|
||
}
|
||
b.WriteString(body[i:j])
|
||
b.WriteString("\n")
|
||
}
|
||
b.WriteString(end)
|
||
b.WriteString("\n")
|
||
return b.String()
|
||
}
|