Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Secure our Electron implementation #7567

Merged
merged 19 commits into from
Feb 8, 2022
Merged

Conversation

roryabraham
Copy link
Contributor

@roryabraham roryabraham commented Feb 4, 2022

Details

This PR implements many of the security best practices outlined in Electron's documentation. There is a lot of context behind why these changes are a good idea, but this is one of the best resources I've found with a good summary: https://github.com/reZach/secure-electron-template/blob/master/docs/newtoelectron.md.

TL;DR we're completely separating the website code (renderer process) from the powerful Node.js and Electron API's, and any communication between the renderer and main processes (which can use those APIs) has to happen through whitelisted channels. There's also some additional context in https://github.com/Expensify/Expensify/issues/193886

Fun fact: A random side-effect of this PR is that if you run npm run desktop, you can also view the renderer process of the desktop app in your browser by going to localhost:PORT. This is almost the same as running npm run web, with the exception of index.desktop.js files will be used instead of index.website.js.

Remaining TODOS:

  • Enable sandbox mode (I couldn't get this working, posted a comment here).
  • Run a local production build and verify it works as expected.

Fixed Issues

$ https://github.com/Expensify/Expensify/issues/193886
$ https://github.com/Expensify/Expensify/issues/166153

Tests / QA steps.

  1. Run the desktop app.
  2. Verify that you can sign in and sign out.
  3. Paste an external link in the chat, verify that clicking that link opens it in your default browser.
  4. Verify that you can right-click in the compose bar to expose a context menu.
  5. In the app menu, click on View Keyboard Shortcuts. Verify the keyboard shortcuts modal opens. This verifies that events from the main process are being sent to the renderer process correctly.
  6. Run the web app (or just open the desktop app in your browser as noted in the Fun Fact above) and sign into a different account.
  7. Make sure the desktop app has a chat open with a different user than the one you're signed into web as.
  8. Send a message from the web account to the desktop account.
  9. Verify that the desktop app's unread count increases. This verifies that events from the renderer process are being sent to the main process correctly.
  10. (dev only) Run a local production build and repeat the test steps in there.
  • Verify that no new errors appear in the JS console (Be extra on the lookout for this with this PR)

Tested On

  • Web
  • Mobile Web
  • Desktop
  • iOS
  • Android

Screenshots

Desktop

image

Successful local production build
image

@roryabraham roryabraham self-assigned this Feb 4, 2022
@botify
Copy link

botify commented Feb 4, 2022

Hey, I noticed you changed some webpack configuration files. This can break production builds. Did you remember to run a production build locally to verify they still work?

@@ -146,8 +146,4 @@ const webpackConfig = {
},
};

if (platform === 'desktop') {
webpackConfig.target = 'electron-renderer';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is no longer needed – because we're using context isolation, the renderer process (our app that's bundled by webpack) is just like a regular web app without any direct access to Electron or Node APIs, except those defined in the contextBridge

@@ -145,7 +141,8 @@ const mainWindow = (() => {
width: 1200,
height: 900,
webPreferences: {
nodeIntegration: true,
preload: `${__dirname}/contextBridge.js`,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These lines right here are the most significant changes

// make sure local urls stay in electron perimeter
if (url.substr(0, 'file://'.length) === 'file://') {
return;
browserWindow.webContents.setWindowOpenHandler(({url}) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The new-window event was deprecated and replaced by this setWindowOpenHandler API in Electron 12.

const denial = {action: 'deny'};

// Make sure local urls stay in electron perimeter
if (url.substr(0, 'file://'.length).toLowerCase() === 'file://') {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: it used to be possible to open apps and files (bypassing the blacklist we had here), simply by using a URL like File:// or fiLE://.

desktop/contextBridge.js Outdated Show resolved Hide resolved
@roryabraham roryabraham marked this pull request as ready for review February 4, 2022 19:54
@roryabraham roryabraham requested a review from a team as a code owner February 4, 2022 19:54
@MelvinBot MelvinBot requested review from neil-marcellini and removed request for a team February 4, 2022 19:55
Copy link
Contributor

@marcaaron marcaaron left a comment

Choose a reason for hiding this comment

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

Ooh nice changes!

desktop/contextBridge.js Outdated Show resolved Hide resolved
Copy link
Contributor

@neil-marcellini neil-marcellini left a comment

Choose a reason for hiding this comment

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

The tests work well and these look like good changes based on the Electron recommendations.

@AndrewGable
Copy link
Contributor

Is merging blocked on this remaining todo? Enable sandbox mode ?

@roryabraham
Copy link
Contributor Author

Is merging blocked on this remaining todo? Enable sandbox mode ?

Nope. We can address that in a follow-up.

@AndrewGable AndrewGable merged commit 95c0292 into main Feb 8, 2022
@AndrewGable AndrewGable deleted the Rory-SecureElectronImplementation branch February 8, 2022 01:47
@OSBotify
Copy link
Contributor

OSBotify commented Feb 8, 2022

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@OSBotify
Copy link
Contributor

OSBotify commented Feb 9, 2022

🚀 Deployed to staging by @AndrewGable in version: 1.1.38-0 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@OSBotify
Copy link
Contributor

🚀 Deployed to production by @Julesssss in version: 1.1.38-3 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

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.

6 participants