Browse Source

fix: disallow loading extensions in temp sessions (#22090)

* fix: disallow loading extensions in temp sessions

* docs
Jeremy Apthorp 5 years ago
parent
commit
af631f8204

+ 3 - 0
docs/api/extensions.md

@@ -28,6 +28,9 @@ session.loadExtension('path/to/unpacked/extension').then(({ id }) => {
 Loaded extensions will not be automatically remembered across exits; if you do
 not call `loadExtension` when the app runs, the extension will not be loaded.
 
+Note that loading extensions is only supported in persistent sessions.
+Attempting to load an extension into an in-memory session will throw an error.
+
 See the [`session`](session.md) documentation for more information about
 loading, unloading, and querying active extensions.
 

+ 5 - 0
docs/api/session.md

@@ -507,6 +507,8 @@ requests an API that Electron does not support) then they will be logged to the
 console.
 
 Note that Electron does not support the full range of Chrome extensions APIs.
+See [Supported Extensions APIs](extensions.md#supported-extensions-apis) for
+more details on what is supported.
 
 Note that in previous versions of Electron, extensions that were loaded would
 be remembered for future runs of the application. This is no longer the case:
@@ -529,6 +531,9 @@ This API does not support loading packed (.crx) extensions.
 **Note:** This API cannot be called before the `ready` event of the `app` module
 is emitted.
 
+**Note:** Loading extensions into in-memory (non-persistent) sessions is not
+supported and will throw an error.
+
 #### `ses.removeExtension(extensionId)`
 
 * `extensionId` String - ID of extension to remove

+ 5 - 0
shell/browser/api/electron_api_session.cc

@@ -613,6 +613,11 @@ v8::Local<v8::Promise> Session::LoadExtension(
     const base::FilePath& extension_path) {
   gin_helper::Promise<const extensions::Extension*> promise(isolate());
   v8::Local<v8::Promise> handle = promise.GetHandle();
+  if (browser_context()->IsOffTheRecord()) {
+    promise.RejectWithErrorMessage(
+        "Extensions cannot be loaded in a temporary session");
+    return handle;
+  }
 
   auto* extension_system = static_cast<extensions::ElectronExtensionSystem*>(
       extensions::ExtensionSystem::Get(browser_context()));

+ 12 - 8
spec-main/extensions-spec.ts

@@ -24,8 +24,13 @@ ifdescribe(process.electronBinding('features').isExtensionsEnabled())('chrome ex
   after(() => {
     server.close()
   })
-
   afterEach(closeAllWindows)
+  afterEach(() => {
+    session.defaultSession.getAllExtensions().forEach((e: any) => {
+      session.defaultSession.removeExtension(e.id)
+    })
+  })
+
   it('loads an extension', async () => {
     // NB. we have to use a persist: session (i.e. non-OTR) because the
     // extension registry is redirected to the main session. so installing an
@@ -73,13 +78,18 @@ ifdescribe(process.electronBinding('features').isExtensionsEnabled())('chrome ex
 
   it('confines an extension to the session it was loaded in', async () => {
     const customSession = session.fromPartition(`persist:${require('uuid').v4()}`)
-    customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'))
+    await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'))
     const w = new BrowserWindow({ show: false }) // not in the session
     await w.loadURL(url)
     const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor')
     expect(bg).to.equal('')
   })
 
+  it('loading an extension in a temporary session throws an error', async () => {
+    const customSession = session.fromPartition(require('uuid').v4())
+    await expect(customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'))).to.eventually.be.rejectedWith('Extensions cannot be loaded in a temporary session')
+  })
+
   describe('chrome.runtime', () => {
     let content: any
     before(async () => {
@@ -239,12 +249,6 @@ ifdescribe(process.electronBinding('features').isExtensionsEnabled())('chrome ex
   })
 
   describe('deprecation shims', () => {
-    afterEach(() => {
-      session.defaultSession.getAllExtensions().forEach((e: any) => {
-        session.defaultSession.removeExtension(e.id)
-      })
-    })
-
     it('loads an extension through BrowserWindow.addExtension', async () => {
       BrowserWindow.addExtension(path.join(fixtures, 'extensions', 'red-bg'))
       const w = new BrowserWindow({ show: false })