68 lines
2.4 KiB
Python
68 lines
2.4 KiB
Python
"""POST one report follow-up and print the complete JSON response (HMAC v2)."""
|
|
|
|
import argparse
|
|
import base64
|
|
import hashlib
|
|
import hmac
|
|
import json
|
|
import os
|
|
import secrets
|
|
import time
|
|
from pathlib import Path
|
|
|
|
import httpx
|
|
|
|
|
|
def sign_follow_up_request(
|
|
method: str,
|
|
url: httpx.URL,
|
|
client_id: str,
|
|
secret: str,
|
|
body: bytes,
|
|
*,
|
|
timestamp: str | None = None,
|
|
nonce: str | None = None,
|
|
) -> dict[str, str]:
|
|
timestamp = timestamp or str(int(time.time()))
|
|
nonce = nonce or secrets.token_urlsafe(18)
|
|
path, _, query = url.raw_path.partition(b"?")
|
|
canonical = b"\n".join((method.upper().encode("ascii"), path, query, timestamp.encode(), nonce.encode(), body))
|
|
return {
|
|
"X-Signature-Version": "2",
|
|
"X-Client-Id": client_id,
|
|
"X-Timestamp": timestamp,
|
|
"X-Nonce": nonce,
|
|
"X-Signature": base64.b64encode(hmac.new(secret.encode(), canonical, hashlib.sha256).digest()).decode(),
|
|
}
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--url", required=True, help="Full /api/v1/integrations/risk-assessments/follow-up URL")
|
|
parser.add_argument("--client-id", default="dieya-plm")
|
|
parser.add_argument(
|
|
"--body-file", type=Path, required=True, help="UTF-8 JSON with requestId/messageRequestId/operator/content"
|
|
)
|
|
args = parser.parse_args()
|
|
secret = os.environ.get("RISK_INTEGRATION_CLIENT_SECRET", "")
|
|
if len(secret) < 32:
|
|
parser.error("Set RISK_INTEGRATION_CLIENT_SECRET to the backend-issued secret (at least 32 characters)")
|
|
url = httpx.URL(args.url)
|
|
if url.scheme not in {"http", "https"} or url.query or url.fragment or url.userinfo:
|
|
parser.error("--url must be HTTP(S) without query, credentials or fragment")
|
|
body = args.body_file.read_bytes()
|
|
data = json.loads(body)
|
|
signed = sign_follow_up_request("POST", url, args.client_id, secret, body)
|
|
signed.update({"Content-Type": "application/json", "Idempotency-Key": data["messageRequestId"]})
|
|
try:
|
|
response = httpx.post(url, content=body, headers=signed, timeout=httpx.Timeout(270, connect=10))
|
|
print(response.text)
|
|
return 0 if response.status_code == 200 else 1
|
|
except httpx.HTTPError as exc:
|
|
print(f"调用未完成({type(exc).__name__}),请使用原 messageRequestId 和原内容重试同一接口。")
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|