Add NRC (Nostr Relay Connect) protocol and web UI (v0.48.9)
Some checks failed
Go / build-and-release (push) Has been cancelled

- Implement NIP-NRC protocol for remote relay access through public relay tunnel
- Add NRC bridge service with NIP-44 encrypted message tunneling
- Add NRC client library for applications
- Add session management with subscription tracking and expiry
- Add URI parsing for nostr+relayconnect:// scheme with secret and CAT auth
- Add NRC API endpoints for connection management (create/list/delete/get-uri)
- Add RelayConnectView.svelte component for managing NRC connections in web UI
- Add NRC database storage for connection secrets and labels
- Add NRC CLI commands (generate, list, revoke)
- Add support for Cashu Access Tokens (CAT) in NRC URIs
- Add ScopeNRC constant for Cashu token scope
- Add wasm build infrastructure and stub files

Files modified:
- app/config/config.go: NRC configuration options
- app/handle-nrc.go: New API handlers for NRC connections
- app/main.go: NRC bridge startup integration
- app/server.go: Register NRC API routes
- app/web/src/App.svelte: Add Relay Connect tab
- app/web/src/RelayConnectView.svelte: New NRC management component
- app/web/src/api.js: NRC API client functions
- main.go: NRC CLI command handlers
- pkg/bunker/acl_adapter.go: Add NRC scope mapping
- pkg/cashu/token/token.go: Add ScopeNRC constant
- pkg/database/nrc.go: NRC connection storage
- pkg/protocol/nrc/: New NRC protocol implementation
- docs/NIP-NRC.md: NIP specification document

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
woikos
2026-01-07 03:40:12 +01:00
parent 0dac41e35e
commit d41c332d06
31 changed files with 5982 additions and 16 deletions

View File

@@ -172,6 +172,13 @@ type C struct {
CashuScopes string `env:"ORLY_CASHU_SCOPES" default:"relay,nip46" usage:"comma-separated list of allowed token scopes"`
CashuReauthorize bool `env:"ORLY_CASHU_REAUTHORIZE" default:"true" usage:"re-check ACL on each token verification for stateless revocation"`
// Nostr Relay Connect (NRC) configuration - tunnel private relay through public relay
NRCEnabled bool `env:"ORLY_NRC_ENABLED" default:"false" usage:"enable NRC bridge to expose this relay through a public rendezvous relay"`
NRCRendezvousURL string `env:"ORLY_NRC_RENDEZVOUS_URL" usage:"WebSocket URL of the public relay to use as rendezvous point (e.g., wss://relay.example.com)"`
NRCAuthorizedKeys string `env:"ORLY_NRC_AUTHORIZED_KEYS" usage:"comma-separated list of authorized client pubkeys (hex) for secret-based auth"`
NRCUseCashu bool `env:"ORLY_NRC_USE_CASHU" default:"false" usage:"use Cashu access tokens for NRC authentication instead of static secrets"`
NRCSessionTimeout string `env:"ORLY_NRC_SESSION_TIMEOUT" default:"30m" usage:"inactivity timeout for NRC sessions"`
// Cluster replication configuration
ClusterPropagatePrivilegedEvents bool `env:"ORLY_CLUSTER_PROPAGATE_PRIVILEGED_EVENTS" default:"true" usage:"propagate privileged events (DMs, gift wraps, etc.) to relay peers for replication"`
@@ -404,6 +411,29 @@ func MigrateRequested() (requested bool, fromType, toType, targetPath string) {
return
}
// NRCRequested checks if the first command line argument is "nrc" and returns
// the NRC subcommand parameters.
//
// Return Values
// - requested: true if the 'nrc' subcommand was provided
// - subcommand: the NRC subcommand (generate, list, revoke)
// - args: additional arguments for the subcommand
func NRCRequested() (requested bool, subcommand string, args []string) {
if len(os.Args) > 1 {
switch strings.ToLower(os.Args[1]) {
case "nrc":
requested = true
if len(os.Args) > 2 {
subcommand = strings.ToLower(os.Args[2])
if len(os.Args) > 3 {
args = os.Args[3:]
}
}
}
}
return
}
// KV is a key/value pair.
type KV struct{ Key, Value string }
@@ -775,3 +805,39 @@ func (cfg *C) GetBboltConfigValues() (
cfg.BboltNoSync,
cfg.BboltMmapSizeMB * 1024 * 1024
}
// GetNRCConfigValues returns the NRC (Nostr Relay Connect) configuration values.
// This avoids circular imports with pkg/protocol/nrc while allowing main.go to construct
// the NRC bridge configuration.
func (cfg *C) GetNRCConfigValues() (
enabled bool,
rendezvousURL string,
authorizedKeys []string,
useCashu bool,
sessionTimeout time.Duration,
) {
// Parse session timeout
sessionTimeout = 30 * time.Minute // Default
if cfg.NRCSessionTimeout != "" {
if d, err := time.ParseDuration(cfg.NRCSessionTimeout); err == nil {
sessionTimeout = d
}
}
// Parse authorized keys
if cfg.NRCAuthorizedKeys != "" {
keys := strings.Split(cfg.NRCAuthorizedKeys, ",")
for _, k := range keys {
k = strings.TrimSpace(k)
if k != "" {
authorizedKeys = append(authorizedKeys, k)
}
}
}
return cfg.NRCEnabled,
cfg.NRCRendezvousURL,
authorizedKeys,
cfg.NRCUseCashu,
sessionTimeout
}