From c92526075f72e94732f57e7555266572973e6d1d Mon Sep 17 00:00:00 2001 From: Kenneth Loeffler Date: Thu, 21 Sep 2023 12:53:39 -0700 Subject: [PATCH] Implement SecurityCapabilities in rbx_binary (#361) This PR implements `SecurityCapabilities` parsing in rbx_binary. I chose to use `read_interleaved_i64_array` and `write_interleaved_i64_array` because Roblox appears to serialize it this way, and it's straightforward enough to cast between `u64` and `i64`. --- README.md | 2 +- rbx_binary/CHANGELOG.md | 3 + rbx_binary/src/deserializer/state.rs | 29 ++++++- rbx_binary/src/serializer/state.rs | 13 ++++ rbx_binary/src/tests/models.rs | 1 + ...s-with-security-capabilities__decoded.snap | 39 ++++++++++ ...s-with-security-capabilities__encoded.snap | 72 ++++++++++++++++++ ...ues-with-security-capabilities__input.snap | 76 +++++++++++++++++++ rbx_binary/src/text_deserializer.rs | 17 ++++- rbx_binary/src/types.rs | 4 + 10 files changed, 251 insertions(+), 5 deletions(-) create mode 100644 rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__decoded.snap create mode 100644 rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__encoded.snap create mode 100644 rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__input.snap diff --git a/README.md b/README.md index 2e19b162e..e6ea64e52 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ Roblox Lua implementation of DOM APIs, allowing Instance reflection from inside | Ref | `Model.PrimaryPart` | ✔ | ✔ | ✔ | ✔ | | Region3 | N/A | ✔ | ✔ | ❌ | ❌ | | Region3int16 | `Terrain.MaxExtents` | ✔ | ✔ | ❌ | ❌ | -| SecurityCapabilities | `Folder.SecurityCapabilities` | ✔ | ❌ | ❌ | ❌ | +| SecurityCapabilities | `Folder.SecurityCapabilities` | ✔ | ❌ | ✔ | ✔ | | SharedString | N/A | ✔ | ✔ | ✔ | ✔ | | String | `Instance.Name` | ✔ | ✔ | ✔ | ✔ | | UDim | `UIListLayout.Padding` | ✔ | ✔ | ✔ | ✔ | diff --git a/rbx_binary/CHANGELOG.md b/rbx_binary/CHANGELOG.md index 1b7ac2325..c3098491f 100644 --- a/rbx_binary/CHANGELOG.md +++ b/rbx_binary/CHANGELOG.md @@ -1,6 +1,9 @@ # rbx_binary Changelog ## Unreleased +* Added support for `SecurityCapabilities` values. ([#361]) + +[#361]: https://github.com/rojo-rbx/rbx-dom/pull/361 ## 0.7.1 (2023-08-09) * Added support for `UniqueId` values. ([#271]) diff --git a/rbx_binary/src/deserializer/state.rs b/rbx_binary/src/deserializer/state.rs index 1ed8762f8..5caf0be25 100644 --- a/rbx_binary/src/deserializer/state.rs +++ b/rbx_binary/src/deserializer/state.rs @@ -9,8 +9,8 @@ use rbx_dom_weak::{ Attributes, Axes, BinaryString, BrickColor, CFrame, Color3, Color3uint8, ColorSequence, ColorSequenceKeypoint, Content, CustomPhysicalProperties, Enum, Faces, Font, FontStyle, FontWeight, MaterialColors, Matrix3, NumberRange, NumberSequence, NumberSequenceKeypoint, - PhysicalProperties, Ray, Rect, Ref, SharedString, Tags, UDim, UDim2, UniqueId, Variant, - VariantType, Vector2, Vector3, Vector3int16, + PhysicalProperties, Ray, Rect, Ref, SecurityCapabilities, SharedString, Tags, UDim, UDim2, + UniqueId, Variant, VariantType, Vector2, Vector3, Vector3int16, }, InstanceBuilder, WeakDom, }; @@ -1361,6 +1361,31 @@ impl<'a, R: Read> DeserializerState<'a, R> { }); } }, + Type::SecurityCapabilities => match canonical_type { + VariantType::SecurityCapabilities => { + let mut values = vec![0; type_info.referents.len()]; + + chunk.read_interleaved_i64_array(values.as_mut_slice())?; + + let values: Vec = values + .into_iter() + .map(|value| SecurityCapabilities::from_bits(value as u64)) + .collect(); + + for (referent, value) in type_info.referents.iter().zip(values) { + let instance = self.instances_by_ref.get_mut(referent).unwrap(); + add_property(instance, &property, value.into()) + } + } + invalid_type => { + return Err(InnerError::PropTypeMismatch { + type_name: type_info.type_name.clone(), + prop_name, + valid_type_names: "SecurityCapabilities", + actual_type_name: format!("{:?}", invalid_type), + }); + } + }, } Ok(()) diff --git a/rbx_binary/src/serializer/state.rs b/rbx_binary/src/serializer/state.rs index a4c3df02f..8cd41132c 100644 --- a/rbx_binary/src/serializer/state.rs +++ b/rbx_binary/src/serializer/state.rs @@ -1186,6 +1186,19 @@ impl<'dom, W: Write> SerializerState<'dom, W> { chunk.write_interleaved_bytes::<16>(&blobs)?; } + Type::SecurityCapabilities => { + let mut capabilities = Vec::with_capacity(values.len()); + + for (i, rbx_value) in values { + if let Variant::SecurityCapabilities(value) = rbx_value.as_ref() { + capabilities.push(value.bits() as i64) + } else { + return type_mismatch(i, &rbx_value, "SecurityCapabilities"); + } + } + + chunk.write_interleaved_i64_array(capabilities.into_iter())?; + } } chunk.dump(&mut self.output)?; diff --git a/rbx_binary/src/tests/models.rs b/rbx_binary/src/tests/models.rs index 1f20772bd..50381c7a7 100644 --- a/rbx_binary/src/tests/models.rs +++ b/rbx_binary/src/tests/models.rs @@ -64,4 +64,5 @@ binary_tests! { gui_inset_and_font_migration, folder_with_cframe_attributes, folder_with_font_attribute, + number_values_with_security_capabilities, } diff --git a/rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__decoded.snap b/rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__decoded.snap new file mode 100644 index 000000000..fece41773 --- /dev/null +++ b/rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__decoded.snap @@ -0,0 +1,39 @@ +--- +source: rbx_binary/src/tests/util.rs +expression: decoded_viewed +--- +- referent: referent-0 + name: Hmmm + class: NumberValue + properties: + Attributes: + Attributes: {} + Capabilities: + SecurityCapabilities: 0 + DefinesCapabilities: + Bool: false + SourceAssetId: + Int64: -1 + Tags: + Tags: [] + Value: + Float64: 2.71828182846 + children: [] +- referent: referent-1 + name: WhereIs + class: NumberValue + properties: + Attributes: + Attributes: {} + Capabilities: + SecurityCapabilities: 2882400000 + DefinesCapabilities: + Bool: false + SourceAssetId: + Int64: -1 + Tags: + Tags: [] + Value: + Float64: 2.71828182846 + children: [] + diff --git a/rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__encoded.snap b/rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__encoded.snap new file mode 100644 index 000000000..935e5a2f6 --- /dev/null +++ b/rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__encoded.snap @@ -0,0 +1,72 @@ +--- +source: rbx_binary/src/tests/util.rs +expression: text_roundtrip +--- +num_types: 1 +num_instances: 2 +chunks: + - Inst: + type_id: 0 + type_name: NumberValue + object_format: 0 + referents: + - 0 + - 1 + - Prop: + type_id: 0 + prop_name: AttributesSerialize + prop_type: String + values: + - "" + - "" + - Prop: + type_id: 0 + prop_name: Capabilities + prop_type: SecurityCapabilities + values: + - 0 + - 2882400000 + - Prop: + type_id: 0 + prop_name: DefinesCapabilities + prop_type: Bool + values: + - false + - false + - Prop: + type_id: 0 + prop_name: Name + prop_type: String + values: + - Hmmm + - WhereIs + - Prop: + type_id: 0 + prop_name: SourceAssetId + prop_type: Int64 + values: + - -1 + - -1 + - Prop: + type_id: 0 + prop_name: Tags + prop_type: String + values: + - "" + - "" + - Prop: + type_id: 0 + prop_name: Value + prop_type: Float64 + values: + - 2.71828182846 + - 2.71828182846 + - Prnt: + version: 0 + links: + - - 0 + - -1 + - - 1 + - -1 + - End + diff --git a/rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__input.snap b/rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__input.snap new file mode 100644 index 000000000..11649dae8 --- /dev/null +++ b/rbx_binary/src/tests/snapshots/rbx_binary__tests__util__number-values-with-security-capabilities__input.snap @@ -0,0 +1,76 @@ +--- +source: rbx_binary/src/tests/util.rs +expression: text_decoded +--- +num_types: 1 +num_instances: 2 +chunks: + - Meta: + entries: + - - ExplicitAutoJoints + - "true" + - Inst: + type_id: 0 + type_name: NumberValue + object_format: 0 + referents: + - 0 + - 1 + - Prop: + type_id: 0 + prop_name: AttributesSerialize + prop_type: String + values: + - "" + - "" + - Prop: + type_id: 0 + prop_name: Capabilities + prop_type: SecurityCapabilities + values: + - 0 + - 2882400000 + - Prop: + type_id: 0 + prop_name: DefinesCapabilities + prop_type: Bool + values: + - false + - false + - Prop: + type_id: 0 + prop_name: Name + prop_type: String + values: + - Hmmm + - WhereIs + - Prop: + type_id: 0 + prop_name: SourceAssetId + prop_type: Int64 + values: + - -1 + - -1 + - Prop: + type_id: 0 + prop_name: Tags + prop_type: String + values: + - "" + - "" + - Prop: + type_id: 0 + prop_name: Value + prop_type: Float64 + values: + - 2.71828182846 + - 2.71828182846 + - Prnt: + version: 0 + links: + - - 0 + - -1 + - - 1 + - -1 + - End + diff --git a/rbx_binary/src/text_deserializer.rs b/rbx_binary/src/text_deserializer.rs index 89513bb66..70e2c214e 100644 --- a/rbx_binary/src/text_deserializer.rs +++ b/rbx_binary/src/text_deserializer.rs @@ -9,8 +9,8 @@ use std::{collections::HashMap, convert::TryInto, fmt::Write, io::Read}; use rbx_dom_weak::types::{ Axes, BrickColor, CFrame, Color3, Color3uint8, ColorSequence, ColorSequenceKeypoint, CustomPhysicalProperties, Enum, Faces, Font, FontStyle, FontWeight, Matrix3, NumberRange, - NumberSequence, NumberSequenceKeypoint, PhysicalProperties, Ray, Rect, SharedString, UDim, - UDim2, UniqueId, Vector2, Vector3, Vector3int16, + NumberSequence, NumberSequenceKeypoint, PhysicalProperties, Ray, Rect, SecurityCapabilities, + SharedString, UDim, UDim2, UniqueId, Vector2, Vector3, Vector3int16, }; use serde::{ser::SerializeSeq, Serialize, Serializer}; @@ -224,6 +224,7 @@ pub enum DecodedValues { OptionalCFrame(Vec>), UniqueId(Vec), Font(Vec), + SecurityCapabilities(Vec), } impl DecodedValues { @@ -712,6 +713,18 @@ impl DecodedValues { Some(DecodedValues::UniqueId(values)) } + Type::SecurityCapabilities => { + let mut values = vec![0; prop_count]; + + reader.read_interleaved_i64_array(&mut values).unwrap(); + + let values = values + .into_iter() + .map(|value| SecurityCapabilities::from_bits(value as u64)) + .collect(); + + Some(DecodedValues::SecurityCapabilities(values)) + } } } } diff --git a/rbx_binary/src/types.rs b/rbx_binary/src/types.rs index 873ccc8f2..74a3a5119 100644 --- a/rbx_binary/src/types.rs +++ b/rbx_binary/src/types.rs @@ -41,6 +41,7 @@ pub enum Type { OptionalCFrame = 0x1E, UniqueId = 0x1F, Font = 0x20, + SecurityCapabilities = 0x21, } impl Type { @@ -81,6 +82,7 @@ impl Type { VariantType::OptionalCFrame => Type::OptionalCFrame, VariantType::UniqueId => Type::UniqueId, VariantType::Font => Type::Font, + VariantType::SecurityCapabilities => Type::SecurityCapabilities, _ => return None, }) } @@ -118,6 +120,7 @@ impl Type { Type::OptionalCFrame => VariantType::OptionalCFrame, Type::UniqueId => VariantType::UniqueId, Type::Font => VariantType::Font, + Type::SecurityCapabilities => VariantType::SecurityCapabilities, }) } } @@ -158,6 +161,7 @@ impl TryFrom for Type { 0x1E => OptionalCFrame, 0x1F => UniqueId, 0x20 => Font, + 0x21 => SecurityCapabilities, _ => return Err(InvalidTypeError(value)), }) }