webvh-watcher 0.10.1

WebVH Watcher, read-only DID mirror service
docs.rs failed to build webvh-watcher-0.10.1
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: webvh-watcher-0.8.3

Affinidi WebVH Watcher

The WebVH Watcher is a read-only DID mirror. The control planes it is configured to mirror push it signed webvh/sync/* Trust Tasks, and it serves what they push publicly. It provides redundancy and geographic distribution for DID resolution without managing DIDs.

The watcher has its own DID, with keys in a VTA context, like every other service here. It verifies every log it mirrors exactly as a hosting server does, and it applies a sync only when its source signed it.

IMPORTANT: did-hosting-service crates are provided "as is" without any warranties or guarantees, and by using this framework, users agree to assume all risks associated with its deployment and use including implementing security, and privacy measures in their applications. Affinidi assumes no liability for any issues arising from the use or modification of the project.

Getting Started

Prerequisites

  • Rust 1.94.0+ (2024 Edition)

1. Build

cargo build --locked -p webvh-watcher --release

The binary is produced at target/release/webvh-watcher.

2. Set up

webvh-watcher setup provisions the watcher's DID from a VTA context (interactive, online), or webvh-watcher setup --from <recipe.toml> for any VTA mode — see examples/webvh-watcher-build.toml. It writes config.toml, stores the DID's keys in the secrets backend, and writes watcher-did.jsonl for you to publish on a hosting server. The part of config.toml that says whom it mirrors:

[sync]
# Only a webvh/sync/* Trust Task signed by one of these DIDs is applied.
source_dids = ["did:webvh:control.example.com"]

3. Configure the control plane

On each control plane the watcher mirrors, map the watcher's URL to its DID:

[[registry.watchers]]
url = "https://watcher1.example.com"
did = "did:webvh:…:watcher1.example.com"

A DID whose log names https://watcher1.example.com in its watchers parameter is then pushed there through the control plane's outbox — the same delivery, retry and acknowledgement as its edges — over the transport the watcher's DID advertises (TSP, DIDComm, or HTTPS).

4. Start the watcher

webvh-watcher --config config.toml

How It Works

control plane ──(signed webvh/sync/update|delete|batch, TSP · DIDComm · HTTPS)──► webvh-watcher

Clients ──(GET /{mnemonic}/did.jsonl)──► webvh-watcher
  1. A DID is published at the control plane.
  2. The control plane queues a signed webvh/sync/update/0.2 for every configured watcher the log names.
  3. The watcher verifies the document's proof (proofPurpose: authentication, bound to its issuer, addressed to the watcher, fresh, not a replay) and that the issuer is one of sync.source_dids; then it verifies the log — its chain and witness proofs, the slot it names, and that it strictly extends anything already mirrored for that DID — and answers with a signed #response, which settles the outbox entry.
  4. Clients resolve DIDs from any watcher.

A document that does not verify gets no reply. A verified one from a DID that is not a source is refused notAuthorized (signed), and is not recorded.

Configuration

The watcher is configured via a TOML file. By default it looks for config.toml in the current directory. You can specify a different path with the --config flag or the WATCHER_CONFIG_PATH environment variable.

Environment Variable Overrides

Variable Description
WATCHER_CONFIG_PATH Path to config file
WATCHER_SERVER_HOST Bind host
WATCHER_SERVER_PORT Bind port
WATCHER_LOG_LEVEL Log level
WATCHER_SERVER_DID The watcher's DID
WATCHER_MEDIATOR_DID Its mediator
WATCHER_SOURCE_DIDS Comma-separated source DIDs
WATCHER_SERVER_RESOLVE_CACHE_MAX_AGE_SECS DID-resolution max-age (0 = no-cache; default 300)
WATCHER_SERVER_RESOLVE_CACHE_SHARED_MAX_AGE_SECS DID-resolution s-maxage (empty clears)
WATCHER_SERVER_RESOLVE_CACHE_STALE_WHILE_REVALIDATE_SECS DID-resolution stale-while-revalidate (empty clears)

The same settings live in [server.resolve_cache] (max_age_secs, shared_max_age_secs, stale_while_revalidate_secs).

CLI Commands

webvh-watcher                                  # Run watcher (default)
webvh-watcher setup                            # Interactive online VTA setup
webvh-watcher setup --setup-key-out <path>     # Mint a setup key for a headless online setup
webvh-watcher setup --from <recipe.toml> [--setup-key-file <path>]
webvh-watcher health                           # Diagnostics

API Endpoints

Public (unauthenticated)

Method Path Description
GET /api/health Health check
GET /{mnemonic}/did.jsonl Resolve DID log
GET /{mnemonic}/did-witness.json Resolve witness
GET /.well-known/did.jsonl Root DID log
GET /.well-known/did-witness.json Root witness

Trust Tasks

Method Path Description
POST /api/trust-tasks The HTTPS binding of webvh/sync/update/0.2, webvh/sync/delete/0.2, webvh/sync/batch/0.1

The same documents are accepted over TSP and DIDComm on the watcher's mediator connection.

Library Usage

The webvh-watcher crate can be used as a library (e.g., by the did-hosting-daemon). It exposes:

  • webvh_watcher::config::AppConfig — configuration
  • webvh_watcher::server::AppState — application state
  • webvh_watcher::routes::router() — Axum router
  • webvh_watcher::server::run() — standalone entry point

Support & feedback

If you face any issues or have suggestions, please don't hesitate to contact us using this link.

Reporting technical issues

If you have a technical issue with the Affinidi DID Hosting Service codebase, you can also create an issue directly in GitHub.

  1. Ensure the bug was not already reported by searching on GitHub under Issues.

  2. If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behaviour that is not occurring.

Contributing

Want to contribute? Head over to our CONTRIBUTING guidelines.