强化支付协议校验与证据保护

This commit is contained in:
yml2213
2026-08-12 23:54:14 +08:00
parent 74a85c8328
commit 99520d9b9b
6 changed files with 292 additions and 143 deletions
@@ -16,6 +16,8 @@ sys.modules[_SPEC.name] = _MODULE
_SPEC.loader.exec_module(_MODULE)
from pyvm.payment_errors import describe_payment_failure
from pyvm.algorithm import derive_key1_from_key16, generate_encrypt_msg_offline
from pyvm.protocol import goods_material_diagnostics, validate_goods_materials
class TestJsdomPay(unittest.TestCase):
@@ -100,6 +102,54 @@ class TestJsdomPay(unittest.TestCase):
self.assertEqual(len(rand_value), 9)
self.assertEqual(rand_value[-1], "\x01")
def test_goods_protocol_template_is_compatible(self):
template = _MODULE.load_template_args()
validate_goods_materials(template, [0] * 59640)
diagnostics = goods_material_diagnostics(_MODULE.ROOT, template, [0] * 59640)
self.assertEqual(diagnostics["goods_xmidas_ops_length"], 59640)
self.assertEqual(diagnostics["args_template_slots"], 18)
self.assertEqual(len(diagnostics["bytecode_sha256_prefix"]), 12)
def test_private_evidence_writer_restricts_permissions(self):
import tempfile
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / "evidence.json"
_MODULE.write_private_text(path, "sensitive")
self.assertEqual(path.read_text(encoding="utf-8"), "sensitive")
self.assertEqual(path.stat().st_mode & 0o777, 0o600)
def test_goods_vm_generates_expected_full_length_ciphertext(self):
"""528B 明文应走完 33 个块,输出 1056 个 hex 字符。"""
import json
template = _MODULE.load_template_args()
xmidas = json.loads((_MODULE.ROOT / "replay" / "xmidasops.json").read_text(encoding="utf-8"))
params = {
"token_id": "token", "openid": "openid", "openkey": "key", "session_id": "openid",
"session_type": "kp_accesstoken", "zoneid": "1", "pay_method": "wechat",
"buy_quantity": "1", "mb_pwd": "", "pay_id": "", "auth_key": "", "card_value": "",
"accounttype": "", "provide_uin": "", "extend": "", "from_h5": "1",
"webversion": "minipayv2",
}
timestamp = "1775990000"
fk_extend = "tdrc_session%3Dpay-test"
for length in range(512):
params["extend"] = "x" * length
rand_value = _MODULE.make_encrypt_rand(params, fk_extend, timestamp, True)
plaintext = _MODULE.build_plaintext(params, fk_extend, timestamp, rand_value)
if len(plaintext.encode("latin-1")) == 528:
break
else:
self.fail("无法构造 528B goods 测试明文")
key16 = list(range(16))
key1 = derive_key1_from_key16(key16, [template[i][0] for i in (1, 2, 3, 4)], template[5][0])
ciphertext = generate_encrypt_msg_offline(
params, fk_extend, timestamp, rand_value, key16=key16, key1=key1,
args_template=template, xmidas=xmidas, xmidas_token="A" * 96,
)
self.assertEqual(len(ciphertext), 1056)
if __name__ == "__main__":
unittest.main()