Electron调用nodejs的cpp .node扩展【安全】

Electron调用nodejs的cpp .node扩展【安全】

环境:

复制代码
electron: 30.1.1
nodejs: 20.14.0

前言

Electron是一个非常流行的跨平台桌面应用框架,它允许开发者使用Web技术来创建原生应用。然而,当应用需要进行高性能计算或访问系统API时,Web技术可能会成为性能瓶颈。这时,开发者可以选择使用C++来开发底层库,并在Electron中调用这些库,以实现高性能的功能。

在前面的文章中,我们使用禁用 contextIsolation 和启用 nodeIntegration的方式来调用C++扩展,这样会降低应用的安全性。

安全的方式为隔离上下文(contextIsolation: true),通过 ipcMain通信使用主线程处理,contextBridge.exposeInMainWorld开放API接口。这种方式推荐在生产环境使用。

代码

复制代码
$ tree
.
+--- build
|   +--- Release
|   |   +--- addon.node
+--- addon.cpp
+--- binding.gyp
+--- CMakeLists.txt
+--- index.html
+--- index.js
+--- package.json
+--- preload.js
+--- renderer.js

index.html

复制代码
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Hello Electron</title>
  <meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline';">
</head>

<body>
  <p id="version"></p>
  <p id="napi"></p>

  <script src="renderer.js"></script>
</body>

</html>

index.js

复制代码
const { app, BrowserWindow,ipcMain } = require('electron/main');
const path = require('path');
const addon = require(path.join(__dirname, '/build/Release/addon.node'));

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      // nodeIntegration: true, // not safe
      // contextIsolation: false // not safe
      preload: path.join(__dirname, 'preload.js'), // preload script must absolute path
      contextIsolation: true,
      enableRemoteModule: false
    }
  })

  win.loadFile('index.html');
}

app.whenReady().then(() => {
    createWindow();
})

ipcMain.handle('ipcAddon', async () => {
  return addon.hello();
})

preload.js

复制代码
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
    getVersion: () => { 
       return `electron: ${process.versions.electron}, nodejs: ${process.versions.node}, chrome: ${process.versions.chrome}, v8: ${process.versions.v8}`; 
    },
    getHello: async () => {
        return await ipcRenderer.invoke('ipcAddon');
    }
});

renderer.js

复制代码
window.addEventListener('DOMContentLoaded', async () => {
    let info = window.electronAPI.getVersion();
    document.getElementById("version").innerHTML = info;
    console.log(info);

    info = await window.electronAPI.getHello();
    document.getElementById("napi").innerHTML = info;
    console.log(info);
});

addon.cpp

复制代码
#include <node_api.h>

static napi_value helloMethod(napi_env env, napi_callback_info info)
{
    napi_value result;
    napi_create_string_utf8(env, "hello world from napi", NAPI_AUTO_LENGTH, &result);

    return result;
}

static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc = {"hello", 0, helloMethod, 0, 0, 0, napi_default, 0};

    napi_define_properties(env, exports, 1, &desc);

    return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

binding.gyp

复制代码
{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon.cpp" ]
    }
  ]
}

CMakeLists.txt

复制代码
cmake_minimum_required(VERSION 2.8.12)

project(addon)

message(STATUS "operation system is ${CMAKE_SYSTEM}")

add_definitions(-std=c++11)

include_directories(${CMAKE_JS_INC})
include_directories(.)

file(GLOB SOURCE_FILES addon.cpp)

add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC})

set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")

target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})

package.json

复制代码
{
  "name": "my-electron-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "electron ."
  }
}

编译

复制代码
node-gyp configure build

结果

复制代码
electron: 30.1.1, nodejs: 20.14.0, chrome: 124.0.6367.243, v8: 12.4.254.20-electron.0

hello world from napi

License

License under CC BY-NC-ND 4.0: 署名-非商业使用-禁止演绎


Reference:

NULL

相关推荐
编程猪猪侠1 天前
解决yarn install 报错 error \node_modules\electron: Command failed.
前端·javascript·electron
zooooooooy2 天前
Electron打包ARM环境deb包
后端·electron
red润3 天前
浏览器离屏渲染 vs. Electron离屏渲染——核心区别与应用场景
前端·electron·canvas
OpenIM4 天前
Electron Demo 的快速编译与启动
前端·javascript·electron
柚子a4 天前
Electron主进程渲染进程间通信的方式
electron
柚子a4 天前
electron使用remote报错
electron
DevUI团队5 天前
Electron 入门学习指南:快速搭建跨平台桌面应用
前端·javascript·electron
RedHood5 天前
鸿蒙投屏实现
electron·harmonyos
黑金IT6 天前
如何在 Electron 应用中安全地进行主进程与渲染器进程通信
服务器·安全·electron
培根芝士6 天前
Electron打包支持多语言
前端·javascript·electron