dieya_risk_prediction_backend/scripts/call_external_follow_up.py

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())