這是一個示例,演示如何快速在你的 Electron 項目中啓用字節碼保護,沒有多餘的廢話。
環境
tech | version |
---|---|
electron | 30.0.6 |
webpack | 5.91.0 |
@herberttn/bytenode-webpack-plugin | 2.3.1 |
nodejs | v20.14.0 |
步驟
Webpack 配置
1// 引入依賴
2const { BytenodeWebpackPlugin } = require('@herberttn/bytenode-webpack-plugin');
3// 在生產環境啓用
4const isEnvProduction = process.env.NODE_ENV === 'production';
5...
6plugins: [
7 isEnvProduction && new BytenodeWebpackPlugin({ compileForElectron: true }),
8],
9...
10// main,preload,renderer 需要更改 entry 配置。我使用了 webpack-merge,如果你沒有使用,忽略即可。
11// main
12const mainConfig = merge(commonConfig, {
13 // entry: './src/main/main.ts',
14 entry: {
15 main: './src/main/main.ts',
16 },
17 target: 'electron-main',
18 output: {
19 filename: '[name].js',
20 devtoolModuleFilenameTemplate: '[absolute-resource-path]',
21 },
22 ...
23})
24// preload
25const preloadConfig = merge(commonConfig, {
26 // entry: './src/preload/preload.ts',
27 entry: {
28 preload: './src/preload/preload.ts',
29 },
30 target: 'electron-preload',
31 output: {
32 filename: '[name].js',
33 devtoolModuleFilenameTemplate: '[absolute-resource-path]',
34 },
35});
36// renderer
37const rendererConfig = merge(commonConfig, {
38 entry: {
39 renderer: './src/renderer/renderer.tsx',
40 },
41 target: 'electron-renderer',
42 output: { devtoolModuleFilenameTemplate: '[absolute-resource-path]' },
43 plugins: [
44 new HtmlWebpackPlugin({
45 template: path.resolve(__dirname, './public/index.html'),
46 }),
47 ],
48});
Electron 入口 main.ts/main.js 配置
1 mainWindow = new BrowserWindow({
2 ...
3 webPreferences: {
4 nodeIntegration: true, // 啓用 jsc 支持
5 contextIsolation: false, // false 是啓用 jsc 支持,但是用不了 preload 的 contextBridge
6 preload: path.join(__dirname, './preload.js'), // bytenode 編譯後生成的 js,用於加載 preload.compiled.jsc
7 webSecurity: false,
8 sandbox: false,
9 },
10});
我知道上面的配置,不符合 Electron 的默認安全配置。但是 Electron 的默認安全配置開啓後,你基本上什麼也做不了。
如果你希望使用字節碼,你必須按照以上配置。
preload contextBridge 修復
contextIsolation: false
會導致 contextBridge 無法使用,這又是 Electron 的一個有趣決定之一。
contextBridge 無法使用,那麼你就無法在使用 ipc,當然,你也不需要了。
此時你可以在 renderer 中直接操作 node 的 api,如 fs 等。但是我建議還是通過 preload 中轉一下,凡事留一線,日後好相見。
1- import { contextBridge } from 'electron';
2- import ipcAPI from '_preload/ipc-api';
3import loadAddon from "_preload/load_node_addon";
4import jb from "_preload/nodejieba";
5
6- contextBridge.exposeInMainWorld('ipcAPI', ipcAPI);
7- contextBridge.exposeInMainWorld('myplugin', loadAddon('myplugin'));
8- contextBridge.exposeInMainWorld('jb', jb);
9
10+ window.ipcAPI = ipcAPI;
11+ window.myplugin = loadAddon('myplugin');
12+ window.jb = jb;
完成
通過 webpack.js,main.js,preload.js 中的以上三處配置,你應該可以在你的項目中使用字節碼了。
字節碼仍然不是最終方案,因爲字節碼很容易被反編譯,目前階段它只是增加了初級破解者的一些成本。
有些人使用了在 rust 中編寫本地插件,和字節碼搭配混淆的方案,如果你對代碼有強烈的保密需求,可以參考,並在可維護性和安全性上取捨。