fix(wechat): don't block init on missing WXP_API_V3_KEY

API v3 key is only needed for callback verification, not payment creation.
- Remove init-time validation (was blocking all wechat payments)
- Gracefully degrade: set api_v3_key=None if invalid, warn at startup
- Raise clear error at callback time if key still missing
This commit is contained in:
yumoqing 2026-07-15 17:40:27 +08:00
parent bf916b98ff
commit 7e37b00672
2 changed files with 13 additions and 7 deletions

View File

@ -65,12 +65,6 @@ def _build_provider_conf(provider_name: str) -> dict:
with open(privkey_path, "rb") as f:
conf["private_key_pem"] = f.read()
del conf["private_key_pem_file"]
# 校验 API v3 密钥AES-256-GCM 需要 32 字节)
api_v3_key = conf.get("api_v3_key", "")
if not api_v3_key or api_v3_key in ("None", "none", ""):
raise ValueError(f"环境变量 WXP_API_V3_KEY 未设置或为占位符: {api_v3_key!r}")
if len(api_v3_key.encode()) != 32:
raise ValueError(f"WXP_API_V3_KEY 长度应为32字节(用于AES-256-GCM), 当前: {len(api_v3_key.encode())}字节")
elif provider_name == "alipay":
priv_path = conf.get("app_private_key_pem_file", "")

View File

@ -29,7 +29,15 @@ class WechatGateway(Gateway):
self.mchid = mchid
self.appid = appid
self.cert_serial_no = cert_serial_no
self.api_v3_key = api_v3_key.encode()
self.api_v3_key = None
try:
key_bytes = api_v3_key.encode()
if len(key_bytes) == 32 and api_v3_key not in ("None", "none", ""):
self.api_v3_key = key_bytes
else:
print(f"[unipay] wechat WXP_API_V3_KEY invalid (len={len(key_bytes)}), callback will be disabled", flush=True)
except Exception:
print(f"[unipay] wechat WXP_API_V3_KEY invalid, callback will be disabled", flush=True)
# 加载私钥
self._private_key = serialization.load_pem_private_key(
@ -86,6 +94,8 @@ class WechatGateway(Gateway):
encrypt_info = cert["encrypt_certificate"]
# 解密平台证书
if self.api_v3_key is None:
raise ValueError("WXP_API_V3_KEY not configured, cannot verify callback")
aesgcm = AESGCM(self.api_v3_key)
pub_pem = aesgcm.decrypt(
nonce=encrypt_info["nonce"].encode(),
@ -130,6 +140,8 @@ class WechatGateway(Gateway):
# 工具:解密 resource.ciphertext
# -----------------------------------------------------
def _decrypt_resource(self, resource: Dict[str, Any]) -> Dict[str, Any]:
if self.api_v3_key is None:
raise ValueError("WXP_API_V3_KEY not configured, cannot decrypt callback")
aesgcm = AESGCM(self.api_v3_key)
plaintext = aesgcm.decrypt(
nonce=resource["nonce"].encode(),