收紧资源布局 revision IPC 精度边界
统一限制资源布局 revision 到 JavaScript 最大安全整数 在 Rust serde、Tauri 输入与前端 IPC 三层拒绝非安全 revision 补充最大值往返、上限失败、超限零副作用与不可信响应回归 同步更新资源画布合同、技术决策与竞态经验
This commit is contained in:
@@ -488,6 +488,37 @@ pub struct GameCreationAppAssetManifestEntry {
|
||||
}
|
||||
|
||||
pub const GAME_CREATION_RESOURCE_LAYOUT_SCHEMA_VERSION: &str = "game-creator-resource-layout.v1";
|
||||
pub const GAME_CREATION_RESOURCE_LAYOUT_MAX_SAFE_REVISION: u64 = 9_007_199_254_740_991;
|
||||
|
||||
pub fn validate_project_resource_canvas_layout_revision(revision: u64) -> Result<(), &'static str> {
|
||||
if revision > GAME_CREATION_RESOURCE_LAYOUT_MAX_SAFE_REVISION {
|
||||
return Err("资源布局 revision 超出 JavaScript 安全整数范围");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_project_resource_canvas_layout_revision<S>(
|
||||
revision: &u64,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
validate_project_resource_canvas_layout_revision(*revision)
|
||||
.map_err(serde::ser::Error::custom)?;
|
||||
serializer.serialize_u64(*revision)
|
||||
}
|
||||
|
||||
fn deserialize_project_resource_canvas_layout_revision<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<u64, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let revision = u64::deserialize(deserializer)?;
|
||||
validate_project_resource_canvas_layout_revision(revision).map_err(serde::de::Error::custom)?;
|
||||
Ok(revision)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
@@ -521,6 +552,10 @@ pub struct ProjectResourceCanvasLayout {
|
||||
pub schema_version: String,
|
||||
pub project_id: String,
|
||||
pub mode: ProjectResourceCanvasLayoutMode,
|
||||
#[serde(
|
||||
deserialize_with = "deserialize_project_resource_canvas_layout_revision",
|
||||
serialize_with = "serialize_project_resource_canvas_layout_revision"
|
||||
)]
|
||||
pub revision: u64,
|
||||
pub positions: Vec<ProjectResourceCanvasPosition>,
|
||||
pub updated_at: u64,
|
||||
@@ -1535,4 +1570,39 @@ mod tests {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resource_canvas_layout_revision_rejects_json_outside_js_safe_integer_range() {
|
||||
let layout = ProjectResourceCanvasLayout {
|
||||
schema_version: GAME_CREATION_RESOURCE_LAYOUT_SCHEMA_VERSION.to_string(),
|
||||
project_id: "project-layout-safe-revision".to_string(),
|
||||
mode: ProjectResourceCanvasLayoutMode::Dependency,
|
||||
revision: GAME_CREATION_RESOURCE_LAYOUT_MAX_SAFE_REVISION,
|
||||
positions: vec![],
|
||||
updated_at: 123,
|
||||
};
|
||||
let serialized = serde_json::to_vec(&layout).expect("safe revision should serialize");
|
||||
let decoded: ProjectResourceCanvasLayout =
|
||||
serde_json::from_slice(&serialized).expect("safe revision should deserialize");
|
||||
assert_eq!(
|
||||
decoded.revision,
|
||||
GAME_CREATION_RESOURCE_LAYOUT_MAX_SAFE_REVISION
|
||||
);
|
||||
|
||||
let unsafe_layout = ProjectResourceCanvasLayout {
|
||||
revision: GAME_CREATION_RESOURCE_LAYOUT_MAX_SAFE_REVISION + 1,
|
||||
..layout
|
||||
};
|
||||
assert!(serde_json::to_value(unsafe_layout).is_err());
|
||||
|
||||
let unsafe_payload = json!({
|
||||
"schemaVersion": "game-creator-resource-layout.v1",
|
||||
"projectId": "project-layout-safe-revision",
|
||||
"mode": "dependency",
|
||||
"revision": GAME_CREATION_RESOURCE_LAYOUT_MAX_SAFE_REVISION + 1,
|
||||
"positions": [],
|
||||
"updatedAt": 123
|
||||
});
|
||||
assert!(serde_json::from_value::<ProjectResourceCanvasLayout>(unsafe_payload).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user