From 3832ca4fab6b72088b783d4da4bc11eaf093bc58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 7 Oct 2026 10:48:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E5=B8=83=E8=B5=84=E6=96=99=E6=91=98?= =?UTF-8?q?=E8=A6=81=E7=BB=99=E5=9B=BE=E7=89=87=E5=AD=97=E8=8A=82=E5=8A=A0?= =?UTF-8?q?=E9=95=BF=E5=BA=A6=E5=89=8D=E7=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - metadata_digest 逐张先写 u64 长度再写字节,分片边界进入摘要 - 否则「封面 [1,2]+截图 [3]」与「封面 [1]+截图 [2,3]」摘要相同,本地幂等账本会误判重放 - 补分片不变性断言 --- .../src/game_distribution_publish.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs b/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs index 92a37e851..f8e86833f 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs @@ -446,6 +446,9 @@ fn metadata_digest( hasher.update(&bytes); hasher.update(price_mud_points.to_le_bytes()); for image in media.cover.iter().chain(media.screenshots.iter()) { + // 逐张带长度前缀:图片之间没有分隔符,只串裸字节会让「封面 [1,2] + 截图 [3]」与 + // 「封面 [1] + 截图 [2,3]」撞成同一摘要,本地幂等账本就会把改过的图当成重放。 + hasher.update((image.bytes.len() as u64).to_le_bytes()); hasher.update(&image.bytes); } Ok(format!("{:x}", hasher.finalize())) @@ -1672,6 +1675,31 @@ mod tests { metadata_digest(&metadata, 0, &media).expect("changed"), first ); + // 分片边界也要进摘要:两组图裸字节串起来相同,但封面/截图的切分不同。 + let split_a = PublishMedia { + cover: Some(DraftImage { + bytes: vec![1, 2], + content_type: "image/png", + }), + screenshots: vec![DraftImage { + bytes: vec![3], + content_type: "image/png", + }], + }; + let split_b = PublishMedia { + cover: Some(DraftImage { + bytes: vec![1], + content_type: "image/png", + }), + screenshots: vec![DraftImage { + bytes: vec![2, 3], + content_type: "image/png", + }], + }; + assert_ne!( + metadata_digest(&metadata, 0, &split_a).expect("split a"), + metadata_digest(&metadata, 0, &split_b).expect("split b") + ); } #[test]