This commit is contained in:
wanghu
2026-09-02 09:38:45 +08:00
commit 8774b6cc44
128 changed files with 9382 additions and 0 deletions
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
"""生成 sign-vectors.json 契约基线(Python hmac 独立实现,与 Java SignUtil / C# SignUtil 对拍)。
规则(与 Java yh-utils-core SignUtil 一致):
- 数据级: source = data + "|" + ts, HmacSHA256(secret), 输出小写 hex
- 请求级: source = METHOD + "\n" + canonicalTarget + "\n" + ts, HmacSHA256(secret), 输出 Base64
约束: secret 长度 >= 16
"""
import base64
import hashlib
import hmac
import json
def data_sign(data, ts, secret):
return hmac.new(secret.encode("utf-8"), (data + "|" + ts).encode("utf-8"), hashlib.sha256).hexdigest()
def request_sign(method, target, ts, secret):
source = method + "\n" + target + "\n" + ts
return base64.b64encode(hmac.new(secret.encode("utf-8"), source.encode("utf-8"), hashlib.sha256).digest()).decode()
S1 = "0123456789abcdef" # 16 位(最低边界)
S2 = "app-secret-100476-yunhai" # 常规 22 位
S3 = "X" * 64 # 超长
cases = [
{"name": "数据级-常规", "data": "hello", "ts": "1700000000000", "secret": S1},
{"name": "数据级-空串", "data": "", "ts": "1700000000000", "secret": S1},
{"name": "数据级-含分隔符", "data": "a|b", "ts": "1700000000000", "secret": S1},
{"name": "数据级-中文UTF8", "data": "云海学通", "ts": "1700000000000", "secret": S2},
{"name": "数据级-JSON体", "data": '{"id":1,"name":"zhang"}', "ts": "1699999999999", "secret": S2},
{"name": "数据级-超长数据", "data": "x" * 4096, "ts": "1700000000000", "secret": S2},
{"name": "数据级-超长密钥", "data": "user/login", "ts": "1700000000010", "secret": S3},
{"name": "请求级-GET无参", "method": "GET", "target": "/userbase/oapi/user/byId", "ts": "1700000000000", "secret": S2},
{"name": "请求级-GET带query", "method": "GET", "target": "/userbase/oapi/user/byId?id=123", "ts": "1700000000000", "secret": S2},
{"name": "请求级-GET多参数", "method": "GET", "target": "/userbase/oapi/group/byId?groupId=9&withSub=true", "ts": "1700000000000", "secret": S1},
{"name": "请求级-POST", "method": "POST", "target": "/userbase/oapi/identity/switch", "ts": "1700000000000", "secret": S2},
{"name": "请求级-中文query", "method": "GET", "target": "/userbase/oapi/user/byLoginName?loginName=张三", "ts": "1700000000001", "secret": S2},
]
vectors = []
for c in cases:
v = {"name": c["name"], "ts": c["ts"], "secret": c["secret"]}
if "method" in c:
v["method"] = c["method"]
v["canonicalTarget"] = c["target"]
v["expectedRequestSignBase64"] = request_sign(c["method"], c["target"], c["ts"], c["secret"])
else:
v["data"] = c["data"]
v["expectedDataSignHex"] = data_sign(c["data"], c["ts"], c["secret"])
vectors.append(v)
# 请求级大小写敏感验证用例:小写 METHOD "get" 与 "GET" 签名不同(请求级验签精确比对)
vectors.append({
"name": "请求级-小写method(与GET不同)",
"method": "get", "canonicalTarget": "/userbase/oapi/user/byId", "ts": "1700000000000", "secret": S1,
"expectedRequestSignBase64": request_sign("get", "/userbase/oapi/user/byId", "1700000000000", S1),
})
out = {
"algorithm": "HmacSHA256",
"dataLevel": {"canonical": "data + '|' + ts", "output": "lowercase hex"},
"requestLevel": {"canonical": "METHOD + '\\n' + canonicalTarget + '\\n' + ts", "output": "base64"},
"minSecretLength": 16,
"cases": vectors,
}
with open("contract/fixtures/sign-vectors.json", "w", encoding="utf-8") as f:
json.dump(out, f, ensure_ascii=False, indent=2)
print("vectors:", len(vectors))