Add DOI recording and duplicate-check endpoints - #9
Conversation
| return Response(status_code=200, content=bson.dumps({}), headers=resp_headers) | ||
|
|
||
|
|
||
| async def _hopauth_multi(authorization: str, ops_path: Optional[str] = None): |
There was a problem hiding this comment.
This function should be given a descriptive name for its purpose, rather than just the fact that it works by making requests to the hopauth multi-request endpoint. If this is always used identically to fetch_message, then that should be refactored to use the extracted function.
| topic = metadata.topic | ||
| if topic not in topic_permission_cache: | ||
| base_topic_name = effective_topic_name_for_access(topic) | ||
| relay, hop_json, extra_headers = await _hopauth_multi( |
There was a problem hiding this comment.
This looks structurally problematic: Forwarding authentication to hopauth is a stateful process when SCRAM authentication is used, causing the client to have to repeat the request, and all logic before the forwarding to hopauth in this server to have to re-run. Forwarding to hopauth should happen at one point (not in a loop) as early as possible in handling the request to prevent duplicated work. I suspect that for tests so far topic_permission_cache has hidden this, but that will only work when the forwarded requests would be fully redundant, which they may not be if multiple topics are involved.
| if authorization is None: | ||
| return authentication_required() | ||
|
|
||
| relay, hop_json, resp_headers = await _hopauth_multi(authorization) |
There was a problem hiding this comment.
This doesn't appear to do any authorization checks beyond that the requesting user is known. I thought our plan was that a user would ned to have write access to the topic on which a message exists to be able to request a DOI for it; did we change that?
Adds two new endpoints on top of the DOI-tracking tables introduced in
archive-core(see companion PR:feature/doi-tracking-tables), letting consumers like Hermes record newly minted DOIs and check whether messages have already been used in one.POST /doi/Records a newly minted DOI and the message UUIDs it covers. Requires a valid, authenticated HopAuth identity (resolved via a
whoamilookup) — but does not require topic-specific write permission, since minting a DOI about messages the caller has already read is a distinct action from writing to a topic, and the real authorization boundary for "can this person mint a DOI at all" is enforced one layer up by the calling service.GET /doi/checkGiven one or more candidate message UUIDs, returns which existing DOI(s), if any, they overlap with. Each UUID's topic is looked up and gated behind the same per-topic Read permission check used elsewhere in this API — a UUID is only included in the response if the caller can actually read its topic.
The response is deliberately privacy-conscious: for each matched DOI it returns only
total_message_count,matched_count, andmatched_uuids(a subset of the caller's own requested UUIDs) — never the identity of any other message belonging to that DOI. This lets a caller compute an exact-duplicate-vs-partial-overlap distinction using simple arithmetic, without archive-api ever exposing message identities the caller didn't already know about.Shared helper:
_hopauth_multi()Both endpoints route their HopAuth calls through a new shared helper that correctly relays HopAuth's own SCRAM challenge back to the original caller when a handshake is incomplete, mirroring fetch_message's existing inline behavior exactly, rather than treating an interim 401 as a hard failure. This matters because SCRAM is a two-hop interactive protocol: an optimistic first attempt is expected to be challenged, and swallowing that challenge into a generic error breaks authentication for every caller, every time.