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

feat: implement allowFileAccess loadExtension option #25198

Merged
merged 7 commits into from
Feb 1, 2021

Conversation

ChALkeR
Copy link
Contributor

@ChALkeR ChALkeR commented Aug 29, 2020

Description of Change

Alternative to #25151.

Allows file access for extensions via an opt-in on per-extension basis.
Pre-9 this was essentially "enabled" by default, until 9.0.0 broke react devtools on local file:// urls (#24011).

  • API / doc is done.
  • Implementation works but is WiP (see below)
  • I don't like how flags are being passed this way, also a FIXME in LoadExtensionForReload() -- not sure yet when that is triggered. Probably replacing that with an additional method that sets the flags for a certain extension id and is stored in-memory would be a better approach.

Fixes: #24011.

Confirmed that react-devtools now works over file:// if allowFileAccess: true is passed and doesn't work otherwise.

cc @nornagon @samuelmaddock @RangerMauve

Thoughts? It would be helpful to hear which approach should be continued, this one or #25151.

Checklist

Release Notes

Notes: Added allowFileAccess option to loadExtension() API.

@electron-cation electron-cation bot added the new-pr 🌱 PR opened in the last 24 hours label Aug 29, 2020
Copy link
Member

@samuelmaddock samuelmaddock left a comment

Choose a reason for hiding this comment

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

I like the options argument for ses.loadExtension. Making use of ExtensionPrefs should help with the remaining work on this PR. 👍

shell/browser/api/electron_api_session.cc Outdated Show resolved Hide resolved
@@ -155,9 +156,10 @@ void ElectronExtensionLoader::LoadExtensionForReload(
LoadErrorBehavior load_error_behavior) {
CHECK(!path.empty());

int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE; // FIXME
Copy link
Member

Choose a reason for hiding this comment

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

I think this is a place where ExtensionPrefs would be useful. Looking at Chrome's installed extension loader, they use this to store global and extension-specific preferences at runtime—including methods for getting/setting file access.

In Session::LoadExtension, we could call ExtensionPrefs::SetAllowFileAccess with the value of the allowFileAccess option. Then ElectronExtensionLoader can derive the load_flags from ExtensionPrefs. Chrome's InstalledLoader::GetCreationFlags is a good example of how this could work.

Copy link
Contributor Author

@ChALkeR ChALkeR Aug 31, 2020

Choose a reason for hiding this comment

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

@samuelmaddock thanks for the feedback!

I thought about that, but the thing I noticed while testing (#24011 (comment)) is that:

  1. This preference doesn't appear to do anything on it's own, or it could do something I don't know yet.
  2. In Chromium, this is apparently not what is used.
    • A call to ExtensionPrefs::SetAllowFileAccess writes to {profile}/Preferences.
    • But in Chromium that doesn't happen when file access is enabled in extension preferences.
    • Instead, Chromium stores that in{profile}/Current Session which is inexistent in Electron.

My concern here is that as Chromium apparently doesn't use it in that scenario, perhaps ExtensionPrefs::SetAllowFileAccess does something else and can have some other side effect?
Or is that not the case?

I can surely port to that if it would be safe to use it here.

Copy link
Member

Choose a reason for hiding this comment

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

After looking more into this, Chrome implements a private API on the chrome://extensions page with a function chrome.developerPrivate.updateExtensionConfiguration(config, callback). It's internal implementation calls a utility which in turn calls ExtensionPrefs::SetAllowFileAccess.

After this function is called, the value will stay in memory and (I think) persist to disk soon after. An extension loader implements a GetCreationFlags method to then derive flags from ExtensionPrefs.

In my opinion, sticking with this pattern close to Chrome will allow us to more naturally build on the extension support in Electron later on.

As for the the location of prefs ({profile}/Preferences), I'm not sure what the right path would be for us. I think we can go with the default and change it later if needed.

Copy link
Member

Choose a reason for hiding this comment

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

I don't believe Electron persists such preferences to disk. Additionally, I'd prefer that the extensions loading stuff doesn't persist anything to disk internally, as that's often surprising for developers (e.g. "i removed the loadExtension(...) line from my app, why is the react devtools extension still loading??" behavior that used to be present.)

Copy link
Member

Choose a reason for hiding this comment

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

Update on ExtensionPrefs, they're mostly used by Chrome to persist extension settings for a profile.

  • Whether an extension has file access or can run in incognito mode.
  • The extension installation time.
  • If an extension is disabled, the reason why.
  • And many other Chrome-specific settings.

These aren't too relevant to an Electron app and could be managed outside of Electron internal code. However, special cases such as chrome.runtime.reload() will cause this setting to be dropped without relying on storage such as ExtensionPrefs.

Additionally, ExtensionPrefs do end up persisting to disk using the same JsonPrefStore as UserPrefs which are setup in ElectronBrowserContext::InitPrefs.

To avoid this behavior, I believe it will be necessary to create an InMemoryPrefStore exclusively for ExtensionPrefs which would be returned from ElectronExtensionsBrowserClient::GetPrefServiceForContext. Possibly a command-line flag could be used if a developer wanted to opt-in to persisting these settings?

Copy link
Member

Choose a reason for hiding this comment

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

@ChALkeR to followup, we can simplify this by avoiding ExtensionPrefs altogether. Adding a map of
extensionId -> allowFileAccess could be added to ElectronExtensionLoader. When an extension is unloaded, we can clear it. That way we can allow persisting file access if an extension is reloaded.

@electron-cation electron-cation bot removed the new-pr 🌱 PR opened in the last 24 hours label Aug 30, 2020
ChALkeR and others added 3 commits August 31, 2020 15:13
@ChALkeR ChALkeR changed the title feat: implement allow_file_access loadExtension option feat: implement allowFileAccess loadExtension option Aug 31, 2020
docs/api/session.md Show resolved Hide resolved
docs/api/session.md Show resolved Hide resolved
@jkleinsc
Copy link
Contributor

The API WG reviewed this at the Sept 21, 2020 meeting

docs/api/session.md Outdated Show resolved Hide resolved
@nornagon nornagon marked this pull request as ready for review November 17, 2020 23:12
@nornagon
Copy link
Member

I'm happy to land this without the fix for remembering file access across extension reload. The latter is a smaller bug than what this fixes.

@RobbieTheWagner
Copy link

What's the status on this?

@andrewschreiber
Copy link

Very important PR to my project. What are the remaining blockers? I'd like to help if possible.

@codebytere
Copy link
Member

@ChALkeR would you still like to move this forward?

@RobbieTheWagner
Copy link

This is a necessary feature, so hopefully it can be moved forward 😃. I'm willing to help too, if more help is needed.

@safareli
Copy link

We really want this to be merged and are ready to help move this forward!

nornagon added a commit that referenced this pull request Feb 11, 2021
Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
@trop
Copy link
Contributor

trop bot commented Feb 11, 2021

@nornagon has manually backported this PR to "12-x-y", please check out #27702

nornagon added a commit that referenced this pull request Feb 11, 2021
Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
@trop
Copy link
Contributor

trop bot commented Feb 11, 2021

@nornagon has manually backported this PR to "11-x-y", please check out #27703

@bedney
Copy link

bedney commented Feb 11, 2021

@nornagon -

Thank you for going the extra mile here with the back ports! We really appreciate it!

@benjaffe
Copy link
Contributor

Yes yes, thank you thank you! <3

@twitharshil
Copy link
Contributor

@nornagon Will the fix for this issue can be backported to electron v9 which is still on the supported line versions?

@nornagon
Copy link
Member

@twitharshil no, we are only backporting security fixes to v9.

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.

Extensions don't work with file:// protocol since 9.0.0