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
|
||||
│ │ │ └─ Menus.ts - Main global menu definition
|
||||
│ │ └─ index.ts - Main process entry point
|
||||
│ │ └─ IPCs.ts - Main process ipc handlers definition
|
||||
│ │ └─ MainRunner.ts - Main process main window processing
|
||||
│ ├─ preload/ - Preload (Electron-Vue communication bridge) process source code
|
||||
│ │ └─ 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 Constants from './utils/Constants'
|
||||
import * as electronRemote from '@electron/remote/main'
|
||||
import IPCs from './IPCs'
|
||||
|
||||
const exitApp = (mainWindow: BrowserWindow): void => {
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
@@ -48,6 +49,9 @@ export const createMainWindow = async (mainWindow: BrowserWindow): Promise<Brows
|
||||
await mainWindow.loadFile(Constants.APP_INDEX_URL_PROD)
|
||||
}
|
||||
|
||||
// Initialize IPC Communication
|
||||
IPCs.initialize(mainWindow)
|
||||
|
||||
return mainWindow
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { join } from 'path'
|
||||
import { name, version } from '../../../package.json'
|
||||
|
||||
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_MAC = process.platform === 'darwin'
|
||||
|
||||
static DEFAULT_WEB_PREFERENCES = {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
nodeIntegrationInWorker: true,
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
enableRemoteModule: false,
|
||||
preload: join(__dirname, '../preload/index.js')
|
||||
}
|
||||
|
||||
|
||||
+18
-4
@@ -1,5 +1,19 @@
|
||||
const main = (): void => {
|
||||
console.log('[Preload] Script loaded.')
|
||||
}
|
||||
import { contextBridge, ipcRenderer, shell } from 'electron'
|
||||
|
||||
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 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)
|
||||
|
||||
app.use(vuetify).use(i18n).use(router).use(createPinia())
|
||||
|
||||
@@ -11,9 +11,16 @@ const { counterIncrease } = useTempStore()
|
||||
const { counter } = storeToRefs(useTempStore())
|
||||
const theme = useTheme()
|
||||
const languages = ref(['en'])
|
||||
const appVersion = ref('Unknown')
|
||||
|
||||
onMounted((): void => {
|
||||
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 => {
|
||||
@@ -51,6 +58,9 @@ const handleCountIncrease = (): void => {
|
||||
<v-col cols="12" md="7">
|
||||
<h2 class="my-4">{{ $t('desc.welcome-title') }}</h2>
|
||||
<p>{{ $t('desc.welcome-desc') }}</p>
|
||||
<p class="my-4"
|
||||
>App Version: <strong>{{ appVersion }}</strong></p
|
||||
>
|
||||
<v-row class="my-4">
|
||||
<v-col cols="3">
|
||||
<v-btn icon color="primary" @click="handleChangeTheme">
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { shell } from 'electron'
|
||||
|
||||
export default class Utils {
|
||||
static getCurrentLocale(): string {
|
||||
return navigator?.language?.split('-')[0] || 'en'
|
||||
}
|
||||
|
||||
static async openExternal(url: string): Promise<void> {
|
||||
await shell.openExternal(url)
|
||||
await window.mainApi.openExternal(url)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,6 @@ export default defineConfig({
|
||||
}
|
||||
]),
|
||||
rendererPlugin({
|
||||
nodeIntegration: true,
|
||||
optimizeDeps: {
|
||||
include: ['path']
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user