docs(core): M240 r2 复审 —— 两处注释口径(= 边界代价写清、DNS 形归属改正)

纯注释,判据/阈值/测试断言/扫描器零改动。

① `is_dotted_token_char` 的 doc 原写「JWT 自己的 `=` 只可能是末尾填充,拆出去不损伤
覆盖面」——作为无条件说法不成立。改成有范围的措辞,并把这条例外并入模块文档
「旧行为抹、新行为留」第 1 条(不新开章节):`-DaccessToken=abcdefgh.ijklmnop.qrstuvwx`
(整段 40 字符、三段各 ≥8,旧规则抹)现在 `=` 切段后值只剩 26 < 40 → 原样留下。
旧/新两侧都实测过(`git show 74be510` + rustc 探针 / 当前代码探针)。

② `cdn_and_mirror_urls_survive` 里 `resources.download.minecraft.example-cdn` 的注释
原写「全靠必须含大写这条必要条件挡住」——不成立:它是 DNS 形状,由 `is_url_authority`
→ `is_dns_host` 豁免(删掉大写判据该测试仍绿)。改成正确归属,与
`lowercase_dotted_names_are_spared` / `the_uppercase_requirement_is_load_bearing` 的
doc 口径对齐(DNS 形靠主机名豁免、非 DNS 形靠必须含大写)。
This commit is contained in:
AskaEth committed 2026-11-11 10:15:49 +08:00
1 parent 66929786c0
commit a07482f828
2 files changed
+14 -3

No files matched your search

+11 -1
View File
@@ -31,6 +31,10 @@
//!
//! 1. **`=` 边界**:`-Dminecraft.launcher.brand=UnluckyLauncher` —— 旧行为把 `键=值` 粘成
//! 一段,键里的点号凑够段数/总长;现在两半各自不达标。(这就是要修的品牌串误杀。)
//! 同一处边界的**代价**:`-DaccessToken=abcdefgh.ijklmnop.qrstuvwx`(整段 40 字符、
//! 三段各 ≥8,旧规则抹)现在 `=` 切段后值只剩 26 < 40 → 原样留下。也就是说
//! **紧跟 `=`、自己又不够 40 的带点值**不再被形状规则兜住,只剩"登记明文值"那条路径,
//! 这是换品牌串保留付出的代价。
//! 2. **填充不算段长**:`eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.c2lnbm==` ——
//! 旧行为把 `==` 算进末段(8 ≥ 8),现在 `=` 在段外、末段实际 6 < 8,整串留下。
//! 真 JWT 的签名段是 43+ 字符(HS256)/ 342(RS256),6–7 字符的末段只可能是被裁剪或
@@ -55,7 +59,13 @@ pub(super) fn is_opaque_char(ch: char) -> bool {
///
/// `=` 是**赋值边界**而不是 token 本体。把它留在字符集里,`-D<key>=<值>` 就会被粘成一个
/// run:键里的点号(`minecraft.launcher.brand`)会把值一起拖进段数统计,M239 实测的品牌串
/// 误杀就是从这儿来的。JWT 自己的 `=` 只可能是末尾填充,拆出去不损伤覆盖面。
/// 误杀就是从这儿来的。
///
/// 这条边界的代价**有范围**,别读成"不损伤覆盖面":`=` 切段之后,**紧跟 `=`、自己又不够
/// 40 字符**的带点值不再被形状规则兜住——`-DaccessToken=abcdefgh.ijklmnop.qrstuvwx`(整段
/// 40 字符、三段各 ≥8,旧规则抹)现在切出 26 < 40 而原样留下。这是换品牌串保留的代价,
/// 记在模块文档「旧行为抹、新行为留」第 1 条的末句;真 token 仍由 [`super::Redactor::with_secret`]
/// 那条明文值替换路径扛住。
pub(super) fn is_dotted_token_char(ch: char) -> bool {
ch != '=' && (is_opaque_char(ch) || ch == '.')
}
+3 -2
View File
@@ -135,7 +135,7 @@ fn hmcl_shaped_argv_survives_verbatim() {
assert_eq!(scrub(argv), argv);
}
/// M239 的 U1–U6:CDN / 镜像主机名(DNS 授权段 + 小写必要条件)。
/// M239 的 U1–U6:CDN / 镜像主机名(判据 = 首段是 DNS 主机名 → 只判路径那半)。
#[test]
fn cdn_and_mirror_urls_survive() {
for text in [
@@ -145,7 +145,8 @@ fn cdn_and_mirror_urls_survive() {
"https://libraries.minecraft.net/net/minecraft/launchwrapper/1.12/launchwrapper-1.12.jar",
"https://api.minecraftservices.com/entitlements/mcstore",
"https://maven.minecraftforge.net/net/minecraftforge/forge/1.20.1-47.2.0/forge.jar",
// 没有点号分段的最长主机名形状(全靠"必须含大写"这条必要条件挡住)
// 40 字符的纯主机名形状:DNS 形 → 靠首段主机名豁免(不是靠大写判据,
// 大写判据只管非 DNS 形状,归属见 `lowercase_dotted_names_are_spared` 的 doc)
"resources.download.minecraft.example-cdn",
// 短域名 + 长路径(内容全是词形名字)
"https://short.host/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",