flnxi-Wu/scripts/build-obfuscated.js

165 lines
4.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* 混淆构建脚本
* 在 Next.js 构建后对敏感代码进行混淆
*
* 使用方法:
* 1. npm run build
* 2. node scripts/build-obfuscated.js
*
* 或者使用组合命令:
* npm run build:prod
*/
const fs = require('fs');
const path = require('path');
const { glob } = require('glob');
// 检查是否安装了 javascript-obfuscator
let JavaScriptObfuscator;
try {
JavaScriptObfuscator = require('javascript-obfuscator');
} catch {
console.error('❌ javascript-obfuscator 未安装,生产混淆不能跳过');
console.error(' 请先运行: npm install');
process.exit(1);
}
const { obfuscatorOptions } = require('./obfuscate-config');
// 构建输出目录
const BUILD_DIR = path.join(process.cwd(), '.next');
const STANDALONE_DIR = path.join(BUILD_DIR, 'standalone');
// 需要混淆的文件模式(在构建输出中)
const PATTERNS = [
// 服务端 chunks(包含许可证相关代码)
'server/chunks/*.js',
// API 路由
'server/app/api/license/**/*.js',
// standalone 目录
'standalone/.next/server/chunks/*.js',
'standalone/.next/server/app/api/license/**/*.js',
];
// 排除的文件
const EXCLUDE = [
'**/node_modules/**',
'**/*.map',
];
async function main() {
console.log('🔒 开始代码混淆...\n');
// 检查构建目录是否存在
if (!fs.existsSync(BUILD_DIR)) {
console.error('❌ 构建目录不存在,请先运行 npm run build');
process.exit(1);
}
let totalFiles = 0;
let targetFiles = 0;
let obfuscatedFiles = 0;
const failedFiles = [];
// 查找需要混淆的文件
for (const pattern of PATTERNS) {
const files = await glob(pattern, {
cwd: BUILD_DIR,
ignore: EXCLUDE,
absolute: false,
});
for (const file of files) {
const filePath = path.join(BUILD_DIR, file);
// 跳过不存在的文件
if (!fs.existsSync(filePath)) continue;
totalFiles++;
try {
const code = fs.readFileSync(filePath, 'utf-8');
// 跳过太小的文件(可能是空文件或只有导出)
if (code.length < 100) continue;
targetFiles++;
console.log(` 混淆: ${file}`);
const result = JavaScriptObfuscator.obfuscate(code, {
...obfuscatorOptions,
sourceMap: false, // 生产环境不生成 source map
});
fs.writeFileSync(filePath, result.getObfuscatedCode());
obfuscatedFiles++;
} catch (error) {
failedFiles.push(`${file}: ${error.message}`);
console.warn(` ⚠️ 混淆失败 ${file}: ${error.message}`);
}
}
}
// 同样处理 standalone 目录(如果存在)
if (fs.existsSync(STANDALONE_DIR)) {
for (const pattern of PATTERNS) {
const files = await glob(pattern, {
cwd: STANDALONE_DIR,
ignore: EXCLUDE,
absolute: false,
});
for (const file of files) {
const filePath = path.join(STANDALONE_DIR, file);
if (!fs.existsSync(filePath)) continue;
totalFiles++;
try {
const code = fs.readFileSync(filePath, 'utf-8');
if (code.length < 100) continue;
targetFiles++;
console.log(` 混淆 (standalone): ${file}`);
const result = JavaScriptObfuscator.obfuscate(code, {
...obfuscatorOptions,
sourceMap: false,
});
fs.writeFileSync(filePath, result.getObfuscatedCode());
obfuscatedFiles++;
} catch (error) {
failedFiles.push(`${file}: ${error.message}`);
console.warn(` ⚠️ 混淆失败 ${file}: ${error.message}`);
}
}
}
}
if (targetFiles === 0) {
console.error('\n❌ 没有找到需要混淆的目标文件,生产镜像不能继续出包');
process.exit(1);
}
if (failedFiles.length > 0) {
console.error('\n❌ 混淆失败的目标文件:');
for (const failedFile of failedFiles) {
console.error(` - ${failedFile}`);
}
process.exit(1);
}
console.log(`\n✅ 混淆完成!`);
console.log(` 扫描文件: ${totalFiles}`);
console.log(` 目标文件: ${targetFiles}`);
console.log(` 混淆文件: ${obfuscatedFiles}`);
}
main().catch((error) => {
console.error('❌ 混淆失败:', error);
process.exit(1);
});