From 87dc80c750945fd02922ee02c88c8ef43168df79 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 19:18:45 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=B8=B8=E6=88=8F=E5=88=86=E5=8F=91?= =?UTF-8?q?=E9=A2=86=E5=9F=9F):=20=E6=B4=BE=E7=94=9F=20gameId=20=E5=89=8D?= =?UTF-8?q?=E5=85=88=20trim=20projectKey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - derive_game_distribution_game_id 原先直接哈希原始字节," proj-1 " 与 "proj-1" 会派生出两个身份 - 与 game_distribution_version_key 的 trim 口径对齐,并补单测断言两侧空白归一化 --- server-rs/crates/module-game-distribution/src/domain.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/server-rs/crates/module-game-distribution/src/domain.rs b/server-rs/crates/module-game-distribution/src/domain.rs index fedf8e68a..9684b95d5 100644 --- a/server-rs/crates/module-game-distribution/src/domain.rs +++ b/server-rs/crates/module-game-distribution/src/domain.rs @@ -69,8 +69,10 @@ pub fn game_distribution_version_key( /// 首次发布的游戏身份:由 `(ownerUserId, project_key)` 确定性派生。 /// /// 确定性派生让媒体 objectKey 前缀在事务前就稳定,重试 / 并发不会落到不同命名空间;结果满足 -/// gameId 的 `[A-Za-z0-9_-]` 约束。 +/// gameId 的 `[A-Za-z0-9_-]` 约束。`project_key` 先 trim,与自然幂等键 +/// [`game_distribution_version_key`] 的归一化口径一致,避免 `" proj-1 "` 与 `"proj-1"` 派生出两个身份。 pub fn derive_game_distribution_game_id(owner_user_id: &str, project_key: &str) -> String { + let project_key = project_key.trim(); let mut hasher = Sha256::new(); hasher.update(owner_user_id.as_bytes()); hasher.update([0]); @@ -278,6 +280,11 @@ mod tests { let other_owner = derive_game_distribution_game_id("owner-2", "proj-1"); let other_project = derive_game_distribution_game_id("owner-1", "proj-2"); assert_eq!(first, again); + assert_eq!( + first, + derive_game_distribution_game_id("owner-1", " proj-1 "), + "project_key 两侧空白必须归一化" + ); assert_ne!(first, other_owner); assert_ne!(first, other_project); assert!(first.starts_with(GAME_ID_PREFIX));