From 4522797a0cf378cc44485ed77a01dee9643b6ebe Mon Sep 17 00:00:00 2001 From: bndw Date: Sat, 7 Mar 2026 18:34:25 -0800 Subject: Make allowed event kinds configurable Replaces hardcoded kind allowlist in isAllowedKind with a configurable allowed_kinds list in relay config. Empty list allows all kinds. Default matches previous hardcoded list. Wired through SetAllowedKinds on the handler. --- internal/config/config.go | 25 ++++++++++--- internal/handler/websocket/handler.go | 68 ++++++++++++++--------------------- 2 files changed, 47 insertions(+), 46 deletions(-) (limited to 'internal') diff --git a/internal/config/config.go b/internal/config/config.go index 36d3e1e..dc347d6 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -25,11 +25,12 @@ type Config struct { } type RelayConfig struct { - Name string `yaml:"name"` - Description string `yaml:"description"` - Pubkey string `yaml:"pubkey"` - Contact string `yaml:"contact"` - Icon string `yaml:"icon"` + Name string `yaml:"name"` + Description string `yaml:"description"` + Pubkey string `yaml:"pubkey"` + Contact string `yaml:"contact"` + Icon string `yaml:"icon"` + AllowedKinds []int32 `yaml:"allowed_kinds"` } type ServerConfig struct { @@ -102,6 +103,20 @@ func Default() *Config { Relay: RelayConfig{ Name: "muxstr relay", Description: "High-performance Nostr relay with gRPC, Connect, and WebSocket support", + AllowedKinds: []int32{ + 0, // Metadata/profile + 1, // Short text note + 3, // Contacts/following + 4, // Encrypted DM + 5, // Event deletion + 6, // Repost + 7, // Reaction + 9735, // Zap + 10000, 10001, 10002, // Mute/pin lists (NIP-51) + 10050, // Relay list metadata + 30023, // Long-form content (NIP-23) + 30078, // Application-specific data (NIP-78) + }, }, Server: ServerConfig{ GrpcAddr: ":50051", diff --git a/internal/handler/websocket/handler.go b/internal/handler/websocket/handler.go index b11171d..c64f3f9 100644 --- a/internal/handler/websocket/handler.go +++ b/internal/handler/websocket/handler.go @@ -64,14 +64,15 @@ type connState struct { } type Handler struct { - store EventStore - auth AuthStore - subs *subscription.Manager - metrics MetricsRecorder - limiter RateLimiter - authConfig *AuthConfig - relayConfig *RelayInfoConfig - indexData IndexData + store EventStore + auth AuthStore + subs *subscription.Manager + metrics MetricsRecorder + limiter RateLimiter + authConfig *AuthConfig + relayConfig *RelayInfoConfig + indexData IndexData + allowedKinds map[int32]bool // nil = allow all } func NewHandler(store EventStore, subs *subscription.Manager) *Handler { @@ -81,6 +82,17 @@ func NewHandler(store EventStore, subs *subscription.Manager) *Handler { } } +func (h *Handler) SetAllowedKinds(kinds []int32) { + if len(kinds) == 0 { + h.allowedKinds = nil // nil = allow all + return + } + h.allowedKinds = make(map[int32]bool, len(kinds)) + for _, k := range kinds { + h.allowedKinds[k] = true + } +} + func (h *Handler) SetMetrics(m MetricsRecorder) { h.metrics = m } @@ -325,8 +337,8 @@ func (h *Handler) handleEvent(ctx context.Context, conn *websocket.Conn, raw []j pbEvent := NostrToPB(&event) canonicalJSON := event.Serialize() - // Reject non-core protocol kinds (spam, ephemeral, chat) - if !isAllowedKind(pbEvent.Kind) { + // Reject kinds not in the allowed list + if !h.isAllowedKind(pbEvent.Kind) { status = "ok" if h.metrics != nil { h.metrics.RecordBlockedEvent(pbEvent.Kind) @@ -623,37 +635,11 @@ func getClientIP(r *http.Request) string { return r.RemoteAddr } -// isAllowedKind returns true if the event kind is a core Nostr protocol kind. -// Rejects spam, ephemeral events, live chat, and other non-essential kinds. -func isAllowedKind(kind int32) bool { - // Core protocol kinds (NIP-01, NIP-02, etc.) - switch kind { - case 0: // Metadata/profile - return true - case 1: // Short text note - return true - case 3: // Contacts/following - return true - case 4: // Encrypted DM - return true - case 5: // Event deletion (handled separately) +// isAllowedKind returns true if the event kind is permitted by the relay config. +// If no allowed kinds are configured, all kinds are accepted. +func (h *Handler) isAllowedKind(kind int32) bool { + if h.allowedKinds == nil { return true - case 6: // Repost - return true - case 7: // Reaction - return true - case 9735: // Zap - return true - case 10000, 10001, 10002: // Mute lists, pin lists (NIP-51) - return true - case 10050: // Relay list metadata - return true - case 30023: // Long-form content (NIP-23) - return true - case 30078: // Application-specific data (NIP-78) - return true - default: - // Reject everything else (chat, ephemeral, spam) - return false } + return h.allowedKinds[kind] } -- cgit v1.2.3