增加WebPack混淆并打包
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
node_modules
|
||||||
33
README.md
33
README.md
@@ -105,9 +105,40 @@ Survey 数据:
|
|||||||
- `farmeworkapi/server.log` 常规日志;`farmeworkapi/admin.log` 管理员操作日志
|
- `farmeworkapi/server.log` 常规日志;`farmeworkapi/admin.log` 管理员操作日志
|
||||||
- dsxapi 独立运行时在控制台输出重要提示与告警
|
- dsxapi 独立运行时在控制台输出重要提示与告警
|
||||||
|
|
||||||
## Docker 与挂载建议
|
## Docker 与挂载
|
||||||
- 挂载 `farmeworkapi/license/` 以便导入许可证
|
- 挂载 `farmeworkapi/license/` 以便导入许可证
|
||||||
- 挂载 `farmeworkapi/network` 供网络配置接口读写
|
- 挂载 `farmeworkapi/network` 供网络配置接口读写
|
||||||
- 挂载 `/hardware_serial` 到容器内,提供硬件序列号以完成许可证绑定
|
- 挂载 `/hardware_serial` 到容器内,提供硬件序列号以完成许可证绑定
|
||||||
- 可选择将 `dsxapi/competition_data/` 与 `dsxapi/competition_tmp/` 映射到持久卷
|
- 可选择将 `dsxapi/competition_data/` 与 `dsxapi/competition_tmp/` 映射到持久卷
|
||||||
|
|
||||||
|
## Webpack 打包与混淆
|
||||||
|
本项目已集成基于 Webpack 的 Node 端打包与 JavaScript 混淆,适用于生产环境分发与提高代码可读性门槛。
|
||||||
|
|
||||||
|
### 前置条件
|
||||||
|
- 建议使用 Node.js 18 或 20。
|
||||||
|
- 安装依赖:`npm install`(包含开发依赖用于构建)。
|
||||||
|
|
||||||
|
### 构建与运行
|
||||||
|
- 构建(打包 + 混淆):`npm run build`
|
||||||
|
- 运行打包版本:`npm run start:dist`
|
||||||
|
- 构建产物位置:`dist/`
|
||||||
|
- 入口:`dist/server.js`
|
||||||
|
- 资产:`.env`、`license/`、`network/`、`pub.pem`、`priv.pem`、`license_issuer.html`、`online_data.json`、`dsxapi/connection_maps`、`dsxapi/competition_data`、`dsxapi/competition_tmp`(已自动复制)
|
||||||
|
|
||||||
|
### 依赖说明
|
||||||
|
- 打包时使用了 `webpack-node-externals` 排除了 `node_modules`,因此部署环境仍需安装生产依赖:
|
||||||
|
- 在部署机(或容器)执行:`npm ci --omit=dev`
|
||||||
|
- 或者在项目根目录(含 `node_modules`)内直接运行 `node dist/server.js`
|
||||||
|
|
||||||
|
### 混淆策略
|
||||||
|
- 已启用 `webpack-obfuscator`,默认配置:开启字符串数组与 RC4 编码、数组旋转,关闭控制流扁平化以保证稳定性。
|
||||||
|
|
||||||
|
|
||||||
|
### 路径与持久化
|
||||||
|
- 打包后 `__dirname` 指向 `dist`,已通过复制插件将运行期必需文件复制到 `dist`,保持现有代码路径逻辑可用。
|
||||||
|
- 运行时写入(如 `server.log`、`admin.log`、`competition_tmp`/`competition_data`)默认位于 `dist` 下。生产中建议:
|
||||||
|
- 使用外部挂载或卷持久化这些目录;或
|
||||||
|
- 改为输出到标准输出并配置外部日志采集/轮转。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
20
dist/.env
vendored
Normal file
20
dist/.env
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Database configuration
|
||||||
|
DB_HOST=est_mysql
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_USER=root
|
||||||
|
DB_PASSWORD=MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDQMYcjqnrMnr9G
|
||||||
|
DB_NAME=login
|
||||||
|
|
||||||
|
# SurveyKing_DB_NAME
|
||||||
|
SurveyKing_DB_HOST=est_mysql
|
||||||
|
SurveyKing_DB_PORT=3306
|
||||||
|
SurveyKing_DB_USER=root
|
||||||
|
SurveyKing_DB_PASSWORD=MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDQMYcjqnrMnr9G
|
||||||
|
SurveyKing_DB_NAME=surveyking
|
||||||
|
|
||||||
|
# JWT configuration
|
||||||
|
JWT_SECRET=MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDQMYcjqnrMnr9G
|
||||||
|
|
||||||
|
# Server configuration
|
||||||
|
PORT=3000
|
||||||
|
|
||||||
9
dist/pub.pem
vendored
Normal file
9
dist/pub.pem
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0DGHI6p6zJ6/RvJMWhvZ
|
||||||
|
idxDRhxR9hI83TmBuPoSOJHDnVDN49ZsCDrDo6+pYhgOTZqthbY7aIpkiOZgtONA
|
||||||
|
fjgRi244vePQ6nhG2JKscSzed+EAJACy7psnWzZgqvdOZhc6TXjyZ0cAwZVT8UeC
|
||||||
|
NPXFfKxZ9c5xJTG+3tyQQ/u4WKFFcrp0HRi091a1ROoLhuoyeFEtTYDttUURp+3H
|
||||||
|
PiL1GJVlXjkWzJyVOa/49tAVP3S7B5WEtrG2heWGNfVP4LPVZlO3/jTw98LKH74w
|
||||||
|
VHZNrt2RMmlHAy+EPY3AcsEQRRmzPCOuzMKUFoV+320pbxV2OsUEwfT3wsQPbeHd
|
||||||
|
BwIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
1
dist/server.js
vendored
Normal file
1
dist/server.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -388,6 +388,9 @@ const initialConnectionMap = {
|
|||||||
performancestatus: "workshop-2p-pass-80m"
|
performancestatus: "workshop-2p-pass-80m"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
CopperAnalyzer:{
|
||||||
|
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化连接映射数据
|
// 初始化连接映射数据
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"payload": "eyJtb2RlbCI6IkVTVC0xMDAiLCJ1c2VyIjoi5LiK5rW35pyX5Z2k5L+h5oGv57O757uf5pyJ6ZmQ5YWs5Y+4IiwiaGFyZHdhcmVfaWQiOiJBQjAwNFoyNzIwMDM0MCIsInNlcmlhbCI6IlNOLUtGWVVUSkE0LTI5MjUyMiIsImFjdGl2YXRpb25fY29kZSI6IkFDVC1aQ0I0VFQtUDlTNyIsImFjdGl2YXRlZF9hdCI6IjIwMjUtMTAtMTZUMDE6MTU6MDguOTM1WiIsImV4cGlyZXNfYXQiOiIyMDI2LTEwLTE2VDAxOjE1OjA4LjkzNVoiLCJnb2xkX3NlcnZpY2VfZXhwaXJlc19hdCI6IjIwMjYtMTAtMTZUMDE6MTU6MDguOTM1WiIsImlzc3VlZF9hdCI6IjIwMjUtMTAtMTZUMDE6MTU6MDguOTM1WiIsImlzc3VlciI6IuS4iua1t+acl+WdpOS/oeaBr+ezu+e7n+aciemZkOWFrOWPuCJ9",
|
|
||||||
"signature": "aLSKrijna6j8Oe00Ol0OhhBv9QAhBZyJCJC11RcwsvNeGgFlmAwo+OOW2SupT/w4DZMe3NXubbBDjAgZYyT27TvjEn/WiOga3PgnbcrB65MNNEH+UaXWf0R4sfI0k7R4j+LeK4MktHv6DPyv+bumzVGxEgHCN9xl6UWRJ8qcjEbUvG9mCGofDPOoXZzuPes+cDFF3yIR3lWiZl+8uHq79biyET3fZMUT72TEQf9NqJCEUudRKgagmkDSboeoWdB+0wHaVthoZpzhdW1kn5YByI+Fy/2F2xWFra/1LKJUkcsKdzVtGGXEs+2V1CIlONod+Cb4r4zbctqZFqbvvUK2EA=="
|
|
||||||
}
|
|
||||||
4
farmeworkapi/license/SN-C8494BU2-466101.lic
Normal file
4
farmeworkapi/license/SN-C8494BU2-466101.lic
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"payload": "eyJtb2RlbCI6IkVTVC0xMDAiLCJ1c2VyIjoi5LiK5rW35pyX5Z2k5L+h5oGv57O757uf5pyJ6ZmQ5YWs5Y+4IiwiaGFyZHdhcmVfaWQiOiJodXNreSIsInNlcmlhbCI6IlNOLUM4NDk0QlUyLTQ2NjEwMSIsImFjdGl2YXRpb25fY29kZSI6IkFDVC03NzI3OVItNFVaUCIsImFjdGl2YXRlZF9hdCI6IjIwMjUtMTAtMjJUMDc6MTc6NTYuMTU3WiIsImV4cGlyZXNfYXQiOiIyMjk5LTA4LTA2VDA3OjE3OjU2LjE1N1oiLCJnb2xkX3NlcnZpY2VfZXhwaXJlc19hdCI6IjIwMzAtMTAtMjFUMDc6MTc6NTYuMTU3WiIsImlzc3VlZF9hdCI6IjIwMjUtMTAtMjJUMDc6MTc6NTYuMTU3WiIsImlzc3VlciI6IuS4iua1t+acl+WdpOS/oeaBr+ezu+e7n+aciemZkOWFrOWPuCJ9",
|
||||||
|
"signature": "uZIyeXwdHEX/YmQlgUovGKCzeXHZRPzoHmzGOB/zHcNF6xx9Q3sTFR6Lqyg8x0NKJF3O7R2JsxZ9qemLVcpLdSnSamcxFMxcyNjLHGXkzQKA7hntofdCvzvlVrLZ4Y0cDLqSOmIQ62vtEgvuduqReTMAK7z4qCgmVbinff9njUSUmhnvWAXfGfnpwyfrtfg5oNntQ5iuumlJoGHq75u/x7zYOvmlILTRwt9ZVSV3/PxPF3syOwSVcBFja3NMmhdKmhPrSN2PQ3xa+iPvXr7Y2QRzn1N6AGTUtGWrV1eonk0c4Sr1yVUSzik8YJfC3L0VPCqLXWFDb7Micw2ryRlzag=="
|
||||||
|
}
|
||||||
@@ -1,15 +1,5 @@
|
|||||||
TYPE=Ethernet
|
TYPE=Ethernet
|
||||||
PROXY_METHOD=none
|
|
||||||
BROWSER_ONLY=no
|
|
||||||
BOOTPROTO=dhcp
|
BOOTPROTO=dhcp
|
||||||
DEFROUTE=yes
|
|
||||||
IPV4_FAILURE_FATAL=no
|
|
||||||
IPV6INIT=yes
|
|
||||||
IPV6_AUTOCONF=yes
|
|
||||||
IPV6_DEFROUTE=yes
|
|
||||||
IPV6_FAILURE_FATAL=no
|
|
||||||
IPV6_ADDR_GEN_MODE=stable-privacy
|
|
||||||
NAME=enp3s0
|
|
||||||
UUID=558d7602-4adc-4ed5-be2f-396676602023
|
|
||||||
DEVICE=enp3s0
|
DEVICE=enp3s0
|
||||||
ONBOOT=yes
|
ONBOOT=yes
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
2025-10-21T07:24:48.007Z - 正在验证 License 文件...
|
|
||||||
2025-10-21T07:24:48.012Z - Error connecting to the database: Error: getaddrinfo EAI_AGAIN est_mysql
|
|
||||||
2025-10-21T07:24:48.012Z - Error connecting to the SurveyKing database: Error: getaddrinfo EAI_AGAIN est_mysql
|
|
||||||
2025-10-21T07:24:48.012Z - 验证最新的 License 文件: EST-100.lic
|
|
||||||
2025-10-21T07:24:48.014Z - 成功读取公钥文件 pub.pem
|
|
||||||
2025-10-21T07:24:48.018Z - 读取硬件序列号失败: ENOENT: no such file or directory, open '/hardware_serial'
|
|
||||||
2025-10-21T07:24:48.018Z - 验证 License 文件失败 (EST-100.lic): ENOENT: no such file or directory, open '/hardware_serial'
|
|
||||||
2025-10-21T07:24:48.019Z - License 验证失败: EST-100.lic
|
|
||||||
2025-10-21T07:24:48.019Z - 签名验证失败
|
|
||||||
2025-10-21T07:24:48.019Z - 硬件码不匹配
|
|
||||||
2025-10-21T07:24:48.019Z - 错误信息: ENOENT: no such file or directory, open '/hardware_serial'
|
|
||||||
2025-10-21T07:24:48.019Z - License 验证完成
|
|
||||||
2795
node_modules/.package-lock.json
generated
vendored
2795
node_modules/.package-lock.json
generated
vendored
File diff suppressed because it is too large
Load Diff
2802
package-lock.json
generated
2802
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@@ -6,7 +6,9 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"start": "node app.js",
|
"start": "node app.js",
|
||||||
"dev": "nodemon app.js"
|
"dev": "nodemon app.js",
|
||||||
|
"build": "webpack --config webpack.config.js",
|
||||||
|
"start:dist": "node dist/server.js"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
@@ -25,5 +27,12 @@
|
|||||||
"mysql2": "^3.11.3",
|
"mysql2": "^3.11.3",
|
||||||
"nodemailer": "^6.9.15",
|
"nodemailer": "^6.9.15",
|
||||||
"nodemon": "^3.1.10"
|
"nodemon": "^3.1.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"copy-webpack-plugin": "^12.0.2",
|
||||||
|
"webpack": "^5.94.0",
|
||||||
|
"webpack-cli": "^5.1.4",
|
||||||
|
"webpack-node-externals": "^3.0.0",
|
||||||
|
"webpack-obfuscator": "^3.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
webpack.config.js
Normal file
46
webpack.config.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const NodeExternals = require('webpack-node-externals');
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
const WebpackObfuscator = require('webpack-obfuscator');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
target: 'node',
|
||||||
|
entry: path.resolve(__dirname, 'app.js'),
|
||||||
|
mode: 'production',
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
filename: 'server.js',
|
||||||
|
},
|
||||||
|
// 不打包 node_modules,减少体积并避免原生模块问题
|
||||||
|
externals: [NodeExternals()],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js'],
|
||||||
|
},
|
||||||
|
// 保持 Node 的 __dirname/__filename 语义,指向 dist 目录
|
||||||
|
node: {
|
||||||
|
__dirname: false,
|
||||||
|
__filename: false,
|
||||||
|
},
|
||||||
|
// 这里不使用 source-map,以免暴露过多信息
|
||||||
|
plugins: [
|
||||||
|
// 将运行期需要的资产复制到 dist 根目录,以适配打包后 __dirname 指向 dist
|
||||||
|
new CopyWebpackPlugin({
|
||||||
|
patterns: [
|
||||||
|
{ from: path.resolve(__dirname, 'farmeworkapi/.env'), to: path.resolve(__dirname, 'dist/.env'), toType: 'file', noErrorOnMissing: true },
|
||||||
|
{ from: path.resolve(__dirname, 'farmeworkapi/pub.pem'), to: path.resolve(__dirname, 'dist/pub.pem'), noErrorOnMissing: true },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
// 在打包产物上进行混淆
|
||||||
|
new WebpackObfuscator({
|
||||||
|
compact: true,
|
||||||
|
controlFlowFlattening: false, // 为稳定性,默认关闭;如需更强混淆可开启
|
||||||
|
deadCodeInjection: false,
|
||||||
|
stringArray: true,
|
||||||
|
rotateStringArray: true,
|
||||||
|
stringArrayEncoding: ['rc4'],
|
||||||
|
stringArrayThreshold: 0.75,
|
||||||
|
disableConsoleOutput: false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user