发布时间:2020-08-23编辑:佚名阅读(1365)
现在NodeJs开发Server端越来越流行,如果Server部署在自己公司的服务器上,那么可以认为环境是相对安全的,不需要做源码保护。但是如果需要在客户方部署,又不希望自己的源码暴露的时候,这个时候就需要源码保护。一般的源码保护方式就是 js 压缩/混淆之类的操作,增加js代码的不可读性,或者说是增加破解难度。
本文讨论另一种使用字节码编译nodejs代码来保护源码的方式。
NodeJs 使用 google 的 V8 引擎进行编译,具体可以参考https://zhuanlan.zhihu.com/p/28590489,同时,我们利用 bytenode 这个插件来辅助生成字节码文件,具体请参考 https://github.com/OsamaAbbas/bytenode。
项目构成:使用 express 创建一个项目,项目目录如下:
主要文件及说明:
bin/www:程序主入口
routes/:路由 js 文件
services/:核心业务逻辑处理的 js 文件
app.js:NodeJs Server 启动入口。
compile.js:字节码编译 js 的文件,后面会讲到。
其余的文件不重要,也不会被编译成字节码。
核心思路就是将关键的 js 代码编译成字节码,以保护我们的业务处理逻辑或者算法。
1. 安装依赖
npm install bytenode
2. compile.js,主要逻辑就是将项目代码拷贝到 dist 目录中,遍历 dist 下 routes 和 services 等核心 js 文件目录,使用 bytenode 插件将所有的 js 转换成 jsc 字节码文件,然后删除 js 源文件。
var bytenode = require('bytenode'); var fs = require('fs'); var path = require("path"); fs.exists('./dist', exist => { if (exist) { delDir('./dist'); } fs.mkdirSync('./dist'); }) // 拷贝目录到 dist 下 fs.readdir('./', (err, files) => { if (err) { console.error(err); return; } for (var i = 0; i < files.length; i++) { var stat = fs.statSync('./' + files[i]); if (stat.isFile()) { if (files[i].indexOf('compile.js') == -1) { fs.writeFileSync('./dist/' + files[i], fs.readFileSync('./' + files[i])); } } else if (stat.isDirectory() && files[i].indexOf('dist') == -1) { createDocs('./' + files[i], './dist/' + files[i], function () { }) } else { } } compileFile() }) function compileFile() { // 编译 app.js 为字节码 bytenode.compileFile({ filename: './dist/app.js' }); fs.unlinkSync('./dist/app.js'); // 编译 filters/routes/services 目录下的js文件为字节码 compileDir('./dist/filters'); compileDir('./dist/routes'); compileDir('./dist/services'); } function compileDir(dir) { var stat = fs.statSync(dir); if (stat.isFile() && dir.indexOf('.js') != -1) { // 文件,直接转换 bytenode.compileFile({ filename: dir }); fs.unlinkSync(dir); } else if (stat.isDirectory()) { // 目录,列出文件列表,循环处理 var files = fs.readdirSync(dir); for (var i = 0; i < files.length; i++) { var file = dir + '/' + files[i]; compileDir(file); } } else { } } //递归创建目录 同步方法 function mkdirsSync(dirname) { if (fs.existsSync(dirname)) { return true; } else { if (mkdirsSync(path.dirname(dirname))) { console.log("mkdirsSync = " + dirname); fs.mkdirSync(dirname); return true; } } } function _copy(src, dist) { var paths = fs.readdirSync(src) paths.forEach(function (p) { var _src = src + '/' + p; var _dist = dist + '/' + p; var stat = fs.statSync(_src) if (stat.isFile()) {// 判断是文件还是目录 fs.writeFileSync(_dist, fs.readFileSync(_src)); } else if (stat.isDirectory()) { copyDir(_src, _dist)// 当是目录是,递归复制 } }) } /* * 复制目录、子目录,及其中的文件 * @param src {String} 要复制的目录 * @param dist {String} 复制到目标目录 */ function copyDir(src, dist) { var b = fs.existsSync(dist) console.log("dist = " + dist) if (!b) { console.log("mk dist = ", dist) mkdirsSync(dist);//创建目录 } console.log("_copy start") _copy(src, dist); } function createDocs(src, dist, callback) { console.log("createDocs...") copyDir(src, dist); console.log("copyDir finish exec callback") if (callback) { callback(); } } function delDir(path) { let files = []; if (fs.existsSync(path)) { files = fs.readdirSync(path); files.forEach((file, index) => { let curPath = path + "/" + file; if (fs.statSync(curPath).isDirectory()) { delDir(curPath); //递归删除文件夹 } else { fs.unlinkSync(curPath); //删除文件 } }); fs.rmdirSync(path); } }
3. 修改 bin/www 文件,在最开始 引入 bytenode
require('bytenode');var app = require('../app');var debug = require('debug')('esreader-server:server');var http = require('http'); ...
4. 执行指令打包编译。
node compile.js
编译完成之后, dist 下面的所有文件即可作为发布到第三方服务器上的server。
这样做完之后,项目的启动,或者使用诸如 pm2 等工具来管理 server 时,都与之前的固有做法一致,不需要特殊处理。
上一篇:导出Notepad++设置
下一篇:OD查找按钮事件处理函数
0人
0人
0人
0人