nuts-foundation / nuts-foundation/nuts-node
connectToDID doesn't resolve DID URL service references, silently skipping peer discovery
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 28
- Forks
- 23
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 76
Description
Description
Network.connectToDID (network/network.go) iterates a discovered peer's node.Service entries and calls service.UnmarshalServiceEndpoint(&nutsCommUrl) directly on the raw NutsComm service entry.
This works for a literal serviceEndpoint (e.g. "grpc://example.com:5555"), but not when the serviceEndpoint is itself a DID URL reference, e.g.:
"serviceEndpoint": "did:nuts:C79u41fohcBHt7EwBF7KQdkhqerLCvAceGuLrEjHUq3S/serviceEndpoint?type=NutsComm"
This is a valid, spec-compliant way to publish a service endpoint (an indirection to another DID document's service) — used e.g. by a care organization's (child) DID document referencing its vendor's (parent) DID document. UnmarshalServiceEndpoint tries to parse this string directly as an absolute URL and fails, which is logged (at Debug level) and that service entry is silently skipped:
msg="Failed to extract NutsComm address from service" did="did:nuts:..." error="url must contain scheme and host"
Because the error is Debug-level and per-service, the node never surfaces that it failed to resolve that DID's NutsComm address.
Root cause
connectToDID reads the service entry directly instead of resolving it. Compare with Network.checkNodeDIDHealth, which correctly follows DID URL service references before parsing:
serviceRef := resolver.MakeServiceReference(nodeDID, transport.NutsCommServiceType)
nutsCommService, err := n.serviceResolver.Resolve(serviceRef, resolver.DefaultMaxServiceReferenceDepth)
connectToDID has access to the same n.serviceResolver but never uses it.
Impact
Discovery through a care organization's (child) DID document that references its vendor's (parent) DID document's NutsComm service fails via this path. In practice this is likely low severity: the vendor's (parent) DID document is discovered separately and publishes the endpoint as a literal URL, so the underlying node still gets discovered and connected to through that document. The gap is that discovery specifically through the child DID document silently fails instead of resolving the reference, which is still worth fixing since it's a valid, spec-compliant endpoint format.
Suggested fix
In connectToDID, resolve the service via n.serviceResolver.Resolve(...) (as checkNodeDIDHealth already does) before unmarshalling into transport.NutsCommURL, instead of unmarshalling the raw did.Service entry directly.
Assisted by AI
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in network/network.go at Network.connectToDID, then compare its service handling with Network.checkNodeDIDHealth. Use the existing serviceResolver path to resolve DID URL service references before unmarshalling into transport.NutsCommURL; done means NutsComm services published by reference are discovered instead of silently skipped.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100