fix(extensions): define platform info to prevent renderer crash (#25357)
This commit is contained in:
parent
fbf32f697f
commit
45170fdbd7
7 changed files with 133 additions and 41 deletions
1
BUILD.gn
1
BUILD.gn
|
@ -642,6 +642,7 @@ source_set("electron_lib") {
|
||||||
"shell/common/extensions/api",
|
"shell/common/extensions/api",
|
||||||
"shell/common/extensions/api:extensions_features",
|
"shell/common/extensions/api:extensions_features",
|
||||||
"//chrome/browser/resources:component_extension_resources",
|
"//chrome/browser/resources:component_extension_resources",
|
||||||
|
"//components/update_client:update_client",
|
||||||
"//components/zoom",
|
"//components/zoom",
|
||||||
"//extensions/browser",
|
"//extensions/browser",
|
||||||
"//extensions/browser:core_api_provider",
|
"//extensions/browser:core_api_provider",
|
||||||
|
|
|
@ -74,6 +74,7 @@ The following methods of `chrome.runtime` are supported:
|
||||||
|
|
||||||
- `chrome.runtime.getBackgroundPage`
|
- `chrome.runtime.getBackgroundPage`
|
||||||
- `chrome.runtime.getManifest`
|
- `chrome.runtime.getManifest`
|
||||||
|
- `chrome.runtime.getPlatformInfo`
|
||||||
- `chrome.runtime.getURL`
|
- `chrome.runtime.getURL`
|
||||||
- `chrome.runtime.connect`
|
- `chrome.runtime.connect`
|
||||||
- `chrome.runtime.sendMessage`
|
- `chrome.runtime.sendMessage`
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
|
#include "components/update_client/update_query_params.h"
|
||||||
#include "extensions/common/api/runtime.h"
|
#include "extensions/common/api/runtime.h"
|
||||||
#include "shell/browser/extensions/electron_extension_system.h"
|
#include "shell/browser/extensions/electron_extension_system.h"
|
||||||
|
|
||||||
|
@ -42,10 +43,49 @@ bool ElectronRuntimeAPIDelegate::CheckForUpdates(
|
||||||
void ElectronRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) {}
|
void ElectronRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) {}
|
||||||
|
|
||||||
bool ElectronRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) {
|
bool ElectronRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) {
|
||||||
// TODO(nornagon): put useful information here.
|
const char* os = update_client::UpdateQueryParams::GetOS();
|
||||||
#if defined(OS_LINUX)
|
if (strcmp(os, "mac") == 0) {
|
||||||
info->os = api::runtime::PLATFORM_OS_LINUX;
|
info->os = extensions::api::runtime::PLATFORM_OS_MAC;
|
||||||
#endif
|
} else if (strcmp(os, "win") == 0) {
|
||||||
|
info->os = extensions::api::runtime::PLATFORM_OS_WIN;
|
||||||
|
} else if (strcmp(os, "linux") == 0) {
|
||||||
|
info->os = extensions::api::runtime::PLATFORM_OS_LINUX;
|
||||||
|
} else if (strcmp(os, "openbsd") == 0) {
|
||||||
|
info->os = extensions::api::runtime::PLATFORM_OS_OPENBSD;
|
||||||
|
} else {
|
||||||
|
NOTREACHED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* arch = update_client::UpdateQueryParams::GetArch();
|
||||||
|
if (strcmp(arch, "arm") == 0) {
|
||||||
|
info->arch = extensions::api::runtime::PLATFORM_ARCH_ARM;
|
||||||
|
} else if (strcmp(arch, "arm64") == 0) {
|
||||||
|
info->arch = extensions::api::runtime::PLATFORM_ARCH_ARM64;
|
||||||
|
} else if (strcmp(arch, "x86") == 0) {
|
||||||
|
info->arch = extensions::api::runtime::PLATFORM_ARCH_X86_32;
|
||||||
|
} else if (strcmp(arch, "x64") == 0) {
|
||||||
|
info->arch = extensions::api::runtime::PLATFORM_ARCH_X86_64;
|
||||||
|
} else {
|
||||||
|
NOTREACHED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* nacl_arch = update_client::UpdateQueryParams::GetNaclArch();
|
||||||
|
if (strcmp(nacl_arch, "arm") == 0) {
|
||||||
|
info->nacl_arch = extensions::api::runtime::PLATFORM_NACL_ARCH_ARM;
|
||||||
|
} else if (strcmp(nacl_arch, "arm64") == 0) {
|
||||||
|
// Use ARM for ARM64 NaCl, as ARM64 NaCl is not available.
|
||||||
|
info->nacl_arch = extensions::api::runtime::PLATFORM_NACL_ARCH_ARM;
|
||||||
|
} else if (strcmp(nacl_arch, "x86-32") == 0) {
|
||||||
|
info->nacl_arch = extensions::api::runtime::PLATFORM_NACL_ARCH_X86_32;
|
||||||
|
} else if (strcmp(nacl_arch, "x86-64") == 0) {
|
||||||
|
info->nacl_arch = extensions::api::runtime::PLATFORM_NACL_ARCH_X86_64;
|
||||||
|
} else {
|
||||||
|
NOTREACHED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} // namespace extensions
|
} // namespace extensions
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,8 @@ describe('chrome extensions', () => {
|
||||||
it('does not crash when using chrome.management', async () => {
|
it('does not crash when using chrome.management', async () => {
|
||||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||||
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
|
||||||
w.loadURL('about:blank');
|
await w.loadURL('about:blank');
|
||||||
|
|
||||||
await emittedOnce(w.webContents, 'dom-ready');
|
|
||||||
await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
|
||||||
const args: any = await emittedOnce(app, 'web-contents-created');
|
const args: any = await emittedOnce(app, 'web-contents-created');
|
||||||
const wc: Electron.WebContents = args[1];
|
const wc: Electron.WebContents = args[1];
|
||||||
|
@ -60,9 +59,8 @@ describe('chrome extensions', () => {
|
||||||
it('can open WebSQLDatabase in a background page', async () => {
|
it('can open WebSQLDatabase in a background page', async () => {
|
||||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||||
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
|
||||||
w.loadURL('about:blank');
|
await w.loadURL('about:blank');
|
||||||
|
|
||||||
await emittedOnce(w.webContents, 'dom-ready');
|
|
||||||
await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
|
||||||
const args: any = await emittedOnce(app, 'web-contents-created');
|
const args: any = await emittedOnce(app, 'web-contents-created');
|
||||||
const wc: Electron.WebContents = args[1];
|
const wc: Electron.WebContents = args[1];
|
||||||
|
@ -77,8 +75,7 @@ describe('chrome extensions', () => {
|
||||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||||
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
|
||||||
const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'ui-page'));
|
const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'ui-page'));
|
||||||
w.loadURL(`${extension.url}bare-page.html`);
|
await w.loadURL(`${extension.url}bare-page.html`);
|
||||||
await emittedOnce(w.webContents, 'dom-ready');
|
|
||||||
await expect(fetch(w.webContents, `${url}/cors`)).to.not.be.rejectedWith(TypeError);
|
await expect(fetch(w.webContents, `${url}/cors`)).to.not.be.rejectedWith(TypeError);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -90,8 +87,7 @@ describe('chrome extensions', () => {
|
||||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||||
await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
|
||||||
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
|
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
|
||||||
w.loadURL(url);
|
await w.loadURL(url);
|
||||||
await emittedOnce(w.webContents, 'dom-ready');
|
|
||||||
const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
|
const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
|
||||||
expect(bg).to.equal('red');
|
expect(bg).to.equal('red');
|
||||||
});
|
});
|
||||||
|
@ -145,8 +141,7 @@ describe('chrome extensions', () => {
|
||||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||||
await 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
|
const w = new BrowserWindow({ show: false }); // not in the session
|
||||||
w.loadURL(url);
|
await w.loadURL(url);
|
||||||
await emittedOnce(w.webContents, 'dom-ready');
|
|
||||||
const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
|
const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
|
||||||
expect(bg).to.equal('');
|
expect(bg).to.equal('');
|
||||||
});
|
});
|
||||||
|
@ -169,8 +164,7 @@ describe('chrome extensions', () => {
|
||||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||||
extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-i18n'));
|
extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-i18n'));
|
||||||
w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
||||||
w.loadURL(url);
|
await w.loadURL(url);
|
||||||
await emittedOnce(w.webContents, 'dom-ready');
|
|
||||||
});
|
});
|
||||||
it('getAcceptLanguages()', async () => {
|
it('getAcceptLanguages()', async () => {
|
||||||
const result = await exec('getAcceptLanguages');
|
const result = await exec('getAcceptLanguages');
|
||||||
|
@ -184,28 +178,37 @@ describe('chrome extensions', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('chrome.runtime', () => {
|
describe('chrome.runtime', () => {
|
||||||
let content: any;
|
let w: BrowserWindow;
|
||||||
before(async () => {
|
const exec = async (name: string) => {
|
||||||
|
const p = emittedOnce(ipcMain, 'success');
|
||||||
|
await w.webContents.executeJavaScript(`exec('${name}')`);
|
||||||
|
const [, result] = await p;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
beforeEach(async () => {
|
||||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||||
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-runtime'));
|
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-runtime'));
|
||||||
const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
|
w = new BrowserWindow({ show: false, webPreferences: { session: customSession, nodeIntegration: true } });
|
||||||
try {
|
await w.loadURL(url);
|
||||||
w.loadURL(url);
|
|
||||||
await emittedOnce(w.webContents, 'dom-ready');
|
|
||||||
content = JSON.parse(await w.webContents.executeJavaScript('document.documentElement.textContent'));
|
|
||||||
expect(content).to.be.an('object');
|
|
||||||
} finally {
|
|
||||||
w.destroy();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
it('getManifest()', () => {
|
it('getManifest()', async () => {
|
||||||
expect(content.manifest).to.be.an('object').with.property('name', 'chrome-runtime');
|
const result = await exec('getManifest');
|
||||||
|
expect(result).to.be.an('object').with.property('name', 'chrome-runtime');
|
||||||
});
|
});
|
||||||
it('id', () => {
|
it('id', async () => {
|
||||||
expect(content.id).to.be.a('string').with.lengthOf(32);
|
const result = await exec('id');
|
||||||
|
expect(result).to.be.a('string').with.lengthOf(32);
|
||||||
});
|
});
|
||||||
it('getURL()', () => {
|
it('getURL()', async () => {
|
||||||
expect(content.url).to.be.a('string').and.match(/^chrome-extension:\/\/.*main.js$/);
|
const result = await exec('getURL');
|
||||||
|
expect(result).to.be.a('string').and.match(/^chrome-extension:\/\/.*main.js$/);
|
||||||
|
});
|
||||||
|
it('getPlatformInfo()', async () => {
|
||||||
|
const result = await exec('getPlatformInfo');
|
||||||
|
expect(result).to.be.an('object');
|
||||||
|
expect(result.os).to.be.a('string');
|
||||||
|
expect(result.arch).to.be.a('string');
|
||||||
|
expect(result.nacl_arch).to.be.a('string');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -562,8 +565,7 @@ describe('chrome extensions', () => {
|
||||||
it('loads a ui page of an extension', async () => {
|
it('loads a ui page of an extension', async () => {
|
||||||
const { id } = await session.defaultSession.loadExtension(path.join(fixtures, 'extensions', 'ui-page'));
|
const { id } = await session.defaultSession.loadExtension(path.join(fixtures, 'extensions', 'ui-page'));
|
||||||
const w = new BrowserWindow({ show: false });
|
const w = new BrowserWindow({ show: false });
|
||||||
w.loadURL(`chrome-extension://${id}/bare-page.html`);
|
await w.loadURL(`chrome-extension://${id}/bare-page.html`);
|
||||||
await emittedOnce(w.webContents, 'dom-ready');
|
|
||||||
const textContent = await w.webContents.executeJavaScript('document.body.textContent');
|
const textContent = await w.webContents.executeJavaScript('document.body.textContent');
|
||||||
expect(textContent).to.equal('ui page loaded ok\n');
|
expect(textContent).to.equal('ui page loaded ok\n');
|
||||||
});
|
});
|
||||||
|
@ -571,8 +573,7 @@ describe('chrome extensions', () => {
|
||||||
it('can load resources', async () => {
|
it('can load resources', async () => {
|
||||||
const { id } = await session.defaultSession.loadExtension(path.join(fixtures, 'extensions', 'ui-page'));
|
const { id } = await session.defaultSession.loadExtension(path.join(fixtures, 'extensions', 'ui-page'));
|
||||||
const w = new BrowserWindow({ show: false });
|
const w = new BrowserWindow({ show: false });
|
||||||
w.loadURL(`chrome-extension://${id}/page-script-load.html`);
|
await w.loadURL(`chrome-extension://${id}/page-script-load.html`);
|
||||||
await emittedOnce(w.webContents, 'dom-ready');
|
|
||||||
const textContent = await w.webContents.executeJavaScript('document.body.textContent');
|
const textContent = await w.webContents.executeJavaScript('document.body.textContent');
|
||||||
expect(textContent).to.equal('script loaded ok\n');
|
expect(textContent).to.equal('script loaded ok\n');
|
||||||
});
|
});
|
||||||
|
|
12
spec-main/fixtures/extensions/chrome-runtime/background.js
Normal file
12
spec-main/fixtures/extensions/chrome-runtime/background.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/* global chrome */
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener((message, sender, reply) => {
|
||||||
|
switch (message) {
|
||||||
|
case 'getPlatformInfo':
|
||||||
|
chrome.runtime.getPlatformInfo(reply);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Respond asynchronously
|
||||||
|
return true;
|
||||||
|
});
|
|
@ -1,6 +1,39 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
document.documentElement.textContent = JSON.stringify({
|
|
||||||
manifest: chrome.runtime.getManifest(),
|
function evalInMainWorld(fn) {
|
||||||
id: chrome.runtime.id,
|
const script = document.createElement('script')
|
||||||
url: chrome.runtime.getURL('main.js')
|
script.textContent = `((${fn})())`
|
||||||
|
document.documentElement.appendChild(script)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exec(name) {
|
||||||
|
let result
|
||||||
|
switch (name) {
|
||||||
|
case 'getManifest':
|
||||||
|
result = chrome.runtime.getManifest()
|
||||||
|
break
|
||||||
|
case 'id':
|
||||||
|
result = chrome.runtime.id
|
||||||
|
break
|
||||||
|
case 'getURL':
|
||||||
|
result = chrome.runtime.getURL('main.js')
|
||||||
|
break
|
||||||
|
case 'getPlatformInfo': {
|
||||||
|
result = await new Promise(resolve => {
|
||||||
|
chrome.runtime.sendMessage(name, resolve)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const funcStr = `() => { require('electron').ipcRenderer.send('success', ${JSON.stringify(result)}) }`
|
||||||
|
evalInMainWorld(funcStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('message', event => {
|
||||||
|
exec(event.data.name)
|
||||||
|
})
|
||||||
|
|
||||||
|
evalInMainWorld(() => {
|
||||||
|
window.exec = name => window.postMessage({ name })
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,5 +8,9 @@
|
||||||
"run_at": "document_end"
|
"run_at": "document_end"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"background": {
|
||||||
|
"scripts": ["background.js"],
|
||||||
|
"persistent": false
|
||||||
|
},
|
||||||
"manifest_version": 2
|
"manifest_version": 2
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue