From 77bb5b2469e6813bed3ffc0be5ed4933a437a969 Mon Sep 17 00:00:00 2001 From: bndw Date: Sun, 15 Feb 2026 07:58:38 -0800 Subject: 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. --- internal/handler/websocket/handler.go | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'internal') 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 pbEvent := NostrToPB(&event) canonicalJSON := event.Serialize() + // Reject non-core protocol kinds (spam, ephemeral, chat) + if !isAllowedKind(pbEvent.Kind) { + status = "ok" + h.sendOK(ctx, conn, event.ID, true, "rejected: kind not supported") + return nil + } + // Handle deletion events (kind 5) - process but don't store if pbEvent.Kind == 5 { if err := h.store.ProcessDeletion(ctx, pbEvent); err != nil { @@ -564,3 +571,38 @@ func getClientIP(r *http.Request) string { // Fall back to RemoteAddr (direct connection or proxy IP) 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) + 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 + } +} -- cgit v1.2.3