fix: WebSocket chat:send — per-user rate limiting, ack payloads, and standardized errors#113
Open
davedumto wants to merge 1 commit intoTevaLabs:mainfrom
Open
fix: WebSocket chat:send — per-user rate limiting, ack payloads, and standardized errors#113davedumto wants to merge 1 commit intoTevaLabs:mainfrom
davedumto wants to merge 1 commit intoTevaLabs:mainfrom
Conversation
…s for socket chat:send
- Add SocketRateLimiter class (sliding-window, keyed by userId) to socket.ts
matching the HTTP chatMessageRateLimiter limit of 5 messages per 60 seconds
- Export chatRateLimiter instance so tests can reset state between cases
- Rewrite chat:send handler to use Socket.IO acknowledgement callbacks,
returning { ok: true, message } on success and
{ ok: false, error, code } on all failure paths
- Typed error codes: AUTH_REQUIRED | INVALID_CONTENT | RATE_LIMITED | SEND_FAILED
- Route chat:send through chatService.sendMessage() instead of duplicating
DB logic inline — profanity filtering and wallet address masking now apply
to WebSocket messages consistently with the HTTP path
- Handle missing callback gracefully (no-op) for backwards-compatible clients
- Add 8 new tests covering: unauthenticated send, empty content, over-500
chars, chatService error, valid send with ack, no-callback safety, burst
spam (5 ok, 6th RATE_LIMITED), and post-window-reset recovery
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
##closes #107
The WebSocket
chat:sendpath validated message content but had no abuse controls — a connected client could flood the chat room without any throttling. There were also no acknowledgement payloads (success or failure), and error responses were inconsistent unstructured objects emitted on a genericerrorevent.This PR closes that gap, bringing the WebSocket chat surface to parity with the HTTP
POST /api/chat/sendendpoint.What Changed
src/socket.tsPer-user rate limiting (
SocketRateLimiter)SocketRateLimiterclass using a sliding-window algorithm keyed byuserId.chatMessageRateLimiter.chatRateLimiterinstance is exported so tests can callchatRateLimiter.reset()to isolate state between test cases.{ ok: false, code: 'RATE_LIMITED' }and logs a warning; no DB write occurs.Acknowledgement-based responses
chat:sendnow accepts an optional second argumentcallback?: (ack: ChatAck) => void, the standard Socket.IO acknowledgement pattern.{ ok: true, message: ChatMessage }{ ok: false, error: string, code: 'AUTH_REQUIRED' | 'INVALID_CONTENT' | 'RATE_LIMITED' | 'SEND_FAILED' }Routed through
chatService.sendMessage()chatServiceentirely — profanity filtering and wallet address masking did not apply to WebSocket messages.chatService.sendMessage(userId, walletAddress, content), making the WebSocket and HTTP paths consistent.src/tests/socket.spec.tsAdded a
chat:senddescribe block with 8 new tests on top of the existing 9:{ ok: false, code: 'AUTH_REQUIRED' }{ ok: false, code: 'INVALID_CONTENT' }{ ok: false, code: 'INVALID_CONTENT' }chatServicethrows{ ok: false, code: 'SEND_FAILED' }{ ok: true, message: <ChatMessage> }, correct args forwarded tochatServiceRATE_LIMITED;chatServicecalled exactly 5 timeschatRateLimiter.reset(), messages are accepted againAlso fixed the
afterAllteardown to callhttpServer.closeAllConnections()beforehttpServer.close()— previously the hook could time out when open socket connections prevented the HTTP server from closing cleanly.Test Run
Definition of Done checklist
codevalues