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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Robo
				Robo