diff options
Diffstat (limited to 'packages/main/src')
-rw-r--r-- | packages/main/src/index.ts | 84 |
1 files changed, 31 insertions, 53 deletions
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 { | |||
22 | app, | 22 | app, |
23 | BrowserView, | 23 | BrowserView, |
24 | BrowserWindow, | 24 | BrowserWindow, |
25 | IpcMainEvent, | 25 | ipcMain, |
26 | } from 'electron'; | 26 | } from 'electron'; |
27 | import { readFile, readFileSync } from 'fs'; | 27 | import { readFile, readFileSync } from 'fs'; |
28 | import { autorun } from 'mobx'; | 28 | import { autorun } from 'mobx'; |
@@ -31,6 +31,7 @@ import { join } from 'path'; | |||
31 | import { | 31 | import { |
32 | ServiceToMainIpcMessage, | 32 | ServiceToMainIpcMessage, |
33 | unreadCount, | 33 | unreadCount, |
34 | WebSource, | ||
34 | } from '@sophie/service-shared'; | 35 | } from '@sophie/service-shared'; |
35 | import { | 36 | import { |
36 | browserViewBounds, | 37 | browserViewBounds, |
@@ -73,30 +74,26 @@ app.commandLine.appendSwitch( | |||
73 | // Remove sophie and electron from the user-agent string to avoid detection. | 74 | // Remove sophie and electron from the user-agent string to avoid detection. |
74 | const originalUserAgent = app.userAgentFallback; | 75 | const originalUserAgent = app.userAgentFallback; |
75 | const userAgent = originalUserAgent.replaceAll(/\s(sophie|Electron)\/\S+/g, ''); | 76 | const userAgent = originalUserAgent.replaceAll(/\s(sophie|Electron)\/\S+/g, ''); |
76 | const platformInUa = userAgent.match(/\((Win|Mac|X11; L)/); | 77 | const chromelessUserAgent = userAgent.replace(/ Chrome\/\S+/, ''); |
77 | let platform = 'Unknown'; | ||
78 | if (platformInUa !== null) { | ||
79 | switch (platformInUa[1]) { | ||
80 | case 'Win': | ||
81 | platform = 'Windows'; | ||
82 | break; | ||
83 | case 'Mac': | ||
84 | platform = 'macOS'; | ||
85 | break; | ||
86 | case 'X11; L': | ||
87 | platform = 'Linux'; | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | const chromiumVersion = process.versions.chrome.split('.')[0]; | ||
92 | // Removing the electron version breaks redux devtools, so we only do this in production. | 78 | // Removing the electron version breaks redux devtools, so we only do this in production. |
93 | if (!isDevelopment) { | 79 | if (!isDevelopment) { |
94 | app.userAgentFallback = userAgent; | 80 | app.userAgentFallback = userAgent; |
95 | } | 81 | } |
96 | 82 | ||
83 | function getResourcePath(relativePath: string): string { | ||
84 | return join(__dirname, relativePath); | ||
85 | } | ||
86 | |||
87 | function getResourceUrl(relativePath: string): string { | ||
88 | return new URL(relativePath, `file://${__dirname}`).toString(); | ||
89 | } | ||
90 | |||
97 | let serviceInjectRelativePath = '../../service-inject/dist/index.cjs'; | 91 | let serviceInjectRelativePath = '../../service-inject/dist/index.cjs'; |
98 | let serviceInjectPath = join(__dirname, serviceInjectRelativePath); | 92 | let serviceInjectPath = getResourcePath(serviceInjectRelativePath); |
99 | let serviceInject: string = readFileSync(serviceInjectPath, 'utf8'); | 93 | let serviceInject: WebSource = { |
94 | code: readFileSync(serviceInjectPath, 'utf8'), | ||
95 | url: getResourceUrl(serviceInjectRelativePath), | ||
96 | }; | ||
100 | 97 | ||
101 | if (isDevelopment) { | 98 | if (isDevelopment) { |
102 | installDevToolsExtensions(app); | 99 | installDevToolsExtensions(app); |
@@ -111,12 +108,12 @@ function createWindow(): Promise<unknown> { | |||
111 | show: false, | 108 | show: false, |
112 | webPreferences: { | 109 | webPreferences: { |
113 | sandbox: true, | 110 | sandbox: true, |
114 | preload: join(__dirname, '../../preload/dist/index.cjs'), | 111 | preload: getResourcePath('../../preload/dist/index.cjs'), |
115 | }, | 112 | }, |
116 | }); | 113 | }); |
117 | 114 | ||
118 | if (isDevelopment) { | 115 | if (isDevelopment) { |
119 | // openDevToolsWhenReady(mainWindow); | 116 | openDevToolsWhenReady(mainWindow); |
120 | } | 117 | } |
121 | 118 | ||
122 | mainWindow.on('ready-to-show', () => { | 119 | mainWindow.on('ready-to-show', () => { |
@@ -131,7 +128,7 @@ function createWindow(): Promise<unknown> { | |||
131 | webPreferences: { | 128 | webPreferences: { |
132 | sandbox: true, | 129 | sandbox: true, |
133 | nodeIntegrationInSubFrames: true, | 130 | nodeIntegrationInSubFrames: true, |
134 | preload: join(__dirname, '../../service-preload/dist/index.cjs'), | 131 | preload: getResourcePath('../../service-preload/dist/index.cjs'), |
135 | partition: 'persist:service', | 132 | partition: 'persist:service', |
136 | }, | 133 | }, |
137 | }); | 134 | }); |
@@ -142,17 +139,6 @@ function createWindow(): Promise<unknown> { | |||
142 | }); | 139 | }); |
143 | mainWindow.setBrowserView(browserView); | 140 | mainWindow.setBrowserView(browserView); |
144 | 141 | ||
145 | browserView.webContents.on( | ||
146 | 'did-frame-navigate', | ||
147 | (_event, _url, _statusCode, _statusText, isMainFrame, _processId, routingId) => { | ||
148 | const { webContents: { mainFrame } } = browserView; | ||
149 | const frame = isMainFrame | ||
150 | ? mainFrame | ||
151 | : mainFrame.framesInSubtree.find((f) => f.routingId === routingId); | ||
152 | frame?.executeJavaScript(serviceInject).catch((err) => console.log(err)); | ||
153 | } | ||
154 | ); | ||
155 | |||
156 | webContents.on('ipc-message', (_event, channel, ...args) => { | 142 | webContents.on('ipc-message', (_event, channel, ...args) => { |
157 | try { | 143 | try { |
158 | switch (channel) { | 144 | switch (channel) { |
@@ -168,7 +154,7 @@ function createWindow(): Promise<unknown> { | |||
168 | case RendererToMainIpcMessage.ReloadAllServices: | 154 | case RendererToMainIpcMessage.ReloadAllServices: |
169 | readFile(serviceInjectPath, 'utf8', (err, data) => { | 155 | readFile(serviceInjectPath, 'utf8', (err, data) => { |
170 | if (err === null) { | 156 | if (err === null) { |
171 | serviceInject = data; | 157 | serviceInject.code = data; |
172 | } else { | 158 | } else { |
173 | console.error('Error while reloading', serviceInjectPath, err); | 159 | console.error('Error while reloading', serviceInjectPath, err); |
174 | } | 160 | } |
@@ -188,10 +174,17 @@ function createWindow(): Promise<unknown> { | |||
188 | webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); | 174 | webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); |
189 | }); | 175 | }); |
190 | 176 | ||
177 | ipcMain.on(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) => { | ||
178 | event.returnValue = event.sender.id == browserView.webContents.id | ||
179 | ? serviceInject | ||
180 | : null; | ||
181 | }); | ||
182 | |||
191 | browserView.webContents.on('ipc-message', (_event, channel, ...args) => { | 183 | browserView.webContents.on('ipc-message', (_event, channel, ...args) => { |
192 | try { | 184 | try { |
193 | switch (channel) { | 185 | switch (channel) { |
194 | case ServiceToMainIpcMessage.ApiExposedInMainWorld: | 186 | case ServiceToMainIpcMessage.ApiExposedInMainWorld: |
187 | // Synchronous message must be handled with `ipcMain.on` | ||
195 | break; | 188 | break; |
196 | case ServiceToMainIpcMessage.SetUnreadCount: | 189 | case ServiceToMainIpcMessage.SetUnreadCount: |
197 | console.log('Unread count:', unreadCount.parse(args[0])); | 190 | console.log('Unread count:', unreadCount.parse(args[0])); |
@@ -205,37 +198,22 @@ function createWindow(): Promise<unknown> { | |||
205 | } | 198 | } |
206 | }); | 199 | }); |
207 | 200 | ||
208 | // Inject CSS to simulate `browserView.setBackgroundColor`. | ||
209 | // This is injected before the page loads, so the styles from the website will overwrite it. | ||
210 | browserView.webContents.on('did-navigate', () => { | ||
211 | browserView.webContents.insertCSS( | ||
212 | 'html { background-color: #fff; }', | ||
213 | { | ||
214 | cssOrigin: 'author', | ||
215 | }, | ||
216 | ); | ||
217 | }); | ||
218 | |||
219 | browserView.webContents.session.webRequest.onBeforeSendHeaders(({ url, requestHeaders }, callback) => { | 201 | browserView.webContents.session.webRequest.onBeforeSendHeaders(({ url, requestHeaders }, callback) => { |
220 | if (url.match(/accounts\.google/)) { | 202 | if (url.match(/^[^:]+:\/\/accounts\.google\.[^.\/]+\//)) { |
221 | requestHeaders['User-Agent'] = userAgent.replace(/ Chrome\/\S+/, ''); | 203 | requestHeaders['User-Agent'] = chromelessUserAgent; |
222 | } else { | 204 | } else { |
223 | requestHeaders['User-Agent'] = userAgent; | 205 | requestHeaders['User-Agent'] = userAgent; |
224 | } | 206 | } |
225 | requestHeaders['User-Agent'] = userAgent; | ||
226 | requestHeaders['Sec-CH-UA'] = `" Not A;Brand";v="99", "Chromium";v="${chromiumVersion}"`; | ||
227 | requestHeaders['Sec-CH-UA-Mobile'] = '?0'; | ||
228 | requestHeaders['Sec-CH-UA-Platform'] = platform; | ||
229 | callback({ requestHeaders }); | 207 | callback({ requestHeaders }); |
230 | }); | 208 | }); |
231 | 209 | ||
232 | const pageUrl = (isDevelopment && import.meta.env.VITE_DEV_SERVER_URL !== undefined) | 210 | const pageUrl = (isDevelopment && import.meta.env.VITE_DEV_SERVER_URL !== undefined) |
233 | ? import.meta.env.VITE_DEV_SERVER_URL | 211 | ? import.meta.env.VITE_DEV_SERVER_URL |
234 | : new URL('../renderer/dist/index.html', `file://${__dirname}`).toString(); | 212 | : getResourceUrl('../renderer/dist/index.html'); |
235 | 213 | ||
236 | return Promise.all([ | 214 | return Promise.all([ |
237 | mainWindow.loadURL(pageUrl), | 215 | mainWindow.loadURL(pageUrl), |
238 | browserView.webContents.loadURL('https://gmail.com').then(() => browserView.webContents.openDevTools()), | 216 | browserView.webContents.loadURL('https://git.marussy.com/sophie/about'), |
239 | ]); | 217 | ]); |
240 | } | 218 | } |
241 | 219 | ||