diff --git a/js/desktop/README.md b/js/desktop/README.md new file mode 100644 index 0000000..68b0596 --- /dev/null +++ b/js/desktop/README.md @@ -0,0 +1,5 @@ +# Notes +## CORS for desktop app +In dev: each renderer process has it's own localhost port. The renderer process passes this in the `Origin` header for requests, and expects appropriate ACAO headers in the response. + +In packaged app: the renderer process does not include `Origin` header, so expects no extra ACAO headers from the server, otherwise the client would fail to accept responses. diff --git a/js/desktop/src/main.ts b/js/desktop/src/main.ts index 38b4fae..d3bbbd7 100644 --- a/js/desktop/src/main.ts +++ b/js/desktop/src/main.ts @@ -26,16 +26,11 @@ if (app.isPackaged) { }); } -// Handle creating/removing shortcuts on Windows when installing/uninstalling. +// Handle creating/removing shortcuts on Windows when installing/updating/uninstalling. if (started) { app.quit(); } -// Set the dock icon for development mode on macOS. -if (process.platform === 'darwin' && !app.isPackaged) { - app.dock?.setIcon(path.join(__dirname, '../../assets/icon.png')); -} - // In dev, `LLINK_PROFILE=foo yarn start` spins up a second instance with an // isolated userData dir so it can coexist with the default one (separate auth, // cookies, leveldb locks). @@ -44,12 +39,10 @@ if (devProfile) { app.setPath('userData', `${app.getPath('userData')}-${devProfile}`); } -// Single-instance lock: on Windows/Linux, clicking a llink:// URL launches a new -// process. The lock makes the losing instance quit and fires `second-instance` on -// the primary, so we focus the existing window instead of spawning a duplicate. -// macOS uses `open-url` instead and doesn't need this, but the lock is harmless. -// Skip the lock when running a named dev profile — those instances are meant to -// run alongside the default one. +// NOTE: on Windows/Linux, clicking a llink:// URL launches a new process. On macOS, +// `open-url` focuses existing instance of an application. + +// Prevent running multiple instances of app, except when in development if (!devProfile && !app.requestSingleInstanceLock()) { app.quit(); } @@ -88,10 +81,7 @@ function hardenWindow(win: BrowserWindow) { const isZoom = cmdOrCtrl && (key === '=' || key === '+' || key === '-' || key === '0'); - if (app.isPackaged && (isDevtools || isReload)) { - event.preventDefault(); - } - if (isZoom) { + if (app.isPackaged && (isDevtools || isReload || isZoom)) { event.preventDefault(); } }); @@ -132,6 +122,9 @@ const createWindow = () => { webPreferences: { preload: path.join(__dirname, 'preload.js'), backgroundThrottling: false, + webSecurity: true, + contextIsolation: true, + nodeIntegration: false, }, }); hardenWindow(mainWindow); @@ -433,38 +426,7 @@ ipcMain.on( }, ); -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. app.on('ready', () => { - // Allow CORS for API requests from the renderer process. - // The server doesn't handle OPTIONS preflight, so we intercept at the - // Electron network layer: inject CORS headers and return 200 for preflight. - session.defaultSession.webRequest.onHeadersReceived( - { urls: [`${appConfig.orionUrl}/*`, 'https://storage.googleapis.com/*'] }, - (details, callback) => { - const headers = { ...details.responseHeaders }; - headers['access-control-allow-origin'] = ['*']; - headers['access-control-allow-headers'] = [ - 'Content-Type', - 'Authorization', - ]; - headers['access-control-allow-methods'] = [ - 'GET', - 'POST', - 'PUT', - 'DELETE', - 'OPTIONS', - ]; - - if (details.method === 'OPTIONS') { - callback({ responseHeaders: headers, statusLine: 'HTTP/1.1 200 OK' }); - } else { - callback({ responseHeaders: headers }); - } - }, - ); - createWindow(); createAutoplayWindow(); }); @@ -503,6 +465,3 @@ app.on('open-url', (event) => { app.on('second-instance', () => { focusMainWindow(); }); - -// In this file you can include the rest of your app's specific main process -// code. You can also put them in separate files and import them here.