fix(electron): do not use async callback in onBeforeSendHeaders (#7894)

it seems using async callback for onBeforeSendHeaders may crash the app.
the main reason why it is async is to read the cookies from session.

fix AF-1172
This commit is contained in:
pengx17
2024-08-16 05:17:47 +00:00
parent b57ce4646f
commit 69c507fded
3 changed files with 45 additions and 77 deletions

View File

@@ -1,7 +1,6 @@
import path from 'node:path';
import type { App, BrowserWindow } from 'electron';
import { ipcMain } from 'electron';
import type { App } from 'electron';
import { buildType, CLOUD_BASE_URL, isDev } from './config';
import { mainWindowOrigin } from './constants';
@@ -103,20 +102,8 @@ async function handleOauthJwt(url: string) {
),
});
let hiddenWindow: BrowserWindow | null = null;
ipcMain.once('affine:login', () => {
hiddenWindow?.destroy();
if (urlObj.searchParams.get('next') === 'onboarding') {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
mainWindow.loadURL(mainWindowOrigin + '/auth/onboarding');
}
});
// hacks to refresh auth state in the main window
hiddenWindow = await handleOpenUrlInHiddenWindow(
mainWindowOrigin + '/auth/signIn'
);
await handleOpenUrlInHiddenWindow(mainWindowOrigin + '/auth/signIn');
} catch (e) {
logger.error('failed to open url in popup', e);
}

View File

@@ -3,8 +3,7 @@ import { join } from 'node:path';
import { net, protocol, session } from 'electron';
import { CLOUD_BASE_URL } from './config';
import { logger } from './logger';
import { getCookie } from './windows-manager';
import { getCookies } from './windows-manager';
protocol.registerSchemesAsPrivileged([
{
@@ -104,33 +103,23 @@ export function registerProtocol() {
);
session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
(async () => {
const url = new URL(details.url);
const pathname = url.pathname;
// if sending request to the cloud, attach the session cookie
if (isNetworkResource(pathname)) {
const cookie = await getCookie(CLOUD_BASE_URL);
if (cookie) {
const cookieString = cookie
.map(c => `${c.name}=${c.value}`)
.join('; ');
details.requestHeaders['cookie'] = cookieString;
}
// add the referer and origin headers
details.requestHeaders['referer'] ??= CLOUD_BASE_URL;
details.requestHeaders['origin'] ??= CLOUD_BASE_URL;
const url = new URL(details.url);
const pathname = url.pathname;
// if sending request to the cloud, attach the session cookie
if (isNetworkResource(pathname)) {
const cookie = getCookies();
if (cookie) {
const cookieString = cookie.map(c => `${c.name}=${c.value}`).join('; ');
details.requestHeaders['cookie'] = cookieString;
}
callback({
cancel: false,
requestHeaders: details.requestHeaders,
});
})().catch(e => {
logger.error('failed to attach cookie', e);
callback({
cancel: false,
requestHeaders: details.requestHeaders,
});
// add the referer and origin headers
details.requestHeaders['referer'] ??= CLOUD_BASE_URL;
details.requestHeaders['origin'] ??= CLOUD_BASE_URL;
}
callback({
cancel: false,
requestHeaders: details.requestHeaders,
});
});
}

View File

@@ -3,6 +3,7 @@ import { join } from 'node:path';
import {
app,
type CookiesSetDetails,
session,
type View,
type WebContents,
WebContentsView,
@@ -22,7 +23,7 @@ import {
} from 'rxjs';
import { isMacOS } from '../../shared/utils';
import { isDev } from '../config';
import { CLOUD_BASE_URL, isDev } from '../config';
import { mainWindowOrigin, shellViewUrl } from '../constants';
import { ensureHelperProcess } from '../helper-process';
import { logger } from '../logger';
@@ -185,6 +186,8 @@ export class WebContentViewsManager {
*/
readonly tabAction$ = new Subject<TabAction>();
cookies: Electron.Cookie[] = [];
readonly activeWorkbenchId$ = this.tabViewsMeta$.pipe(
map(m => m?.activeWorkbenchId ?? m?.workbenches[0].id)
);
@@ -672,7 +675,6 @@ export class WebContentViewsManager {
disposables.push(
windowReadyToShow$.subscribe(w => {
handleWebContentsResize().catch(logger.error);
const screenSizeChangeEvents = ['resize', 'maximize', 'unmaximize'];
const onResize = () => {
if (this.activeWorkbenchView) {
@@ -689,6 +691,23 @@ export class WebContentViewsManager {
// add shell view
this.createAndAddView('shell').catch(logger.error);
(async () => {
const updateCookies = () => {
session.defaultSession.cookies
.get({
url: CLOUD_BASE_URL,
})
.then(cookies => {
this.cookies = cookies;
})
.catch(err => {
logger.error('failed to get cookies', err);
});
};
updateCookies();
session.defaultSession.cookies.on('changed', () => {
updateCookies();
});
if (this.tabViewsMeta.workbenches.length === 0) {
// create a default view (e.g., on first launch)
await this.addTab();
@@ -705,40 +724,17 @@ export class WebContentViewsManager {
});
};
setCookie = async (cookie: CookiesSetDetails) => {
setCookie = async (cookiesSetDetails: CookiesSetDetails) => {
const views = this.allViews;
if (!views) {
return;
}
logger.info('setting cookie to main window view(s)', cookie);
logger.info('setting cookie to main window view(s)', cookiesSetDetails);
for (const view of views) {
await view.webContents.session.cookies.set(cookie);
await view.webContents.session.cookies.set(cookiesSetDetails);
}
};
removeCookie = async (url: string, name: string) => {
const views = this.allViews;
if (!views) {
return;
}
logger.info('removing cookie from main window view(s)', { url, name });
for (const view of views) {
await view.webContents.session.cookies.remove(url, name);
}
};
getCookie = (url?: string, name?: string) => {
// all webviews share the same session
const view = this.allViews?.at(0);
if (!view) {
return;
}
return view.webContents.session.cookies.get({
url,
name,
});
};
getViewById = (id: string) => {
if (id === 'shell') {
return this.shellView;
@@ -865,12 +861,8 @@ export async function setCookie(
return WebContentViewsManager.instance.setCookie(details);
}
export async function removeCookie(url: string, name: string): Promise<void> {
return WebContentViewsManager.instance.removeCookie(url, name);
}
export async function getCookie(url?: string, name?: string) {
return WebContentViewsManager.instance.getCookie(url, name);
export function getCookies() {
return WebContentViewsManager.instance.cookies;
}
// there is no proper way to listen to webContents resize event