const Terser = require('terser'); const fs = require('fs'); async function obfuscate() { let code = fs.readFileSync('workers.js', 'utf8'); // 第一步:将所有中文变量名替换为英文 const replacements = [ // 变量名替换 ['config_JSON', 'cfgData'], ['反代IP', 'proxyIp'], ['启用SOCKS5反代', 'enableSocks5'], ['启用SOCKS5全局反代', 'globalSocks5'], ['我的SOCKS5账号', 'socks5Account'], ['parsedSocks5Address', 'parsedS5Addr'], ['缓存反代IP', 'cachedProxyIp'], ['缓存反代解析数组', 'cachedProxyArr'], ['缓存反代数组索引', 'cachedProxyIdx'], ['启用反代兜底', 'enableFallback'], ['ECH_DOH', 'echDoh'], ['SOCKS5白名单', 'socks5Whitelist'], ['Pages静态页面', 'staticPages'], ['管理员密码', 'adminPass'], ['加密秘钥', 'encKey'], ['userIDMD5', 'uidMd5'], ['uuidRegex', 'uidRegex'], ['envUUID', 'envUid'], ['userID', 'uid'], ['访问IP', 'clientIp'], ['upgradeHeader', 'upHeader'], // 函数名替换 ['整理成数组', 'toArray'], ['MD5MD5', 'hashMd5'], ['解析SOCKS5地址', 'parseSocks5'], ['获取配置', 'getConfig'], ['获取随机IP', 'getRandIp'], ['解析订阅地址', 'parseSub'], ['记录日志', 'logRecord'], ['脱敏', 'maskStr'], ['获取CF用量', 'getCfUsage'], ['检测SOCKS5', 'checkSocks5'], ['处理websocket', 'handleWs'], ['处理TCP出站', 'handleTcp'], ['处理UDP', 'handleUdp'], ['关闭ws连接', 'closeWs'], ['写入ws流', 'writeToWs'], ['是否禁止地址', 'isBlocked'], ['SOCKS5出站', 'socks5Out'], ['HTTP代理出站', 'httpProxyOut'], // 其他变量 ['双层代理', 'twoProxy'], ['地址', 'addr'], ['端口', 'port'], ['主机名', 'hostname'], ['用户名', 'username'], ['密码', 'password'], ['协议', 'protocol'], ['路径', 'path'], ['域名', 'domain'], ['响应', 'response'], ['请求', 'request'], ['链接', 'link'], ['配置', 'config'], ['错误', 'error'], ['成功', 'success'], ['失败', 'failed'], ['开始', 'start'], ['结束', 'end'], ['时间', 'time'], ['日期', 'date'], ['消息', 'message'], ['数据', 'data'], ['结果', 'result'], ['状态', 'status'], ['类型', 'type'], ['长度', 'length'], ['索引', 'index'], ['数组', 'array'], ['对象', 'object'], ['字符串', 'string'], ['数字', 'number'], ['布尔', 'boolean'], ['函数', 'func'], ['方法', 'method'], ['属性', 'prop'], ['参数', 'param'], ['返回', 'ret'], ['继续', 'cont'], ['跳过', 'skip'], ['等待', 'wait'], ['加载', 'load'], ['保存', 'save'], ['删除', 'del'], ['更新', 'update'], ['读取', 'read'], ['写入', 'write'], ['发送', 'send'], ['接收', 'recv'], ['连接', 'connect'], ['断开', 'disconnect'], ['启动', 'launch'], ['停止', 'stop'], ['初始化', 'init'], ['销毁', 'destroy'], ['创建', 'create'], ['获取', 'get'], ['设置', 'set'], ['检查', 'check'], ['验证', 'verify'], ['解析', 'parse'], ['格式化', 'format'], ['转换', 'convert'], ['编码', 'encode'], ['解码', 'decode'], ['加密', 'encrypt'], ['解密', 'decrypt'], ['压缩', 'compress'], ['解压', 'decompress'], ['排序', 'sort'], ['过滤', 'filter'], ['映射', 'map'], ['查找', 'find'], ['替换', 'replace'], ['分割', 'split'], ['合并', 'merge'], ['复制', 'copy'], ['移动', 'move'], ['交换', 'swap'], ['比较', 'compare'], ['计算', 'calc'], ['统计', 'stat'], ['生成', 'gen'], ['随机', 'rand'], ['默认', 'def'], ['自定义', 'custom'], ['系统', 'system'], ['用户', 'user'], ['管理', 'manage'], ['权限', 'permission'], ['角色', 'role'], ['组', 'group'], ['文件', 'file'], ['目录', 'dir'], ['网络', 'network'], ['服务', 'service'], ['客户端', 'client'], ['服务器', 'server'], ['代理', 'proxy'], ['转发', 'forward'], ['重定向', 'redirect'], ['缓存', 'cache'], ['存储', 'storage'], ['数据库', 'database'], ['表', 'table'], ['记录', 'record'], ['字段', 'field'], ['键', 'key'], ['值', 'value'], ['选项', 'option'], ['设定', 'setting'], ['模式', 'mode'], ['版本', 'version'], ['环境', 'env'], ['调试', 'debug'], ['测试', 'test'], ['生产', 'prod'], ['开发', 'dev'], ['正式', 'release'], ['草稿', 'draft'], ['发布', 'publish'], ['订阅', 'subscribe'], ['取消', 'cancel'], ['确认', 'confirm'], ['提交', 'submit'], ['重置', 'reset'], ['刷新', 'refresh'], ['同步', 'sync'], ['异步', 'async'], ['超时', 'timeout'], ['重试', 'retry'], ['限制', 'limit'], ['最大', 'max'], ['最小', 'min'], ['平均', 'avg'], ['总计', 'total'], ['当前', 'current'], ['上一个', 'prev'], ['下一个', 'next'], ['第一个', 'first'], ['最后一个', 'last'], ['全部', 'all'], ['部分', 'part'], ['其他', 'other'], ['未知', 'unknown'], ['空', 'empty'], ['非空', 'notEmpty'], ['有效', 'valid'], ['无效', 'invalid'], ['启用', 'enabled'], ['禁用', 'disabled'], ['是', 'yes'], ['否', 'no'], ['真', 'trueVal'], ['假', 'falseVal'], ['输入', 'input'], ['输出', 'output'], ['来源', 'source'], ['目标', 'target'], ['原始', 'raw'], ['处理后', 'processed'], ['临时', 'temp'], ['永久', 'permanent'], ['公开', 'pub'], ['私有', 'priv'], ['共享', 'shared'], ['独占', 'exclusive'], ['只读', 'readOnly'], ['可写', 'writable'], ['可执行', 'executable'], ['隐藏', 'hidden'], ['显示', 'visible'], ['激活', 'active'], ['不活动', 'inactive'], ['在线', 'online'], ['离线', 'offline'], ['忙碌', 'busy'], ['空闲', 'idle'], ['等待中', 'waiting'], ['运行中', 'running'], ['已完成', 'completed'], ['已取消', 'cancelled'], ['已失败', 'failedStatus'], ['已暂停', 'paused'], ['已恢复', 'resumed'], ['公开模式', 'publicMode'], ['荷兰节点', 'nlNode'], ['香港节点', 'hkNode'], ['联通优选', 'cuOptimal'], ['移动优选', 'cmccOptimal'], ['电信优选', 'ctOptimal'], ['官方优选', 'cfOptimal'], ['请求次数', 'reqCount'], ['流量', 'traffic'], ['位置', 'location'], ['地区', 'region'], ['国家', 'country'], ['城市', 'city'], ['速度', 'speed'], ['延迟', 'latency'], ['节点', 'node'], ['订阅链接', 'subLink'], ['配置文件', 'configFile'], ['日志', 'log'], ['通知', 'notify'], ['告警', 'alert'], ['警告', 'warn'], ['信息', 'info'], ]; // 按长度排序(长的先替换,避免部分匹配问题) replacements.sort((a, b) => b[0].length - a[0].length); for (const [cn, en] of replacements) { // 使用正则匹配完整词,避免部分替换 const regex = new RegExp(cn.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'); code = code.replace(regex, en); } // 第二步:使用 Terser 进行混淆和压缩 const result = await Terser.minify(code, { compress: { dead_code: true, drop_console: false, // 保留 console.log 便于调试 drop_debugger: true, passes: 2, }, mangle: { toplevel: true, reserved: ['fetch', 'Request', 'Response', 'Headers', 'URL', 'WebSocket', 'WebSocketPair', 'crypto', 'atob', 'btoa', 'TextEncoder', 'TextDecoder', 'ReadableStream', 'WritableStream', 'DataView', 'Uint8Array', 'ArrayBuffer', 'JSON', 'Math', 'Date', 'Promise', 'Error', 'console', 'performance', 'globalThis', 'AbortController'], }, format: { comments: false, }, module: true, }); if (result.error) { console.error('Terser error:', result.error); process.exit(1); } // 写入输出文件 fs.writeFileSync('破皮版workers.js', result.code, 'utf8'); const originalSize = Buffer.byteLength(fs.readFileSync('workers.js', 'utf8'), 'utf8'); const outputSize = Buffer.byteLength(result.code, 'utf8'); console.log(`Original size: ${(originalSize / 1024).toFixed(1)} KB`); console.log(`Obfuscated size: ${(outputSize / 1024).toFixed(1)} KB`); console.log(`Compression ratio: ${((1 - outputSize / originalSize) * 100).toFixed(1)}%`); console.log('Done! Output: 破皮版workers.js'); } obfuscate().catch(err => { console.error('Error:', err); process.exit(1); });