feat(rooms-wasm)!: a browser can verify a did:webvh room's invitation - #1382
Open
stormer78 wants to merge 1 commit into
Open
feat(rooms-wasm)!: a browser can verify a did:webvh room's invitation#1382stormer78 wants to merge 1 commit into
stormer78 wants to merge 1 commit into
Conversation
The invitation gate resolved `did:key` and `did:peer` and refused everything else, which meant a browser member could be admitted to the rooms this crate's demo mints and to nothing else. **A production room is a `did:webvh`** — so is a VTC-hosted one — and resolving one means fetching a log over HTTPS and verifying its history. That is I/O, and this crate compiles to a target where I/O belongs to the host page. So the caller may now supply the issuer's key. The split moves where trust sits, and the module says so precisely rather than leaving a reader to work it out: - `did:key` and `did:peer` derive the key **from the identifier**, and a supplied one is ignored. Preferring the caller's would let them talk this module out of the one check it can make entirely alone — asserted, not just described. - Anything else is the caller's resolution, and the resolution is the trust. The proof must still name the issuer and still verify under the key given, so a wrong key fails; what this module cannot do is tell a correctly-resolved key from a convincingly-wrong one. That is the resolver's job, and it is why this is a parameter rather than an HTTP client this crate could not use. Breaking: `verify`, `mint_key_package`, `RoomMember::join` and the two `_js` wrappers take `issuer_key: Option<Vec<u8>>`. `None` is exactly the old behaviour. Writing the test found something worth keeping: the first cut signed with a `did:key` secret and rewrote `verificationMethod` afterwards, which fails — an `eddsa-jcs-2022` proof covers its own proof options. The fixture signs under the room's own method instead.
stormer78
added a commit
to stormer78/vti-data-room-demo
that referenced
this pull request
Sep 9, 2026
`advertised()` opened with `if (!did.startsWith("did:peer:")) return null`,
which meant the site could dial the rooms this sample mints and nothing
else. A production room is a `did:webvh`. So is a VTC-hosted one. So the
front door only opened onto the demo.
It now goes through the stack's own resolver — `did:key` and `did:peer`
still by computation, `did:webvh` by fetching and verifying its log,
which is why resolution became async and why that rippled.
That second half needs a change in wasm, and this carries the JS side of
it (OpenVTC/verifiable-trust-infrastructure#1382). The invitation gate
cannot resolve a `did:webvh`: it means HTTPS and log verification, which
is I/O, and wasm has none. So this page resolves the room's signing key
and passes it in — and passes `null` for `did:key` and `did:peer`, where
the gate derives the key from the identifier and ignores anything offered.
Nothing this page believes about those rooms can affect the verdict, which
is the property worth keeping and the reason `issuerKey` returns null
rather than being helpful.
Verified against the live mediator: a `did:webvh` resolves to its DIDComm
service and yields a 32-byte issuer key, a `did:key` resolves to no
service, and joining a `did:peer` room still works unchanged.
One bug of my own on the way, and the comment stays where it bit: the
resolved key was called `key`, which shadows this file's `key(suffix)`
storage helper. A working join failed with "key is not a function" from a
line well below the declaration.
|
🛡️ AI Agentic Security Code Review — all clear. We checked this change and found nothing to report. Keep shipping secure code! Note: for major, breaking, or feature-introducing changes, you can always request an in-depth review from the security team. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The invitation gate resolved
did:keyanddid:peerand refused everything else. So a browser member could be admitted to the rooms this crate's own demo mints, and to nothing else.A production room is a
did:webvh. So is a VTC-hosted one. Resolving one means fetching a log over HTTPS and verifying its history — that is I/O, and this crate compiles to a target where I/O belongs to the host page.The caller may now supply the issuer's key
That moves where trust sits, so the module states it precisely rather than leaving a reader to infer it:
did:keyanddid:peerderive the key from the identifier, and a supplied key is ignored. Preferring the caller's would let them talk this module out of the one check it can make entirely on its own. Asserted, not merely described — the test passes a wrong key to adid:keyroom and expects it to verify anyway.Breaking
verify,mint_key_package,RoomMember::joinand the two_jswrappers takeissuer_key: Option<Vec<u8>>.Noneis precisely the previous behaviour, so every existing call site is a one-word change.A note from writing the test
The first cut signed with a
did:keysecret and rewroteverificationMethodto point at the room afterwards. That fails — aneddsa-jcs-2022proof covers its own proof options,verificationMethodincluded — which is the proof doing its job. The fixture gained a helper that signs under an arbitrary verification method, so the credential is genuine rather than edited.Testing
11 tests pass; clippy clean; builds for
wasm32-unknown-unknownunder thewasm-releaseprofile.