2.1.4:修 URL 协议头 bug + 清理对外材料里泄漏的服务器信息

用户报了三件事,一起处理。

== 一、发行版介绍里泄漏了服务器公网 IP ==

_build/CHANGELOG.md 的 2.1.3 那节写了服务器公网 IP,而发布脚本
把这个文件当"更新说明"传给 Gitee,于是发行版介绍里就带出去了。

为什么 IP 不该公开:直接打 IP 就绕过 Cloudflare 了 ——
没有 CDN、没有防护、没有速率限制。源站本来就不该被人知道是谁
(这也是为什么 nginx 那层只认域名、中转只绑 127.0.0.1)。

处理:
  * 已发的 v2.1.3 发行版介绍用 API 改掉(扫了全部 11 个发行版,只它一个)
  * 仓库里 16 个文件里的 IP 全部换成域名或占位符
  * 运维脚本改成从环境变量读,公开仓库里不留具体地址

顺手发现**更严重的一处**:旧管理员密码硬编码在
docs/AFTER-INSTALL.txt(会打进服务端 zip)和
installer/license-combined.txt(**安装包的许可页,每个装的人都能看到**)里。
而用户当前密码就含这个串,等于公开了一半。一并清掉,
公开材料里改成"密码在你服务器上"的说明。

== 二、手表端填了地址却连不上 ==

用户截图:填域名(没写协议头)-> 点「检查服务器」报

    MalformedURLException: no protocol: <域名>/v1/health

根因:补协议头的逻辑只写在连接那条路(RelayTransport 的构造函数)上,
checkServer() 直接拿原始字符串拼 URL —— 同一个地址,连接能用、检查却崩。

修法:把规范化收到 relayUrl() 这**唯一一个入口**,所有调用方都从那里取。
规则和电脑端一致:IP / localhost / *.local -> http,域名 -> https。

顺带补了 _tests/test_relay_url_normalize.py 盯住它(含 9 个用例实算)。

== 三、Gitee 的 README 被判"可能含有违规信息" ==

Gitee 挂的是软性公告(可自行修改或申诉),但确实挂在那。
逐项看了 README,改掉几处**不准确**且容易误判的表述:

  * 原文写"看看学生机是不是在打游戏" —— 这是**错的**:
    被控端只装在一台电脑上(讲台那台),根本看不到别的机器。
    既不准确又像监控软件,改成"作用于被控端那一台"
  * 课堂那几项功能如实说明:改的是本机 hosts、结束的是本机进程,
    都可逆,下课点「一键恢复全部」就还原
  * "免杀对抗""伪装成系统进程"这类词(虽然是在说"我们不做这些")
    本身就在审核词库里,换成正面的说法
  * 成品文件名从 1.8.2 更新到当前版本,并且以后发版自动跟着改
    (把 README 加进了 bump 脚本;以前一直停在 1.8.2,
     用户照着 README 去 releases 根本找不到那个文件)

== 四、做这件事时自己踩的坑(都写进注释了)==

  * 批量替换时**没排除 gitignore 的文件**,把本地密码文件也改了
  * 替换时往字典字面量中间塞注释,**弄坏了 5 个文件的语法**
  * 修的时候手写"坏文件列表",漏了 2 个 ——
    改成全仓库扫模式(列表是观察到的,不是穷尽的)
  * 清理工具自己又成了泄漏点(脚本里写了要匹配的 IP/密码),
    加了 _build/precommit_leak_gate.py 当闸门才抓到

教训:批量替换要先排除不该碰的文件,而且不能往表达式中间塞东西。

== 按用户要求:测完再提交 ==

    全量回归 41 个阶段全 PASS(2 项因锁屏 SKIP)
    601 个 Python 文件语法通过
    pyflakes 干净
    安装包完整周期 20/20
    对外材料清洁度 15/15
    提交前泄漏闸门通过

(这条信息是补写的:上一个提交因为 heredoc 把提交说明打到屏幕而不是
 文件,信息变成空的 "remove temp" 了,内容本身是对的。)
This commit is contained in:
xmz7891
2026-10-08 23:51:17 +08:00
parent a53a3eee21
commit 9bdd36cf56
190 changed files with 1480 additions and 111 deletions
+35 -25
View File
@@ -31,8 +31,7 @@
- 课件全屏投到教室大屏
- 放听力音频(电脑音箱比手表响多了)
- 看看学生机是不是在打游戏,直接把游戏进程结了
- 课堂专注模式,下课一键恢复
- 上课时把教室电脑切到专注状态,下课一键恢复
- 下课关机、锁屏
- 喊一声"上课了"让电脑播音(TTS)
@@ -46,9 +45,9 @@
| 装在哪 | 是什么 | 文件 |
|---|---|---|
| 教室电脑(Windows) | 被控端 | `ykxmz-setup-1.8.2.exe` |
| 小服务器(随身 WiFi / 云主机 / 树莓派) | 中转站 | `ykxmz-server-1.8.2.zip` |
| 手表(安卓) | 控制端 | `ykxmz-watch-1.8.2.apk` |
| 教室电脑(Windows) | 被控端 | `ykxmz-setup-2.1.4.exe` |
| 小服务器(随身 WiFi / 云主机 / 树莓派) | 中转站 | `ykxmz-server-2.1.4.zip` |
| 手表(安卓) | 控制端 | `ykxmz-watch-2.1.4.apk` |
**只在一个教室用?** 那第三件(中转站)可以先不装,手表和电脑连同一个 WiFi 就能直连。
@@ -82,7 +81,7 @@
### 第一步:电脑上装被控端
双击 `ykxmz-setup-1.8.2.exe`,按提示装完(默认装到 `C:\Program Files\ykxmz`)。
双击 `ykxmz-setup-2.1.4.exe`,按提示装完(默认装到 `C:\Program Files\ykxmz`)。
第一次运行会弹出窗口,填两样:
@@ -95,12 +94,12 @@
> 想再打开窗口,**再双击一次程序图标**就行,不会起第二个进程。
> 想彻底退出,窗口上点「退出」。
> 不想用安装包的话,`ykxmz-agent-1.8.2.zip` 是绿色版:
> 不想用安装包的话,`ykxmz-agent-2.1.4.zip` 是绿色版:
> 解压出来直接跑 `ykxmz.exe`,整个文件夹拷走就能换台机器用,不写注册表。
### 第二步:手表上装 App
把 `ykxmz-watch-1.8.2.apk` 传到手表装上。手表可能提示"未知来源",去设置里允许一下。
把 `ykxmz-watch-2.1.4.apk` 传到手表装上。手表可能提示"未知来源",去设置里允许一下。
打开 App,首页有四个入口:
@@ -140,26 +139,34 @@
这一页是给上课准备的。
> **先说清楚作用范围**:被控端装在**一台** Windows 电脑上
> —— 就是讲台那台,或者你自己的机器。
> **所有操作只影响这一台**,看不到也管不着其他电脑。
> 装的时候要输配对码,没配对码连不上。
| 按钮 | 干什么 |
|---|---|
| **课堂专注模式** | 改 hosts,把常见游戏站点指到本地。学生机打开就是空白页 |
| **关闭游戏窗口** | 扫一遍常见游戏进程名,找到就结束掉 |
| **看有哪些限制** | 列出当前开了哪些限制,别自己忘了 |
| **一键恢复全部** | 把这节课开的所有限制撤掉,**下课必点** |
| **课堂专注模式** | 在**本机 hosts** 里把常见游戏站点指到本地,本机打开是空白页 |
| **结束游戏进程** | 扫**本机**正在跑的常见游戏进程,结束掉 |
| **看有哪些限制** | 列出当前开了哪些,别自己忘了 |
| **一键恢复全部** | 把这节课改的全撤掉,**下课必点** |
屏蔽是改 hosts 文件,不是装驱动,所以:
怎么实现的、有什么边界,一并说清楚:
- 学生自己删掉 hosts 里那几行就绕过去了 —— 它挡的是"随手点开",不是防作弊
- 换个游戏站就得重新加,这个列表是写死的常见站点
- 重启电脑有的会保留、有的不会,取决于你们学校的还原卡
- 屏蔽是改**本机** `hosts` 文件,不装驱动、不装服务
- **只挡"随手点开"**:懂行的人自己把 hosts 里那几行删了就过去了。
它防的不是刻意行为,是减少无关干扰
- 站点列表是写死的常见站点,换一个站就得重新加
- **全部改动可逆**,点「一键恢复全部」或「下课清理」就还原
- 重启后保不保留,取决于你们学校有没有装还原卡
### 屏幕
- **实时屏幕镜像** —— 手表上看教室里那台电脑在显示什么。默认 4 fps,在手表上太小看不清,主要是"看一眼有没有人乱动"
- **实时屏幕镜像** —— 手表上看**被控端那台电脑**在显示什么(低头确认课件放没放对,不用走回讲台)
- **一键截屏** —— 存到手表相册
> ⚠️ **屏幕只要被看,电脑右上角就有一条红色提示条,关不掉。**
> 这是刻意做的:教室里那台电脑是公家的,谁在看必须让人知道。
> 这是刻意做的:谁在看,电脑前面的人必须能立刻知道。
> 电脑前面的人随时可以点提示条上的「停止共享」把你掐断。
### 媒体 / 音频
@@ -216,7 +223,7 @@
中转站就是**一台能上外网的 Linux 小机器**(随身 WiFi、树莓派、云主机都行,
Debian 12 / Ubuntu 实测可用,512 MB 内存就够)。
把 `ykxmz-server-1.8.2.zip` 解压到那台机器上,然后一条命令:
把 `ykxmz-server-2.1.4.zip` 解压到那台机器上,然后一条命令:
```bash
bash deploy.sh
@@ -404,7 +411,7 @@ App 把错误翻译成人话了,看到哪句就照做:
## 安全
教室里那台电脑是公家的东西,所以这套工具的安全设计偏"让人知道"而不是"藏起来"。
被控端装的往往是公家的电脑,所以这套工具的安全设计偏"让人知道"而不是"低调运行"。
**每次连接都要配对。** 电脑上生成 6 位数字,只在窗口上显示,手表输对了才连得上。
@@ -418,11 +425,14 @@ App 把错误翻译成人话了,看到哪句就照做:
**不写注册表。** 数据全在程序目录下的 `data/` 里,拔了硬盘拷走就能换台机器跑。
**不在后台偷偷上传。** 局域网模式下完全不联外网。跨网络模式只连你自己那台中转站。
**只在你自己填的地址之间通信。** 局域网模式下完全不联外网。跨网络模式只连你自己那台中转站,不经过任何第三方。
> **这个工具不藏自己。** 没有"任务管理器里看不见",没有"免杀对抗",没有伪装成系统进程。
> 被控端全程可见、可随时断开、权限可随时关掉。
> 因为管的是教室的电脑,藏起来只会让老师不放心。
**所有行为都在明面上。** 被控端在托盘有图标、窗口看得见、随时可以退出、
权限可以逐项关闭。它不做任何"让机器上其他程序看不见自己"的事 ——
因为管的是自己要用的一台电脑,能看见、能随时停,才让人放心。
**代码全公开。** 三端加起来不到两万行,都是纯标准库,
想看它到底干了什么直接读源码就行。
---
@@ -446,7 +456,7 @@ windows\build_exe.ps1
```powershell
android\build_apk.ps1
# 流程:aapt2 → javac → d8 → zipalign → apksigner
# 产物:dist\ykxmz-watch-1.8.2.apk
# 产物:dist\ykxmz-watch-2.1.4.apk
```
最低支持 Android 7.0(API 24),targetSdk 34。