import { app, dialog, BrowserWindow, shell, ipcMain } from 'electron' import * as path from 'path' let mainWindow: BrowserWindow | null = null // Quit when all windows are closed. app.on('window-all-closed', () => { app.quit() }) function decorateURL (url: string) { // safely add `?utm_source=default_app const parsedUrl = new URL(url) parsedUrl.searchParams.append('utm_source', 'default_app') return parsedUrl.toString() } // Find the shortest path to the electron binary const absoluteElectronPath = process.execPath const relativeElectronPath = path.relative(process.cwd(), absoluteElectronPath) const electronPath = absoluteElectronPath.length < relativeElectronPath.length ? absoluteElectronPath : relativeElectronPath const indexPath = path.resolve(app.getAppPath(), 'index.html') function isTrustedSender (webContents: Electron.WebContents) { if (webContents !== (mainWindow && mainWindow.webContents)) { return false } const parsedUrl = new URL(webContents.getURL()) const urlPath = process.platform === 'win32' // Strip the prefixed "/" that occurs on windows ? path.resolve(parsedUrl.pathname.substr(1)) : parsedUrl.pathname return parsedUrl.protocol === 'file:' && urlPath === indexPath } ipcMain.on('bootstrap', (event) => { try { event.returnValue = isTrustedSender(event.sender) ? electronPath : null } catch { event.returnValue = null } }) async function createWindow () { await app.whenReady() const options: Electron.BrowserWindowConstructorOptions = { width: 900, height: 600, autoHideMenuBar: true, backgroundColor: '#FFFFFF', webPreferences: { preload: path.resolve(__dirname, 'preload.js'), contextIsolation: true, sandbox: true, enableRemoteModule: false }, useContentSize: true, show: false } if (process.platform === 'linux') { options.icon = path.join(__dirname, 'icon.png') } mainWindow = new BrowserWindow(options) mainWindow.on('ready-to-show', () => mainWindow!.show()) mainWindow.webContents.on('new-window', (event, url) => { event.preventDefault() shell.openExternal(decorateURL(url)) }) mainWindow.webContents.session.setPermissionRequestHandler((webContents, permission, done) => { const parsedUrl = new URL(webContents.getURL()) const options: Electron.MessageBoxOptions = { title: 'Permission Request', message: `Allow '${parsedUrl.origin}' to access '${permission}'?`, buttons: ['OK', 'Cancel'], cancelId: 1 } dialog.showMessageBox(mainWindow!, options).then(({ response }) => { done(response === 0) }) }) return mainWindow } export const loadURL = async (appUrl: string) => { mainWindow = await createWindow() mainWindow.loadURL(appUrl) mainWindow.focus() } export const loadFile = async (appPath: string) => { mainWindow = await createWindow() mainWindow.loadFile(appPath) mainWindow.focus() }