From e321534fbea9f09b139d440584f6b84ad0afb80f Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sat, 25 Dec 2021 00:01:18 +0100 Subject: refactor: Simplify script injection Inject CSS and main world scripts synchronously to avoid race conditions with page loading. Don't try to miming userAgentData for now, since it won't bypass google's checks. However, simply omitting chrome from the user agent does bypass them, at least for now. --- packages/main/src/index.ts | 84 +++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 53 deletions(-) (limited to 'packages/main') diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts index 02d6c97..0c0a585 100644 --- a/packages/main/src/index.ts +++ b/packages/main/src/index.ts @@ -22,7 +22,7 @@ import { app, BrowserView, BrowserWindow, - IpcMainEvent, + ipcMain, } from 'electron'; import { readFile, readFileSync } from 'fs'; import { autorun } from 'mobx'; @@ -31,6 +31,7 @@ import { join } from 'path'; import { ServiceToMainIpcMessage, unreadCount, + WebSource, } from '@sophie/service-shared'; import { browserViewBounds, @@ -73,30 +74,26 @@ app.commandLine.appendSwitch( // Remove sophie and electron from the user-agent string to avoid detection. const originalUserAgent = app.userAgentFallback; const userAgent = originalUserAgent.replaceAll(/\s(sophie|Electron)\/\S+/g, ''); -const platformInUa = userAgent.match(/\((Win|Mac|X11; L)/); -let platform = 'Unknown'; -if (platformInUa !== null) { - switch (platformInUa[1]) { - case 'Win': - platform = 'Windows'; - break; - case 'Mac': - platform = 'macOS'; - break; - case 'X11; L': - platform = 'Linux'; - break; - } -} -const chromiumVersion = process.versions.chrome.split('.')[0]; +const chromelessUserAgent = userAgent.replace(/ Chrome\/\S+/, ''); // Removing the electron version breaks redux devtools, so we only do this in production. if (!isDevelopment) { app.userAgentFallback = userAgent; } +function getResourcePath(relativePath: string): string { + return join(__dirname, relativePath); +} + +function getResourceUrl(relativePath: string): string { + return new URL(relativePath, `file://${__dirname}`).toString(); +} + let serviceInjectRelativePath = '../../service-inject/dist/index.cjs'; -let serviceInjectPath = join(__dirname, serviceInjectRelativePath); -let serviceInject: string = readFileSync(serviceInjectPath, 'utf8'); +let serviceInjectPath = getResourcePath(serviceInjectRelativePath); +let serviceInject: WebSource = { + code: readFileSync(serviceInjectPath, 'utf8'), + url: getResourceUrl(serviceInjectRelativePath), +}; if (isDevelopment) { installDevToolsExtensions(app); @@ -111,12 +108,12 @@ function createWindow(): Promise { show: false, webPreferences: { sandbox: true, - preload: join(__dirname, '../../preload/dist/index.cjs'), + preload: getResourcePath('../../preload/dist/index.cjs'), }, }); if (isDevelopment) { - // openDevToolsWhenReady(mainWindow); + openDevToolsWhenReady(mainWindow); } mainWindow.on('ready-to-show', () => { @@ -131,7 +128,7 @@ function createWindow(): Promise { webPreferences: { sandbox: true, nodeIntegrationInSubFrames: true, - preload: join(__dirname, '../../service-preload/dist/index.cjs'), + preload: getResourcePath('../../service-preload/dist/index.cjs'), partition: 'persist:service', }, }); @@ -142,17 +139,6 @@ function createWindow(): Promise { }); mainWindow.setBrowserView(browserView); - browserView.webContents.on( - 'did-frame-navigate', - (_event, _url, _statusCode, _statusText, isMainFrame, _processId, routingId) => { - const { webContents: { mainFrame } } = browserView; - const frame = isMainFrame - ? mainFrame - : mainFrame.framesInSubtree.find((f) => f.routingId === routingId); - frame?.executeJavaScript(serviceInject).catch((err) => console.log(err)); - } - ); - webContents.on('ipc-message', (_event, channel, ...args) => { try { switch (channel) { @@ -168,7 +154,7 @@ function createWindow(): Promise { case RendererToMainIpcMessage.ReloadAllServices: readFile(serviceInjectPath, 'utf8', (err, data) => { if (err === null) { - serviceInject = data; + serviceInject.code = data; } else { console.error('Error while reloading', serviceInjectPath, err); } @@ -188,10 +174,17 @@ function createWindow(): Promise { webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); }); + ipcMain.on(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) => { + event.returnValue = event.sender.id == browserView.webContents.id + ? serviceInject + : null; + }); + browserView.webContents.on('ipc-message', (_event, channel, ...args) => { try { switch (channel) { case ServiceToMainIpcMessage.ApiExposedInMainWorld: + // Synchronous message must be handled with `ipcMain.on` break; case ServiceToMainIpcMessage.SetUnreadCount: console.log('Unread count:', unreadCount.parse(args[0])); @@ -205,37 +198,22 @@ function createWindow(): Promise { } }); - // Inject CSS to simulate `browserView.setBackgroundColor`. - // This is injected before the page loads, so the styles from the website will overwrite it. - browserView.webContents.on('did-navigate', () => { - browserView.webContents.insertCSS( - 'html { background-color: #fff; }', - { - cssOrigin: 'author', - }, - ); - }); - browserView.webContents.session.webRequest.onBeforeSendHeaders(({ url, requestHeaders }, callback) => { - if (url.match(/accounts\.google/)) { - requestHeaders['User-Agent'] = userAgent.replace(/ Chrome\/\S+/, ''); + if (url.match(/^[^:]+:\/\/accounts\.google\.[^.\/]+\//)) { + requestHeaders['User-Agent'] = chromelessUserAgent; } else { requestHeaders['User-Agent'] = userAgent; } - requestHeaders['User-Agent'] = userAgent; - requestHeaders['Sec-CH-UA'] = `" Not A;Brand";v="99", "Chromium";v="${chromiumVersion}"`; - requestHeaders['Sec-CH-UA-Mobile'] = '?0'; - requestHeaders['Sec-CH-UA-Platform'] = platform; callback({ requestHeaders }); }); const pageUrl = (isDevelopment && import.meta.env.VITE_DEV_SERVER_URL !== undefined) ? import.meta.env.VITE_DEV_SERVER_URL - : new URL('../renderer/dist/index.html', `file://${__dirname}`).toString(); + : getResourceUrl('../renderer/dist/index.html'); return Promise.all([ mainWindow.loadURL(pageUrl), - browserView.webContents.loadURL('https://gmail.com').then(() => browserView.webContents.openDevTools()), + browserView.webContents.loadURL('https://git.marussy.com/sophie/about'), ]); } -- cgit v1.2.3-54-g00ecf