Skip to content

fix: add timeout to CAS popup login to prevent infinite hang#40161

Open
Kgupta62 wants to merge 1 commit intoRocketChat:developfrom
Kgupta62:fix/cas-popup-timeout
Open

fix: add timeout to CAS popup login to prevent infinite hang#40161
Kgupta62 wants to merge 1 commit intoRocketChat:developfrom
Kgupta62:fix/cas-popup-timeout

Conversation

@Kgupta62
Copy link
Copy Markdown

@Kgupta62 Kgupta62 commented Apr 15, 2026

Summary

Closes #40153

  • openCASLoginPopup() polls popup.closed every 100ms with no timeout, causing the login flow to hang indefinitely if the popup never closes
  • Added a 120-second timeout using Promise.race() that rejects with a user-friendly error message and attempts to close the stale popup
  • No changes to the happy path -- if the popup closes normally, the timeout is never triggered

Changes

  • apps/meteor/client/lib/openCASLoginPopup.ts: Wrapped the polling promise in Promise.race() alongside a 120-second timeout promise that rejects with "CAS login timed out. Please try again."

Test plan

  • Verify CAS login still works normally when the popup closes as expected
  • Simulate a stuck popup (e.g. block the CAS redirect) and confirm the login rejects with the timeout error after ~120 seconds instead of hanging forever

Note

This PR was authored with assistance from an AI coding tool (Claude Code by Anthropic).

Summary by CodeRabbit

Bug Fixes

  • CAS login popup now enforces a 120-second timeout for authentication attempts. If the authentication process doesn't complete within this timeframe, the popup will automatically close and display a timeout error message. This prevents users from being stuck indefinitely and improves the overall authentication experience.

@Kgupta62 Kgupta62 requested a review from a team as a code owner April 15, 2026 05:36
@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot bot commented Apr 15, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 15, 2026

⚠️ No Changeset found

Latest commit: 8e8711c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

Walkthrough

Added a timeout mechanism to CAS popup login to prevent indefinite waiting. The waitForPopupClose function now races a 120-second timeout against popup closure detection, automatically closing the popup and rejecting with a timeout error if the popup does not close within the time limit.

Changes

Cohort / File(s) Summary
CAS Popup Timeout
apps/meteor/client/lib/openCASLoginPopup.ts
Added CAS_POPUP_TIMEOUT_MS constant (120000ms) and implemented timeout race against popup closure polling in waitForPopupClose. On timeout, attempts popup closure (with cross-origin error handling) and rejects with timeout error message.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

type: bug, area: authentication

🚥 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 and concisely describes the main change: adding a timeout to prevent CAS popup login from hanging indefinitely.
Linked Issues check ✅ Passed The PR directly addresses issue #40153 by implementing a 120-second timeout with proper error messaging and popup cleanup, fulfilling the core requirement to prevent infinite hangs.
Out of Scope Changes check ✅ Passed All changes are contained within the target file (openCASLoginPopup.ts) and directly address the timeout requirement from the linked issue with no extraneous modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/client/lib/openCASLoginPopup.ts`:
- Line 60: Remove the inline comment inside the catch block in
apps/meteor/client/lib/openCASLoginPopup.ts (the catch handling around the
popup/window check in function openCASLoginPopup), i.e., delete the comment text
"// popup may already be closed or cross-origin" so the catch block contains no
implementation comment and matches repository style; leave the catch body empty
or add a minimal TODO or proper error handling if required by project policy.
- Around line 46-67: The polling interval and timeout are not cleared in both
completion paths; update the logic in openCASLoginPopup (the pollClosed Promise
and timeout Promise using checkPopupOpen interval and the setTimeout with
CAS_POPUP_TIMEOUT_MS) so that when either path completes you clear the other
timer: store the interval id (checkPopupOpen) and timeout id, call
clearInterval(checkPopupOpen) and clearTimeout(timeoutId) inside the pollClosed
resolve branch and likewise clearInterval/checkPopupOpen before rejecting in the
timeout branch (ensure popup.close() remains wrapped in try/catch).
🪄 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: 7719af75-046c-4d40-add0-14ce44381d94

📥 Commits

Reviewing files that changed from the base of the PR and between 41f6662 and 8e8711c.

📒 Files selected for processing (1)
  • apps/meteor/client/lib/openCASLoginPopup.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/lib/openCASLoginPopup.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `page.waitFor()` with specific conditions instead of hardcoded timeouts in Playwright tests
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `page.waitFor()` with specific conditions instead of hardcoded timeouts in Playwright tests

Applied to files:

  • apps/meteor/client/lib/openCASLoginPopup.ts
📚 Learning: 2026-02-10T16:32:42.586Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38528
File: apps/meteor/client/startup/roles.ts:14-14
Timestamp: 2026-02-10T16:32:42.586Z
Learning: In Rocket.Chat's Meteor client code, DDP streams use EJSON and Date fields arrive as Date objects; do not manually construct new Date() in stream handlers (for example, in sdk.stream()). Only REST API responses return plain JSON where dates are strings, so implement explicit conversion there if needed. Apply this guidance to all TypeScript files under apps/meteor/client to ensure consistent date handling in DDP streams and REST responses.

Applied to files:

  • apps/meteor/client/lib/openCASLoginPopup.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/client/lib/openCASLoginPopup.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/client/lib/openCASLoginPopup.ts
🔇 Additional comments (1)
apps/meteor/client/lib/openCASLoginPopup.ts (1)

43-44: Nice extraction of popup timeout constant.

Good call centralizing the timeout value; this keeps the flow readable and easier to adjust later.

Comment on lines +46 to 67
const pollClosed = new Promise<void>((resolve) => {
const checkPopupOpen = setInterval(() => {
if (popup.closed || popup.closed === undefined) {
clearInterval(checkPopupOpen);
resolve();
}
}, 100);
});

const timeout = new Promise<never>((_, reject) => {
setTimeout(() => {
try {
popup.close();
} catch {
// popup may already be closed or cross-origin
}
reject(new Error('CAS login timed out. Please try again.'));
}, CAS_POPUP_TIMEOUT_MS);
});

return Promise.race([pollClosed, timeout]);
};
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.

⚠️ Potential issue | 🟠 Major

Clear timer handles on both completion paths.

On Line 46 and Line 55, interval/timeout are created independently but never jointly cleaned up. If the timeout path hits Line 57 and popup.close() fails, polling may continue forever; if polling wins first, the timeout still executes later.

Proposed fix
 const waitForPopupClose = (popup: Window) => {
-	const pollClosed = new Promise<void>((resolve) => {
-		const checkPopupOpen = setInterval(() => {
-			if (popup.closed || popup.closed === undefined) {
-				clearInterval(checkPopupOpen);
-				resolve();
-			}
-		}, 100);
-	});
-
-	const timeout = new Promise<never>((_, reject) => {
-		setTimeout(() => {
-			try {
-				popup.close();
-			} catch {
-				// popup may already be closed or cross-origin
-			}
-			reject(new Error('CAS login timed out. Please try again.'));
-		}, CAS_POPUP_TIMEOUT_MS);
-	});
-
-	return Promise.race([pollClosed, timeout]);
+	return new Promise<void>((resolve, reject) => {
+		const checkPopupOpen = window.setInterval(() => {
+			if (popup.closed || popup.closed === undefined) {
+				cleanup();
+				resolve();
+			}
+		}, 100);
+
+		const timeoutId = window.setTimeout(() => {
+			cleanup();
+			try {
+				popup.close();
+			} catch {}
+			reject(new Error('CAS login timed out. Please try again.'));
+		}, CAS_POPUP_TIMEOUT_MS);
+
+		const cleanup = (): void => {
+			window.clearInterval(checkPopupOpen);
+			window.clearTimeout(timeoutId);
+		};
+	});
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/lib/openCASLoginPopup.ts` around lines 46 - 67, The
polling interval and timeout are not cleared in both completion paths; update
the logic in openCASLoginPopup (the pollClosed Promise and timeout Promise using
checkPopupOpen interval and the setTimeout with CAS_POPUP_TIMEOUT_MS) so that
when either path completes you clear the other timer: store the interval id
(checkPopupOpen) and timeout id, call clearInterval(checkPopupOpen) and
clearTimeout(timeoutId) inside the pollClosed resolve branch and likewise
clearInterval/checkPopupOpen before rejecting in the timeout branch (ensure
popup.close() remains wrapped in try/catch).

try {
popup.close();
} catch {
// popup may already be closed or cross-origin
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.

⚠️ Potential issue | 🟡 Minor

Remove inline catch comment to match repository style.

Line 60 adds an implementation comment in production code; this should be removed to follow project conventions.

As per coding guidelines "Avoid code comments in the implementation".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/lib/openCASLoginPopup.ts` at line 60, Remove the inline
comment inside the catch block in apps/meteor/client/lib/openCASLoginPopup.ts
(the catch handling around the popup/window check in function
openCASLoginPopup), i.e., delete the comment text "// popup may already be
closed or cross-origin" so the catch block contains no implementation comment
and matches repository style; leave the catch body empty or add a minimal TODO
or proper error handling if required by project policy.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

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.

CAS popup login can hang forever if the popup does not close

2 participants