Repository navigation
Conversation
EmbeddedChatApi.logout() only cleared the auth token via auth.logout(). The DDP connection and its active subscriptions were left running, so the client kept receiving live messages and events for a session that was no longer authenticated. logout() now tears the connection down via the existing close() method. The teardown runs in a finally block so the socket is also closed when the logout request itself fails, and close() errors are logged rather than propagated so they cannot mask the logout result. Fixes RocketChat#1158
|
Thanks for picking this up :) |
close() now invalidates a connect() which is still awaiting, so that subscriptions are not registered after the socket has been torn down. Previously, if logout happened while _doConnect() was awaiting joinRoom() (or the connection/login steps), the connect would resume afterwards and register the stream subscriptions on the closed connection, which the DDP client replays on the next connection. Addresses review feedback on RocketChat#1394.
|
Thanks for the review @Aryan-Verma-999 — you're right, and the window was wider than just
Fixed in
I also pulled the teardown out into Verification
Before: After: I ran the harness against the previous commit first to confirm it actually reproduces the bug rather than passing vacuously. Also run: One thing still outside this PR's reach: CI hasn't run on any of my PRs yet — the workflow runs are sitting at |
…ocketChat#1158) (#4) * fix: close realtime connection on logout to prevent ghost sessions EmbeddedChatApi.logout() only cleared the auth token via auth.logout(). The DDP connection and its active subscriptions were left running, so the client kept receiving live messages and events for a session that was no longer authenticated. logout() now tears the connection down via the existing close() method. The teardown runs in a finally block so the socket is also closed when the logout request itself fails, and close() errors are logged rather than propagated so they cannot mask the logout result. Fixes RocketChat#1158 * [DOCS] Align Node.js requirement in docs README with package.json engines * feat: keep emoji picker open for multiple selections * chore: format code * fix: cancel in-flight connect on logout to prevent ghost subscriptions close() now invalidates a connect() which is still awaiting, so that subscriptions are not registered after the socket has been torn down. Previously, if logout happened while _doConnect() was awaiting joinRoom() (or the connection/login steps), the connect would resume afterwards and register the stream subscriptions on the closed connection, which the DDP client replays on the next connection. Addresses review feedback on RocketChat#1394. --------- Co-authored-by: swarnendusahu10-dotcom <[email protected]> Co-authored-by: Aryan Verma <[email protected]> Co-authored-by: iRahul360 <[email protected]>
|
Hi @Aryan-Verma-999 — a brief follow-up on the race fix: the generation-counter change is on the PR head (). The latest Build and Lint / Playwright runs are still and need maintainer approval before they can provide CI results. If you consider the change ready, could someone approve those workflows when convenient? Happy to address any further review feedback; no urgency. |
|
Correction to my previous note: the fix is commit dceb793, and the required workflow runs currently show action_required. They need maintainer approval to start; could someone approve the Build and Lint and Playwright workflows when convenient? Thank you. |
Fixes #1158
Problem
EmbeddedChatApi.logout()only awaitedthis.auth.logout(), which clears the auth token. The DDP connection and its_activeSubscriptionswere left running, so after a "logout" the client kept receiving live messages and events for a session that was no longer authenticated — a privacy leak, and inconsistent state if another user logged in without a full page refresh.The class already has a
close()method that stops_activeSubscriptionsand callssdk.connection.close().logout()simply never called it.Fix
logout()now tears the connection down via the existingclose(), with two deliberate details:finallyblock, so the socket is also closed when the logout request itself fails (a failed logout previously left a fully live session behind);close()errors are logged rather than propagated, so they cannot mask the logout result. Other call sites already treatclose()as rejectable (EmbeddedChat.jswraps it in.catch())._connectPromiseeven whenconnection.connect()never settles. Cleanup is identity-guarded so an abandoned handshake cannot clear a newer connection attempt.Verification
Added
packages/api/test/connection-lifecycle.test.mjsand an API test command. The regression test covers the reviewed race directly:connect()starts a fresh handshake and callsloginWithToken();Validated with Node 24:
yarn workspace @embeddedchat/api test— 1/1 passed;yarn tsc --noEmit -p packages/api/tsconfig.json— clean;yarn workspace @embeddedchat/api build— passed;yarn lint— 0 errors (existing warnings only).The original teardown harness also passes all seven logout assertions on this branch and fails five of them on unpatched
develop, confirming the base logout regression remains covered.Prior art
@Aryan-Verma-999's earlier #1171 identified the same root cause and was closed unmerged. This PR keeps that insight and adds the
finallyhandling so a failed logout cannot leave a live socket behind.