diff options
Diffstat (limited to 'internal/handler/websocket/handler.go')
| -rw-r--r-- | internal/handler/websocket/handler.go | 68 |
1 files changed, 27 insertions, 41 deletions
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 | ||
| 66 | type Handler struct { | 66 | type 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 | ||
| 77 | func NewHandler(store EventStore, subs *subscription.Manager) *Handler { | 78 | func 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 | ||
| 85 | func (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 | |||
| 84 | func (h *Handler) SetMetrics(m MetricsRecorder) { | 96 | func (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. |
| 628 | func isAllowedKind(kind int32) bool { | 640 | func (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 | } |
