Skip to content

fix: prevent popup crash by ensuring DOM is loaded before accessing elements#81

Open
Khushi5623 wants to merge 6 commits into
Stanzin7:masterfrom
Khushi5623:fix-popup-crash
Open

fix: prevent popup crash by ensuring DOM is loaded before accessing elements#81
Khushi5623 wants to merge 6 commits into
Stanzin7:masterfrom
Khushi5623:fix-popup-crash

Conversation

@Khushi5623
Copy link
Copy Markdown

@Khushi5623 Khushi5623 commented Apr 3, 2026

🛠 Fix: Prevent Popup Crash by Ensuring DOM Readiness

🚨 Issue

The popup script was accessing DOM elements before the document was fully loaded, which could lead to null references and potential crashes.

✅ Changes Made

  • Wrapped popup logic inside DOMContentLoaded event listener
  • Ensured DOM elements are accessed after full load
  • Prevented potential null reference errors

🎯 Impact

  • Improves popup stability
  • Prevents runtime crashes
  • Enhances user experience

This fix aligns with best practices for Chrome Extension development and improves overall reliability.

Summary by CodeRabbit

  • New Features

    • Scan button now disables during active scans, providing clearer user feedback.
  • Bug Fixes

    • Improved popup initialization timing for better stability.
    • Enhanced error handling for edge cases.
    • Updated invalid-input error message for clarity.

@sapnilbiswas
Copy link
Copy Markdown
Collaborator

@Khushi5623 Contains conflict, also the audit is failing

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 24, 2026

📝 Walkthrough

Walkthrough

The popup script now initializes only after DOM content loads, implements disabled-state management for the scan submit button across all result paths, hardens the string escape helper to safely handle null/undefined values, and refactors the scan function from permission-checking to direct extension management queries with improved error reporting.

Changes

Cohort / File(s) Summary
Popup Initialization & Submit Handler
packages/extension/src/popup.js
Added DOMContentLoaded event wrapper for initialization sequencing. Implemented scanUrlSubmit.disabled guards across success, error, timeout, and network failure paths. Updated invalid-input error message prompt. Hardened esc helper to coerce values via String() and handle null/undefined safely. Refactored scan(force) from chrome.permissions.contains gating to direct chrome.management.getAll filtering with try/catch error reporting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Initialization waits for content to bloom,
Buttons now toggle with disable-room,
Escape strings safely, null won't cause fright,
Scanning refactored, extensions in sight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: wrapping popup logic in DOMContentLoaded to prevent crashes from accessing elements before DOM is ready.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions github-actions Bot added area: extension Changes to the browser extension package bug Bug report or bug fix related work labels Apr 24, 2026
Copy link
Copy Markdown

@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 `@packages/extension/src/popup.js`:
- Around line 191-193: The handler handleScanUrlSubmit is not guarded against
re-entry so Enter-key calls can start overlapping scans; add a shared lock
(e.g., a module-level boolean isScanning) or an early-return guard at the top of
handleScanUrlSubmit that returns immediately when scanning is true, set
isScanning = true when a scan begins and set it back to false in all
completion/error paths, ensure the existing scanUrlSubmit.disabled = true/false
code is kept in sync with isScanning so both button clicks and Enter-key
invocations use the same lock.
- Around line 676-706: The initial scan should be gated by the optional
"management" permission: inside scan(force) before calling
chrome.management.getAll, call chrome.permissions.contains({permissions:
['management']}, callback) and if the permission is not granted hideStatus() and
render the permission-request state (reuse the same UI/handler used by the
existing permission button flow that requests management) instead of calling
chrome.management.getAll and showing "Cannot access extensions"; if
permissions.contains reports granted, proceed to call chrome.management.getAll
and then runScanWithExtensions(exts, force); keep the existing try/catch for
unexpected errors.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dfbdabae-7768-4cb3-aaab-933836159ab1

📥 Commits

Reviewing files that changed from the base of the PR and between 1b1b9da and 2fdf479.

📒 Files selected for processing (1)
  • packages/extension/src/popup.js

Comment on lines +191 to +193
if (scanUrlSubmit) {
scanUrlSubmit.disabled = true;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard handleScanUrlSubmit() itself against re-entry.

Disabling the button only blocks pointer clicks. The Enter-key handler still calls handleScanUrlSubmit() directly at Lines 315-318, so users can start overlapping scans while the first one is still in flight. Add an early return at the top of the handler (or a dedicated isScanning flag) so every entry path shares the same lock.

Suggested fix
 function handleScanUrlSubmit() {
+    if (scanUrlSubmit && scanUrlSubmit.disabled) return;
     var raw = scanUrlInput && scanUrlInput.value ? scanUrlInput.value.trim() : '';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/extension/src/popup.js` around lines 191 - 193, The handler
handleScanUrlSubmit is not guarded against re-entry so Enter-key calls can start
overlapping scans; add a shared lock (e.g., a module-level boolean isScanning)
or an early-return guard at the top of handleScanUrlSubmit that returns
immediately when scanning is true, set isScanning = true when a scan begins and
set it back to false in all completion/error paths, ensure the existing
scanUrlSubmit.disabled = true/false code is kept in sync with isScanning so both
button clicks and Enter-key invocations use the same lock.

Comment on lines +676 to +706
function scan(force) {
showStatus('Getting extensions…');

try {
chrome.management.getAll(function (all) {
if (chrome.runtime.lastError || !all) {
hideStatus();
showError('Cannot access extensions');
return;
}

showStatus('Getting extensions…');
var selfId = chrome.runtime.id;
var exts = [];

chrome.runtime.sendMessage({ action: 'getAllExtensions' }, function (all) {
if (chrome.runtime.lastError || !all) {
chrome.management.getAll(function (fallbackAll) {
if (chrome.runtime.lastError) {
hideStatus();
showError('Cannot access extensions: ' + (chrome.runtime.lastError.message || 'unknown'));
return;
}
var selfId = chrome.runtime.id;
var filtered = [];
for (var j = 0; j < fallbackAll.length; j++) {
if (!fallbackAll[j].permissions) fallbackAll[j].permissions = [];
if (fallbackAll[j].type === 'extension' && fallbackAll[j].id !== selfId && fallbackAll[j].enabled) filtered.push(fallbackAll[j]);
}
runScanWithExtensions(filtered, force);
});
return;
for (var i = 0; i < all.length; i++) {
if (
all[i].type === 'extension' &&
all[i].id !== selfId &&
all[i].enabled
) {
exts.push(all[i]);
}
}

var exts = [];
for (var i = 0; i < all.length; i++) {
if (!all[i].permissions) all[i].permissions = [];
if (all[i].enabled) exts.push(all[i]);
}
runScanWithExtensions(exts, force);
});
runScanWithExtensions(exts, force);
});
} catch (e) {
hideStatus();
showError('Unexpected error while scanning');
}
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Apr 24, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e

echo "== manifest permission model =="
sed -n '1,40p' packages/extension/src/manifest.json

echo
echo "== popup startup + management API usage =="
rg -n -C3 'scan\(false\)|chrome\.management\.getAll|chrome\.permissions\.(contains|request)' \
  packages/extension/src/popup.js \
  packages/extension/src/background.js

Repository: Stanzin7/ExtensionShield

Length of output: 3415


🏁 Script executed:

sed -n '65,80p' packages/extension/src/popup.js

Repository: Stanzin7/ExtensionShield

Length of output: 573


Gate the initial scan on the optional management permission.

scan(false) runs unconditionally on popup load (line 792), but packages/extension/src/manifest.json declares "management" under optional_permissions, not required permissions. On a fresh install, chrome.management.getAll() at line 680 will fail and the popup opens directly to "Cannot access extensions" instead of prompting for permission. The button handler at lines 70–76 correctly checks chrome.permissions.contains() before requesting the permission, but the startup scan bypasses this entirely. Apply the same permission-gating pattern to the initial scan(false) call and render a permission-request state instead of treating missing permission as a scan error.

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

In `@packages/extension/src/popup.js` around lines 676 - 706, The initial scan
should be gated by the optional "management" permission: inside scan(force)
before calling chrome.management.getAll, call
chrome.permissions.contains({permissions: ['management']}, callback) and if the
permission is not granted hideStatus() and render the permission-request state
(reuse the same UI/handler used by the existing permission button flow that
requests management) instead of calling chrome.management.getAll and showing
"Cannot access extensions"; if permissions.contains reports granted, proceed to
call chrome.management.getAll and then runScanWithExtensions(exts, force); keep
the existing try/catch for unexpected errors.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Khushi5623 Please have a check on this

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: extension Changes to the browser extension package bug Bug report or bug fix related work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants