Skip to content

Conversation

@adamlow-wire
Copy link

@adamlow-wire adamlow-wire commented Dec 15, 2025

Pull Request

Summary

This PR enables Electron context isolation for the main window.

What Changed

  1. Enabled context isolation (contextIsolation: true) in main window webPreferences
  2. Refactored preload scripts to use contextBridge.exposeInMainWorld() instead of direct window property assignments
  3. Updated all renderer code to use window.electronAPI.* instead of direct window properties
  4. Fixed context menu actions to work correctly with webviews by executing actions directly on webContents
  5. Added error handling for account removal when webviews aren't fully initialized
  6. Fixed locale timing issue by replacing broken setTimeout approach with a getter function

Testing

Manual testing of context menu's, account addition/removal, can't test SSO as don't have the setup to do so.

Security Checklist (required)

  • External inputs are validated & sanitized on client and/or server where applicable.
    • IPC handlers validate inputs before processing
    • Account IDs are validated before operations
  • API responses are validated; unexpected shapes are handled safely (fallbacks or errors).
    • Error handling added for account removal edge cases
    • Try-catch blocks around webContents operations
  • No unsafe HTML is rendered; if unavoidable, sanitization is applied and documented where it happens.
    • No HTML rendering changes in this PR
  • Injection risks (XSS/SQL/command) are prevented via safe APIs and/or escaping.
    • Context isolation itself prevents XSS by isolating contexts
    • IPC communication uses typed channels, not string concatenation

Standards Acknowledgement (required)


Screenshots or demo (if the user interface changed)

No UI changes - this is a security hardening change that maintains existing functionality.


Notes for reviewers

Testing Checklist

  • Context menus work (text, image, link, selection)
  • Account operations work (add, remove, logout)
  • SSO flow works
  • Locale/language switching works
  • No console errors
  • IPC communication works correctly

- Enable contextIsolation: true in main window webPreferences
- Refactor preload-app.ts to use contextBridge.exposeInMainWorld()
- Update all renderer code to use window.electronAPI.* instead of direct window properties
- Fix locale module to lazy-load electronAPI to avoid timing issues
- Remove path module usage from preload scripts (preparation for sandboxing)
- Add documentation: ELECTRON_REMOTE_AUDIT.md and PR_BREAKDOWN.md

This is PR 1 of the Electron security hardening effort.
@sonarqubecloud
Copy link

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enhances Electron security by enabling context isolation for the main window, which prevents renderer processes from directly accessing Node.js and Electron APIs. This is a significant security hardening change that isolates contexts and uses the contextBridge API to expose only necessary functionality to the renderer.

Key changes:

  • Enabled contextIsolation: true in main window webPreferences
  • Refactored preload scripts to use contextBridge.exposeInMainWorld() for API exposure
  • Updated all renderer code to access APIs via window.electronAPI namespace
  • Enhanced context menu actions to handle webviews correctly by passing webContents IDs
  • Added error handling for account removal operations

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
electron/src/main.ts Enables context isolation in webPreferences
electron/src/types/globals.d.ts Updates Window interface to define electronAPI structure
electron/src/preload/preload-app.ts Exposes APIs via contextBridge; adds webContents ID handling for edit operations
electron/src/preload/preload-webview.ts Updates logger initialization to use string literal
electron/src/preload/menu/preload-context.ts Adds webContents ID parameter to menu actions and direct webContents operations for webviews
electron/renderer/src/lib/locale.ts Adds lazy loading pattern for locale info from electronAPI
electron/renderer/src/lib/WindowUrl.ts Updates to use getWrapperLocale() function
electron/renderer/src/components/context/EditAccountMenu.tsx Updates to use electronAPI and adds error handling for account deletion
electron/renderer/src/components/WebView/Webview.tsx Updates to use electronAPI; adds early return for non-existent webviews; improves error handling
electron/renderer/src/actions/index.ts Updates to use electronAPI for sendBadgeCount

Comment on lines +81 to +85
.catch(error => {
console.error('Failed to delete account:', error);
// Still abort account creation even if deletion fails
connected.abortAccountCreation(accountId);
});
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

Error handling logs to console.error but provides no user feedback. When account deletion fails, the user should be notified through the UI (e.g., a toast or dialog) rather than silently failing with only a console log. This is important for user experience as they may not know the operation failed.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +46 to +47
webview.blur();
webview.focus();
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The focusWebviewByContentsId function attempts to focus a webview but also calls blur() first. The purpose of calling blur() before focus() is unclear and could be confusing. Consider adding a comment explaining why blur() is necessary before focus(), or remove it if it's not needed.

Copilot uses AI. Check for mistakes.

logger.info(`Processing deletion of "${truncatedId}"`);
const viewInstanceId = accountWebview.getWebContentsId();
ipcRenderer.on(EVENT_TYPE.ACCOUNT.DATA_DELETED, () => resolve());
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The ipcRenderer.on listener for EVENT_TYPE.ACCOUNT.DATA_DELETED is registered every time sendDeleteAccount is called, but never removed. This creates a memory leak where multiple listeners accumulate with each account deletion. The listener should be removed after it fires using ipcRenderer.once instead of ipcRenderer.on, or explicitly removed in the callback.

Suggested change
ipcRenderer.on(EVENT_TYPE.ACCOUNT.DATA_DELETED, () => resolve());
ipcRenderer.once(EVENT_TYPE.ACCOUNT.DATA_DELETED, () => resolve());

Copilot uses AI. Check for mistakes.
Comment on lines +138 to +140
submitDeepLink: (url: string): void => {
ipcRenderer.send(EVENT_TYPE.ACTION.DEEP_LINK_SUBMIT, url);
};

window.sendDeleteAccount = (accountId: string, sessionID?: string): Promise<void> => {
},
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

Input validation is missing for the submitDeepLink function. The url parameter should be validated to ensure it's a properly formatted URL and matches expected patterns before being sent via IPC to prevent potential injection or processing of malicious URLs.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +135 to +137
sendBadgeCount: (count: number, ignoreFlash: boolean): void => {
ipcRenderer.send(EVENT_TYPE.UI.BADGE_COUNT, {count, ignoreFlash});
};

window.submitDeepLink = (url: string): void => {
},
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

Input validation is missing for sendBadgeCount. The count parameter should be validated to ensure it's a non-negative integer to prevent unexpected behavior or display issues with badge counts.

Copilot generated this review using guidance from repository custom instructions.
ipcRenderer.send(EVENT_TYPE.ACCOUNT.DELETE_DATA, viewInstanceId, accountId, sessionID);
} catch (error) {
// eslint-disable-next-line prefer-promise-reject-errors
reject(`Failed to get webContents ID for account "${truncatedId}": ${error}`);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The error variable should be included in the rejection message. Currently the template string includes ${error} but 'error' is the catch parameter name. Consider using String(error) or error.message to ensure proper error information is passed in the rejection.

Suggested change
reject(`Failed to get webContents ID for account "${truncatedId}": ${error}`);
const errorMessage = error instanceof Error ? error.message : String(error);
reject(`Failed to get webContents ID for account "${truncatedId}": ${errorMessage}`);

Copilot uses AI. Check for mistakes.
Comment on lines +302 to +306
.catch(error => {
console.error('Failed to delete account:', error);
// Still abort account creation even if deletion fails
abortAccountCreation(account.id);
});
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

Error handling logs to console.error but provides no user feedback. When account deletion fails, the user should be notified through the UI (e.g., a toast or dialog) rather than silently failing with only a console log. This is important for user experience as they may not know the operation failed.

Copilot generated this review using guidance from repository custom instructions.
@EnricoSchw EnricoSchw self-requested a review December 18, 2025 08:32
Copy link
Contributor

@EnricoSchw EnricoSchw left a comment

Choose a reason for hiding this comment

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

Hi @adamlow-wire ,

thx for this PR, we need to test this change thoroughly. Because If we place the app in an isolated context, this change will affect our calling.

Please note that audio and video streams are singletons. The isolated context may make them inaccessible in parts of our app. Therefore, we need to test this changes.

Furthermore, our app runs in a sandbox on Mac, which maybe makes things more complicated.

That's why I built the app locally, signed it, and launched it in a sandbox. Unfortunately, I couldn't get past the login screen. Here the error I see.

Bildschirmfoto 2025-12-18 um 09 28 00

Unfortunately, it's not very informative, but maybe you can make something of it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants