aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-03-07 18:34:25 -0800
committerbndw <ben@bdw.to>2026-03-07 18:34:25 -0800
commit4522797a0cf378cc44485ed77a01dee9643b6ebe (patch)
treefaa7a1970885635df0cc49cbc4a1aef6fcbea5fa
parent5195d8031b7930069ba5441a6cd1e7a59c21c546 (diff)
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.
-rw-r--r--cmd/relay/main.go1
-rw-r--r--internal/config/config.go25
-rw-r--r--internal/handler/websocket/handler.go68
3 files changed, 48 insertions, 46 deletions
diff --git a/cmd/relay/main.go b/cmd/relay/main.go
index 78ee469..601b2e8 100644
--- a/cmd/relay/main.go
+++ b/cmd/relay/main.go
@@ -123,6 +123,7 @@ func main() {
123 Contact: cfg.Relay.Contact, 123 Contact: cfg.Relay.Contact,
124 Icon: cfg.Relay.Icon, 124 Icon: cfg.Relay.Icon,
125 }) 125 })
126 wsHandler.SetAllowedKinds(cfg.Relay.AllowedKinds)
126 127
127 if cfg.Auth.Read.Enabled || cfg.Auth.Write.Enabled { 128 if cfg.Auth.Read.Enabled || cfg.Auth.Write.Enabled {
128 wsHandler.SetAuth(store) 129 wsHandler.SetAuth(store)
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 {
25} 25}
26 26
27type RelayConfig struct { 27type RelayConfig struct {
28 Name string `yaml:"name"` 28 Name string `yaml:"name"`
29 Description string `yaml:"description"` 29 Description string `yaml:"description"`
30 Pubkey string `yaml:"pubkey"` 30 Pubkey string `yaml:"pubkey"`
31 Contact string `yaml:"contact"` 31 Contact string `yaml:"contact"`
32 Icon string `yaml:"icon"` 32 Icon string `yaml:"icon"`
33 AllowedKinds []int32 `yaml:"allowed_kinds"`
33} 34}
34 35
35type ServerConfig struct { 36type ServerConfig struct {
@@ -102,6 +103,20 @@ func Default() *Config {
102 Relay: RelayConfig{ 103 Relay: RelayConfig{
103 Name: "muxstr relay", 104 Name: "muxstr relay",
104 Description: "High-performance Nostr relay with gRPC, Connect, and WebSocket support", 105 Description: "High-performance Nostr relay with gRPC, Connect, and WebSocket support",
106 AllowedKinds: []int32{
107 0, // Metadata/profile
108 1, // Short text note
109 3, // Contacts/following
110 4, // Encrypted DM
111 5, // Event deletion
112 6, // Repost
113 7, // Reaction
114 9735, // Zap
115 10000, 10001, 10002, // Mute/pin lists (NIP-51)
116 10050, // Relay list metadata
117 30023, // Long-form content (NIP-23)
118 30078, // Application-specific data (NIP-78)
119 },
105 }, 120 },
106 Server: ServerConfig{ 121 Server: ServerConfig{
107 GrpcAddr: ":50051", 122 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 {
64} 64}
65 65
66type Handler struct { 66type Handler struct {
67 store EventStore 67 store EventStore
68 auth AuthStore 68 auth AuthStore
69 subs *subscription.Manager 69 subs *subscription.Manager
70 metrics MetricsRecorder 70 metrics MetricsRecorder
71 limiter RateLimiter 71 limiter RateLimiter
72 authConfig *AuthConfig 72 authConfig *AuthConfig
73 relayConfig *RelayInfoConfig 73 relayConfig *RelayInfoConfig
74 indexData IndexData 74 indexData IndexData
75 allowedKinds map[int32]bool // nil = allow all
75} 76}
76 77
77func NewHandler(store EventStore, subs *subscription.Manager) *Handler { 78func NewHandler(store EventStore, subs *subscription.Manager) *Handler {
@@ -81,6 +82,17 @@ func NewHandler(store EventStore, subs *subscription.Manager) *Handler {
81 } 82 }
82} 83}
83 84
85func (h *Handler) SetAllowedKinds(kinds []int32) {
86 if len(kinds) == 0 {
87 h.allowedKinds = nil // nil = allow all
88 return
89 }
90 h.allowedKinds = make(map[int32]bool, len(kinds))
91 for _, k := range kinds {
92 h.allowedKinds[k] = true
93 }
94}
95
84func (h *Handler) SetMetrics(m MetricsRecorder) { 96func (h *Handler) SetMetrics(m MetricsRecorder) {
85 h.metrics = m 97 h.metrics = m
86} 98}
@@ -325,8 +337,8 @@ func (h *Handler) handleEvent(ctx context.Context, conn *websocket.Conn, raw []j
325 pbEvent := NostrToPB(&event) 337 pbEvent := NostrToPB(&event)
326 canonicalJSON := event.Serialize() 338 canonicalJSON := event.Serialize()
327 339
328 // Reject non-core protocol kinds (spam, ephemeral, chat) 340 // Reject kinds not in the allowed list
329 if !isAllowedKind(pbEvent.Kind) { 341 if !h.isAllowedKind(pbEvent.Kind) {
330 status = "ok" 342 status = "ok"
331 if h.metrics != nil { 343 if h.metrics != nil {
332 h.metrics.RecordBlockedEvent(pbEvent.Kind) 344 h.metrics.RecordBlockedEvent(pbEvent.Kind)
@@ -623,37 +635,11 @@ func getClientIP(r *http.Request) string {
623 return r.RemoteAddr 635 return r.RemoteAddr
624} 636}
625 637
626// isAllowedKind returns true if the event kind is a core Nostr protocol kind. 638// isAllowedKind returns true if the event kind is permitted by the relay config.
627// Rejects spam, ephemeral events, live chat, and other non-essential kinds. 639// If no allowed kinds are configured, all kinds are accepted.
628func isAllowedKind(kind int32) bool { 640func (h *Handler) isAllowedKind(kind int32) bool {
629 // Core protocol kinds (NIP-01, NIP-02, etc.) 641 if h.allowedKinds == nil {
630 switch kind {
631 case 0: // Metadata/profile
632 return true
633 case 1: // Short text note
634 return true
635 case 3: // Contacts/following
636 return true
637 case 4: // Encrypted DM
638 return true
639 case 5: // Event deletion (handled separately)
640 return true 642 return true
641 case 6: // Repost
642 return true
643 case 7: // Reaction
644 return true
645 case 9735: // Zap
646 return true
647 case 10000, 10001, 10002: // Mute lists, pin lists (NIP-51)
648 return true
649 case 10050: // Relay list metadata
650 return true
651 case 30023: // Long-form content (NIP-23)
652 return true
653 case 30078: // Application-specific data (NIP-78)
654 return true
655 default:
656 // Reject everything else (chat, ephemeral, spam)
657 return false
658 } 643 }
644 return h.allowedKinds[kind]
659} 645}