# Security

# Node Integration

As of v2.0 of VCPEB, Electron nodeIntegration is disabled by default. This blocks all node APIs such as require. This reduces security risks (opens new window), and is a recommended best practice by the Electron team. If you need to use native modules such as fs or sqlite in the renderer process, you can enable nodeIntegration in vue.config.js:

module.exports = {
  pluginOptions: {
    electronBuilder: {
      nodeIntegration: true
    }
  }
}

IPC Without Node Integration

You can still use IPC (opens new window) without nodeIntegration. Just create a preload script with the following code:

import { ipcRenderer } from 'electron'
window.ipcRenderer = ipcRenderer

Now, you can access ipcRenderer with window.ipcRenderer in your Vue app.

If you want to use IPC without nodeIntegration and with contextIsolation, use this:

import { contextBridge, ipcRenderer } from 'electron'

// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld('ipcRenderer', {
  send: (channel, data) => {
    // whitelist channels
    let validChannels = ['toMain']
    if (validChannels.includes(channel)) {
      ipcRenderer.send(channel, data)
    }
  },
  receive: (channel, func) => {
    let validChannels = ['fromMain']
    if (validChannels.includes(channel)) {
      // Deliberately strip event as it includes `sender`
      ipcRenderer.on(channel, (event, ...args) => func(...args))
    }
  }
})

Then, you can use window.ipcRenderer.(send/receive) in the renderer process.

(Solution from this StackOverflow answer (opens new window))

# Loading Local Images/Resources

If WebSecurity is enabled, you won't be able to load resources from the file system, ie <img src="file:///path/to/some/image.png"/>. However, you will still be able to load images and other resources from the public folder, see handling static assets. If you need to load resources from outside of the public folder you will have to disable WebSecurity or use a custom protocol. Disabling WebSecurity is strongly discouraged (opens new window), so you should instead use the following technique to load local resources and keep WebSecurity enabled.

Add the following to your main process file (background.(js|ts) by default):

app.on('ready', () => {
  registerLocalResourceProtocol()
  ...
})

function registerLocalResourceProtocol() {
  protocol.registerFileProtocol('local-resource', (request, callback) => {
    const url = request.url.replace(/^local-resource:\/\//, '')
    // Decode URL to prevent errors when loading filenames with UTF-8 chars or chars like "#"
    const decodedUrl = decodeURI(url) // Needed in case URL contains spaces
    try {
      return callback(decodedUrl)
    }
    catch (error) {
      console.error('ERROR: registerLocalResourceProtocol: Could not get file path:', error)
    }
  })
}

Then, simply prefix local image urls with local-resource://, ie <img src="local-resource://image.png"/>