summaryrefslogtreecommitdiffstats
path: root/internal/handler/websocket
Commit message (Collapse)AuthorAgeFilesLines
* feat: add metrics for blocked eventsbndw2 days1-0/+4
| | | | | | | | | | | | Track and display blocked event counts with per-kind breakdown. - Add events_blocked_total counter with kind label - Add RecordBlockedEvent method to metrics - Display blocked count in dashboard Storage section - Call metric when rejecting non-core protocol kinds Allows monitoring spam patterns and verifying kind filter effectiveness. Raw metrics show breakdown by kind (e.g., kind=20001, kind=30311).
* feat: filter events to core Nostr protocol kinds onlybndw2 days1-0/+42
| | | | | | | | | | | | | | | | | | | | 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.
* feat: track WebSocket requests in metricsbndw2 days1-0/+46
| | | | | | | | | | | | | Add request tracking for EVENT and REQ messages to match gRPC behavior. Dashboard now shows total/success/error counts for all requests. - Add RecordRequest to MetricsRecorder interface - Track timing and status in handleEvent and handleReq - Record metrics with status: ok, error, unauthenticated, rate_limited - Measure request duration for performance monitoring WebSocket is the primary interface, so tracking these requests is critical for understanding relay usage and performance.
* fix: track WebSocket connections in metricsbndw2 days1-0/+13
| | | | | | | | | | | Connection metrics were defined but never called. Add IncrementConnections and DecrementConnections to MetricsRecorder interface and call them when WebSocket connections are established/closed. - Add connection methods to MetricsRecorder interface - Increment on successful WebSocket upgrade - Decrement in defer when connection closes - Dashboard will now show active connection count
* feat: add rate limiting to WebSocket connectionsbndw3 days1-1/+53
| | | | | | | | | | | | | | | WebSocket clients were completely unprotected from abuse. Add RateLimiter interface to WebSocket handler and enforce limits on EVENT and REQ messages. - Add RateLimiter interface with Allow(identifier, method) method - Track client IP in connState (proxy-aware via X-Forwarded-For) - Check rate limits in handleEvent and handleReq - Use authenticated pubkey as identifier, fallback to IP - Share same rate limiter instance with gRPC - Add getClientIP() helper that checks proxy headers first Critical security fix for production deployment. Without this, any client could spam unlimited events/subscriptions via WebSocket.
* refactor: use AuthStore interface and remove type assertionsbndw3 days1-34/+51
| | | | | | | | | | | | | Replace runtime type assertions with compile-time safe AuthStore interface. Add connState struct for cleaner per-connection state management instead of mutable pointer parameters. Reduce auth challenge TTL from 10min to 2min. - Add AuthStore interface with CreateAuthChallenge and ValidateAndConsumeChallenge - Add connState struct for authenticatedPubkey and authChallenge - Remove fragile type assertion pattern in requireAuth and handleAuth - Add nil checks for auth store with clear error messages - Update Handler to have separate auth field - Wire auth store in main.go when auth is enabled
* fix: silently wait for auth instead of sending NOTICEbndw3 days1-1/+9
| | | | | | | After sending AUTH challenge, return nil instead of error to avoid sending NOTICE messages to clients. Add explicit checks in handleEvent and handleReq to silently ignore requests when auth is required but client hasn't authenticated yet. This follows NIP-42 spec more closely.
* feat: implement NIP-42 WebSocket authenticationbndw3 days1-6/+126
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Add support for authenticating WebSocket clients using NIP-42 protocol, enabling auth restrictions for normal Nostr clients. Storage layer (internal/storage/auth.go): - CreateAuthChallenge() - Generate random 32-byte challenge with 10min TTL - ValidateAndConsumeChallenge() - Verify challenge validity and mark as used - CleanupExpiredChallenges() - Remove old challenges from database - Uses existing auth_challenges table WebSocket handler (internal/handler/websocket/handler.go): - Track authenticatedPubkey per connection - Track authChallenge per connection - requireAuth() - Check if operation requires authentication - handleAuth() - Process AUTH responses (kind 22242 events) - sendAuthChallenge() - Send AUTH challenge to client - Enforce auth on EVENT (writes) and REQ (reads) messages - Support separate read/write allowlists Main (cmd/relay/main.go): - Wire auth config from YAML to WebSocket handler - Pass read/write enabled flags and allowed npub lists NIP-42 Flow: 1. Client sends EVENT/REQ without auth 2. If auth required, relay sends: ["AUTH", "<challenge>"] 3. Client signs kind 22242 event with challenge tag 4. Client sends: ["AUTH", <signed-event>] 5. Relay validates signature, challenge, and allowlist 6. Connection marked as authenticated 7. Client can now EVENT/REQ Example config to restrict writes to your npub: ```yaml auth: write: enabled: true allowed_npubs: - npub1your-npub-here... ``` WebSocket clients (Damus, Amethyst, etc.) can now authenticate!
* feat: track WebSocket subscriptions in metricsbndw3 days1-0/+27
| | | | | | | | | | | | | | | | | Add metrics tracking for WebSocket (NIP-01) subscriptions in addition to existing gRPC subscription tracking. Changes: - Add Count() method to subscription.Manager - Add MetricsRecorder interface to WebSocket handler - Update subscription metrics when REQ/CLOSE messages processed - Wire up metrics to WebSocket handler in main.go Before: Only gRPC stream subscriptions were counted After: Both gRPC and WebSocket subscriptions tracked accurately This fixes the dashboard showing 0 subscriptions when clients connect via WebSocket (e.g., nak req --stream).
* refactor: remove frivolous comments from auth validation/credentialsbndw3 days2-2/+2
| | | | Also removed internal/nostr package - now using northwest.io/nostr library.
* index updatebndw3 days1-1/+1
|
* index updatebndw3 days1-4/+4
|
* Update index pagebndw3 days1-9/+1
|
* refactor: simplify footer text on index pagebndw3 days1-1/+1
|
* refactor: remove PGP signature block from index pagebndw3 days1-8/+0
|
* feat: add muxstr SVG logo to index pagebndw3 days1-11/+16
| | | | | Replace ASCII art banner with SVG logo featuring the muxstr branding. Update page title and background color to match brand identity.
* refactor: rename project from nostr-grpc to muxstrbndw3 days3-9/+9
| | | | | | Update module path from northwest.io/nostr-grpc to northwest.io/muxstr. This includes updating all Go imports, protobuf definitions, generated files, and documentation.
* fix: allow WebSocket upgrades to bypass HTML indexbndw4 days1-2/+3
| | | | | | | | | | WebSocket connections start as GET requests with 'Upgrade: websocket' header. The handler was serving HTML for ALL GET requests, preventing WebSocket upgrades from ever happening. Fix by checking for Upgrade header and only serving HTML/NIP-11 for non-WebSocket GET requests. Now WebSocket connections return status 101 (Switching Protocols) instead of 200 (OK).
* fix: remove duplicate protocol prefix in WebSocket URLbndw4 days1-1/+1
| | | | | | | | | | | The template was hardcoding 'ws://' prefix, but when using --public-url we were already passing 'wss://'. This caused the URL to display as 'ws://wss://domain/'. Fix by: - Removing 'ws://' prefix from template - Always including protocol in the variable (ws:// or wss://) - Also add http:// prefix for local development consistency
* redesign: early web minimalism + cypherpunkbndw4 days1-408/+115
| | | | | | | | | | | | | | | | | | | | | | | | | | | Complete aesthetic reversal - from cyber-brutalist to minimal: AESTHETIC: 1995 web document meets cypherpunks mailing list - Courier New system font (no web fonts) - Black on white for readability - Semantic HTML with minimal CSS - PGP signature blocks (cypherpunk heritage) - Classic underlined blue links - Horizontal rules for section breaks - Looks like a .txt file rendered as HTML PHILOSOPHY: Throwback to when the web was just documents. No animations, no grids, no gradients. Just semantic HTML, monospace type, and information. Fast loading, accessible, timeless. CYPHERPUNK TOUCHES: - PGP signature blocks - Hash fingerprints - Technical language - Cryptographic references - Feels like reading crypto mailing list archives Zero frameworks, zero build tools, maximum signal.
* redesign: cyber-brutalist terminal aestheticbndw4 days1-101/+367
| | | | | | | | | | | | | | | | | | | | | | | | | | Complete visual overhaul with bold conceptual direction: AESTHETIC: Cyber-brutalist terminal interface - JetBrains Mono monospace throughout - Deep black (#0a0e14) with cyan/green accents - ASCII art Nostr logo with glitch animation - Animated grid background (scrolling terminal feel) - Terminal-style status bar with pulse indicators - Protocol cards with scanning line effects - Information-dense but organized layout MOTION & EFFECTS: - Glitching ASCII logo animation - Scanning line on protocol cards - Pulsing status indicators - Animated grid background - Staggered fade-in on page load - Hover effects with glow DIFFERENTIATION: Feels like SSH into a relay node. Unapologetically technical, embracing Nostr's decentralized, cypherpunk ethos. Zero generic design patterns - full commitment to terminal aesthetic.
* feat: add HTML index page for browser viewingbndw4 days2-4/+218
| | | | | | | | | | Add a beautiful HTML landing page when visiting relay in browser: - Shows all three protocol endpoints (gRPC, Connect, WebSocket) - Lists supported NIPs (01, 09, 11) - Displays relay features and info - Responsive design with gradient styling - Serves on GET requests (regular Accept header) - NIP-11 still served for Accept: application/nostr+json
* feat: implement NIP-09 with hard deletebndw4 days1-0/+11
| | | | | | | | | | | Implement event deletion (NIP-09) using hard delete approach: - Kind 5 events trigger deletion but are not stored themselves - ProcessDeletion hard deletes referenced events (DELETE FROM events) - Only authors can delete their own events (pubkey verification) - Support multiple event IDs in single deletion request - No deletions table needed (simpler schema) - Added 4 deletion tests covering various scenarios - All 45 tests passing
* refactor: simplify deletion handling (remove NIP-09 processing)bndw4 days1-8/+0
| | | | | | | | | | Remove deletion processing logic in favor of simpler approach: - Remove deletions table from schema - Delete deletions.go and deletions_test.go - Remove ProcessDeletion from EventStore interface - Kind 5 events now stored like any other event (no special handling) - Update storage test to expect 2 tables instead of 3 - All 41 tests passing
* feat: implement NIP-09 (deletions) and NIP-11 (relay info)bndw4 days2-0/+73
| | | | | | | | | | | | | | | | | | | | | | NIP-11 (Relay Information Document): - Serves relay metadata at GET / with Accept: application/nostr+json - Returns name, description, supported NIPs, limitations - CORS headers for browser compatibility NIP-09 (Event Deletion): - Kind 5 events delete events referenced in 'e' tags - Only authors can delete their own events - Soft delete (marks deleted=1) - Records deletion in deletions table - Works across all protocols (gRPC, Connect, WebSocket) Fixed deletions schema: - deleted_event_id as PRIMARY KEY (not deletion_event_id) - Allows one deletion event to delete multiple events 3 new tests, 44 total tests passing Supported NIPs now: 1, 9, 11
* feat: add WebSocket server with full NIP-01 supportbndw4 days2-0/+322
WebSocket handler: - NIP-01 protocol (EVENT, REQ, CLOSE, OK, EOSE, NOTICE) - JSON envelope parsing - Shares subscription manager with gRPC (unified event fan-out) - Standard Nostr client compatibility Relay now serves dual protocols: - gRPC on :50051 (binary, high performance) - WebSocket on :8080 (JSON, Nostr standard) Both protocols share: - Same storage layer - Same subscription manager - Same validation logic Compatible with all Nostr clients!