feat: add enableWebSQL webpreference (#23311)
* feat: add enableWebSQL webpreference * chore: update indexedDB test
This commit is contained in:
parent
2a680e107b
commit
a707a3eda3
9 changed files with 187 additions and 3 deletions
|
@ -385,6 +385,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||||
visible to users.
|
visible to users.
|
||||||
* `spellcheck` Boolean (optional) - Whether to enable the builtin spellchecker.
|
* `spellcheck` Boolean (optional) - Whether to enable the builtin spellchecker.
|
||||||
Default is `true`.
|
Default is `true`.
|
||||||
|
* `enableWebSQL` Boolean (optional) - Whether to enable the [WebSQL api](https://www.w3.org/TR/webdatabase/).
|
||||||
|
Default is `true`.
|
||||||
|
|
||||||
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
||||||
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
||||||
|
|
|
@ -217,7 +217,8 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
||||||
['nodeIntegration', false],
|
['nodeIntegration', false],
|
||||||
['enableRemoteModule', false],
|
['enableRemoteModule', false],
|
||||||
['sandbox', true],
|
['sandbox', true],
|
||||||
['nodeIntegrationInSubFrames', false]
|
['nodeIntegrationInSubFrames', false],
|
||||||
|
['enableWebSQL', false]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Inherit certain option values from embedder
|
// Inherit certain option values from embedder
|
||||||
|
|
|
@ -19,7 +19,8 @@ const inheritedWebPreferences = new Map([
|
||||||
['enableRemoteModule', false],
|
['enableRemoteModule', false],
|
||||||
['sandbox', true],
|
['sandbox', true],
|
||||||
['webviewTag', false],
|
['webviewTag', false],
|
||||||
['nodeIntegrationInSubFrames', false]
|
['nodeIntegrationInSubFrames', false],
|
||||||
|
['enableWebSQL', false]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Copy attribute of |parent| to |child| if it is not defined in |child|.
|
// Copy attribute of |parent| to |child| if it is not defined in |child|.
|
||||||
|
|
|
@ -130,6 +130,7 @@ WebContentsPreferences::WebContentsPreferences(
|
||||||
SetDefaultBoolIfUndefined(options::kImages, true);
|
SetDefaultBoolIfUndefined(options::kImages, true);
|
||||||
SetDefaultBoolIfUndefined(options::kTextAreasAreResizable, true);
|
SetDefaultBoolIfUndefined(options::kTextAreasAreResizable, true);
|
||||||
SetDefaultBoolIfUndefined(options::kWebGL, true);
|
SetDefaultBoolIfUndefined(options::kWebGL, true);
|
||||||
|
SetDefaultBoolIfUndefined(options::kEnableWebSQL, true);
|
||||||
bool webSecurity = true;
|
bool webSecurity = true;
|
||||||
SetDefaultBoolIfUndefined(options::kWebSecurity, webSecurity);
|
SetDefaultBoolIfUndefined(options::kWebSecurity, webSecurity);
|
||||||
// If webSecurity was explicity set to false, let's inherit that into
|
// If webSecurity was explicity set to false, let's inherit that into
|
||||||
|
@ -419,6 +420,10 @@ void WebContentsPreferences::AppendCommandLineSwitches(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Whether to allow the WebSQL api
|
||||||
|
if (IsEnabled(options::kEnableWebSQL))
|
||||||
|
command_line->AppendSwitch(switches::kEnableWebSQL);
|
||||||
|
|
||||||
// We are appending args to a webContents so let's save the current state
|
// We are appending args to a webContents so let's save the current state
|
||||||
// of our preferences object so that during the lifetime of the WebContents
|
// of our preferences object so that during the lifetime of the WebContents
|
||||||
// we can fetch the options used to initally configure the WebContents
|
// we can fetch the options used to initally configure the WebContents
|
||||||
|
|
|
@ -182,6 +182,8 @@ const char kSpellcheck[] = "spellcheck";
|
||||||
const char kEnableRemoteModule[] = "enableRemoteModule";
|
const char kEnableRemoteModule[] = "enableRemoteModule";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const char kEnableWebSQL[] = "enableWebSQL";
|
||||||
|
|
||||||
} // namespace options
|
} // namespace options
|
||||||
|
|
||||||
namespace switches {
|
namespace switches {
|
||||||
|
@ -250,6 +252,10 @@ const char kNodeIntegrationInWorker[] = "node-integration-in-worker";
|
||||||
// environments will be created in sub-frames.
|
// environments will be created in sub-frames.
|
||||||
const char kNodeIntegrationInSubFrames[] = "node-integration-in-subframes";
|
const char kNodeIntegrationInSubFrames[] = "node-integration-in-subframes";
|
||||||
|
|
||||||
|
// Command switch passed to render process to control whether WebSQL api
|
||||||
|
// is allowed.
|
||||||
|
const char kEnableWebSQL[] = "enable-websql";
|
||||||
|
|
||||||
// Widevine options
|
// Widevine options
|
||||||
// Path to Widevine CDM binaries.
|
// Path to Widevine CDM binaries.
|
||||||
const char kWidevineCdmPath[] = "widevine-cdm-path";
|
const char kWidevineCdmPath[] = "widevine-cdm-path";
|
||||||
|
|
|
@ -84,6 +84,7 @@ extern const char kImages[];
|
||||||
extern const char kTextAreasAreResizable[];
|
extern const char kTextAreasAreResizable[];
|
||||||
extern const char kWebGL[];
|
extern const char kWebGL[];
|
||||||
extern const char kNavigateOnDragDrop[];
|
extern const char kNavigateOnDragDrop[];
|
||||||
|
extern const char kEnableWebSQL[];
|
||||||
|
|
||||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||||
extern const char kSpellcheck[];
|
extern const char kSpellcheck[];
|
||||||
|
@ -129,6 +130,7 @@ extern const char kWebviewTag[];
|
||||||
extern const char kNodeIntegrationInSubFrames[];
|
extern const char kNodeIntegrationInSubFrames[];
|
||||||
extern const char kDisableElectronSiteInstanceOverrides[];
|
extern const char kDisableElectronSiteInstanceOverrides[];
|
||||||
extern const char kEnableNodeLeakageInRenderers[];
|
extern const char kEnableNodeLeakageInRenderers[];
|
||||||
|
extern const char kEnableWebSQL[];
|
||||||
|
|
||||||
extern const char kWidevineCdmPath[];
|
extern const char kWidevineCdmPath[];
|
||||||
extern const char kWidevineCdmVersion[];
|
extern const char kWidevineCdmVersion[];
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "shell/renderer/content_settings_observer.h"
|
#include "shell/renderer/content_settings_observer.h"
|
||||||
|
|
||||||
#include "content/public/renderer/render_frame.h"
|
#include "content/public/renderer/render_frame.h"
|
||||||
|
#include "shell/common/options_switches.h"
|
||||||
#include "third_party/blink/public/platform/url_conversion.h"
|
#include "third_party/blink/public/platform/url_conversion.h"
|
||||||
#include "third_party/blink/public/platform/web_security_origin.h"
|
#include "third_party/blink/public/platform/web_security_origin.h"
|
||||||
#include "third_party/blink/public/web/web_local_frame.h"
|
#include "third_party/blink/public/web/web_local_frame.h"
|
||||||
|
@ -20,6 +21,11 @@ ContentSettingsObserver::ContentSettingsObserver(
|
||||||
ContentSettingsObserver::~ContentSettingsObserver() = default;
|
ContentSettingsObserver::~ContentSettingsObserver() = default;
|
||||||
|
|
||||||
bool ContentSettingsObserver::AllowDatabase() {
|
bool ContentSettingsObserver::AllowDatabase() {
|
||||||
|
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||||
|
switches::kEnableWebSQL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
blink::WebFrame* frame = render_frame()->GetWebFrame();
|
blink::WebFrame* frame = render_frame()->GetWebFrame();
|
||||||
if (frame->GetSecurityOrigin().IsOpaque() ||
|
if (frame->GetSecurityOrigin().IsOpaque() ||
|
||||||
frame->Top()->GetSecurityOrigin().IsOpaque())
|
frame->Top()->GetSecurityOrigin().IsOpaque())
|
||||||
|
|
|
@ -1010,6 +1010,166 @@ describe('chromium features', () => {
|
||||||
testLocalStorageAfterXSiteRedirect('after a cross-site redirect');
|
testLocalStorageAfterXSiteRedirect('after a cross-site redirect');
|
||||||
testLocalStorageAfterXSiteRedirect('after a cross-site redirect in sandbox mode', { sandbox: true });
|
testLocalStorageAfterXSiteRedirect('after a cross-site redirect in sandbox mode', { sandbox: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('enableWebSQL webpreference', () => {
|
||||||
|
const standardScheme = (global as any).standardScheme;
|
||||||
|
const origin = `${standardScheme}://fake-host`;
|
||||||
|
const filePath = path.join(fixturesPath, 'pages', 'storage', 'web_sql.html');
|
||||||
|
const sqlPartition = 'web-sql-preference-test';
|
||||||
|
const sqlSession = session.fromPartition(sqlPartition);
|
||||||
|
const securityError = 'An attempt was made to break through the security policy of the user agent.';
|
||||||
|
let contents: WebContents, w: BrowserWindow;
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
sqlSession.protocol.registerFileProtocol(standardScheme, (request, callback) => {
|
||||||
|
callback({ path: filePath });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
sqlSession.protocol.unregisterProtocol(standardScheme);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
if (contents) {
|
||||||
|
(contents as any).destroy();
|
||||||
|
contents = null as any;
|
||||||
|
}
|
||||||
|
await closeAllWindows();
|
||||||
|
(w as any) = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('default value allows websql', async () => {
|
||||||
|
contents = (webContents as any).create({
|
||||||
|
session: sqlSession,
|
||||||
|
nodeIntegration: true
|
||||||
|
});
|
||||||
|
contents.loadURL(origin);
|
||||||
|
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
|
||||||
|
expect(error).to.be.null();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('when set to false can disallow websql', async () => {
|
||||||
|
contents = (webContents as any).create({
|
||||||
|
session: sqlSession,
|
||||||
|
nodeIntegration: true,
|
||||||
|
enableWebSQL: false
|
||||||
|
});
|
||||||
|
contents.loadURL(origin);
|
||||||
|
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
|
||||||
|
expect(error).to.equal(securityError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('when set to false does not disable indexedDB', async () => {
|
||||||
|
contents = (webContents as any).create({
|
||||||
|
session: sqlSession,
|
||||||
|
nodeIntegration: true,
|
||||||
|
enableWebSQL: false
|
||||||
|
});
|
||||||
|
contents.loadURL(origin);
|
||||||
|
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
|
||||||
|
expect(error).to.equal(securityError);
|
||||||
|
const dbName = 'random';
|
||||||
|
const result = await contents.executeJavaScript(`
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
let req = window.indexedDB.open('${dbName}');
|
||||||
|
req.onsuccess = (event) => {
|
||||||
|
let db = req.result;
|
||||||
|
resolve(db.name);
|
||||||
|
}
|
||||||
|
req.onerror = (event) => { resolve(event.target.code); }
|
||||||
|
} catch (e) {
|
||||||
|
resolve(e.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
expect(result).to.equal(dbName);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('child webContents can override when the embedder has allowed websql', async () => {
|
||||||
|
w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
webviewTag: true,
|
||||||
|
session: sqlSession
|
||||||
|
}
|
||||||
|
});
|
||||||
|
w.webContents.loadURL(origin);
|
||||||
|
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
|
||||||
|
expect(error).to.be.null();
|
||||||
|
const webviewResult = emittedOnce(ipcMain, 'web-sql-response');
|
||||||
|
await w.webContents.executeJavaScript(`
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const webview = new WebView();
|
||||||
|
webview.setAttribute('src', '${origin}');
|
||||||
|
webview.setAttribute('webpreferences', 'enableWebSQL=0');
|
||||||
|
webview.setAttribute('partition', '${sqlPartition}');
|
||||||
|
webview.setAttribute('nodeIntegration', 'on');
|
||||||
|
document.body.appendChild(webview);
|
||||||
|
webview.addEventListener('dom-ready', () => resolve());
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
const [, childError] = await webviewResult;
|
||||||
|
expect(childError).to.equal(securityError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('child webContents cannot override when the embedder has disallowed websql', async () => {
|
||||||
|
w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
enableWebSQL: false,
|
||||||
|
webviewTag: true,
|
||||||
|
session: sqlSession
|
||||||
|
}
|
||||||
|
});
|
||||||
|
w.webContents.loadURL('data:text/html,<html></html>');
|
||||||
|
const webviewResult = emittedOnce(ipcMain, 'web-sql-response');
|
||||||
|
await w.webContents.executeJavaScript(`
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const webview = new WebView();
|
||||||
|
webview.setAttribute('src', '${origin}');
|
||||||
|
webview.setAttribute('webpreferences', 'enableWebSQL=1');
|
||||||
|
webview.setAttribute('partition', '${sqlPartition}');
|
||||||
|
webview.setAttribute('nodeIntegration', 'on');
|
||||||
|
document.body.appendChild(webview);
|
||||||
|
webview.addEventListener('dom-ready', () => resolve());
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
const [, childError] = await webviewResult;
|
||||||
|
expect(childError).to.equal(securityError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('child webContents can use websql when the embedder has allowed websql', async () => {
|
||||||
|
w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
webviewTag: true,
|
||||||
|
session: sqlSession
|
||||||
|
}
|
||||||
|
});
|
||||||
|
w.webContents.loadURL(origin);
|
||||||
|
const [, error] = await emittedOnce(ipcMain, 'web-sql-response');
|
||||||
|
expect(error).to.be.null();
|
||||||
|
const webviewResult = emittedOnce(ipcMain, 'web-sql-response');
|
||||||
|
await w.webContents.executeJavaScript(`
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const webview = new WebView();
|
||||||
|
webview.setAttribute('src', '${origin}');
|
||||||
|
webview.setAttribute('webpreferences', 'enableWebSQL=1');
|
||||||
|
webview.setAttribute('partition', '${sqlPartition}');
|
||||||
|
webview.setAttribute('nodeIntegration', 'on');
|
||||||
|
document.body.appendChild(webview);
|
||||||
|
webview.addEventListener('dom-ready', () => resolve());
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
const [, childError] = await webviewResult;
|
||||||
|
expect(childError).to.be.null();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ifdescribe(features.isPDFViewerEnabled())('PDF Viewer', () => {
|
ifdescribe(features.isPDFViewerEnabled())('PDF Viewer', () => {
|
||||||
|
|
3
spec/fixtures/pages/storage/web_sql.html
vendored
3
spec/fixtures/pages/storage/web_sql.html
vendored
|
@ -1,8 +1,9 @@
|
||||||
<script>
|
<script>
|
||||||
|
const {ipcRenderer} = require('electron')
|
||||||
try {
|
try {
|
||||||
window.openDatabase('test', '1.0', 'test database', 65536)
|
window.openDatabase('test', '1.0', 'test database', 65536)
|
||||||
|
ipcRenderer.send('web-sql-response', null)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const {ipcRenderer} = require('electron')
|
|
||||||
ipcRenderer.send('web-sql-response', e.message)
|
ipcRenderer.send('web-sql-response', e.message)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue