mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 13:40:45 +00:00
ykxmz 1.5.0:修复手表端 TLS 证书校验 + MTU 修复网络稳定性
被控端 - 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%) - 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败) - 每分钟回头找局域网,自动切回快 400 倍的路径 - 画面心跳帧:静止时省流量,客户端仍知道流是活的 - 锁屏时给出可操作的提示 手表端 - 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException - 连接错误翻译成人话(证书/时间/解析/超时分别提示) - 经中转连上后用服务器报的地址刷新已配对记录 - 新增局域网连接页面、服务器延迟检测 服务器端 - 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502) - 网络调优脚本 net-tune.sh(开机自动应用) - 管理页:批量删除、网络体检、下载区 - 隧道改 HTTP/2 + 双连接 文档 - 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""全项目编码审计(收窄版)。
|
||||
|
||||
上一版太吵:把 Java 字节码、测试用的 .bin、还有审计脚本自己
|
||||
(源码里就写着乱码样本)全当成文本查了。
|
||||
|
||||
这一版:
|
||||
* 用**内容**判断是不是二进制(不是只看扩展名)
|
||||
* 跳过编译产物和测试数据目录
|
||||
* 跳过审计脚本自己
|
||||
|
||||
只查真正要交付和要跑的东西。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
SELF = Path(__file__).resolve()
|
||||
|
||||
# 这些目录是产物/数据,不是源码
|
||||
SKIP_DIRS = {
|
||||
"_build", "__pycache__", ".git", "dist_exe", "dist", "pyinstaller_work",
|
||||
"node_modules", "out_java", "received", "gen", "javacheck", "javacheck2",
|
||||
"javacheck3", "javacheck4", "javacheck5", "build_tmp", "toolchain",
|
||||
}
|
||||
SKIP_SUFFIX = {
|
||||
".pyc", ".png", ".jpg", ".jpeg", ".gif", ".ico", ".apk", ".exe", ".dll",
|
||||
".pyd", ".zip", ".idsig", ".so", ".class", ".bin", ".jar", ".keystore",
|
||||
".jks", ".der", ".pem", ".7z",
|
||||
}
|
||||
|
||||
MOJIBAKE = [
|
||||
"锟斤拷", "�", "â€", "ä", "é", "è", "а", "Ñ€",
|
||||
"\ufffd",
|
||||
"ä¸", "å¤", "æµ", "è¯", "é€",
|
||||
]
|
||||
|
||||
# 只查这些扩展名(其余一律不问)
|
||||
TEXT_SUFFIX = {".py", ".java", ".ps1", ".sh", ".bat", ".cmd", ".txt",
|
||||
".md", ".json", ".yml", ".yaml", ".xml", ".gradle", ".cfg",
|
||||
".ini", ".properties", ".pro", ".service", ".timer"}
|
||||
|
||||
problems = []
|
||||
stats = {}
|
||||
scanned = 0
|
||||
|
||||
|
||||
def report(level: str, path, message: str) -> None:
|
||||
label = str(path.relative_to(ROOT)) if isinstance(path, Path) \
|
||||
and str(path).startswith(str(ROOT)) else str(path)
|
||||
problems.append((level, label, message))
|
||||
|
||||
|
||||
def looks_binary(body: bytes) -> bool:
|
||||
if b"\x00" in body[:4096]:
|
||||
return True
|
||||
# 非文本字节比例过高就当二进制
|
||||
sample = body[:4096]
|
||||
if not sample:
|
||||
return False
|
||||
weird = sum(1 for byte in sample
|
||||
if byte < 8 or (14 <= byte < 32 and byte != 27))
|
||||
return weird / len(sample) > 0.10
|
||||
|
||||
|
||||
def check_bytes(path, name: str, suffix: str, raw: bytes) -> None:
|
||||
"""对一份内容做编码检查。path 只用于报错定位。"""
|
||||
global scanned
|
||||
scanned += 1
|
||||
stats[suffix] = stats.get(suffix, 0) + 1
|
||||
|
||||
has_bom = raw.startswith(b"\xef\xbb\xbf")
|
||||
body = raw[3:] if has_bom else raw
|
||||
|
||||
# .bat 走特殊逻辑:cmd.exe 在中文 Windows 上默认代码页 936,
|
||||
# 所以 .bat 里要写中文就必须是 **GBK**(UTF-8 的中文会变乱码)。
|
||||
# 纯 ASCII 的 .bat 两种代码页下都对,最保险。
|
||||
if suffix in (".bat", ".cmd"):
|
||||
if has_bom:
|
||||
report("警告", path, f"{name} 有 BOM(cmd 会把 BOM 当命令)")
|
||||
try:
|
||||
text = body.decode("gbk")
|
||||
encoding_name = "GBK"
|
||||
except UnicodeDecodeError:
|
||||
try:
|
||||
text = body.decode("utf-8")
|
||||
if any("\u4e00" <= ch <= "\u9fff" for ch in text):
|
||||
report("严重", path,
|
||||
f"{name} 是 UTF-8 且含中文 —— cmd.exe 下会乱码,应为 GBK")
|
||||
encoding_name = "UTF-8(纯ASCII)"
|
||||
except UnicodeDecodeError as exc:
|
||||
report("严重", path, f"{name} GBK/UTF-8 都解不开:{exc}")
|
||||
return
|
||||
crlf = body.count(b"\r\n")
|
||||
lf_only = body.count(b"\n") - crlf
|
||||
if lf_only:
|
||||
report("警告", path, f"{name} 有 {lf_only} 处纯 LF(.bat 应为 CRLF)")
|
||||
stats[suffix] = stats.get(suffix, 0) + 1
|
||||
scanned += 1
|
||||
return
|
||||
|
||||
try:
|
||||
text = body.decode("utf-8")
|
||||
except UnicodeDecodeError as exc:
|
||||
report("严重", path, f"{name} 不是合法 UTF-8:{exc}")
|
||||
return
|
||||
|
||||
if suffix == ".ps1" and not has_bom:
|
||||
report("严重", path, f"{name} 缺 UTF-8 BOM(PowerShell 5.1 会按 GBK 读)")
|
||||
if suffix in (".py", ".java", ".sh") and has_bom:
|
||||
report("警告", path, f"{name} 不应有 BOM")
|
||||
if suffix in (".bat", ".cmd") and has_bom:
|
||||
report("警告", path, f"{name} 不应有 BOM")
|
||||
|
||||
for token in MOJIBAKE:
|
||||
if token in text:
|
||||
line = next((i + 1 for i, l in enumerate(text.splitlines())
|
||||
if token in l), 0)
|
||||
report("严重", path, f"{name} 疑似乱码 {token!r}(第 {line} 行)")
|
||||
break
|
||||
|
||||
crlf = body.count(b"\r\n")
|
||||
lf_only = body.count(b"\n") - crlf
|
||||
cr_only = body.count(b"\r") - crlf
|
||||
|
||||
if suffix == ".sh" and (crlf or cr_only):
|
||||
report("严重", path, f"{name} 有 CR(CRLF {crlf} 处)—— Linux 上跑不起来")
|
||||
if suffix in (".bat", ".cmd") and lf_only:
|
||||
report("警告", path, f"{name} 有 {lf_only} 处纯 LF")
|
||||
if cr_only:
|
||||
report("警告", path, f"{name} 有 {cr_only} 处孤立 CR")
|
||||
if crlf and lf_only and suffix not in (".bat", ".cmd"):
|
||||
report("提示", path, f"{name} 行尾混用(CRLF {crlf} / LF {lf_only})")
|
||||
|
||||
|
||||
def check_zip(zip_path: Path) -> None:
|
||||
if not zip_path.is_file():
|
||||
return
|
||||
print(f" 交付包:{zip_path.name}")
|
||||
with zipfile.ZipFile(zip_path) as archive:
|
||||
for name in archive.namelist():
|
||||
if name.endswith("/"):
|
||||
continue
|
||||
suffix = Path(name).suffix.lower()
|
||||
if suffix not in TEXT_SUFFIX:
|
||||
continue
|
||||
raw = archive.read(name)
|
||||
if not raw or looks_binary(raw):
|
||||
continue
|
||||
check_bytes(zip_path, f"包内 {name}", suffix, raw)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
print("=" * 74)
|
||||
print(" 编码审计(只查要交付 / 要跑的文本文件)")
|
||||
print("=" * 74)
|
||||
|
||||
targets = []
|
||||
for path in ROOT.rglob("*"):
|
||||
if not path.is_file() or path.resolve() == SELF:
|
||||
continue
|
||||
rel = path.relative_to(ROOT)
|
||||
if set(rel.parts) & SKIP_DIRS:
|
||||
continue
|
||||
if path.suffix.lower() in SKIP_SUFFIX:
|
||||
continue
|
||||
if path.suffix.lower() not in TEXT_SUFFIX:
|
||||
continue
|
||||
targets.append(path)
|
||||
|
||||
print(f" 源码目录扫描 {len(targets)} 个文本文件…")
|
||||
for path in sorted(targets):
|
||||
raw = path.read_bytes()
|
||||
if not raw or looks_binary(raw):
|
||||
continue
|
||||
check_bytes(path, path.name, path.suffix.lower(), raw)
|
||||
|
||||
print()
|
||||
check_zip(ROOT / "dist" / "ykxmz-1.4.0.zip")
|
||||
|
||||
print()
|
||||
print(" 按类型统计:")
|
||||
for suffix, count in sorted(stats.items(), key=lambda x: -x[1]):
|
||||
print(f" {suffix:<12} {count:>5} 个")
|
||||
|
||||
print()
|
||||
print("=" * 74)
|
||||
if not problems:
|
||||
print(" ✓ 全部通过,没有编码问题")
|
||||
return 0
|
||||
|
||||
by_level: dict = {}
|
||||
for level, path, message in problems:
|
||||
by_level.setdefault(level, []).append((path, message))
|
||||
|
||||
for level in ("严重", "警告", "提示"):
|
||||
items = by_level.get(level, [])
|
||||
if not items:
|
||||
continue
|
||||
print(f" 【{level}】{len(items)} 条")
|
||||
for path, message in items[:20]:
|
||||
print(f" {path}")
|
||||
print(f" {message}")
|
||||
if len(items) > 20:
|
||||
print(f" …还有 {len(items) - 20} 条")
|
||||
print()
|
||||
print(f" 合计 {len(problems)} 条")
|
||||
return 1 if by_level.get("严重") else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user