main: add context bridge communication example via preload script, set nodeIntegration to false by default, improve security
This commit is contained in:
1 parent
a540caf9d3
commit
8057a3521a
9 files changed
+64
-12
No files matched your search
@@ -22,6 +22,7 @@
|
|||||||
│ │ │ └─ Constants.ts - Main global definition
|
│ │ │ └─ Constants.ts - Main global definition
|
||||||
│ │ │ └─ Menus.ts - Main global menu definition
|
│ │ │ └─ Menus.ts - Main global menu definition
|
||||||
│ │ └─ index.ts - Main process entry point
|
│ │ └─ index.ts - Main process entry point
|
||||||
|
│ │ └─ IPCs.ts - Main process ipc handlers definition
|
||||||
│ │ └─ MainRunner.ts - Main process main window processing
|
│ │ └─ MainRunner.ts - Main process main window processing
|
||||||
│ ├─ preload/ - Preload (Electron-Vue communication bridge) process source code
|
│ ├─ preload/ - Preload (Electron-Vue communication bridge) process source code
|
||||||
│ │ └─ index.ts
|
│ │ └─ index.ts
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { BrowserWindow, ipcMain } from 'electron'
|
||||||
|
import Constants from './utils/Constants'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IPC Communications
|
||||||
|
* */
|
||||||
|
export default class IPCs {
|
||||||
|
static initialize(window: BrowserWindow) {
|
||||||
|
// Get application version
|
||||||
|
ipcMain.on('msgRequestGetVersion', () => {
|
||||||
|
window.webContents.send('msgReceivedVersion', Constants.APP_VERSION)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { app, BrowserWindow, RenderProcessGoneDetails } from 'electron'
|
import { app, BrowserWindow, RenderProcessGoneDetails } from 'electron'
|
||||||
import Constants from './utils/Constants'
|
import Constants from './utils/Constants'
|
||||||
import * as electronRemote from '@electron/remote/main'
|
import * as electronRemote from '@electron/remote/main'
|
||||||
|
import IPCs from './IPCs'
|
||||||
|
|
||||||
const exitApp = (mainWindow: BrowserWindow): void => {
|
const exitApp = (mainWindow: BrowserWindow): void => {
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
@@ -48,6 +49,9 @@ export const createMainWindow = async (mainWindow: BrowserWindow): Promise<Brows
|
|||||||
await mainWindow.loadFile(Constants.APP_INDEX_URL_PROD)
|
await mainWindow.loadFile(Constants.APP_INDEX_URL_PROD)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize IPC Communication
|
||||||
|
IPCs.initialize(mainWindow)
|
||||||
|
|
||||||
return mainWindow
|
return mainWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
|
import { name, version } from '../../../package.json'
|
||||||
|
|
||||||
export default class Constants {
|
export default class Constants {
|
||||||
static APP_NAME = 'Vutron'
|
// Display app name (uppercase first letter)
|
||||||
|
static APP_NAME = name.charAt(0).toUpperCase() + name.slice(1)
|
||||||
|
|
||||||
|
static APP_VERSION = version
|
||||||
|
|
||||||
static IS_DEV_ENV = process.env.NODE_ENV === 'development'
|
static IS_DEV_ENV = process.env.NODE_ENV === 'development'
|
||||||
|
|
||||||
static IS_MAC = process.platform === 'darwin'
|
static IS_MAC = process.platform === 'darwin'
|
||||||
|
|
||||||
static DEFAULT_WEB_PREFERENCES = {
|
static DEFAULT_WEB_PREFERENCES = {
|
||||||
nodeIntegration: true,
|
nodeIntegration: false,
|
||||||
contextIsolation: false,
|
contextIsolation: true,
|
||||||
nodeIntegrationInWorker: true,
|
enableRemoteModule: false,
|
||||||
preload: join(__dirname, '../preload/index.js')
|
preload: join(__dirname, '../preload/index.js')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-4
@@ -1,5 +1,19 @@
|
|||||||
const main = (): void => {
|
import { contextBridge, ipcRenderer, shell } from 'electron'
|
||||||
console.log('[Preload] Script loaded.')
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
// Whitelist of valid channels used for IPC communication (Send message from Renderer to Main)
|
||||||
|
const mainAvailChannels = ['msgRequestGetVersion']
|
||||||
|
const rendererAvailChannels = ['msgReceivedVersion']
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld('mainApi', {
|
||||||
|
openExternal: async (url) => await shell.openExternal(url),
|
||||||
|
send: (channel, data) => {
|
||||||
|
if (mainAvailChannels.includes(channel)) {
|
||||||
|
ipcRenderer.send(channel, data)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
receive: (channel, cbFunc) => {
|
||||||
|
if (rendererAvailChannels.includes(channel)) {
|
||||||
|
ipcRenderer.on(channel, (event, ...args) => cbFunc(...args))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -6,6 +6,14 @@ import router from '@/renderer/router'
|
|||||||
import vuetify from '@/renderer/plugins/vuetify'
|
import vuetify from '@/renderer/plugins/vuetify'
|
||||||
import i18n from '@/renderer/plugins/i18n'
|
import i18n from '@/renderer/plugins/i18n'
|
||||||
|
|
||||||
|
// Add API key defined in contextBridge to window object type
|
||||||
|
declare global {
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
interface Window {
|
||||||
|
mainApi?: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
app.use(vuetify).use(i18n).use(router).use(createPinia())
|
app.use(vuetify).use(i18n).use(router).use(createPinia())
|
||||||
|
|||||||
@@ -11,9 +11,16 @@ const { counterIncrease } = useTempStore()
|
|||||||
const { counter } = storeToRefs(useTempStore())
|
const { counter } = storeToRefs(useTempStore())
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const languages = ref(['en'])
|
const languages = ref(['en'])
|
||||||
|
const appVersion = ref('Unknown')
|
||||||
|
|
||||||
onMounted((): void => {
|
onMounted((): void => {
|
||||||
languages.value = availableLocales
|
languages.value = availableLocales
|
||||||
|
|
||||||
|
// Get application version from package.json version string (Using IPC communication)
|
||||||
|
window.mainApi.receive('msgReceivedVersion', (version: string) => {
|
||||||
|
appVersion.value = version
|
||||||
|
})
|
||||||
|
window.mainApi.send('msgRequestGetVersion')
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleChangeTheme = (): void => {
|
const handleChangeTheme = (): void => {
|
||||||
@@ -51,6 +58,9 @@ const handleCountIncrease = (): void => {
|
|||||||
<v-col cols="12" md="7">
|
<v-col cols="12" md="7">
|
||||||
<h2 class="my-4">{{ $t('desc.welcome-title') }}</h2>
|
<h2 class="my-4">{{ $t('desc.welcome-title') }}</h2>
|
||||||
<p>{{ $t('desc.welcome-desc') }}</p>
|
<p>{{ $t('desc.welcome-desc') }}</p>
|
||||||
|
<p class="my-4"
|
||||||
|
>App Version: <strong>{{ appVersion }}</strong></p
|
||||||
|
>
|
||||||
<v-row class="my-4">
|
<v-row class="my-4">
|
||||||
<v-col cols="3">
|
<v-col cols="3">
|
||||||
<v-btn icon color="primary" @click="handleChangeTheme">
|
<v-btn icon color="primary" @click="handleChangeTheme">
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import { shell } from 'electron'
|
|
||||||
|
|
||||||
export default class Utils {
|
export default class Utils {
|
||||||
static getCurrentLocale(): string {
|
static getCurrentLocale(): string {
|
||||||
return navigator?.language?.split('-')[0] || 'en'
|
return navigator?.language?.split('-')[0] || 'en'
|
||||||
}
|
}
|
||||||
|
|
||||||
static async openExternal(url: string): Promise<void> {
|
static async openExternal(url: string): Promise<void> {
|
||||||
await shell.openExternal(url)
|
await window.mainApi.openExternal(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
rendererPlugin({
|
rendererPlugin({
|
||||||
nodeIntegration: true,
|
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
include: ['path']
|
include: ['path']
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user