diff --git a/default_app/default_app.ts b/default_app/default_app.ts
index b5ea5757a5f5..a7924cbd569e 100644
--- a/default_app/default_app.ts
+++ b/default_app/default_app.ts
@@ -1,4 +1,4 @@
-import { app, BrowserWindow, BrowserWindowConstructorOptions } from 'electron'
+import { app, dialog, BrowserWindow, shell, ipcMain } from 'electron'
import * as path from 'path'
let mainWindow: BrowserWindow | null = null
@@ -8,18 +8,52 @@ app.on('window-all-closed', () => {
app.quit()
})
-export const load = async (appUrl: string) => {
+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())
+ return parsedUrl.protocol === 'file:' && parsedUrl.pathname === 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: BrowserWindowConstructorOptions = {
+ const options: Electron.BrowserWindowConstructorOptions = {
width: 900,
height: 600,
autoHideMenuBar: true,
backgroundColor: '#FFFFFF',
webPreferences: {
+ preload: path.resolve(__dirname, 'preload.js'),
contextIsolation: true,
- preload: path.resolve(__dirname, 'renderer.js'),
- webviewTag: false
+ sandbox: true,
+ enableRemoteModule: false
},
useContentSize: true,
show: false
@@ -30,9 +64,39 @@ export const load = async (appUrl: string) => {
}
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, (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()
+}
diff --git a/default_app/index.html b/default_app/index.html
index cba87e5eef31..68edcf818061 100644
--- a/default_app/index.html
+++ b/default_app/index.html
@@ -2,9 +2,10 @@
Electron
-
+
+
@@ -52,31 +53,31 @@