Skip to content

BSVanon/AnvilCast

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AnvilCast

P2P screen sharing with wallet-verified identity over the Anvil BSV mesh.

Live demo · Features · Quick Start · Architecture


AnvilCast is a screen-sharing service where every session is identified by a BRC-100 wallet, every signaling envelope is gossiped through the BSV mesh, and every contact is a secp256k1 public key — not an account, not an email, not a phone number.

Two people open it, both have wallets, and they share a screen. There is no sign-up. There is no observation pixel, no analytics, no server-side recording, no account database. The server holds nothing about you that survives the session.

Features

Feature Status
Screen sharing with system audio (getDisplayMedia) desktop / Android Chrome
Microphone with mute toggle host
Camera with PiP overlay on viewer (getUserMedia) host
Recording to local .webm (MediaRecorder) both
Screen annotation — draw / highlight on the shared video viewer
File drop — drag a file into chat, sent over WebRTC data channel (50 MB cap) both
Chat — server-signed envelopes via Anvil messagebox topic both
Wallet identity — BRC-100 / BRC-103 challenge–response optional
Contacts — wallet-discovered + local nicknames + presence dots host
Ring — call a contact who's currently in their inbox (presence WebSocket) host
Invite — leave an invitation in someone's BRC-33 inbox for whenever they next come online host
TURN relay — coturn fallback for NAT traversal, HMAC ephemeral credentials server-side
Proof Rooms integration — BRC-60 hash chain of session events for auditable evidence capture both

Two trust modes

  • Quick Share (unsecured): a 16-character room code, click a link, watch. No wallet required. Server-managed ephemeral keys. Good for showing somebody a thing.
  • Secured (wallet-verified): both sides authenticate their BRC-100 wallet via nonce challenge. Identity keys are exchanged. Contacts persist (locally) across sessions. Required for the proof-rooms evidence flow.

Live Demo

https://anvil.sendbsv.com/cast/

You will need a BRC-100 wallet for the Secured flow. BSV Desktop and the BSV Association mobile browser are tested. The unsecured Quick Share flow requires nothing.

Platform Support

Platform View Host
Desktop (Chrome / Firefox / Edge / Safari) yes yes
Android Chrome yes yes
Android — BSV Association browser (React Native WebView) yes no (WebView lacks getDisplayMedia)
iOS — any browser yes no (Apple has not implemented the Screen Capture API)

Quick Start

git clone https://github.com/BSVanon/AnvilCast.git
cd AnvilCast
go build -o bin/anvilcast ./cmd/server
./bin/anvilcast

Open http://localhost:8080. Pick a role, share a link.

Anvil Mesh mode

Route signaling through the Anvil BSV mesh instead of direct WebSocket relay:

./bin/anvilcast \
  -anvil-host  http://127.0.0.1:9333 \
  -anvil-viewer http://127.0.0.1:9334

In mesh mode, every signaling message is a secp256k1-signed envelope gossiped to all connected Anvil peers. You need two Anvil nodes — see the Anvil README for setup.

TURN relay (for NAT traversal)

Symmetric NAT and CGNAT (most cellular networks) will block direct P2P. Configure a coturn relay in HMAC ephemeral mode:

TURN_SECRET=$(openssl rand -hex 32) ./bin/anvilcast \
  -turn-url turns:your.turn.host:5349 \
  -turn-ttl 1h

The same secret goes in coturn's static-auth-secret config. The server generates fresh credentials per /api/config request — credentials never live longer than -turn-ttl.

TLS

For production, terminate TLS at a reverse proxy (nginx is what the reference deploy uses) and pass -origins to lock down WebSocket origins:

./bin/anvilcast \
  -addr :8090 \
  -origins https://your.domain

Or use the built-in TLS support:

./bin/anvilcast \
  -cert /path/to/cert.pem \
  -key /path/to/key.pem

Flags

Flag Default Description
-addr :8080 Listen address
-web ./web Static file directory
-cert TLS certificate path (enables HTTPS)
-key TLS key path
-origins Comma-separated allowed WebSocket origins (empty ⇒ allow all, dev only)
-anvil-host Anvil node URL for host signaling
-anvil-viewer Anvil node URL for viewer signaling
-turn-url TURN server URL for ICE config
-turn-ttl 1h TURN credential lifetime

Environment Variables

Read from env to avoid ps aux exposure:

Var Description
ANVIL_HOST_AUTH Bearer token for the host Anvil node (optional)
ANVIL_VIEWER_AUTH Bearer token for the viewer Anvil node (optional)
TURN_SECRET Shared secret for HMAC ephemeral TURN credentials

Architecture

  Browser (Host)                                 Browser (Viewer)
        |                                              |
        |--- /ws (signaling) ----+        +---- /ws (signaling) ---|
        |--- /ws/presence -------+        +---- /ws/presence ------|
        |                        |        |                       |
        |                        v        v                       |
        |                 ┌────────────────────┐                  |
        |                 │   AnvilCast Go     │                  |
        |                 │      Server        │                  |
        |                 │                    │                  |
        |                 │  Hub  Presence     │                  |
        |                 │  Relay Registry    │                  |
        |                 │  ProofChain        │                  |
        |                 └─────────┬──────────┘                  |
        |                           |                              |
        |               ┌───────────┴───────────┐                  |
        |               v                       v                  |
        |       Anvil Node A             Anvil Node B              |
        |       :9333 (host)             :9334 (viewer)            |
        |               |                       |                  |
        |               └───── mesh gossip ─────┘                  |
        |                                                          |
        +─── WebRTC media (P2P, with TURN fallback via coturn) ────+
  • /ws — signaling WebSocket. SDP offer/answer, ICE candidates. Bridged to Anvil mesh in mesh mode, otherwise direct relay.
  • /ws/presence — authenticated contact presence. Tracks who's online by identity key, broadcasts presence updates to anyone watching that key.
  • WebRTC media — browser-native, peer-to-peer. STUN by default, TURN relay if configured.
  • Anvil mesh — every signaling envelope is a secp256k1-signed message gossiped to all peers. The server cannot forge or modify a signed envelope; verification happens at the Anvil node level.
  • Identity — BRC-100 wallet challenge–response. Per BRC-3/BRC-42, the server cannot independently verify wallet signatures (derived child keys require the counterparty's shared secret), so identity is established by the wallet's participation in the nonce challenge — the act of producing a valid createSignature response is itself the proof.
  • Proof Rooms — when a session is created from a proof_room_request (TrueProof contract), every lifecycle event is appended to a BRC-60 hash chain. On session end, the full chain plus its head hash is sent back via the trueproof_proof_room messagebox for evidence anchoring.

API

WebSocket

Path Description
/ws?role=host|viewer&room=<id> Signaling — SDP, ICE, room lifecycle
/ws/presence Presence — contact status, presence-initiated rooms

REST / SSE

Endpoint Method Description
/api/config GET ICE config (STUN servers + ephemeral TURN credentials)
/api/identity GET Server's Anvil node identity pubkeys (mesh mode only)
/api/identify/create POST Host generates a sign-up token for an invite link
/api/identify/challenge GET Viewer requests a signing nonce
/api/identify/respond POST Viewer submits identity proof
/api/identify/poll GET Host polls for viewer verification result
/api/messagebox/send POST Send a message to a recipient's BRC-33 inbox
/api/messagebox/list POST BRC-33 listMessages
/api/messagebox/acknowledge POST BRC-33 acknowledgeMessage
/api/messagebox/subscribe GET (SSE) Live stream of inbox messages
/api/messagebox/chat POST Send a chat message into a room topic
/api/messagebox/chat/subscribe GET (SSE) Live stream of room chat
/api/messagebox/live/announce POST Announce a public live session
/api/messagebox/live GET (SSE) Discover public live sessions
/api/utxo/check GET UTXO unspent check (used for BRC-52 cert revocation)
/api/ring POST Legacy invite-by-pubkey endpoint

There is also a diagnostic endpoint, /api/debug/presence, that lists currently registered presence users. It is locked to direct loopback only — any request with an X-Forwarded-For or X-Real-IP header is rejected, so it is unreachable through a reverse proxy.

BRC Compliance

BRC Used For
BRC-100 Wallet-to-application interface
BRC-103 Mutual authentication (challenge–response)
BRC-73 Grouped wallet permissions (one prompt for many ops)
BRC-52 Identity certificates (three-tier name resolution)
BRC-42 / BRC-43 Per-session derived keys
BRC-33 Messagebox (send / list / acknowledge)
BRC-77 Wallet-to-wallet message signing
BRC-60 Hash chain over session events (proof rooms)

Tests

go test ./...           # full suite
go test -race ./...     # race detector
go test -cover ./...    # coverage

The presence flow has integration tests against a real httptest server (see internal/signaling/presence_test.go) that exercise host-first, friend-first, and case-mismatch scenarios. The BRC-60 hash chain has cross-language test vectors (internal/proofchain/chain_test.go) that verify byte-identical SHA-256 output against the TypeScript reference implementation in trueproof/proof-rooms.

Security

Pre-release audit history lives outside this repo (private), but the reference deploy at anvil.sendbsv.com/cast/ runs the BUG_HUNTS release-gate before each tag. The pre-v1.0.0 audit (2026-04-07) ran:

  • go vet, staticcheck — clean
  • govulncheck — clean (after go.mod toolchain bump to 1.26.1)
  • gosec — only false-positives accepted (SSRF on a server-controlled URL, SHA-1 in coturn HMAC by spec)
  • gitleaks — clean
  • semgrep — only false-positives accepted (io.WriteString on SSE handlers writing JSON-marshaled structs, WebSocket origin check configured in upgrader constructor)
  • go test -race — clean across all packages

If you find a security issue, please report it privately (open a GitHub issue with minimal detail and tag it security) before disclosing publicly.

Dependencies

Go modules (all permissively licensed):

Module License Purpose
github.com/gorilla/websocket BSD-2-Clause WebSocket signaling + presence
github.com/bsv-blockchain/go-sdk Open BSV BEEF transaction signing
github.com/decred/dcrd/dcrec/secp256k1/v4 ISC Envelope signing, identity keys

JS libraries (vendored):

Library License Notice
QRCode for JavaScript (Kazuhiko Arase, 2009) MIT See NOTICE.md and web/js/lib/qrcode.js header

License

Open BSV License version 4

The Software, and any software derived from it, may only be used on the Bitcoin SV blockchains.

Third-party components are listed in NOTICE.md.

About

P2P screen sharing with wallet-verified identity over the Anvil BSV mesh. Camera, recording, annotation, file drop, chat — all wallet-secured.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors