aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main/src/index.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/main/src/index.ts')
-rw-r--r--packages/main/src/index.ts84
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';
27import { readFile, readFileSync } from 'fs'; 27import { readFile, readFileSync } from 'fs';
28import { autorun } from 'mobx'; 28import { autorun } from 'mobx';
@@ -31,6 +31,7 @@ import { join } from 'path';
31import { 31import {
32 ServiceToMainIpcMessage, 32 ServiceToMainIpcMessage,
33 unreadCount, 33 unreadCount,
34 WebSource,
34} from '@sophie/service-shared'; 35} from '@sophie/service-shared';
35import { 36import {
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.
74const originalUserAgent = app.userAgentFallback; 75const originalUserAgent = app.userAgentFallback;
75const userAgent = originalUserAgent.replaceAll(/\s(sophie|Electron)\/\S+/g, ''); 76const userAgent = originalUserAgent.replaceAll(/\s(sophie|Electron)\/\S+/g, '');
76const platformInUa = userAgent.match(/\((Win|Mac|X11; L)/); 77const chromelessUserAgent = userAgent.replace(/ Chrome\/\S+/, '');
77let platform = 'Unknown';
78if (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}
91const 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.
93if (!isDevelopment) { 79if (!isDevelopment) {
94 app.userAgentFallback = userAgent; 80 app.userAgentFallback = userAgent;
95} 81}
96 82
83function getResourcePath(relativePath: string): string {
84 return join(__dirname, relativePath);
85}
86
87function getResourceUrl(relativePath: string): string {
88 return new URL(relativePath, `file://${__dirname}`).toString();
89}
90
97let serviceInjectRelativePath = '../../service-inject/dist/index.cjs'; 91let serviceInjectRelativePath = '../../service-inject/dist/index.cjs';
98let serviceInjectPath = join(__dirname, serviceInjectRelativePath); 92let serviceInjectPath = getResourcePath(serviceInjectRelativePath);
99let serviceInject: string = readFileSync(serviceInjectPath, 'utf8'); 93let serviceInject: WebSource = {
94 code: readFileSync(serviceInjectPath, 'utf8'),
95 url: getResourceUrl(serviceInjectRelativePath),
96};
100 97
101if (isDevelopment) { 98if (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