破皮版完整实现功能

This commit is contained in:
violettools
2026-01-25 16:50:59 +08:00
parent e45e582a52
commit 51413e8b58
9 changed files with 1662 additions and 16 deletions

View File

@@ -167,9 +167,197 @@ X27CN v2 使用以下加密步骤:
3. **位旋转** - 循环左移 5 位
4. **状态混合** - 使用累积状态值混淆
## 代码压缩混淆v1.2.0 新增)
除了加密型混淆X27CN 还提供专业的代码压缩和标识符混淆功能。
### Python API
```python
import x27cn
# 压缩 CSS
minified_css = x27cn.minify_css('body { color: red; }')
# 输出: 'body{color:red}'
# 压缩 JavaScript带变量名混淆
minified_js = x27cn.minify_js('function hello() { var name = "world"; return name; }')
# 输出: 'function hello(){var _a="world";return _a}'
# 压缩 HTML自动处理内联 CSS/JS
minified_html = x27cn.minify_html('<html> <body> </body> </html>')
# 输出: '<html><body></body></html>'
# 使用 Node.js 工具(效果更好,需安装 terser/clean-css
minified = x27cn.minify_js_node(js_code)
# 压缩文件
x27cn.minify_file('app.js') # 生成 app.min.js
x27cn.minify_file('style.css', 'dist/style.css')
```
### 高级混淆
```python
import x27cn
# 标识符混淆(变量名替换为 _$0, _$1, ...
obfuscated = x27cn.obfuscate_identifiers(js_code)
# 添加死代码(增加逆向难度)
obfuscated = x27cn.add_dead_code(js_code, complexity=3)
```
### 命令行
```bash
# 压缩 JavaScript
x27cn minify app.js
# 压缩 CSS
x27cn minify style.css dist/style.min.css
# 不混淆变量名
x27cn minify app.js --no-mangle
# 不使用 Node.js 工具(纯 Python
x27cn minify app.js --no-node
# 添加死代码
x27cn minify app.js --dead-code=3
# 额外标识符混淆
x27cn minify app.js --identifiers
```
### Node.js 工具支持
如果安装了以下 npm 包X27CN 会自动使用它们以获得更好的压缩效果:
```bash
npm install -g terser clean-css-cli html-minifier-terser
```
如果未安装,会自动降级到纯 Python 实现。
### 压缩 vs 加密混淆对比
| 特性 | `minify` | `obfuscate` |
|------|----------|-------------|
| 可读性 | 低 | 极低 |
| 代码可执行 | 直接执行 | 需解密 |
| 密钥需求 | 不需要 | 需要 |
| 文件大小 | 显著减小 | 略增大 |
| 安全性 | 中等 | 较高 |
| 性能影响 | 无 | 有解密开销 |
**推荐使用场景:**
- `minify`: 生产环境部署、减小文件体积、基础代码保护
- `obfuscate`: 需要更强保护的敏感代码、API密钥保护
## 密码安全v1.3.0 新增)
X27CN 现在提供安全的密码处理功能,适合用户认证场景。
### 密码哈希(存储密码)
```python
import x27cn
# 哈希密码(用于存储)
hashed = x27cn.hash_password('mypassword123')
# 输出: '$x27cn$100000$base64salt$base64hash'
# 验证密码
if x27cn.verify_password('mypassword123', hashed):
print('登录成功')
else:
print('密码错误')
```
### 密码强度检测
```python
result = x27cn.check_password_strength('abc123')
print(result['level']) # 'weak'
print(result['score']) # 15
print(result['suggestions']) # ['添加大写字母', '添加特殊字符']
```
### 生成安全密码
```python
# 生成 16 位随机密码
pwd = x27cn.generate_password(16)
# 自定义选项
pwd = x27cn.generate_password(
length=20,
include_upper=True,
include_lower=True,
include_digits=True,
include_special=True,
exclude_ambiguous=True # 排除 0O1lI 等易混淆字符
)
```
### 基于密码的加密
```python
# 使用密码加密数据(比 key 更安全)
encrypted = x27cn.encrypt_with_password('敏感数据', 'mypassword')
# 输出: <p7d0><xx><xx>...<xxxx><xxxx>... (标准 <xxxx> 格式)
# 解密
decrypted = x27cn.decrypt_with_password(encrypted, 'mypassword')
```
格式说明:
- `<p7d0>` - 魔数标识(表示密码加密)
- 后续 16 个 `<xx>` - 随机盐值
- 剩余部分 - 加密数据
### 快速哈希
```python
# MD5不推荐用于密码仅用于校验
x27cn.md5('hello') # '5d41402abc4b2a76b9719d911017c592'
# SHA256
x27cn.sha256('hello') # '2cf24dba5fb0a30e...'
# SHA512
x27cn.sha512('hello')
```
### 命令行
```bash
# 哈希密码
x27cn password hash "mypassword123"
# 验证密码
x27cn password verify "mypassword123" "$x27cn$100000$..."
# 生成密码
x27cn password generate --length=20 --count=5
# 检查密码强度
x27cn password check "abc123"
# 使用密码加密文件
x27cn encrypt secret.txt --password="mypassword"
# 使用密码解密
x27cn decrypt secret.txt.enc --password="mypassword"
```
## 安全说明
X27CN 设计用于**代码混淆**,不是密码学安全的加密算法。
X27CN 提供两种安全级别:
### 1. 代码混淆encrypt/obfuscate
设计用于**代码混淆**,不是密码学安全的加密算法。
适用场景:
- 前端代码混淆保护
@@ -177,10 +365,39 @@ X27CN 设计用于**代码混淆**,不是密码学安全的加密算法。
- 配置文件保护
- 防止代码被轻易复制
不适用场景:
- 密码存储(请使用 bcrypt/argon2
- 敏感数据加密(请使用 AES-256
### 2. 密码安全hash_password/encrypt_with_password
使用行业标准的 **PBKDF2-SHA256** 算法。
适用场景:
- 用户密码存储 ✓
- 敏感数据加密 ✓
- 配置文件加密 ✓
安全特性:
- PBKDF2-SHA256 密钥派生100000 次迭代)
- 随机盐值防止彩虹表攻击
- 恒定时间比较防止时序攻击
### 不适用场景
- 通信加密(请使用 TLS
- 金融级加密(请使用 AES-256-GCM
## 完整 API 参考
| 函数 | 说明 |
|------|------|
| `encrypt(text, key)` | X27CN 加密 |
| `decrypt(text, key)` | X27CN 解密 |
| `obfuscate_file(path)` | 文件混淆加密 |
| `minify(content)` | 代码压缩 |
| `minify_js(js)` | JS 压缩 + 变量混淆 |
| `hash_password(pwd)` | 密码哈希 |
| `verify_password(pwd, hash)` | 验证密码 |
| `generate_password(len)` | 生成随机密码 |
| `check_password_strength(pwd)` | 检测密码强度 |
| `encrypt_with_password(data, pwd)` | 密码加密数据 |
| `decrypt_with_password(data, pwd)` | 密码解密数据 |
| `md5(text)` / `sha256(text)` | 快速哈希 |
## License

7
x27cn/debug_mangle.py Normal file
View File

@@ -0,0 +1,7 @@
from x27cn.minify import _mangle_variables
js = 'var name="x";var greeting="y"+name;'
print("输入:", js)
result = _mangle_variables(js)
print("输出:", result)

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "x27cn"
version = "1.1.0"
version = "1.3.0"
description = "X27CN 代码混淆加密库 - Code obfuscation and encryption library"
readme = "README.md"
license = "MIT"

View File

@@ -40,7 +40,35 @@ from .obfuscate import (
obfuscate_inline_css,
)
__version__ = '1.1.0'
from .minify import (
minify,
minify_file,
minify_css,
minify_js,
minify_html,
minify_css_node,
minify_js_node,
minify_html_node,
obfuscate_identifiers,
add_dead_code,
flatten_control_flow,
flatten_control_flow_safe,
)
from .password import (
hash_password,
verify_password,
check_password_strength,
generate_password,
encrypt_with_password,
decrypt_with_password,
quick_hash,
md5,
sha256,
sha512,
)
__version__ = '1.3.0'
__author__ = 'CFspider'
__all__ = [
# 核心加密
@@ -52,12 +80,36 @@ __all__ = [
'decrypt_base64',
'generate_key',
'DEFAULT_KEY',
# 文件混淆
# 文件混淆(加密型)
'obfuscate_html',
'obfuscate_js',
'obfuscate_css',
'obfuscate_file',
'obfuscate_inline_js',
'obfuscate_inline_css',
# 代码压缩混淆
'minify',
'minify_file',
'minify_css',
'minify_js',
'minify_html',
'minify_css_node',
'minify_js_node',
'minify_html_node',
'obfuscate_identifiers',
'add_dead_code',
'flatten_control_flow',
'flatten_control_flow_safe',
# 密码安全
'hash_password',
'verify_password',
'check_password_strength',
'generate_password',
'encrypt_with_password',
'decrypt_with_password',
'quick_hash',
'md5',
'sha256',
'sha512',
]

View File

@@ -5,12 +5,23 @@ X27CN 命令行工具
x27cn encrypt <file> [output] [--key=密钥]
x27cn decrypt <file> [output] [--key=密钥]
x27cn obfuscate <file> [output] [--key=密钥]
x27cn minify <file> [output] [--no-mangle] [--no-node]
x27cn flatten <file> [output] [--intensity=2] [--safe]
x27cn password hash <password>
x27cn password verify <password> <hash>
x27cn password generate [--length=16]
x27cn password check <password>
"""
import argparse
import sys
from .core import encrypt, decrypt, DEFAULT_KEY
from .obfuscate import obfuscate_file
from .minify import minify_file, obfuscate_identifiers, add_dead_code, flatten_control_flow, flatten_control_flow_safe
from .password import (
hash_password, verify_password, generate_password,
check_password_strength, encrypt_with_password, decrypt_with_password
)
def main():
@@ -18,7 +29,7 @@ def main():
prog='x27cn',
description='X27CN 代码混淆加密工具'
)
parser.add_argument('--version', action='version', version='x27cn 1.0.0')
parser.add_argument('--version', action='version', version='x27cn 1.3.0')
subparsers = parser.add_subparsers(dest='command', help='命令')
@@ -28,6 +39,7 @@ def main():
enc_parser.add_argument('output', nargs='?', help='输出文件(可选)')
enc_parser.add_argument('--key', '-k', default=DEFAULT_KEY, help='加密密钥')
enc_parser.add_argument('--text', '-t', action='store_true', help='将 input 作为文本而非文件')
enc_parser.add_argument('--password', '-p', help='使用密码加密(更安全)')
# decrypt 命令
dec_parser = subparsers.add_parser('decrypt', help='解密文本或文件')
@@ -35,6 +47,7 @@ def main():
dec_parser.add_argument('output', nargs='?', help='输出文件(可选)')
dec_parser.add_argument('--key', '-k', default=DEFAULT_KEY, help='解密密钥')
dec_parser.add_argument('--text', '-t', action='store_true', help='将 input 作为文本而非文件')
dec_parser.add_argument('--password', '-p', help='使用密码解密')
# obfuscate 命令
obf_parser = subparsers.add_parser('obfuscate', help='混淆加密文件(生成自解密代码)')
@@ -42,6 +55,47 @@ def main():
obf_parser.add_argument('output', nargs='?', help='输出文件(可选)')
obf_parser.add_argument('--key', '-k', default=DEFAULT_KEY, help='加密密钥')
# minify 命令
min_parser = subparsers.add_parser('minify', help='压缩混淆文件(不加密)')
min_parser.add_argument('input', help='输入文件 (.html/.js/.css)')
min_parser.add_argument('output', nargs='?', help='输出文件(可选)')
min_parser.add_argument('--no-mangle', action='store_true', help='不混淆变量名')
min_parser.add_argument('--no-node', action='store_true', help='不使用 Node.js 工具')
min_parser.add_argument('--dead-code', type=int, default=0, help='添加死代码复杂度 (1-5)')
min_parser.add_argument('--identifiers', action='store_true', help='额外混淆标识符')
# flatten 命令
flat_parser = subparsers.add_parser('flatten', help='控制流扁平化混淆仅JS')
flat_parser.add_argument('input', help='输入 JavaScript 文件')
flat_parser.add_argument('output', nargs='?', help='输出文件(可选)')
flat_parser.add_argument('--intensity', '-i', type=int, default=2, choices=[1, 2, 3],
help='扁平化强度 (1=轻, 2=中, 3=强)')
flat_parser.add_argument('--safe', '-s', action='store_true', help='使用安全模式(更保守)')
# password 命令
pwd_parser = subparsers.add_parser('password', help='密码工具')
pwd_subparsers = pwd_parser.add_subparsers(dest='pwd_command', help='密码子命令')
# password hash
pwd_hash = pwd_subparsers.add_parser('hash', help='哈希密码')
pwd_hash.add_argument('password', help='要哈希的密码')
pwd_hash.add_argument('--iterations', '-i', type=int, default=100000, help='迭代次数')
# password verify
pwd_verify = pwd_subparsers.add_parser('verify', help='验证密码')
pwd_verify.add_argument('password', help='明文密码')
pwd_verify.add_argument('hash', help='哈希值')
# password generate
pwd_gen = pwd_subparsers.add_parser('generate', help='生成随机密码')
pwd_gen.add_argument('--length', '-l', type=int, default=16, help='密码长度')
pwd_gen.add_argument('--no-special', action='store_true', help='不包含特殊字符')
pwd_gen.add_argument('--count', '-c', type=int, default=1, help='生成数量')
# password check
pwd_check = pwd_subparsers.add_parser('check', help='检查密码强度')
pwd_check.add_argument('password', help='要检查的密码')
args = parser.parse_args()
if not args.command:
@@ -51,12 +105,18 @@ def main():
try:
if args.command == 'encrypt':
if args.text:
result = encrypt(args.input, args.key)
if args.password:
result = encrypt_with_password(args.input, args.password)
else:
result = encrypt(args.input, args.key)
print(result)
else:
with open(args.input, 'r', encoding='utf-8') as f:
content = f.read()
result = encrypt(content, args.key)
if args.password:
result = encrypt_with_password(content, args.password)
else:
result = encrypt(content, args.key)
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
f.write(result)
@@ -66,12 +126,18 @@ def main():
elif args.command == 'decrypt':
if args.text:
result = decrypt(args.input, args.key)
if args.password:
result = decrypt_with_password(args.input, args.password)
else:
result = decrypt(args.input, args.key)
print(result)
else:
with open(args.input, 'r', encoding='utf-8') as f:
content = f.read()
result = decrypt(content, args.key)
if args.password:
result = decrypt_with_password(content, args.password)
else:
result = decrypt(content, args.key)
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
f.write(result)
@@ -82,6 +148,87 @@ def main():
elif args.command == 'obfuscate':
output = obfuscate_file(args.input, args.output, args.key)
print(f'混淆完成: {output}')
elif args.command == 'minify':
output = minify_file(
args.input,
args.output,
use_node=not args.no_node,
mangle=not args.no_mangle
)
# 后处理
if args.dead_code > 0 or args.identifiers:
with open(output, 'r', encoding='utf-8') as f:
content = f.read()
if args.identifiers and output.endswith('.js'):
content = obfuscate_identifiers(content)
if args.dead_code > 0 and output.endswith('.js'):
content = add_dead_code(content, args.dead_code)
with open(output, 'w', encoding='utf-8') as f:
f.write(content)
print(f'压缩完成: {output}')
elif args.command == 'flatten':
with open(args.input, 'r', encoding='utf-8') as f:
content = f.read()
if args.safe:
result = flatten_control_flow_safe(content)
else:
result = flatten_control_flow(content, intensity=args.intensity)
import os
if args.output:
output_path = args.output
else:
base, ext = os.path.splitext(args.input)
output_path = f"{base}.flat{ext}"
with open(output_path, 'w', encoding='utf-8') as f:
f.write(result)
print(f'控制流扁平化完成: {output_path}')
elif args.command == 'password':
if args.pwd_command == 'hash':
hashed = hash_password(args.password, iterations=args.iterations)
print(hashed)
elif args.pwd_command == 'verify':
if verify_password(args.password, args.hash):
print('✓ 密码正确')
else:
print('✗ 密码错误')
sys.exit(1)
elif args.pwd_command == 'generate':
for _ in range(args.count):
pwd = generate_password(
length=args.length,
include_special=not args.no_special
)
print(pwd)
elif args.pwd_command == 'check':
result = check_password_strength(args.password)
level_colors = {
'weak': '🔴',
'fair': '🟠',
'good': '🟡',
'strong': '🟢',
'excellent': '💚'
}
print(f"{level_colors.get(result['level'], '')} 强度: {result['level'].upper()} ({result['score']}/100)")
print(f" 长度: {result['length']} 字符")
print(f" 小写: {'' if result['has_lower'] else ''}")
print(f" 大写: {'' if result['has_upper'] else ''}")
print(f" 数字: {'' if result['has_digit'] else ''}")
print(f" 特殊字符: {'' if result['has_special'] else ''}")
if result['suggestions']:
print("\n建议:")
for s in result['suggestions']:
print(f" - {s}")
else:
pwd_parser.print_help()
except FileNotFoundError:
print(f'错误: 文件不存在 - {args.input}', file=sys.stderr)

804
x27cn/x27cn/minify.py Normal file
View File

@@ -0,0 +1,804 @@
"""
X27CN 代码压缩混淆模块
提供 HTML/CSS/JS 的专业压缩和混淆功能:
1. 纯Python实现的压缩无需额外依赖
2. Node.js工具调用如果可用效果更好
"""
import re
import os
import json
import subprocess
import shutil
from typing import Optional, Dict, Any
# ============== 纯 Python 压缩实现 ==============
def minify_css(css: str) -> str:
"""
压缩 CSS 代码纯Python实现
Args:
css: CSS 源代码
Returns:
压缩后的 CSS
Example:
>>> minify_css('body { color: red; }')
'body{color:red}'
"""
# 移除注释
css = re.sub(r'/\*[\s\S]*?\*/', '', css)
# 移除多余空白
css = re.sub(r'\s+', ' ', css)
# 移除选择器和属性周围的空白
css = re.sub(r'\s*([{};:,>+~])\s*', r'\1', css)
# 移除最后的分号
css = re.sub(r';}', '}', css)
# 移除0值的单位
css = re.sub(r'(\s|:)0(px|em|rem|%|pt|cm|mm|in|pc|ex|ch|vw|vh|vmin|vmax)', r'\g<1>0', css)
# 简化颜色
css = re.sub(r'#([0-9a-fA-F])\1([0-9a-fA-F])\2([0-9a-fA-F])\3', r'#\1\2\3', css)
# 移除开头结尾空白
css = css.strip()
return css
def minify_js(js: str, mangle: bool = True) -> str:
"""
压缩 JavaScript 代码纯Python实现
Args:
js: JavaScript 源代码
mangle: 是否混淆变量名
Returns:
压缩后的 JavaScript
Example:
>>> minify_js('function test() { return 1; }')
'function test(){return 1}'
"""
# 先混淆变量名(在原始代码上,保持完整语法)
if mangle:
js = _mangle_variables(js)
# 保护字符串和正则表达式
strings = []
def save_string(match):
idx = len(strings)
strings.append(match.group(0))
return f'__STR_{idx}__'
# 保护单引号、双引号和反引号字符串
js = re.sub(r"'(?:[^'\\]|\\.)*'", save_string, js)
js = re.sub(r'"(?:[^"\\]|\\.)*"', save_string, js)
js = re.sub(r'`(?:[^`\\]|\\.)*`', save_string, js)
# 移除单行注释
js = re.sub(r'//[^\n]*', '', js)
# 移除多行注释
js = re.sub(r'/\*[\s\S]*?\*/', '', js)
# 压缩空白
js = re.sub(r'\s+', ' ', js)
# 移除操作符周围的空白
js = re.sub(r'\s*([{}\[\]();,<>=+\-*/%&|!?:])\s*', r'\1', js)
# 关键字后保留空格
for kw in ['return', 'throw', 'new', 'delete', 'typeof', 'void', 'in', 'instanceof', 'else', 'case', 'var', 'let', 'const', 'function', 'class', 'extends', 'async', 'await', 'yield', 'import', 'export', 'from', 'as', 'of']:
js = re.sub(rf'({kw})([a-zA-Z_$])', rf'\1 \2', js)
# 恢复字符串
for i, s in enumerate(strings):
js = js.replace(f'__STR_{i}__', s)
# 移除开头结尾空白
js = js.strip()
return js
def _mangle_variables(js: str) -> str:
"""混淆局部变量名"""
# 保护字符串
strings = []
def save_string(match):
idx = len(strings)
strings.append(match.group(0))
return f'__STR_{idx}__'
js = re.sub(r"'(?:[^'\\]|\\.)*'", save_string, js)
js = re.sub(r'"(?:[^"\\]|\\.)*"', save_string, js)
js = re.sub(r'`(?:[^`\\]|\\.)*`', save_string, js)
# 找到函数作用域内的变量声明
var_pattern = re.compile(r'\b(var|let|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)')
# 生成短变量名
def gen_name(index):
chars = 'abcdefghijklmnopqrstuvwxyz'
if index < 26:
return '_' + chars[index]
return '_' + chars[index // 26 - 1] + chars[index % 26]
# 收集变量
var_map = {}
index = 0
for match in var_pattern.finditer(js):
name = match.group(2)
if name not in var_map and name not in ['undefined', 'null', 'true', 'false', 'NaN', 'Infinity']:
var_map[name] = gen_name(index)
index += 1
# 替换变量(从长到短排序避免部分替换)
for old_name in sorted(var_map.keys(), key=len, reverse=True):
new_name = var_map[old_name]
# 只替换完整单词
js = re.sub(rf'\b{re.escape(old_name)}\b', new_name, js)
# 恢复字符串
for i, s in enumerate(strings):
js = js.replace(f'__STR_{i}__', s)
return js
def minify_html(html: str, minify_inline: bool = True) -> str:
"""
压缩 HTML 代码
Args:
html: HTML 源代码
minify_inline: 是否压缩内联的CSS/JS
Returns:
压缩后的 HTML
"""
# 保护 <pre>、<script>、<style>、<textarea> 内容
preserved = []
def save_block(tag_name):
def replacer(match):
idx = len(preserved)
preserved.append(match.group(0))
return f'__BLOCK_{idx}__'
return replacer
# 保存这些标签的内容
for tag in ['pre', 'code', 'textarea']:
html = re.sub(rf'<{tag}[^>]*>[\s\S]*?</{tag}>', save_block(tag), html, flags=re.IGNORECASE)
# 处理 script 和 style
if minify_inline:
# 压缩内联 JS
def process_script(match):
attrs = match.group(1)
content = match.group(2)
# 跳过外部脚本
if 'src=' in attrs.lower():
return match.group(0)
minified = minify_js(content, mangle=False)
return f'<script{attrs}>{minified}</script>'
html = re.sub(r'<script([^>]*)>([\s\S]*?)</script>', process_script, html, flags=re.IGNORECASE)
# 压缩内联 CSS
def process_style(match):
attrs = match.group(1)
content = match.group(2)
minified = minify_css(content)
return f'<style{attrs}>{minified}</style>'
html = re.sub(r'<style([^>]*)>([\s\S]*?)</style>', process_style, html, flags=re.IGNORECASE)
else:
# 保护 script 和 style
html = re.sub(r'<script[^>]*>[\s\S]*?</script>', save_block('script'), html, flags=re.IGNORECASE)
html = re.sub(r'<style[^>]*>[\s\S]*?</style>', save_block('style'), html, flags=re.IGNORECASE)
# 移除 HTML 注释
html = re.sub(r'<!--[\s\S]*?-->', '', html)
# 压缩空白(但保留单个空格)
html = re.sub(r'\s+', ' ', html)
# 移除标签周围的空白
html = re.sub(r'>\s+<', '><', html)
# 移除属性值周围的引号(可选值)
# html = re.sub(r'=\s*"([^"\s]+)"', r'=\1', html)
# 移除冗余属性
html = re.sub(r'\s+type\s*=\s*["\']?text/javascript["\']?', '', html, flags=re.IGNORECASE)
html = re.sub(r'\s+type\s*=\s*["\']?text/css["\']?', '', html, flags=re.IGNORECASE)
# 恢复保护的内容
for i, block in enumerate(preserved):
html = html.replace(f'__BLOCK_{i}__', block)
return html.strip()
# ============== Node.js 工具调用 ==============
def _check_node() -> bool:
"""检查 Node.js 是否可用"""
return shutil.which('node') is not None
def _check_npm_package(package: str) -> bool:
"""检查 npm 包是否安装"""
try:
result = subprocess.run(
['npm', 'list', package],
capture_output=True,
text=True,
timeout=10
)
return result.returncode == 0
except:
return False
def minify_css_node(css: str) -> str:
"""
使用 clean-css (Node.js) 压缩 CSS
如果 Node.js 不可用,自动降级到纯 Python 实现。
"""
if not _check_node():
return minify_css(css)
try:
# 写入临时文件
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.css', delete=False, encoding='utf-8') as f:
f.write(css)
temp_path = f.name
# 调用 cleancss
result = subprocess.run(
['npx', 'cleancss', temp_path],
capture_output=True,
text=True,
timeout=30
)
os.unlink(temp_path)
if result.returncode == 0 and result.stdout:
return result.stdout
else:
return minify_css(css)
except Exception:
return minify_css(css)
def minify_js_node(js: str, mangle: bool = True) -> str:
"""
使用 Terser (Node.js) 压缩混淆 JavaScript
如果 Node.js 不可用,自动降级到纯 Python 实现。
"""
if not _check_node():
return minify_js(js, mangle)
try:
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False, encoding='utf-8') as f:
f.write(js)
temp_path = f.name
cmd = ['npx', 'terser', temp_path, '--compress', '--format', 'comments=false']
if mangle:
cmd.append('--mangle')
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=30
)
os.unlink(temp_path)
if result.returncode == 0 and result.stdout:
return result.stdout
else:
return minify_js(js, mangle)
except Exception:
return minify_js(js, mangle)
def minify_html_node(html: str) -> str:
"""
使用 html-minifier-terser (Node.js) 压缩 HTML
如果 Node.js 不可用,自动降级到纯 Python 实现。
"""
if not _check_node():
return minify_html(html)
try:
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8') as f:
f.write(html)
temp_path = f.name
result = subprocess.run(
['npx', 'html-minifier-terser',
'--collapse-whitespace',
'--remove-comments',
'--minify-css', 'true',
'--minify-js', 'true',
temp_path],
capture_output=True,
text=True,
timeout=30
)
os.unlink(temp_path)
if result.returncode == 0 and result.stdout:
return result.stdout
else:
return minify_html(html)
except Exception:
return minify_html(html)
# ============== 高级混淆功能 ==============
def obfuscate_identifiers(js: str) -> str:
"""
混淆 JavaScript 标识符(变量名、函数名)
Args:
js: JavaScript 源代码
Returns:
混淆后的代码
"""
# 保护字符串和正则
protected = []
def save_protected(match):
idx = len(protected)
protected.append(match.group(0))
return f'__PROT_{idx}__'
# 保护字符串
js = re.sub(r"'(?:[^'\\]|\\.)*'", save_protected, js)
js = re.sub(r'"(?:[^"\\]|\\.)*"', save_protected, js)
js = re.sub(r'`(?:[^`\\]|\\.)*`', save_protected, js)
# 保护正则
js = re.sub(r'/(?![/*])(?:[^/\\]|\\.)+/[gimsuy]*', save_protected, js)
# 收集声明的变量和函数
declarations = set()
# var/let/const 声明
for match in re.finditer(r'\b(?:var|let|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)', js):
declarations.add(match.group(1))
# function 声明
for match in re.finditer(r'\bfunction\s+([a-zA-Z_$][a-zA-Z0-9_$]*)', js):
declarations.add(match.group(1))
# 生成混淆名
def gen_name(index):
# 使用 _$0, _$1, ... 格式
return f'_${index:x}'
# 过滤保留字和内置对象
reserved = {
'undefined', 'null', 'true', 'false', 'NaN', 'Infinity',
'Object', 'Array', 'String', 'Number', 'Boolean', 'Function',
'Symbol', 'BigInt', 'Math', 'Date', 'RegExp', 'Error',
'JSON', 'console', 'window', 'document', 'navigator',
'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
'Promise', 'async', 'await', 'class', 'extends', 'super',
'this', 'new', 'delete', 'typeof', 'instanceof', 'in',
'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'break',
'continue', 'return', 'throw', 'try', 'catch', 'finally',
'import', 'export', 'default', 'from', 'as', 'of',
'arguments', 'eval', 'with', 'debugger',
'crypto', 'fetch', 'Response', 'Request', 'Headers', 'URL',
'TextEncoder', 'TextDecoder', 'Uint8Array', 'ArrayBuffer',
'atob', 'btoa', 'encodeURIComponent', 'decodeURIComponent',
}
# 创建映射
name_map = {}
idx = 0
for name in sorted(declarations, key=len, reverse=True):
if name not in reserved and len(name) > 1:
name_map[name] = gen_name(idx)
idx += 1
# 替换
for old_name, new_name in name_map.items():
js = re.sub(rf'\b{re.escape(old_name)}\b', new_name, js)
# 恢复保护的内容
for i, p in enumerate(protected):
js = js.replace(f'__PROT_{i}__', p)
return js
def add_dead_code(js: str, complexity: int = 2) -> str:
"""
添加无效代码增加逆向难度
Args:
js: JavaScript 源代码
complexity: 复杂度 (1-5)
Returns:
添加死代码后的代码
"""
dead_code_templates = [
'var _$d0=function(){return Math.random()>2};',
'var _$d1=(function(){var _=[];for(var i=0;i<0;i++)_.push(i);return _})();',
'if(typeof _$d2==="undefined")var _$d2=null;',
'try{if(false)throw new Error()}catch(_$e){}',
'var _$d3=Date.now()%1===2?1:0;',
]
import random
dead_codes = random.sample(dead_code_templates, min(complexity, len(dead_code_templates)))
# 在代码开头添加
return ''.join(dead_codes) + js
# ============== 统一接口 ==============
def minify(
content: str,
content_type: str = 'auto',
use_node: bool = True,
mangle: bool = True
) -> str:
"""
统一的压缩混淆接口
Args:
content: 源代码
content_type: 类型 ('html', 'css', 'js', 'auto')
use_node: 是否尝试使用 Node.js 工具
mangle: 是否混淆变量名(仅 JS
Returns:
压缩后的代码
Example:
>>> minify('body { color: red; }', 'css')
'body{color:red}'
>>> minify('<html>...</html>', 'html')
'<html>...</html>'
"""
# 自动检测类型
if content_type == 'auto':
content_lower = content.strip().lower()
if content_lower.startswith('<!doctype') or content_lower.startswith('<html'):
content_type = 'html'
elif '{' in content and (':' in content or '@' in content):
# 可能是 CSS
if re.search(r'[.#]?[\w-]+\s*\{', content):
content_type = 'css'
else:
content_type = 'js'
else:
content_type = 'js'
# 调用对应的压缩函数
if content_type == 'html':
return minify_html_node(content) if use_node else minify_html(content)
elif content_type == 'css':
return minify_css_node(content) if use_node else minify_css(content)
else: # js
result = minify_js_node(content, mangle) if use_node else minify_js(content, mangle)
return result
def minify_file(
input_path: str,
output_path: Optional[str] = None,
use_node: bool = True,
mangle: bool = True
) -> str:
"""
压缩混淆文件
Args:
input_path: 输入文件路径
output_path: 输出文件路径(默认添加 .min 后缀)
use_node: 是否使用 Node.js 工具
mangle: 是否混淆变量名
Returns:
输出文件路径
Example:
>>> minify_file('app.js')
'app.min.js'
>>> minify_file('style.css', 'dist/style.css')
'dist/style.css'
"""
# 读取文件
with open(input_path, 'r', encoding='utf-8') as f:
content = f.read()
# 检测类型
ext = os.path.splitext(input_path)[1].lower()
if ext in ['.html', '.htm']:
content_type = 'html'
elif ext == '.css':
content_type = 'css'
elif ext == '.js':
content_type = 'js'
else:
content_type = 'auto'
# 压缩
minified = minify(content, content_type, use_node, mangle)
# 输出路径
if output_path is None:
base, ext = os.path.splitext(input_path)
output_path = f"{base}.min{ext}"
# 写入
with open(output_path, 'w', encoding='utf-8') as f:
f.write(minified)
return output_path
# ============== 控制流扁平化 ==============
def flatten_control_flow(js: str, intensity: int = 2) -> str:
"""
控制流扁平化 - 将顺序执行的代码块打乱为 switch-case 结构
Args:
js: JavaScript 源代码
intensity: 扁平化强度 (1-3)
1: 仅扁平化顶层语句
2: 扁平化函数体内语句
3: 递归扁平化所有代码块
Returns:
扁平化后的 JavaScript 代码
Example:
原始代码:
step1(); step2(); step3();
扁平化后:
var _$s=[2,1,3,0],_$i=0;
while(_$s[_$i]!==0){
switch(_$s[_$i++]){
case 1:step1();break;
case 2:step2();break;
case 3:step3();break;
}
}
"""
import random
# 保护字符串和正则
protected = []
def save_protected(match):
idx = len(protected)
protected.append(match.group(0))
return f'__PROT_{idx}__'
js = re.sub(r"'(?:[^'\\]|\\.)*'", save_protected, js)
js = re.sub(r'"(?:[^"\\]|\\.)*"', save_protected, js)
js = re.sub(r'`(?:[^`\\]|\\.)*`', save_protected, js)
js = re.sub(r'/(?![/*])(?:[^/\\]|\\.)+/[gimsuy]*', save_protected, js)
def flatten_block(code: str, depth: int = 0) -> str:
"""扁平化一个代码块"""
if depth >= intensity:
return code
# 分割语句(简化版本,处理基本情况)
statements = _split_statements(code)
if len(statements) < 3:
return code
# 过滤空语句
statements = [s.strip() for s in statements if s.strip()]
if len(statements) < 3:
return code
# 生成随机编号
indices = list(range(1, len(statements) + 1))
random.shuffle(indices)
indices.append(0) # 结束标志
# 生成唯一变量名
var_s = f'_$s{depth}'
var_i = f'_$i{depth}'
# 构建 switch 语句
cases = []
for i, stmt in enumerate(statements):
case_num = i + 1
# 递归扁平化函数体
if intensity >= 2 and 'function' in stmt:
stmt = _flatten_function_body(stmt, depth + 1, intensity)
cases.append(f'case {case_num}:{stmt};break;')
# 组装结果
order_array = ','.join(str(i) for i in indices)
result = f'var {var_s}=[{order_array}],{var_i}=0;'
result += f'while({var_s}[{var_i}]!==0){{'
result += f'switch({var_s}[{var_i}++]){{'
result += ''.join(cases)
result += '}}'
return result
def _split_statements(code: str) -> list:
"""分割语句(简化版本)"""
statements = []
current = ''
brace_depth = 0
paren_depth = 0
bracket_depth = 0
in_string = None
i = 0
while i < len(code):
c = code[i]
# 检查字符串
if c in '"\'`' and (i == 0 or code[i-1] != '\\'):
if in_string is None:
in_string = c
elif in_string == c:
in_string = None
current += c
i += 1
continue
if in_string:
current += c
i += 1
continue
# 跟踪括号
if c == '{':
brace_depth += 1
elif c == '}':
brace_depth -= 1
elif c == '(':
paren_depth += 1
elif c == ')':
paren_depth -= 1
elif c == '[':
bracket_depth += 1
elif c == ']':
bracket_depth -= 1
# 分割点
if c == ';' and brace_depth == 0 and paren_depth == 0 and bracket_depth == 0:
if current.strip():
statements.append(current.strip())
current = ''
elif c == '}' and brace_depth == 0 and paren_depth == 0 and bracket_depth == 0:
current += c
if current.strip():
statements.append(current.strip())
current = ''
else:
current += c
i += 1
if current.strip():
statements.append(current.strip())
return statements
def _flatten_function_body(func_code: str, depth: int, intensity: int) -> str:
"""扁平化函数体内容"""
# 找到函数体
match = re.search(r'(function[^{]*\{)([\s\S]*)(\})\s*$', func_code)
if not match:
return func_code
prefix = match.group(1)
body = match.group(2)
suffix = match.group(3)
# 扁平化函数体
flattened_body = flatten_block(body, depth)
return prefix + flattened_body + suffix
# 处理整个代码
result = flatten_block(js, 0)
# 恢复保护的内容
for i, p in enumerate(protected):
result = result.replace(f'__PROT_{i}__', p)
return result
def flatten_control_flow_safe(js: str) -> str:
"""
安全的控制流扁平化(仅处理简单函数)
此版本更保守,只处理明确可以扁平化的代码块,
避免破坏复杂语法结构。
Args:
js: JavaScript 源代码
Returns:
扁平化后的代码
"""
import random
# 保护字符串、正则、模板字符串
protected = []
def save_protected(match):
idx = len(protected)
protected.append(match.group(0))
return f'__PROT_{idx}__'
js = re.sub(r"'(?:[^'\\]|\\.)*'", save_protected, js)
js = re.sub(r'"(?:[^"\\]|\\.)*"', save_protected, js)
js = re.sub(r'`(?:[^`\\]|\\.)*`', save_protected, js)
# 找到简单的立即执行函数 (IIFE)
def process_iife(match):
inner = match.group(1)
# 分割为简单语句
stmts = [s.strip() for s in inner.split(';') if s.strip()]
if len(stmts) < 3:
return match.group(0)
# 过滤包含控制流语句的代码
for stmt in stmts:
if any(kw in stmt for kw in ['if', 'for', 'while', 'switch', 'try', 'function']):
return match.group(0)
# 生成扁平化代码
indices = list(range(1, len(stmts) + 1))
random.shuffle(indices)
indices.append(0)
order = ','.join(str(i) for i in indices)
cases = ''.join('case {}:{};break;'.format(i+1, stmts[i]) for i in range(len(stmts)))
return '(function(){{var _$f=[{}],_$g=0;while(_$f[_$g]!==0){{switch(_$f[_$g++]){{{}}}}}}}})()'.format(order, cases)
# 处理 IIFE
js = re.sub(r'\(function\(\)\{([^{}]*)\}\)\(\)', process_iife, js)
# 恢复保护的内容
for i, p in enumerate(protected):
js = js.replace(f'__PROT_{i}__', p)
return js

411
x27cn/x27cn/password.py Normal file
View File

@@ -0,0 +1,411 @@
"""
X27CN 密码加密模块
提供安全的密码哈希和验证功能:
- PBKDF2-SHA256 密码哈希(适合密码存储)
- 密码强度检测
- 基于密码的加密/解密
"""
import os
import re
import hashlib
import hmac
import base64
import secrets
from typing import Tuple, Optional
# ============== 密码哈希 ==============
def hash_password(
password: str,
salt: Optional[bytes] = None,
iterations: int = 100000
) -> str:
"""
使用 PBKDF2-SHA256 哈希密码
Args:
password: 明文密码
salt: 盐值可选默认自动生成16字节
iterations: 迭代次数默认100000越高越安全但越慢
Returns:
格式化的哈希字符串: $x27cn$iterations$salt$hash
Example:
>>> hashed = hash_password('mypassword123')
>>> print(hashed)
'$x27cn$100000$abc123...$def456...'
"""
if salt is None:
salt = os.urandom(16)
# PBKDF2-SHA256 派生
dk = hashlib.pbkdf2_hmac(
'sha256',
password.encode('utf-8'),
salt,
iterations,
dklen=32
)
# 编码为 base64
salt_b64 = base64.b64encode(salt).decode('ascii')
hash_b64 = base64.b64encode(dk).decode('ascii')
return f'$x27cn${iterations}${salt_b64}${hash_b64}'
def verify_password(password: str, hashed: str) -> bool:
"""
验证密码是否匹配哈希
Args:
password: 待验证的明文密码
hashed: hash_password 返回的哈希字符串
Returns:
密码是否正确
Example:
>>> hashed = hash_password('mypassword123')
>>> verify_password('mypassword123', hashed)
True
>>> verify_password('wrongpassword', hashed)
False
"""
try:
parts = hashed.split('$')
if len(parts) != 5 or parts[1] != 'x27cn':
return False
iterations = int(parts[2])
salt = base64.b64decode(parts[3])
expected_hash = base64.b64decode(parts[4])
# 重新计算
dk = hashlib.pbkdf2_hmac(
'sha256',
password.encode('utf-8'),
salt,
iterations,
dklen=32
)
# 使用恒定时间比较防止时序攻击
return hmac.compare_digest(dk, expected_hash)
except Exception:
return False
# ============== 密码强度 ==============
def check_password_strength(password: str) -> dict:
"""
检测密码强度
Args:
password: 待检测的密码
Returns:
包含强度信息的字典:
- score: 分数 (0-100)
- level: 等级 ('weak', 'fair', 'good', 'strong', 'excellent')
- suggestions: 改进建议列表
Example:
>>> result = check_password_strength('abc123')
>>> print(result['level'])
'weak'
"""
score = 0
suggestions = []
length = len(password)
# 长度评分
if length >= 16:
score += 30
elif length >= 12:
score += 25
elif length >= 8:
score += 15
elif length >= 6:
score += 10
else:
suggestions.append('密码长度至少需要8个字符')
# 复杂性评分
has_lower = bool(re.search(r'[a-z]', password))
has_upper = bool(re.search(r'[A-Z]', password))
has_digit = bool(re.search(r'[0-9]', password))
has_special = bool(re.search(r'[!@#$%^&*(),.?":{}|<>_\-+=\[\]\\\/`~]', password))
complexity = sum([has_lower, has_upper, has_digit, has_special])
score += complexity * 15
if not has_lower:
suggestions.append('添加小写字母')
if not has_upper:
suggestions.append('添加大写字母')
if not has_digit:
suggestions.append('添加数字')
if not has_special:
suggestions.append('添加特殊字符 (!@#$%^&* 等)')
# 熵评分(字符多样性)
unique_chars = len(set(password))
if unique_chars >= 10:
score += 10
elif unique_chars >= 6:
score += 5
# 常见模式扣分
common_patterns = [
r'123', r'abc', r'qwerty', r'password', r'admin',
r'111', r'000', r'aaa', r'(.)\1{2,}' # 连续重复字符
]
for pattern in common_patterns:
if re.search(pattern, password.lower()):
score -= 10
if pattern == r'(.)\1{2,}':
suggestions.append('避免连续重复的字符')
else:
suggestions.append('避免使用常见模式')
break
# 限制分数范围
score = max(0, min(100, score))
# 确定等级
if score >= 80:
level = 'excellent'
elif score >= 60:
level = 'strong'
elif score >= 40:
level = 'good'
elif score >= 20:
level = 'fair'
else:
level = 'weak'
return {
'score': score,
'level': level,
'suggestions': suggestions,
'length': length,
'has_lower': has_lower,
'has_upper': has_upper,
'has_digit': has_digit,
'has_special': has_special,
}
# ============== 密码生成 ==============
def generate_password(
length: int = 16,
include_upper: bool = True,
include_lower: bool = True,
include_digits: bool = True,
include_special: bool = True,
exclude_ambiguous: bool = True
) -> str:
"""
生成安全的随机密码
Args:
length: 密码长度默认16
include_upper: 包含大写字母
include_lower: 包含小写字母
include_digits: 包含数字
include_special: 包含特殊字符
exclude_ambiguous: 排除易混淆字符 (0O1lI)
Returns:
随机密码
Example:
>>> pwd = generate_password(20)
>>> print(len(pwd))
20
"""
chars = ''
required = []
lower_chars = 'abcdefghijkmnopqrstuvwxyz' if exclude_ambiguous else 'abcdefghijklmnopqrstuvwxyz'
upper_chars = 'ABCDEFGHJKMNPQRSTUVWXYZ' if exclude_ambiguous else 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
digit_chars = '23456789' if exclude_ambiguous else '0123456789'
special_chars = '!@#$%^&*-_=+?'
if include_lower:
chars += lower_chars
required.append(secrets.choice(lower_chars))
if include_upper:
chars += upper_chars
required.append(secrets.choice(upper_chars))
if include_digits:
chars += digit_chars
required.append(secrets.choice(digit_chars))
if include_special:
chars += special_chars
required.append(secrets.choice(special_chars))
if not chars:
raise ValueError('至少需要选择一种字符类型')
# 生成剩余字符
remaining = length - len(required)
password_chars = required + [secrets.choice(chars) for _ in range(remaining)]
# 打乱顺序
secrets.SystemRandom().shuffle(password_chars)
return ''.join(password_chars)
# ============== 基于密码的加密 ==============
def encrypt_with_password(plaintext: str, password: str) -> str:
"""
使用密码加密数据
使用 PBKDF2 派生加密密钥,然后用 X27CN 算法加密。
输出格式为 <xxxx> 标准格式,盐值编码在开头。
Args:
plaintext: 明文数据
password: 加密密码
Returns:
加密后的密文(<xxxx> 格式,包含盐值)
Example:
>>> encrypted = encrypt_with_password('secret data', 'mypassword')
>>> # 输出: <p7d0><salt16bytes><encrypted...>
>>> decrypted = decrypt_with_password(encrypted, 'mypassword')
>>> print(decrypted)
'secret data'
"""
from .core import encrypt
# 生成随机盐16字节
salt = os.urandom(16)
# 派生密钥
key = hashlib.pbkdf2_hmac(
'sha256',
password.encode('utf-8'),
salt,
50000,
dklen=32
)
key_str = base64.b64encode(key).decode('ascii')[:32]
# 加密数据
encrypted = encrypt(plaintext, key_str)
# 将盐值编码为 <xxxx> 格式
salt_hex = ''.join(f'<{b:02x}>' for b in salt)
# 添加魔数标识 <p7d0> 表示密码加密
return f'<p7d0>{salt_hex}{encrypted}'
def decrypt_with_password(ciphertext: str, password: str) -> str:
"""
使用密码解密数据
Args:
ciphertext: encrypt_with_password 返回的密文(<xxxx> 格式)
password: 解密密码
Returns:
解密后的明文
Raises:
ValueError: 密码错误或数据损坏
Example:
>>> encrypted = encrypt_with_password('hello', 'pass123')
>>> decrypt_with_password(encrypted, 'pass123')
'hello'
"""
from .core import decrypt
try:
# 检查魔数
if not ciphertext.startswith('<p7d0>'):
raise ValueError('无效的密文格式(缺少密码加密标识)')
# 移除魔数
data = ciphertext[6:] # 去掉 <p7d0>
# 提取盐值16字节 = 16个 <xx> 块 = 64字符
salt_part = data[:64] # 16 * 4 = 64
encrypted_data = data[64:]
# 解析盐值
salt_bytes = []
import re
salt_matches = re.findall(r'<([0-9a-fA-F]{2})>', salt_part)
if len(salt_matches) != 16:
raise ValueError('无效的盐值格式')
salt = bytes(int(h, 16) for h in salt_matches)
# 派生密钥
key = hashlib.pbkdf2_hmac(
'sha256',
password.encode('utf-8'),
salt,
50000,
dklen=32
)
key_str = base64.b64encode(key).decode('ascii')[:32]
# 解密
return decrypt(encrypted_data, key_str)
except ValueError:
raise
except Exception as e:
raise ValueError(f'解密失败(密码可能错误): {e}')
# ============== 快速哈希 ==============
def quick_hash(data: str, algorithm: str = 'sha256') -> str:
"""
快速计算字符串哈希值
Args:
data: 要哈希的数据
algorithm: 算法 ('md5', 'sha1', 'sha256', 'sha512')
Returns:
十六进制哈希值
Example:
>>> quick_hash('hello')
'2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
"""
h = hashlib.new(algorithm)
h.update(data.encode('utf-8'))
return h.hexdigest()
def md5(data: str) -> str:
"""计算 MD5 哈希"""
return quick_hash(data, 'md5')
def sha256(data: str) -> str:
"""计算 SHA256 哈希"""
return quick_hash(data, 'sha256')
def sha512(data: str) -> str:
"""计算 SHA512 哈希"""
return quick_hash(data, 'sha512')

File diff suppressed because one or more lines are too long

View File

@@ -197,6 +197,14 @@ export default {
const userAgent = request.headers.get('User-Agent') || 'null';
const upgradeHeader = request.headers.get('Upgrade');
// 获取原始主机名 (支持 EdgeOne/CDN 回源)
// 优先级: 环境变量 > X-Forwarded-Host > Host 头 > url.hostname
const originalHost = env.CUSTOM_HOST || env.HOST ||
request.headers.get('X-Forwarded-Host') ||
request.headers.get('X-Original-Host') ||
request.headers.get('Host') ||
url.hostname;
// 获取管理员密码和加密密钥
const adminPassword = env.ADMIN || env.admin || env.PASSWORD || env.password ||
env.pswd || env.TOKEN || env.KEY || env.UUID || env.uuid || 'cfspider-public';
@@ -268,7 +276,7 @@ export default {
// /x2727admin - 返回加密的密钥提示
if (path === 'x2727admin') {
const fullUrl = `https://${url.hostname}/x2727admin/${accessKey}`;
const fullUrl = `https://${originalHost}/x2727admin/${accessKey}`;
// 构建提示信息
const message = `您的密钥为: ${accessKey}
@@ -316,13 +324,13 @@ ${fullUrl}
// 密钥验证通过,返回加密的配置信息
const colo = request.cf?.colo || 'UNKNOWN';
const vlessPath = '/' + userID + (twoProxy ? '?two_proxy=' + encodeURIComponent(twoProxy) : '');
const vlessLink = `vless://${userID}@${url.hostname}:443?security=tls&type=ws&host=${url.hostname}&sni=${url.hostname}&path=${encodeURIComponent(vlessPath)}&encryption=none#Node-${colo}`;
const vlessLink = `vless://${userID}@${originalHost}:443?security=tls&type=ws&host=${originalHost}&sni=${originalHost}&path=${encodeURIComponent(vlessPath)}&encryption=none#Node-${colo}`;
const configData = {
status: 'online',
version: '1.8.7',
colo: colo,
host: url.hostname,
host: originalHost,
uuid: userID,
vless: vlessLink,
two_proxy: twoProxy || null,