bag
This commit is contained in:
@@ -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))
|
||||
Reference in New Issue
Block a user