Files
ykxmz/_tests/fuzz_features.py
T
xmz7891 b62ac865ea 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 + 双连接

文档
- 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
2026-10-06 19:01:05 +08:00

274 lines
10 KiB
Python
Raw 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.
# -*- coding: utf-8 -*-
"""功能全量模糊测试:找出会"崩"的功能。
约定:参数不合法应该抛 ValueError(会被转成给用户看的错误提示)。
抛其它异常(TypeError / KeyError / AttributeError / IndexError / OSError…)
就是 bug。
设计要点(第一版太慢,这里改过):
* 只 fuzz 功能**自己声明**的参数(key / key2),不再瞎塞 13 个 key。
之前 perf / installed_apps 这类会真去调 PowerShell,被调了几百次。
* 有副作用的功能用 DANGEROUS 列表跳过实测。
* 全屏类每次调用后立刻关掉,避免堆窗口。
"""
from __future__ import annotations
import sys
import tempfile
import tkinter as tk
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "windows"))
# 会真的动系统,不实测
DANGEROUS = {
"empty_recycle", "close_windows", "sign_out", "sleep", "hibernate",
"restart_graphics", "minimize_all", "task_view", "restart_explorer",
"lock_only", "lock_and_off", "clear_clip", "open_recycle", "open_file",
"display_mode", "fade_volume", "monitor_on", "volume_up", "volume_down",
"mute_all", "flush_dns", "password_gen", "cinema_mode", "random_song",
"play_video", "stop_after", "pomodoro", "reminder", "cheer",
"clip_fav_add", "download_file", "qr_code", "speed_test", "public_ip",
}
# 会开全屏窗口的:能测,但测完要关
FULLSCREEN = {
"big_text", "big_text_quiet", "countdown_screen", "roll_call", "whiteboard",
"danmaku", "marquee", "lottery", "dice", "coin_flip", "countdown_321",
"score_board", "score_change", "matrix_rain", "starfield", "dashboard",
"stopwatch",
}
# 读一次就够、不跟参数走的(避免重复 shell 调用拖慢测试)
EXPENSIVE = {
"perf", "disk", "battery", "uptime", "installed_apps", "top_services",
"event_errors", "temperature", "hardware_info", "startup_items",
"scheduled_tasks", "system_detail", "recent_files", "network_speed",
"gpu_info", "arp_devices", "net_adapters", "wifi_password", "disk_by_type",
"world_clock", "timestamp_now", "uuid_gen", "screen_color",
}
JUNK = [None, [], {}, "", "abc", 999999, -1, 0, "a" * 3000]
PASSED = 0
CRASHES: list[tuple[str, str, str]] = []
SLOW_SKIPPED: list[str] = []
def main() -> int:
global PASSED
from lanremote.actions import Actions
from lanremote.config import Store
from lanremote.features import Features
tmp = Path(tempfile.mkdtemp())
store = Store(tmp)
class FakeUI:
root = tk.Tk()
root.withdraw()
def ui_call(self, fn, timeout=5.0):
return fn()
def screen_size(self):
return (1920, 1080)
def notify(self, *a, **k):
pass
def log(self, *a, **k):
pass
def show_message(self, *a, **k):
pass
def close_image(self):
pass
actions = Actions(FakeUI(), store)
features = Features(actions)
defs = {d["name"]: d for d in features.defs()}
print(f"功能总数: {len(defs)}", flush=True)
def cleanup_fullscreen(name):
if name in FULLSCREEN:
try:
features.run("big_text_clear", {})
except Exception: # noqa: BLE001
pass
try:
FakeUI.root.update()
except tk.TclError:
pass
# ---------------- 一、空参数 ----------------
print()
print("=" * 74)
print("一、空参数({})")
print("=" * 74, flush=True)
for name in sorted(defs):
if name in DANGEROUS:
continue
try:
features.run(name, {})
PASSED += 1
except ValueError:
PASSED += 1
except Exception as exc: # noqa: BLE001
CRASHES.append((name, "{}", f"{type(exc).__name__}: {exc}"))
print(f" [崩溃] {name}({{}}) -> {type(exc).__name__}: {exc}", flush=True)
cleanup_fullscreen(name)
# ---------------- 二、垃圾参数 ----------------
print()
print("=" * 74)
print("二、垃圾参数(只喂功能自己声明的 key)")
print("=" * 74, flush=True)
for name in sorted(defs):
if name in DANGEROUS:
continue
spec = defs[name]
keys = [k for k in (spec.get("key"), spec.get("key2")) if k]
if not keys:
continue # 不接参数的功能,上面那轮已经覆盖
if name in EXPENSIVE:
SLOW_SKIPPED.append(name)
continue
for key in keys:
for junk in JUNK:
try:
features.run(name, {key: junk})
PASSED += 1
except ValueError:
PASSED += 1
except Exception as exc: # noqa: BLE001
CRASHES.append((name, f"{key}={junk!r}"[:40],
f"{type(exc).__name__}: {exc}"))
print(f" [崩溃] {name}({key}={junk!r}) -> "
f"{type(exc).__name__}: {exc}", flush=True)
break
cleanup_fullscreen(name)
# ---------------- 三、越权路径 ----------------
print()
print("=" * 74)
print("三、路径越权(必须全部拒绝)")
print("=" * 74, flush=True)
escapes = [
r"C:\Windows\System32\drivers\etc\hosts",
r"..\..\Windows\win.ini",
r"C:\Windows",
"/etc/passwd",
r"\\?\C:\Windows\win.ini",
r"C:Windows\win.ini",
r"\Windows\win.ini",
r"C:\Windows\..\Windows\win.ini",
" C:\\Windows\\win.ini ",
]
for path in escapes:
try:
resolved = features.resolve_in_roots(path)
allowed = [str(r.resolve()).lower() for r in features.allowed_roots()]
inside = any(str(resolved).lower().startswith(a) for a in allowed)
if inside:
PASSED += 1
else:
CRASHES.append(("resolve_in_roots", repr(path),
f"逃出允许范围: {resolved}"))
print(f" [越权!] {path!r} -> {resolved}", flush=True)
except ValueError:
PASSED += 1
except Exception as exc: # noqa: BLE001
CRASHES.append(("resolve_in_roots", repr(path),
f"{type(exc).__name__}: {exc}"))
print(f" [崩溃] {path!r} -> {type(exc).__name__}: {exc}", flush=True)
# 注意:search_files 接的是 keyword(拿去当文件名匹配),不是路径,
# 它本来就逃不出允许目录,所以不放在路径测试里。
file_features = ["list_dir", "make_dir", "rename_file",
"delete_file", "open_file", "copy_file", "move_file",
"zip_dir", "unzip", "file_info", "folder_size"]
for name in file_features:
for path in escapes[:5]:
try:
features.run(name, {"path": path, "to": path, "name": "zz",
"keyword": "zz"})
CRASHES.append((name, repr(path), "越权路径竟然被执行了"))
print(f" [越权!] {name}({path!r}) 竟然执行了", flush=True)
except ValueError:
PASSED += 1
except Exception as exc: # noqa: BLE001
CRASHES.append((name, repr(path), f"{type(exc).__name__}: {exc}"))
print(f" [崩溃] {name}({path!r}) -> "
f"{type(exc).__name__}: {exc}", flush=True)
# ---------------- 四、目录守卫 ----------------
print()
print("=" * 74)
print("四、目录守卫(不能对允许目录本身动手)")
print("=" * 74, flush=True)
for name, params in (("rename_file", {"path": "Downloads", "name": "zz"}),
("delete_file", {"path": "Desktop"}),
("move_file", {"path": "Downloads", "to": "Documents"}),
("copy_file", {"path": "Desktop", "to": "Downloads"})):
try:
features.run(name, params)
CRASHES.append((name, str(params), "竟然允许对允许目录本身动手"))
print(f" [危险!] {name} 竟然允许了", flush=True)
except ValueError:
PASSED += 1
except Exception as exc: # noqa: BLE001
CRASHES.append((name, str(params), f"{type(exc).__name__}: {exc}"))
print(f" [崩溃] {name} -> {type(exc).__name__}: {exc}", flush=True)
# ---------------- 五、数据目录 ----------------
print()
print("五、数据目录(配对码 / 设备令牌)不可访问")
# 用真实的 store.dir 构成绝对路径来测 —— 相对路径会解析到 Downloads 下,
# 那是允许目录,测不出东西。真正的 CWD 相对路径由端到端测试覆盖。
probes = [str(store.dir / "settings.json"), str(store.dir / "devices.json"),
str(store.dir)]
for probe in probes:
try:
features.resolve_in_roots(probe)
CRASHES.append(("resolve_in_roots", probe, "数据目录竟然可访问"))
print(f" [危险!] {probe} 竟然可访问", flush=True)
except ValueError:
PASSED += 1
except Exception as exc: # noqa: BLE001
CRASHES.append(("resolve_in_roots", probe,
f"{type(exc).__name__}: {exc}"))
print(f" [崩溃] {probe} -> {type(exc).__name__}: {exc}", flush=True)
try:
FakeUI.root.destroy()
except tk.TclError:
pass
print()
print("=" * 74)
print("汇总")
print("=" * 74)
print(f" 正常: {PASSED}")
print(f" 崩溃/越权: {len(CRASHES)}")
if SLOW_SKIPPED:
print(f" 跳过的慢功能(只测了空参数): {', '.join(SLOW_SKIPPED)}")
if CRASHES:
print()
print(" ---- 需要修 ----")
seen = set()
for name, arg, err in CRASHES:
key = (name, err.split(":")[0])
if key in seen:
continue
seen.add(key)
print(f" {name}({arg})\n {err}")
return 1 if CRASHES else 0
if __name__ == "__main__":
sys.exit(main())