fix: post data+SHA256 to VeraeTime and poll job for CID certificate
Live /api/timestamp rejects {hash,sync}; it wants {data,hashAlg:SHA256}
and returns a job whose result is a multihash certificate.
This commit is contained in:
parent
0714fff7fa
commit
b1219c64bc
2 changed files with 43 additions and 8 deletions
|
|
@ -8,6 +8,7 @@ from __future__ import annotations
|
|||
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
|
@ -42,7 +43,7 @@ class UrllibHttp:
|
|||
def request(
|
||||
self, method: str, url: str, payload: dict[str, Any], headers: dict[str, str]
|
||||
) -> _UrllibResp:
|
||||
data = json.dumps(payload).encode()
|
||||
data = None if method == "GET" else json.dumps(payload).encode()
|
||||
req = urllib.request.Request(url, data=data, method=method)
|
||||
for key, value in headers.items():
|
||||
req.add_header(key, value)
|
||||
|
|
@ -106,7 +107,7 @@ class GlobalClient:
|
|||
res = self.http.request(
|
||||
"POST",
|
||||
url,
|
||||
payload={"hash": digest, "sync": True},
|
||||
payload={"data": digest, "hashAlg": "SHA256"},
|
||||
headers=self._headers(),
|
||||
)
|
||||
if res.status_code >= 300:
|
||||
|
|
@ -115,13 +116,37 @@ class GlobalClient:
|
|||
job_id = parsed.get("jobId") or parsed.get("blockHash") or ""
|
||||
if not job_id:
|
||||
raise ValueError("global timestamp response missing jobId")
|
||||
created = str(parsed.get("timestamp") or "")
|
||||
merkle = str(parsed.get("blockHash") or "")
|
||||
receipt_id = str(job_id)
|
||||
status_url = f"{self.base_url}/api/status/{job_id}"
|
||||
for _ in range(20):
|
||||
st = self.http.request("GET", status_url, payload={}, headers=self._headers())
|
||||
if st.status_code >= 300:
|
||||
break
|
||||
body = st.json() if hasattr(st, "json") else {}
|
||||
if not isinstance(body, dict):
|
||||
break
|
||||
state = str(body.get("status") or "")
|
||||
if state == "failed":
|
||||
raise ValueError(str(body.get("error") or "global timestamp job failed"))
|
||||
if state == "completed":
|
||||
receipt_id = str(body.get("result") or body.get("id") or job_id)
|
||||
meta = body.get("metadata") or {}
|
||||
created = str(meta.get("timestamp") or body.get("completedAt") or created)
|
||||
merkle = str(meta.get("blockIndex") or meta.get("blockHash") or merkle)
|
||||
break
|
||||
if state in ("pending", "running", ""):
|
||||
time.sleep(0.25)
|
||||
continue
|
||||
break
|
||||
return Receipt(
|
||||
receipt_id=str(job_id),
|
||||
receipt_id=receipt_id,
|
||||
hash=digest,
|
||||
scope="global",
|
||||
cube_id=cube_id,
|
||||
created_at=str(parsed.get("timestamp") or ""),
|
||||
merkle=str(parsed.get("blockHash") or ""),
|
||||
created_at=created,
|
||||
merkle=merkle,
|
||||
)
|
||||
|
||||
def verify_certificate(self, receipt_id: str) -> VerifyResult:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class FakeHttp:
|
|||
200,
|
||||
{
|
||||
"jobId": "job-1",
|
||||
"hash": payload["hash"],
|
||||
"hash": payload.get("data") or payload.get("hash"),
|
||||
"timestamp": "2026-08-15T00:00:00Z",
|
||||
"blockHash": "0xdead",
|
||||
},
|
||||
|
|
@ -38,6 +38,16 @@ class FakeHttp:
|
|||
if payload.get("certificate") == "job-1":
|
||||
return _Resp(200, {"valid": True, "hash": SHA256_EMPTY})
|
||||
return _Resp(200, {"valid": False})
|
||||
if "/api/status/" in url:
|
||||
return _Resp(
|
||||
200,
|
||||
{
|
||||
"id": "job-1",
|
||||
"status": "completed",
|
||||
"result": "job-1",
|
||||
"metadata": {"timestamp": "2026-08-15T00:00:00Z", "blockHash": "0xdead"},
|
||||
},
|
||||
)
|
||||
return _Resp(404, {"error": "nope"})
|
||||
|
||||
|
||||
|
|
@ -49,7 +59,7 @@ async def test_global_stamp_posts_hash_sync_and_maps_receipt():
|
|||
method, url, payload, headers = http.calls[0]
|
||||
assert method == "POST"
|
||||
assert url == "https://api.veraetime.net/api/timestamp"
|
||||
assert payload == {"hash": SHA256_EMPTY, "sync": True}
|
||||
assert payload == {"data": SHA256_EMPTY, "hashAlg": "SHA256"}
|
||||
assert headers["Authorization"] == "Bearer secret"
|
||||
assert rec.scope == "global"
|
||||
assert rec.receipt_id == "job-1"
|
||||
|
|
@ -84,7 +94,7 @@ async def test_routing_sends_only_global_scope_to_central():
|
|||
[g] = await routed.stamp(SHA256_EMPTY, scope="global", cube_id="cube-1")
|
||||
assert g.scope == "global"
|
||||
assert g.receipt_id == "job-1"
|
||||
assert len(http.calls) == 1
|
||||
assert http.calls[0][1].endswith("/api/timestamp")
|
||||
|
||||
cached = await routed.hash_report(SHA256_EMPTY, want_scope="global")
|
||||
assert cached[0].receipt_id == "job-1"
|
||||
|
|
|
|||
Loading…
Reference in a new issue