发布资料摘要给图片字节加长度前缀

- metadata_digest 逐张先写 u64 长度再写字节,分片边界进入摘要
- 否则「封面 [1,2]+截图 [3]」与「封面 [1]+截图 [2,3]」摘要相同,本地幂等账本会误判重放
- 补分片不变性断言
This commit is contained in:
2026-10-07 10:48:16 +08:00
parent ab9789d11a
commit 3832ca4fab
@@ -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]