mirror of
https://github.com/violettoolssite/CFspider.git
synced 2026-04-05 03:09:01 +08:00
简化加密格式,移除Unicode混淆
This commit is contained in:
121
add_encryption.js
Normal file
121
add_encryption.js
Normal file
@@ -0,0 +1,121 @@
|
||||
const fs = require('fs');
|
||||
|
||||
// 读取翻译后的代码
|
||||
let code = fs.readFileSync('workers_translated.js', 'utf8');
|
||||
|
||||
// ======================== 步骤1: 添加x27cn加密函数 ========================
|
||||
const x27cnFunctions = `
|
||||
const X27CN_KEY='x27cn2026';
|
||||
function x27cnEnc(t,k=X27CN_KEY){if(!t)return'';const kb=new TextEncoder().encode(k),tb=new TextEncoder().encode(t),r=new Uint8Array(tb.length);for(let i=0;i<tb.length;i++){let b=tb[i]^kb[i%kb.length];b=((b<<3)|(b>>5))&0xFF;b=(b+i)&0xFF;r[i]=b}return Array.from(r).map(b=>b.toString(16).padStart(2,'0')).join('')}
|
||||
`;
|
||||
|
||||
// 在import语句后添加加密函数
|
||||
code = code.replace(
|
||||
`import { connect } from "cloudflare:sockets";`,
|
||||
`import { connect } from "cloudflare:sockets";${x27cnFunctions}`
|
||||
);
|
||||
|
||||
// ======================== 步骤2: 修改根路径JSON响应 ========================
|
||||
// 使用更精确的多行匹配
|
||||
code = code.replace(
|
||||
/return new Response\(JSON\.stringify\(\{\s*status:\s*'online',\s*version:\s*'1\.8\.7',\s*colo:\s*colo,\s*host:\s*url\.hostname,\s*uuid:\s*userID,\s*vless:\s*vlessLink,\s*two_proxy:\s*twoProxy\s*\|\|\s*null\s*\},\s*null,\s*2\),\s*\{\s*headers:\s*\{\s*'Content-Type':\s*'application\/json',\s*'Access-Control-Allow-Origin':\s*'\*'\s*\}\s*\}\);/g,
|
||||
`return new Response(JSON.stringify({
|
||||
s: 'ok',
|
||||
v: '1.8.7',
|
||||
c: colo,
|
||||
h: url.hostname,
|
||||
enc: true,
|
||||
d: x27cnEnc(JSON.stringify({u: userID, l: vlessLink, t: twoProxy || null}))
|
||||
}, null, 2), {
|
||||
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }
|
||||
});`
|
||||
);
|
||||
|
||||
// ======================== 步骤3: 检查是否成功 ========================
|
||||
if (code.includes('enc: true')) {
|
||||
console.log('Root response encrypted successfully!');
|
||||
} else {
|
||||
console.log('WARNING: Root response not encrypted, trying alternative method...');
|
||||
|
||||
// 备用方法:按行替换
|
||||
const lines = code.split('\n');
|
||||
let inRootResponse = false;
|
||||
let braceCount = 0;
|
||||
let startLine = -1;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i].includes("status: 'online'")) {
|
||||
// 往前找到 return new Response
|
||||
for (let j = i - 1; j >= 0 && j > i - 5; j--) {
|
||||
if (lines[j].includes('return new Response(JSON.stringify({')) {
|
||||
startLine = j;
|
||||
inRootResponse = true;
|
||||
braceCount = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inRootResponse && startLine !== -1) {
|
||||
// 计算花括号
|
||||
for (const ch of lines[i]) {
|
||||
if (ch === '{') braceCount++;
|
||||
if (ch === '}') braceCount--;
|
||||
}
|
||||
|
||||
if (braceCount === 0 && lines[i].includes('});')) {
|
||||
// 找到结束位置,替换整个响应块
|
||||
const newResponse = ` return new Response(JSON.stringify({
|
||||
s: 'ok',
|
||||
v: '1.8.7',
|
||||
c: colo,
|
||||
h: url.hostname,
|
||||
enc: true,
|
||||
d: x27cnEnc(JSON.stringify({u: userID, l: vlessLink, t: twoProxy || null}))
|
||||
}, null, 2), {
|
||||
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }
|
||||
});`;
|
||||
|
||||
// 删除原有行
|
||||
lines.splice(startLine, i - startLine + 1, newResponse);
|
||||
console.log('Replaced using alternative method!');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code = lines.join('\n');
|
||||
}
|
||||
|
||||
// ======================== 步骤4: 加密api/uuid和api/config中的uuid ========================
|
||||
// 替换 configResponse.uuid = userID;
|
||||
code = code.replace(
|
||||
/configResponse\.uuid\s*=\s*userID;/g,
|
||||
`configResponse.d = x27cnEnc(userID);`
|
||||
);
|
||||
|
||||
// ======================== 步骤5: 修改LINK生成(config中的vless链接) ========================
|
||||
code = code.replace(
|
||||
/config_JSON\.LINK\s*=\s*`\$\{config_JSON\.protocolType\}/g,
|
||||
`config_JSON.LINK = x27cnEnc(\`\${config_JSON.protocolType}`
|
||||
);
|
||||
|
||||
// 添加结尾括号
|
||||
code = code.replace(
|
||||
/\$\{config_JSON\.skipCertVerify\s*\?\s*"&insecure=1&allowInsecure=1"\s*:\s*""\}#\$\{encodeURIComponent\(config_JSON\.subGenerator\.SUBNAME\)\}`;/g,
|
||||
`\${config_JSON.skipCertVerify ? "&insecure=1&allowInsecure=1" : ""}#\${encodeURIComponent(config_JSON.subGenerator.SUBNAME)}\`);`
|
||||
);
|
||||
|
||||
// ======================== 步骤6: 保存 ========================
|
||||
fs.writeFileSync('workers_encrypted.js', code, 'utf8');
|
||||
console.log('Saved to workers_encrypted.js');
|
||||
|
||||
// 验证
|
||||
if (code.includes('x27cnEnc')) {
|
||||
console.log('✓ x27cnEnc function present');
|
||||
}
|
||||
if (code.includes('enc: true')) {
|
||||
console.log('✓ Root response encrypted');
|
||||
} else {
|
||||
console.log('✗ Root response NOT encrypted - manual check needed');
|
||||
}
|
||||
224
build_encrypted.js
Normal file
224
build_encrypted.js
Normal file
@@ -0,0 +1,224 @@
|
||||
const fs = require('fs');
|
||||
|
||||
// 读取原始文件
|
||||
let code = fs.readFileSync('workers.js', 'utf8');
|
||||
|
||||
// ======================== 步骤1: 添加x27cn加密函数 ========================
|
||||
const x27cnFunctions = `
|
||||
// x27cn encryption
|
||||
const X27CN_KEY = 'x27cn2026';
|
||||
function x27cnEnc(t, k = X27CN_KEY) {
|
||||
if (!t) return '';
|
||||
const kb = new TextEncoder().encode(k);
|
||||
const tb = new TextEncoder().encode(t);
|
||||
const r = new Uint8Array(tb.length);
|
||||
for (let i = 0; i < tb.length; i++) {
|
||||
let b = tb[i] ^ kb[i % kb.length];
|
||||
b = ((b << 3) | (b >> 5)) & 0xFF;
|
||||
b = (b + i) & 0xFF;
|
||||
r[i] = b;
|
||||
}
|
||||
return Array.from(r).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
`;
|
||||
|
||||
// 在import语句后添加加密函数
|
||||
code = code.replace(
|
||||
`import { connect } from "cloudflare:sockets";`,
|
||||
`import { connect } from "cloudflare:sockets";${x27cnFunctions}`
|
||||
);
|
||||
|
||||
// ======================== 步骤2: 修改根路径JSON响应 ========================
|
||||
// 找到返回vless链接的地方,加密敏感信息
|
||||
code = code.replace(
|
||||
/return new Response\(JSON\.stringify\(\{\s*status: 'online',\s*version: '1\.8\.7',\s*colo: colo,\s*host: url\.hostname,\s*uuid: userID,\s*vless: vlessLink,\s*two_proxy: twoProxy \|\| null\s*\}, null, 2\)/g,
|
||||
`return new Response(JSON.stringify({
|
||||
status: 'online',
|
||||
version: '1.8.7',
|
||||
colo: colo,
|
||||
host: url.hostname,
|
||||
encrypted: true,
|
||||
data: x27cnEnc(JSON.stringify({uuid: userID, vless: vlessLink, two_proxy: twoProxy || null})),
|
||||
decrypt_url: 'https://gist.github.com/x27cn/decrypt'
|
||||
}, null, 2)`
|
||||
);
|
||||
|
||||
// ======================== 步骤3: 修改api/config响应 ========================
|
||||
// 加密uuid和vless_path
|
||||
code = code.replace(
|
||||
/configResponse\.uuid = userID;/g,
|
||||
`configResponse.data = x27cnEnc(userID);`
|
||||
);
|
||||
|
||||
code = code.replace(
|
||||
/configResponse\.vless_path = twoProxy/g,
|
||||
`configResponse.path_data = x27cnEnc(twoProxy`
|
||||
);
|
||||
|
||||
// ======================== 步骤4: 删除中文注释 ========================
|
||||
code = code.split('\n').map(line => {
|
||||
if (/^\s*\/\/.*[\u4e00-\u9fff]/.test(line)) return '';
|
||||
if (/\/\/.*[\u4e00-\u9fff]/.test(line)) {
|
||||
return line.replace(/\/\/.*[\u4e00-\u9fff].*$/, '');
|
||||
}
|
||||
return line;
|
||||
}).join('\n');
|
||||
|
||||
// 删除多行注释
|
||||
code = code.replace(/\/\*[\s\S]*?[\u4e00-\u9fff][\s\S]*?\*\//g, '');
|
||||
|
||||
// ======================== 步骤5: 翻译中文变量名 ========================
|
||||
const translations = {
|
||||
// 敏感变量名和字符串替换
|
||||
'cfspiderPath': 'apiPath',
|
||||
'cfspider-public-00000000-0000': 'pub-node-00000000-0000',
|
||||
'x-cfspider-header-': 'x-custom-header-',
|
||||
'X-CFspider-Version': 'X-Worker-Version',
|
||||
'X-CFspider-TwoProxy': 'X-Two-Proxy',
|
||||
'CFspider/1.8.3': 'Mozilla/5.0',
|
||||
'cfspider.get': 'client.get',
|
||||
'CFspider-': 'Node-',
|
||||
'#CFspider': '#Node',
|
||||
|
||||
// 变量名翻译
|
||||
'反代IP': 'proxyIP',
|
||||
'启用SOCKS5反代': 'enableSOCKS5Proxy',
|
||||
'启用SOCKS5全局反代': 'enableGlobalSOCKS5',
|
||||
'我的SOCKS5账号': 'mySOCKS5Account',
|
||||
'缓存反代IP': 'cachedProxyIP',
|
||||
'缓存反代解析数组': 'cachedProxyArray',
|
||||
'缓存反代数组索引': 'cachedProxyIndex',
|
||||
'启用反代兜底': 'enableProxyFallback',
|
||||
'SOCKS5白名单': 'socks5Whitelist',
|
||||
'Pages静态页面': 'pagesStaticUrl',
|
||||
'管理员密码': 'adminPassword',
|
||||
'加密秘钥': 'encryptKey',
|
||||
'访问IP': 'clientIP',
|
||||
'整理成数组': 'parseToArray',
|
||||
'优选订阅生成': 'subGenerator',
|
||||
'本地IP库': 'localIPPool',
|
||||
'随机数量': 'randomCount',
|
||||
'指定端口': 'specifiedPort',
|
||||
'随机IP': 'randomIP',
|
||||
'订阅转换配置': 'subConverterConfig',
|
||||
'反代': 'reverseProxy',
|
||||
'全局': 'globalMode',
|
||||
'账号': 'account',
|
||||
'白名单': 'whitelist',
|
||||
'传输协议': 'transport',
|
||||
'跳过证书验证': 'skipCertVerify',
|
||||
'启用0RTT': 'enable0RTT',
|
||||
'TLS分片': 'tlsFragment',
|
||||
'随机路径': 'randomPath',
|
||||
'本地': 'local',
|
||||
'协议类型': 'protocolType',
|
||||
'区分大小写访问': 'caseSensitivePath',
|
||||
'输入密码': 'inputPassword',
|
||||
'日志内容': 'logContent',
|
||||
'待验证优选': 'pendingOptimal',
|
||||
'请求优选': 'requestOptimal',
|
||||
'完整优选': 'fullOptimal',
|
||||
'其他节点': 'otherNodes',
|
||||
'节点': 'node',
|
||||
'内容': 'content',
|
||||
'优选': 'optimal',
|
||||
'保存自定义': 'saveCustom',
|
||||
'生成': 'gen',
|
||||
'订阅': 'sub',
|
||||
'地址备注分离': 'addrRemarkSplit',
|
||||
'订阅行列表': 'subLineList',
|
||||
'行内容': 'lineContent',
|
||||
'地址匹配': 'addrMatch',
|
||||
'地址端口': 'addrPort',
|
||||
'备注': 'remark',
|
||||
'原始地址': 'origAddr',
|
||||
'节点地址': 'nodeAddr',
|
||||
'节点端口': 'nodePort',
|
||||
'节点备注': 'nodeRemark',
|
||||
'订阅转换': 'subConvert',
|
||||
'订阅配置文件热补丁': 'subConfigHotfix',
|
||||
'批量替换': 'batchReplace',
|
||||
'获取': 'get',
|
||||
'处理': 'handle',
|
||||
'请求': 'request',
|
||||
'伪装页': 'fakePage',
|
||||
'新请求头': 'newHeaders',
|
||||
'响应内容': 'respContent',
|
||||
'响应': 'resp',
|
||||
'目标': 'target',
|
||||
'所有': 'all',
|
||||
'数组': 'arr',
|
||||
'兜底': 'fallback',
|
||||
'地址': 'addr',
|
||||
'端口': 'port',
|
||||
'索引': 'idx',
|
||||
'错误': 'err',
|
||||
'代理': 'proxy',
|
||||
'验证': 'verify',
|
||||
'原始': 'raw',
|
||||
'启用': 'enable',
|
||||
'当前': 'curr',
|
||||
'日志数组': 'logArr',
|
||||
'编码器': 'encoder',
|
||||
'第一次哈希': 'hash1',
|
||||
'第二次哈希': 'hash2',
|
||||
'常用': 'common',
|
||||
'目录': 'dir',
|
||||
'随机数': 'randNum',
|
||||
'字符集': 'charset',
|
||||
'重置配置': 'resetCfg',
|
||||
'初始化': 'init',
|
||||
'加载': 'load',
|
||||
'官方优选': 'officialOptimal',
|
||||
'默认端口': 'defPort',
|
||||
'超时': 'timeout',
|
||||
'国家': 'country',
|
||||
'城市': 'city',
|
||||
'解析': 'parse',
|
||||
'总计': 'totalCnt',
|
||||
'查询': 'query',
|
||||
'记录': 'record',
|
||||
'代理协议': 'proxyProto',
|
||||
'格式化': 'format',
|
||||
'随机字符串': 'randStr',
|
||||
'访问': 'visit',
|
||||
'失败': 'failed',
|
||||
'荷兰节点': 'nlNode',
|
||||
'香港节点': 'hkNode',
|
||||
'未知IP': 'unknownIP',
|
||||
'双层代理': 'twoProxy',
|
||||
'下载速度': 'dlSpeed',
|
||||
'数据中心': 'dataCenter',
|
||||
'延迟': 'latency',
|
||||
'移动优选': 'CMCCOptimal',
|
||||
'联通优选': 'CUOptimal',
|
||||
'电信优选': 'CTOptimal',
|
||||
'CF优选': 'CFOptimal',
|
||||
'的': '',
|
||||
'了': '',
|
||||
'个': ''
|
||||
};
|
||||
|
||||
// 按长度排序
|
||||
const sortedKeys = Object.keys(translations).sort((a, b) => b.length - a.length);
|
||||
for (const cn of sortedKeys) {
|
||||
code = code.split(cn).join(translations[cn]);
|
||||
}
|
||||
|
||||
// 删除空行
|
||||
code = code.replace(/\n{3,}/g, '\n\n');
|
||||
|
||||
// 保存翻译后的代码
|
||||
fs.writeFileSync('workers_encrypted.js', code, 'utf8');
|
||||
console.log('Step 1: Translation complete!');
|
||||
|
||||
// 检查剩余中文
|
||||
const remaining = code.match(/[\u4e00-\u9fff]+/g);
|
||||
if (remaining) {
|
||||
const unique = [...new Set(remaining)];
|
||||
console.log(`Remaining Chinese: ${unique.length}`);
|
||||
unique.slice(0, 10).forEach(c => console.log(' ' + c));
|
||||
} else {
|
||||
console.log('No Chinese characters!');
|
||||
}
|
||||
|
||||
97
deep_obfuscate.js
Normal file
97
deep_obfuscate.js
Normal file
@@ -0,0 +1,97 @@
|
||||
const fs = require('fs');
|
||||
|
||||
// 读取翻译后但未混淆的代码
|
||||
let code = fs.readFileSync('workers_translated.js', 'utf8');
|
||||
|
||||
// 创建一个函数来生成base64解码表达式
|
||||
function b64(str) {
|
||||
return `atob("${Buffer.from(str).toString('base64')}")`;
|
||||
}
|
||||
|
||||
// 敏感字符串替换映射 - 在代码混淆前替换
|
||||
const sensitiveReplacements = {
|
||||
// 动态拼接的字符串
|
||||
"'.proxyip.cmliussss.net'": `(${b64('.proxyip.cmliussss.net')})`,
|
||||
'".proxyip.cmliussss.net"': `(${b64('.proxyip.cmliussss.net')})`,
|
||||
"'.proxyip.'": `(${b64('.proxyip.')})`,
|
||||
'".proxyip."': `(${b64('.proxyip.')})`,
|
||||
"'doh.cmliussss.com'": b64('doh.cmliussss.com'),
|
||||
'"doh.cmliussss.com"': b64('doh.cmliussss.com'),
|
||||
'https://doh.cmliussss.com/CMLiussss': '"+atob("aHR0cHM6Ly9kb2guY21saXVzc3NzLmNvbS9DTUxpdXNzc3M=")+"',
|
||||
'useCfspiderGetWithTwoProxy': 'useClientWithTwoProxy',
|
||||
'notSupportedViaProxyAPI': 'notSupportedViaAPI',
|
||||
|
||||
// 协议相关
|
||||
"'vless://'": `(${b64('vless://')})`,
|
||||
'"vless://"': `(${b64('vless://')})`,
|
||||
"'trojan://'": `(${b64('trojan://')})`,
|
||||
'"trojan://"': `(${b64('trojan://')})`,
|
||||
"'vless'": b64('vless'),
|
||||
'"vless"': b64('vless'),
|
||||
"'trojan'": b64('trojan'),
|
||||
'"trojan"': b64('trojan'),
|
||||
|
||||
// 域名相关
|
||||
"'proxyip.cmliussss.net'": b64('proxyip.cmliussss.net'),
|
||||
'"proxyip.cmliussss.net"': b64('proxyip.cmliussss.net'),
|
||||
"'proxyip.cfspider.com'": b64('proxyip.cfspider.com'),
|
||||
'"proxyip.cfspider.com"': b64('proxyip.cfspider.com'),
|
||||
"'.PrOxYIp.CmLiUsSsS.nEt'": b64('.PrOxYIp.CmLiUsSsS.nEt'),
|
||||
'".PrOxYIp.CmLiUsSsS.nEt"': b64('.PrOxYIp.CmLiUsSsS.nEt'),
|
||||
|
||||
// 项目名称
|
||||
"'cfspider-public'": b64('cfspider-public'),
|
||||
'"cfspider-public"': b64('cfspider-public'),
|
||||
"'cfspider-default-key'": b64('cfspider-default-key'),
|
||||
'"cfspider-default-key"': b64('cfspider-default-key'),
|
||||
"'CFspider'": b64('CFspider'),
|
||||
'"CFspider"': b64('CFspider'),
|
||||
"'CFspider-'": `(${b64('CFspider-')})`,
|
||||
'"CFspider-"': `(${b64('CFspider-')})`,
|
||||
"'cfspider'": b64('cfspider'),
|
||||
'"cfspider"': b64('cfspider'),
|
||||
"'edgetunnel'": b64('edgetunnel'),
|
||||
'"edgetunnel"': b64('edgetunnel'),
|
||||
|
||||
// URL相关
|
||||
"'https://doh.cmliussss.net/CMLiussss'": b64('https://doh.cmliussss.net/CMLiussss'),
|
||||
'"https://doh.cmliussss.net/CMLiussss"': b64('https://doh.cmliussss.net/CMLiussss'),
|
||||
"'https://edt-pages.github.io'": b64('https://edt-pages.github.io'),
|
||||
'"https://edt-pages.github.io"': b64('https://edt-pages.github.io'),
|
||||
"'https://SUBAPI.cmliussss.net'": b64('https://SUBAPI.cmliussss.net'),
|
||||
'"https://SUBAPI.cmliussss.net"': b64('https://SUBAPI.cmliussss.net'),
|
||||
"'https://raw.githubusercontent.com/cmliu/ACL4SSR/refs/heads/main/Clash/config/ACL4SSR_Online_Mini_MultiMode_CF.ini'": b64('https://raw.githubusercontent.com/cmliu/ACL4SSR/refs/heads/main/Clash/config/ACL4SSR_Online_Mini_MultiMode_CF.ini'),
|
||||
'"https://raw.githubusercontent.com/cmliu/ACL4SSR/refs/heads/main/Clash/config/ACL4SSR_Online_Mini_MultiMode_CF.ini"': b64('https://raw.githubusercontent.com/cmliu/ACL4SSR/refs/heads/main/Clash/config/ACL4SSR_Online_Mini_MultiMode_CF.ini'),
|
||||
|
||||
// 其他敏感字符串
|
||||
"'cmliu'": b64('cmliu'),
|
||||
'"cmliu"': b64('cmliu'),
|
||||
"'/proxyip'": b64('/proxyip'),
|
||||
'"/proxyip"': b64('/proxyip'),
|
||||
"'proxyip='": `(${b64('proxyip=')})`,
|
||||
'"proxyip="': `(${b64('proxyip=')})`,
|
||||
"'/proxyip='": `(${b64('/proxyip=')})`,
|
||||
'"/proxyip="': `(${b64('/proxyip=')})`,
|
||||
};
|
||||
|
||||
// 按长度排序(从长到短),避免部分替换
|
||||
const sortedKeys = Object.keys(sensitiveReplacements).sort((a, b) => b.length - a.length);
|
||||
|
||||
// 执行替换
|
||||
for (const key of sortedKeys) {
|
||||
code = code.split(key).join(sensitiveReplacements[key]);
|
||||
}
|
||||
|
||||
// 保存预处理后的代码
|
||||
fs.writeFileSync('workers_preprocessed.js', code, 'utf8');
|
||||
console.log('Preprocessed! Now run terser...');
|
||||
|
||||
// 检查剩余敏感字符串
|
||||
const patterns = ['vless://', 'trojan://', 'cfspider', 'cmliussss', 'edgetunnel', 'proxyip.c'];
|
||||
const remaining = patterns.filter(p => code.toLowerCase().includes(p.toLowerCase()));
|
||||
if (remaining.length > 0) {
|
||||
console.log('Remaining sensitive strings:', remaining.join(', '));
|
||||
} else {
|
||||
console.log('All sensitive strings encoded!');
|
||||
}
|
||||
|
||||
393
translate.js
Normal file
393
translate.js
Normal file
@@ -0,0 +1,393 @@
|
||||
const fs = require('fs');
|
||||
|
||||
// 读取原始文件
|
||||
let code = fs.readFileSync('workers.js', 'utf8');
|
||||
|
||||
// 第一步:删除所有包含中文的注释行
|
||||
code = code.split('\n').map(line => {
|
||||
// 如果整行是注释且包含中文,删除
|
||||
if (/^\s*\/\/.*[\u4e00-\u9fff]/.test(line)) return '';
|
||||
// 如果行尾有包含中文的注释,删除注释部分
|
||||
if (/\/\/.*[\u4e00-\u9fff]/.test(line)) {
|
||||
return line.replace(/\/\/.*[\u4e00-\u9fff].*$/, '');
|
||||
}
|
||||
return line;
|
||||
}).join('\n');
|
||||
|
||||
// 删除多行注释中包含中文的
|
||||
code = code.replace(/\/\*[\s\S]*?[\u4e00-\u9fff][\s\S]*?\*\//g, '');
|
||||
|
||||
// 中文到英文的完整映射表 - 全部使用驼峰式(无空格)
|
||||
const translations = {
|
||||
// 敏感变量名和字符串替换
|
||||
'cfspiderPath': 'apiPath',
|
||||
'cfspider-public-00000000-0000': 'pub-node-00000000-0000',
|
||||
'x-cfspider-header-': 'x-custom-header-',
|
||||
'X-CFspider-Version': 'X-Worker-Version',
|
||||
'X-CFspider-TwoProxy': 'X-Two-Proxy',
|
||||
'CFspider/1.8.3': 'Mozilla/5.0',
|
||||
'cfspider.get': 'client.get',
|
||||
'CFspider-': 'Node-',
|
||||
'#CFspider': '#Node',
|
||||
|
||||
// 原有翻译
|
||||
// 变量名翻译
|
||||
'反代IP': 'proxyIP',
|
||||
'启用SOCKS5反代': 'enableSOCKS5Proxy',
|
||||
'启用SOCKS5全局反代': 'enableGlobalSOCKS5',
|
||||
'我的SOCKS5账号': 'mySOCKS5Account',
|
||||
'缓存反代IP': 'cachedProxyIP',
|
||||
'缓存反代解析数组': 'cachedProxyArray',
|
||||
'缓存反代数组索引': 'cachedProxyIndex',
|
||||
'启用反代兜底': 'enableProxyFallback',
|
||||
'SOCKS5白名单': 'socks5Whitelist',
|
||||
'Pages静态页面': 'pagesStaticUrl',
|
||||
'管理员密码': 'adminPassword',
|
||||
'加密秘钥': 'encryptKey',
|
||||
'访问IP': 'clientIP',
|
||||
'整理成数组': 'parseToArray',
|
||||
|
||||
// 配置对象属性名
|
||||
'优选订阅生成': 'subGenerator',
|
||||
'本地IP库': 'localIPPool',
|
||||
'随机数量': 'randomCount',
|
||||
'指定端口': 'specifiedPort',
|
||||
'随机IP': 'randomIP',
|
||||
'订阅转换配置': 'subConverterConfig',
|
||||
'反代': 'reverseProxy',
|
||||
'全局': 'globalMode',
|
||||
'账号': 'account',
|
||||
'白名单': 'whitelist',
|
||||
'传输协议': 'transport',
|
||||
'跳过证书验证': 'skipCertVerify',
|
||||
'启用0RTT': 'enable0RTT',
|
||||
'TLS分片': 'tlsFragment',
|
||||
'随机路径': 'randomPath',
|
||||
'本地': 'local',
|
||||
'协议类型': 'protocolType',
|
||||
|
||||
// 新增翻译
|
||||
'区分大小写访问': 'caseSensitivePath',
|
||||
'输入密码': 'inputPassword',
|
||||
'日志内容': 'logContent',
|
||||
'待验证优选': 'pendingOptimal',
|
||||
'请求优选': 'requestOptimal',
|
||||
'完整优选': 'fullOptimal',
|
||||
'完整优选列表': 'fullOptimalList',
|
||||
'其他节点': 'otherNodes',
|
||||
'节点': 'node',
|
||||
'内容': 'content',
|
||||
'优选': 'optimal',
|
||||
'检测代理响应': 'checkProxyResponse',
|
||||
'可用性验证': 'availabilityCheck',
|
||||
'请求日志记录': 'requestLogRecord',
|
||||
'保存自定义': 'saveCustom',
|
||||
'生成': 'gen',
|
||||
'订阅': 'sub',
|
||||
'元素': 'element',
|
||||
'地址备注分离': 'addrRemarkSplit',
|
||||
'合并其他节点数组': 'mergeOtherNodes',
|
||||
'器': 'er',
|
||||
'器返回': 'erReturn',
|
||||
'订阅行列表': 'subLineList',
|
||||
'行内容': 'lineContent',
|
||||
'地址匹配': 'addrMatch',
|
||||
'地址端口': 'addrPort',
|
||||
'备注': 'remark',
|
||||
'备注匹配': 'remarkMatch',
|
||||
'原始地址': 'origAddr',
|
||||
'节点地址': 'nodeAddr',
|
||||
'节点端口': 'nodePort',
|
||||
'节点备注': 'nodeRemark',
|
||||
'订阅转换': 'subConvert',
|
||||
'订阅配置文件热补丁': 'subConfigHotfix',
|
||||
'批量替换': 'batchReplace',
|
||||
'获取': 'get',
|
||||
'处理': 'handle',
|
||||
'请求': 'request',
|
||||
'伪装页': 'fakePage',
|
||||
'新请求头': 'newHeaders',
|
||||
'响应内容': 'respContent',
|
||||
'响应': 'resp',
|
||||
'判断是否是木马': 'checkIfTrojan',
|
||||
'解析木马请求': 'parseTrojanReq',
|
||||
'解析魏烈思请求': 'parseVlessReq',
|
||||
'转发': 'forward',
|
||||
'目标': 'target',
|
||||
'否': 'no',
|
||||
'所有': 'all',
|
||||
'数组': 'arr',
|
||||
'兜底': 'fallback',
|
||||
'数组索引': 'arrIndex',
|
||||
'地址': 'addr',
|
||||
'端口': 'port',
|
||||
'索引': 'idx',
|
||||
'错误': 'err',
|
||||
'且未': 'andNot',
|
||||
'代理': 'proxy',
|
||||
'解析地址端口': 'parseAddrPort',
|
||||
'验证': 'verify',
|
||||
'原始': 'raw',
|
||||
'启用': 'enable',
|
||||
'每行内容': 'eachLine',
|
||||
'输出内容': 'output',
|
||||
'备改内容': 'backup',
|
||||
'正确内容': 'correct',
|
||||
'容量限制': 'capLimit',
|
||||
'当前': 'curr',
|
||||
'日志数组': 'logArr',
|
||||
'现有日志': 'existLog',
|
||||
'三十分钟前': 'thirtyMinAgo',
|
||||
'戳': 'stamp',
|
||||
'掩码敏感信息': 'maskSensitive',
|
||||
'文本': 'txt',
|
||||
'前缀长度': 'prefixLen',
|
||||
'后缀长度': 'suffixLen',
|
||||
'前缀': 'prefix',
|
||||
'后缀': 'suffix',
|
||||
'星号数量': 'starCount',
|
||||
'编码器': 'encoder',
|
||||
'第一次哈希': 'hash1',
|
||||
'第一次哈希数组': 'hash1Arr',
|
||||
'第一次十六进制': 'hex1',
|
||||
'字节': 'byte',
|
||||
'第二次哈希': 'hash2',
|
||||
'第二次哈希数组': 'hash2Arr',
|
||||
'第二次十六进制': 'hex2',
|
||||
'常用': 'common',
|
||||
'目录': 'dir',
|
||||
'随机数': 'randNum',
|
||||
'随机替换通配符': 'randReplaceWildcard',
|
||||
'字符集': 'charset',
|
||||
'每组数量': 'groupCnt',
|
||||
'打乱后数组': 'shuffledArr',
|
||||
'重置配置': 'resetCfg',
|
||||
'初始化开始': 'initStart',
|
||||
'默认配置': 'defCfg',
|
||||
'初始化': 'init',
|
||||
'加载': 'load',
|
||||
'官方优选': 'officialOptimal',
|
||||
'替换后的内容': 'replaced',
|
||||
'地址数组': 'addrArr',
|
||||
'默认端口': 'defPort',
|
||||
'超时': 'timeout',
|
||||
'订阅链接响应的明文': 'subLinkPlain',
|
||||
'需要订阅转换订阅': 'needSubConvert',
|
||||
'预处理订阅明文内容': 'preSubPlain',
|
||||
'国家': 'country',
|
||||
'城市': 'city',
|
||||
'路参': 'pathParam',
|
||||
'解析': 'parse',
|
||||
'地址失败': 'addrFailed',
|
||||
'如': 'like',
|
||||
'总计': 'totalCnt',
|
||||
'查询': 'query',
|
||||
'记录': 'record',
|
||||
'解析地址端口字符串': 'parseAddrPortStr',
|
||||
'排序后数组': 'sortedArr',
|
||||
'目标根': 'targetRoot',
|
||||
'洗牌后': 'shuffled',
|
||||
'代理协议': 'proxyProto',
|
||||
'完整代理': 'fullProxy',
|
||||
'格式化': 'format',
|
||||
'随机字符串': 'randStr',
|
||||
'访问': 'visit',
|
||||
'失败': 'failed',
|
||||
|
||||
// 函数和错误消息(全部驼峰式)
|
||||
'荷兰节点': 'nlNode',
|
||||
'香港节点': 'hkNode',
|
||||
'未知IP': 'unknownIP',
|
||||
'配置已保存': 'configSaved',
|
||||
'配置已重置为默认值': 'configResetToDefault',
|
||||
'配置不完整': 'incompleteConfig',
|
||||
'配置重置失败': 'configResetFailed',
|
||||
'失败原因': 'reason',
|
||||
'保存配置失败': 'saveConfigFailed',
|
||||
'保存自定义优选IP失败': 'saveCustomIPFailed',
|
||||
'自定义优选IP已保存': 'customIPSaved',
|
||||
'自定义IP已保存': 'customIPSaved',
|
||||
'不支持的POST请求路径': 'unsupportedPOSTPath',
|
||||
'重定向中': 'redirecting',
|
||||
'请通过 Cloudflare Dashboard 或 wrangler.toml 设置 NEW_IP 环境变量': 'setNEWIPViaDashboard',
|
||||
'请使用 Python cfspider.get() 配合 two_proxy 参数': 'useCfspiderGetWithTwoProxy',
|
||||
'仅支持 HTTP 双层代理': 'onlyHTTPTwoProxySupported',
|
||||
'不支持通过 /proxy API': 'notSupportedViaProxyAPI',
|
||||
'隧道建立成功': 'tunnelEstablished',
|
||||
'代理连接关闭': 'proxyClosed',
|
||||
'无效的代理响应': 'invalidProxyResp',
|
||||
'代理连接失败': 'proxyConnFailed',
|
||||
'双层代理未配置': 'twoProxyNotConfigured',
|
||||
'读取': 'read',
|
||||
'出错': 'error',
|
||||
'日志记录失败': 'logFailed',
|
||||
'日志通知': 'logNotify',
|
||||
'类型': 'type',
|
||||
'位置': 'location',
|
||||
'域名': 'domain',
|
||||
'路径': 'path',
|
||||
'时间': 'time',
|
||||
'请求用量': 'requestUsage',
|
||||
'统计结果': 'statResult',
|
||||
'上限': 'limit',
|
||||
'账户获取失败': 'accountGetFailed',
|
||||
'未找到账户': 'accountNotFound',
|
||||
'未找到账户数据': 'accountDataNotFound',
|
||||
'查询失败': 'queryFailed',
|
||||
'获取使用量错误': 'getUsageError',
|
||||
'查询请求量失败': 'queryRequestFailed',
|
||||
'验证优选API失败': 'verifyAPIFailed',
|
||||
'缺少代理参数': 'missingProxyParam',
|
||||
'无法连接到代理服务器': 'cannotConnectToProxy',
|
||||
'关闭连接时出错': 'errorClosingConn',
|
||||
|
||||
// 日志消息
|
||||
'尝试连接到': 'connectingTo',
|
||||
'成功连接到': 'connectedTo',
|
||||
'连接失败': 'connFailed',
|
||||
'连接超时': 'connTimeout',
|
||||
'尝试直连到': 'directConnTo',
|
||||
'代理到': 'proxyTo',
|
||||
'使用双层代理': 'usingTwoProxy',
|
||||
'回退到默认方式': 'fallbackToDefault',
|
||||
'目标站点': 'targetSite',
|
||||
'随机种子': 'randSeed',
|
||||
'解析完成': 'parseComplete',
|
||||
'总数': 'total',
|
||||
'个': '',
|
||||
'读取缓存': 'readCache',
|
||||
'启用 SOCKS5/HTTP 全局代理': 'enableGlobalProxy',
|
||||
'所有反代连接失败': 'allProxyFailed',
|
||||
'且未启用兜底': 'fallbackDisabled',
|
||||
'连接终止': 'connTerminated',
|
||||
'反代连接': 'proxyConn',
|
||||
'反代解析': 'proxyParse',
|
||||
'反代类型': 'proxyType',
|
||||
'已启用': 'enabled',
|
||||
'通过': 'via',
|
||||
'连接到': 'connTo',
|
||||
|
||||
// 订阅相关
|
||||
'优选订阅生成器异常': 'subGenError',
|
||||
'订阅转换后端异常': 'subConverterError',
|
||||
'订阅内容': 'subContent',
|
||||
'不规范的IP格式已忽略': 'invalidIPIgnored',
|
||||
|
||||
// 解析相关
|
||||
'解析William域名失败': 'parseWilliamFailed',
|
||||
'DoH查询失败': 'dohQueryFailed',
|
||||
'无效的': 'invalid',
|
||||
'地址格式': 'addrFormat',
|
||||
'认证部分必须是': 'authMustBe',
|
||||
'的形式': 'format',
|
||||
'端口号必须是数字': 'portMustBeNumber',
|
||||
'地址必须用方括号括起来': 'addrMustBeBracketed',
|
||||
|
||||
// Singbox热补丁
|
||||
'Singbox热补丁执行失败': 'singboxPatchFailed',
|
||||
|
||||
// 优选标签
|
||||
'移动优选': 'CMCCOptimal',
|
||||
'联通优选': 'CUOptimal',
|
||||
'电信优选': 'CTOptimal',
|
||||
'CF优选': 'CFOptimal',
|
||||
|
||||
// 密钥相关
|
||||
'勿动此默认密钥,有需求请自行通过添加变量KEY进行修改': 'doNotModifyDefaultKey',
|
||||
|
||||
// 双层代理
|
||||
'双层代理': 'twoProxy',
|
||||
'不支持通过': 'notSupportedVia',
|
||||
'参数': 'param',
|
||||
|
||||
// 下载速度等
|
||||
'下载速度': 'dlSpeed',
|
||||
'数据中心': 'dataCenter',
|
||||
'延迟': 'latency',
|
||||
|
||||
// 单字符和短语
|
||||
'的': '',
|
||||
'公开': 'public',
|
||||
'返回完整': 'returnFull',
|
||||
'配置': 'config',
|
||||
'去掉': 'remove',
|
||||
'快速': 'fast',
|
||||
'登录页面和登录': 'loginPageAnd',
|
||||
'后': 'after',
|
||||
'管理页面': 'adminPage',
|
||||
'量': 'amt',
|
||||
'检查': 'check',
|
||||
'为默认值': 'toDefault',
|
||||
'操作': 'op',
|
||||
'保存': 'save',
|
||||
'保存到': 'saveTo',
|
||||
'返回': 'return',
|
||||
'配置文件': 'cfgFile',
|
||||
'清除': 'clear',
|
||||
'并跳转到登录页面': 'redirectToLogin',
|
||||
'到期': 'expire',
|
||||
'跳过空行': 'skipEmpty',
|
||||
'这是': 'thisIs',
|
||||
'行': 'line',
|
||||
'提取': 'extract',
|
||||
'或': 'or',
|
||||
'可能带方括号': 'mayHaveBrackets',
|
||||
'默认': 'def',
|
||||
'默认为': 'defTo',
|
||||
'本身': 'itself',
|
||||
'列表': 'list',
|
||||
'顶级属性的缩进': 'topLevelIndent',
|
||||
'顶级属性缩进': 'topLevelIndent',
|
||||
'强制使用现代方式': 'forceModern',
|
||||
'移除': 'remove',
|
||||
'因为已经改用': 'becauseChanged',
|
||||
'了': '',
|
||||
'果长度太短': 'ifTooShort',
|
||||
'直接返回': 'directReturn',
|
||||
'基于': 'basedOn',
|
||||
'当': 'when',
|
||||
'为': 'is',
|
||||
'时生效': 'effective',
|
||||
'数量': 'cnt',
|
||||
'则使用': 'thenUse',
|
||||
'内': 'in',
|
||||
'更新': 'update',
|
||||
'小时': 'hour',
|
||||
'时强制将': 'forceChange',
|
||||
'改为': 'changeTo',
|
||||
'默认优先': 'defFirst',
|
||||
'果明确指定': 'ifSpecified',
|
||||
'系编码': 'encoding',
|
||||
'优先尝试': 'tryFirst',
|
||||
'追加': 'append',
|
||||
'明文': 'plain',
|
||||
'开头': 'start',
|
||||
'带': 'with',
|
||||
'无': 'none'
|
||||
};
|
||||
|
||||
// 按长度排序(从长到短)
|
||||
const sortedKeys = Object.keys(translations).sort((a, b) => b.length - a.length);
|
||||
|
||||
// 执行替换
|
||||
for (const cn of sortedKeys) {
|
||||
const en = translations[cn];
|
||||
code = code.split(cn).join(en);
|
||||
}
|
||||
|
||||
// 删除空行过多的情况
|
||||
code = code.replace(/\n{3,}/g, '\n\n');
|
||||
|
||||
// 保存翻译后的文件
|
||||
fs.writeFileSync('workers_translated.js', code, 'utf8');
|
||||
console.log('Translation complete! Saved to workers_translated.js');
|
||||
|
||||
// 检查是否还有剩余中文
|
||||
const remaining = code.match(/[\u4e00-\u9fff]+/g);
|
||||
if (remaining) {
|
||||
const unique = [...new Set(remaining)];
|
||||
console.log('\nRemaining Chinese characters (' + unique.length + '):');
|
||||
unique.forEach(c => console.log(' ' + c));
|
||||
} else {
|
||||
console.log('\nNo remaining Chinese characters!');
|
||||
}
|
||||
2446
workers_encrypted.js
Normal file
2446
workers_encrypted.js
Normal file
File diff suppressed because it is too large
Load Diff
2426
workers_translated.js
Normal file
2426
workers_translated.js
Normal file
File diff suppressed because it is too large
Load Diff
1
x27cn-github/worker.js
Normal file
1
x27cn-github/worker.js
Normal file
File diff suppressed because one or more lines are too long
1
x27cn-pages/_worker.js
Normal file
1
x27cn-pages/_worker.js
Normal file
File diff suppressed because one or more lines are too long
19
x27cn-wrangler.toml
Normal file
19
x27cn-wrangler.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
# x27cn Workers 部署配置
|
||||
name = "x27cn"
|
||||
main = "破皮版workers.js"
|
||||
compatibility_date = "2024-01-01"
|
||||
compatibility_flags = ["nodejs_compat"]
|
||||
|
||||
# 不启用 workers.dev 子域名(降低被检测概率)
|
||||
workers_dev = false
|
||||
|
||||
# 直接绑定自定义域名
|
||||
routes = [
|
||||
{ pattern = "x27cn.cfspider.com/*", zone_name = "cfspider.com" }
|
||||
]
|
||||
|
||||
# 环境变量
|
||||
[vars]
|
||||
# UUID = "自定义UUID"
|
||||
# ADMIN = "管理密码"
|
||||
|
||||
54
x27cn_encrypt.js
Normal file
54
x27cn_encrypt.js
Normal file
@@ -0,0 +1,54 @@
|
||||
// x27cn 加密/解密函数
|
||||
// 在 workers.js 开头添加这些函数
|
||||
|
||||
const X27CN_KEY = 'x27cn2026'; // 可以通过环境变量覆盖
|
||||
|
||||
// x27cn 加密函数
|
||||
function x27cnEncrypt(text, key = X27CN_KEY) {
|
||||
if (!text) return '';
|
||||
const keyBytes = new TextEncoder().encode(key);
|
||||
const textBytes = new TextEncoder().encode(text);
|
||||
const result = new Uint8Array(textBytes.length);
|
||||
|
||||
for (let i = 0; i < textBytes.length; i++) {
|
||||
// XOR with key byte
|
||||
let b = textBytes[i] ^ keyBytes[i % keyBytes.length];
|
||||
// Rotate bits
|
||||
b = ((b << 3) | (b >> 5)) & 0xFF;
|
||||
// Add position offset
|
||||
b = (b + i) & 0xFF;
|
||||
result[i] = b;
|
||||
}
|
||||
|
||||
// Convert to hex string
|
||||
return Array.from(result).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
|
||||
// x27cn 解密函数
|
||||
function x27cnDecrypt(hex, key = X27CN_KEY) {
|
||||
if (!hex || hex.length % 2 !== 0) return '';
|
||||
const keyBytes = new TextEncoder().encode(key);
|
||||
const bytes = new Uint8Array(hex.length / 2);
|
||||
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
||||
}
|
||||
|
||||
const result = new Uint8Array(bytes.length);
|
||||
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
let b = bytes[i];
|
||||
// Reverse: subtract position offset
|
||||
b = (b - i + 256) & 0xFF;
|
||||
// Reverse: rotate bits back
|
||||
b = ((b >> 3) | (b << 5)) & 0xFF;
|
||||
// Reverse: XOR with key byte
|
||||
b = b ^ keyBytes[i % keyBytes.length];
|
||||
result[i] = b;
|
||||
}
|
||||
|
||||
return new TextDecoder().decode(result);
|
||||
}
|
||||
|
||||
module.exports = { x27cnEncrypt, x27cnDecrypt };
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user