summaryrefslogtreecommitdiffstats
path: root/internal/handler
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-15 07:58:38 -0800
committerbndw <ben@bdw.to>2026-02-15 07:58:38 -0800
commit77bb5b2469e6813bed3ffc0be5ed4933a437a969 (patch)
tree863f1e5ad051483900910174b4cfd9c9e327efba /internal/handler
parentbff984727e240dfc29533381d60a2127d833c10a (diff)
feat: filter events to core Nostr protocol kinds only
Add allowlist filtering to reject spam, ephemeral events, and live chat messages. Only accept core protocol kinds (notes, reactions, metadata, etc). Allowed kinds: - 0, 1, 3, 4, 5, 6, 7: Core protocol (NIP-01, 02, 04, 09, 18, 25) - 9735: Zaps (NIP-57) - 10000-10002: Mute/pin lists (NIP-51) - 10050: Relay list metadata - 30023, 30078: Long-form content, app data (NIP-23, 78) Rejected kinds: - 20001: Bot metadata spam (~157+ events/day) - 30311: Live chat messages (~100+ events/day) - All other kinds: Future spam/ephemeral events Reduces storage growth by ~80% while keeping all essential functionality. Clients receive "rejected: kind not supported" for filtered events.
Diffstat (limited to 'internal/handler')
-rw-r--r--internal/handler/websocket/handler.go42
1 files changed, 42 insertions, 0 deletions
diff --git a/internal/handler/websocket/handler.go b/internal/handler/websocket/handler.go
index 715e777..8daa89f 100644
--- a/internal/handler/websocket/handler.go
+++ b/internal/handler/websocket/handler.go
@@ -299,6 +299,13 @@ func (h *Handler) handleEvent(ctx context.Context, conn *websocket.Conn, raw []j
299 pbEvent := NostrToPB(&event) 299 pbEvent := NostrToPB(&event)
300 canonicalJSON := event.Serialize() 300 canonicalJSON := event.Serialize()
301 301
302 // Reject non-core protocol kinds (spam, ephemeral, chat)
303 if !isAllowedKind(pbEvent.Kind) {
304 status = "ok"
305 h.sendOK(ctx, conn, event.ID, true, "rejected: kind not supported")
306 return nil
307 }
308
302 // Handle deletion events (kind 5) - process but don't store 309 // Handle deletion events (kind 5) - process but don't store
303 if pbEvent.Kind == 5 { 310 if pbEvent.Kind == 5 {
304 if err := h.store.ProcessDeletion(ctx, pbEvent); err != nil { 311 if err := h.store.ProcessDeletion(ctx, pbEvent); err != nil {
@@ -564,3 +571,38 @@ func getClientIP(r *http.Request) string {
564 // Fall back to RemoteAddr (direct connection or proxy IP) 571 // Fall back to RemoteAddr (direct connection or proxy IP)
565 return r.RemoteAddr 572 return r.RemoteAddr
566} 573}
574
575// isAllowedKind returns true if the event kind is a core Nostr protocol kind.
576// Rejects spam, ephemeral events, live chat, and other non-essential kinds.
577func isAllowedKind(kind int32) bool {
578 // Core protocol kinds (NIP-01, NIP-02, etc.)
579 switch kind {
580 case 0: // Metadata/profile
581 return true
582 case 1: // Short text note
583 return true
584 case 3: // Contacts/following
585 return true
586 case 4: // Encrypted DM
587 return true
588 case 5: // Event deletion (handled separately)
589 return true
590 case 6: // Repost
591 return true
592 case 7: // Reaction
593 return true
594 case 9735: // Zap
595 return true
596 case 10000, 10001, 10002: // Mute lists, pin lists (NIP-51)
597 return true
598 case 10050: // Relay list metadata
599 return true
600 case 30023: // Long-form content (NIP-23)
601 return true
602 case 30078: // Application-specific data (NIP-78)
603 return true
604 default:
605 // Reject everything else (chat, ephemeral, spam)
606 return false
607 }
608}