Skip to content

security(CORE-1130): clear session data on logout transition - #3398

Merged
jeanfbrito merged 1 commit into
masterfrom
security/CORE-1130-logout-clear
Jul 9, 2026
Merged

security(CORE-1130): clear session data on logout transition#3398
jeanfbrito merged 1 commit into
masterfrom
security/CORE-1130-logout-clear

Conversation

@jeanfbrito

@jeanfbrito jeanfbrito commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

  • CORE-1130 (2022 pentest finding: Insufficient Deletion of Application Data On Logout). Session data (cookies, localStorage, indexedDB, service workers) was only cleared via a manual "Clear Cache" dialog action — logging out of a server through the normal webapp UI left that data behind.
  • The logout signal already existed end-to-end (src/injected.tsWEBVIEW_USER_LOGGED_IN action) but had no main-process listener reacting to it — this PR wires it up. No webapp-side (Rocket.Chat repo) change needed.
  • Added handleUserLoggedOutDataClearing() in src/servers/cache.ts: tracks each server's prior userLoggedIn state and only clears on a genuine true → false transition — not on the initial false emitted at webview attach/startup, which would otherwise wipe storage and reload before the user ever logs in.
  • Scope: clears the webview's session storage/cookies/cache for the server the user logged out of. Does not wipe other servers' data or app-level Redux-persisted preferences — correct for a multi-server client where a user may stay logged into other servers.

Test plan

  • npx tsc --noEmit clean
  • yarn eslint clean
  • New spec src/servers/main/cache.spec.ts (4 cases, independently re-run and verified): logged-in→logged-out triggers clear; initial false at startup does NOT trigger (critical regression guard); logged-out→logged-in does NOT trigger; missing webContents is a safe no-op

Summary by CodeRabbit

  • New Features

    • Guest browsing data is now automatically cleared when a user logs out of a server, helping prevent stale session data from carrying over.
    • The affected web view is refreshed after logout so the next session starts cleanly.
  • Bug Fixes

    • Fixed an issue where logging out could leave behind cached or stored login-related data for the same server.

WEBVIEW_USER_LOGGED_IN was dispatched by the webview preload bridge
on every login/logout, but only the reducer consumed it (updating
server.userLoggedIn in Redux state). No main-process side effect
cleared the logged-out server's session storage/cookies/cache, so
login data for a server the user explicitly logged out of remained
on disk and in memory.

Add handleUserLoggedOutDataClearing() in servers/cache.ts, wired in
main.ts next to the existing handleClearCacheDialog(). It listens on
WEBVIEW_USER_LOGGED_IN and reuses the existing
clearWebviewStorageDeletingLoginData() primitive (previously only
reachable from the manual "Clear Cache" dialog).

Transition guard: the action fires userLoggedIn=false on webview
attach/startup before the user has ever logged in, not just on an
actual logout. Reacting to every false payload would wipe storage
and reload the webview on every app launch — a regression, not a
fix. A per-server-URL Map tracks the previously observed
userLoggedIn value (independent of the Redux reducer, which already
overwrites server.userLoggedIn by the time listeners run) so the
clear only fires on a genuine logged-in(true) -> logged-out(false)
transition. Initial false, false->true, and true->true are all
no-ops.

Scope: this only clears webview session storage/cookies/cache for
the server that logged out - it intentionally does not touch
app-level data (download history, persisted preferences) or other
servers' sessions, since a multi-server client can have one server
logged out while staying logged into another.

Test: src/servers/main/cache.spec.ts (named to match jest's
main-process testMatch, which only discovers src/*/main/**/*.spec.ts
or src/**/main.spec.ts - a flat src/servers/cache.main.spec.ts is
not picked up). Covers: logged-in->logged-out triggers the clear;
initial false at startup does not; logged-out->logged-in does not;
missing webContents is a safe no-op.
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR adds a handler that clears guest webview storage (cache, storage data, reload) when a server's user transitions from logged-in to logged-out, tracked per server URL via a module-level map, wires it into app startup, and adds corresponding Jest tests.

Changes

Logout Data Clearing

Layer / File(s) Summary
Logout data clearing handler
src/servers/cache.ts
Tracks previous userLoggedIn state per server URL in a map, listens for WEBVIEW_USER_LOGGED_IN actions, and clears guest webview storage when a logged-in → logged-out transition is detected.
Startup wiring and tests
src/main.ts, src/servers/main/cache.spec.ts
Imports and invokes the new handler during app startup; adds tests validating clearing only on logout transitions, no-op on other transitions, and safe handling when no web contents is found.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Store
  participant CacheModule as handleUserLoggedOutDataClearing
  participant WebContentsResolver as getWebContentsByServerUrl
  participant GuestWebContents

  Store->>CacheModule: WEBVIEW_USER_LOGGED_IN action (url, userLoggedIn)
  CacheModule->>CacheModule: compare previous vs new login state
  alt logged-in to logged-out transition
    CacheModule->>WebContentsResolver: getWebContentsByServerUrl(url)
    WebContentsResolver-->>CacheModule: guestWebContents
    CacheModule->>GuestWebContents: clearWebviewStorageDeletingLoginData(guestWebContents)
  end
Loading

Suggested labels: type: bug

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: clearing session data when a user logs out, and is concise and specific.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • CORE-1130: Request failed with status code 401

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/servers/main/cache.spec.ts`:
- Around line 54-57: The cache.spec.ts setup only clears mocks, but the
module-level previousUserLoggedInByUrl state in cache.ts persists across tests
and can hide the initial-state path. Update the tests to load the cache module
with fresh module state per case, using jest.isolateModules around the imports
that define handleUserLoggedOutDataClearing, so previousUserLoggedInByUrl starts
empty for each test and the “initial logged-out state” scenario truly exercises
the undefined transition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a9cb4c9b-5d10-4c85-a6ef-6aaf83904f39

📥 Commits

Reviewing files that changed from the base of the PR and between a459f10 and 6b54bb3.

📒 Files selected for processing (3)
  • src/main.ts
  • src/servers/cache.ts
  • src/servers/main/cache.spec.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Use TypeScript for all new code unless explicitly told otherwise
Use optional chaining with fallbacks for platform-specific APIs instead of mocking when possible. Example: const uid = process.getuid?.() ?? 1000;

Files:

  • src/servers/main/cache.spec.ts
  • src/main.ts
  • src/servers/cache.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{tsx,ts}: MANDATORY: Use Fuselage components for all UI work. Only create custom components when Fuselage doesn't provide what's needed
Import UI components from @rocket.chat/fuselage and check Theme.d.ts for valid color tokens
Use React functional components with hooks
Use PascalCase for component file names

Files:

  • src/servers/main/cache.spec.ts
  • src/main.ts
  • src/servers/cache.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use *.spec.ts file naming for Renderer process tests

Files:

  • src/servers/main/cache.spec.ts
**/*.{spec.ts,main.spec.ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Only mock platform-specific APIs when defensive coding isn't possible. Linux-only APIs requiring mocks: process.getuid(), process.getgid(), process.geteuid(), process.getegid()

Files:

  • src/servers/main/cache.spec.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Redux actions must follow FSA (Flux Standard Action) pattern
Avoid unnecessary comments — write self-documenting code through clear naming
Always verify libraries by checking official docs and .d.ts files in node_modules/. Never assume props, tokens, or APIs work without verification
Avoid subjective descriptors ('smart', 'excellent', 'dumb') in documentation and comments
Use measurable descriptions in code documentation: 'reduced memory usage', 'improved by X%' instead of subjective claims
NEVER invent metrics — don't include estimated time spent or speculated user counts. Only include numbers from actual logs, error messages, or documented sources

Files:

  • src/servers/main/cache.spec.ts
  • src/main.ts
  • src/servers/cache.ts
🔇 Additional comments (2)
src/servers/cache.ts (1)

7-10: LGTM!

Also applies to: 57-79

src/main.ts (1)

41-44: LGTM!

Also applies to: 161-161

Comment on lines +54 to +57
beforeEach(() => {
jest.clearAllMocks();
handleUserLoggedOutDataClearing();
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Reset previousUserLoggedInByUrl between tests for proper isolation.

jest.clearAllMocks() resets mock call history but does not reset the module-level previousUserLoggedInByUrl Map in cache.ts. After test 1 dispatches true then false, the map retains { url: false }. Test 2 ("does not clear on the initial logged-out state at startup/attach") then runs with wasLoggedIn = false instead of undefined — it passes, but doesn't exercise the actual initial-state path described in its name.

If the transition condition were ever changed to distinguish undefined from false, this test would give false confidence. Use jest.isolateModules to get a fresh module registry per test:

🧪 Proposed fix for test isolation
 beforeEach(() => {
   jest.clearAllMocks();
-  handleUserLoggedOutDataClearing();
+  jest.isolateModules(() => {
+    // eslint-disable-next-line `@typescript-eslint/no-var-requires`
+    const { handleUserLoggedOutDataClearing } = require('../cache');
+    handleUserLoggedOutDataClearing();
+  });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/servers/main/cache.spec.ts` around lines 54 - 57, The cache.spec.ts setup
only clears mocks, but the module-level previousUserLoggedInByUrl state in
cache.ts persists across tests and can hide the initial-state path. Update the
tests to load the cache module with fresh module state per case, using
jest.isolateModules around the imports that define
handleUserLoggedOutDataClearing, so previousUserLoggedInByUrl starts empty for
each test and the “initial logged-out state” scenario truly exercises the
undefined transition.

@jeanfbrito
jeanfbrito merged commit 05f7a3c into master Jul 9, 2026
10 checks passed
@jeanfbrito
jeanfbrito deleted the security/CORE-1130-logout-clear branch July 9, 2026 14:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant