fix: void validate arguments/properties name (#358)

This commit is contained in:
black_desk 2025-01-16 04:18:37 +08:00 committed by GitHub
parent e7750caed5
commit f58f1a6466
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 89 additions and 27 deletions

View File

@ -260,7 +260,11 @@ class MessageBus(BaseMessageBus):
return await future
async def introspect(
self, bus_name: str, path: str, timeout: float = 30.0
self,
bus_name: str,
path: str,
timeout: float = 30.0,
validate_property_names: bool = True,
) -> intr.Node:
"""Get introspection data for the node at the given path from the given
bus name.
@ -274,6 +278,8 @@ class MessageBus(BaseMessageBus):
:type path: str
:param timeout: The timeout to introspect.
:type timeout: float
:param validate_property_names: Whether to validate property names or not.
:type validate_property_names: bool
:returns: The introspection data for the name at the path.
:rtype: :class:`Node <dbus_fast.introspection.Node>`
@ -295,6 +301,7 @@ class MessageBus(BaseMessageBus):
path,
partial(self._reply_handler, future),
check_callback_type=False,
validate_property_names=validate_property_names,
)
timer_handle = self._loop.call_later(

View File

@ -34,9 +34,6 @@ class Arg:
direction: Optional[list[ArgDirection]] = None,
name: Optional[str] = None,
):
if name is not None:
assert_member_name_valid(name)
type_ = None
if type(signature) is SignatureType:
type_ = signature
@ -245,8 +242,10 @@ class Property:
name: str,
signature: str,
access: PropertyAccess = PropertyAccess.READWRITE,
validate: bool = True,
):
assert_member_name_valid(name)
if validate:
assert_member_name_valid(name)
tree = get_signature_tree(signature)
if len(tree.types) != 1:
@ -259,7 +258,7 @@ class Property:
self.access = access
self.type = tree.types[0]
def from_xml(element):
def from_xml(element, validate: bool = True):
"""Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Property`.
The element must be valid DBus introspection XML for a ``property``.
@ -279,7 +278,7 @@ class Property:
if not signature:
raise InvalidIntrospectionError('properties must have a "type" attribute')
return Property(name, signature, access)
return Property(name, signature, access, validate=validate)
def to_xml(self) -> ET.Element:
"""Convert this :class:`Property` into an :class:`xml.etree.ElementTree.Element`."""
@ -324,7 +323,9 @@ class Interface:
self.properties = properties if properties is not None else []
@staticmethod
def from_xml(element: ET.Element) -> "Interface":
def from_xml(
element: ET.Element, validate_property_names: bool = True
) -> "Interface":
"""Convert a :class:`xml.etree.ElementTree.Element` into a
:class:`Interface`.
@ -348,7 +349,9 @@ class Interface:
elif child.tag == "signal":
interface.signals.append(Signal.from_xml(child))
elif child.tag == "property":
interface.properties.append(Property.from_xml(child))
interface.properties.append(
Property.from_xml(child, validate=validate_property_names)
)
return interface
@ -409,7 +412,9 @@ class Node:
self.is_root = is_root
@staticmethod
def from_xml(element: ET.Element, is_root: bool = False):
def from_xml(
element: ET.Element, is_root: bool = False, validate_property_names: bool = True
) -> "Node":
"""Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Node`.
The element must be valid DBus introspection XML for a ``node``.
@ -418,6 +423,8 @@ class Node:
:type element: :class:`xml.etree.ElementTree.Element`
:param is_root: Whether this is the root node
:type is_root: bool
:param validate_property_names: Whether to validate property names or not
:type validate_property_names: bool
:raises:
- :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
@ -426,20 +433,30 @@ class Node:
for child in element:
if child.tag == "interface":
node.interfaces.append(Interface.from_xml(child))
node.interfaces.append(
Interface.from_xml(
child, validate_property_names=validate_property_names
)
)
elif child.tag == "node":
node.nodes.append(Node.from_xml(child))
node.nodes.append(
Node.from_xml(
child, validate_property_names=validate_property_names
)
)
return node
@staticmethod
def parse(data: str) -> "Node":
def parse(data: str, validate_property_names: bool = True) -> "Node":
"""Parse XML data as a string into a :class:`Node`.
The string must be valid DBus introspection XML.
:param data: The XMl string.
:type data: str
:param validate_property_names: Whether to validate property names or not
:type validate_property_names: bool
:raises:
- :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the string is not valid introspection data.
@ -450,7 +467,9 @@ class Node:
'introspection data must have a "node" for the root element'
)
return Node.from_xml(element, is_root=True)
return Node.from_xml(
element, is_root=True, validate_property_names=validate_property_names
)
def to_xml(self) -> ET.Element:
"""Convert this :class:`Node` into an :class:`xml.etree.ElementTree.Element`."""

View File

@ -262,6 +262,7 @@ class BaseMessageBus:
path: str,
callback: Callable[[Optional[intr.Node], Optional[Exception]], None],
check_callback_type: bool = True,
validate_property_names: bool = True,
) -> None:
"""Get introspection data for the node at the given path from the given
bus name.
@ -276,6 +277,10 @@ class BaseMessageBus:
:param callback: A callback that will be called with the introspection
data as a :class:`Node <dbus_fast.introspection.Node>`.
:type callback: :class:`Callable`
:param check_callback_type: Whether to check callback type or not.
:type check_callback_type: bool
:param validate_property_names: Whether to validate property names or not.
:type validate_property_names: bool
:raises:
- :class:`InvalidObjectPathError <dbus_fast.InvalidObjectPathError>` - If the given object path is not valid.
@ -287,7 +292,9 @@ class BaseMessageBus:
def reply_notify(reply: Optional[Message], err: Optional[Exception]) -> None:
try:
BaseMessageBus._check_method_return(reply, err, "s")
result = intr.Node.parse(reply.body[0]) # type: ignore[union-attr]
result = intr.Node.parse(
reply.body[0], validate_property_names=validate_property_names
) # type: ignore[union-attr]
except Exception as e:
callback(None, e)
return

View File

@ -0,0 +1,10 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/com/example/sample_object0">
<interface name="com.example.SampleInterface0">
<method name="Frobate">
<arg name="0-foo-bar" type="i" direction="in"/>
</method>
<property name="0-baz-qux" type="y" access="write"/>
</interface>
</node>

View File

@ -5,7 +5,7 @@
<method name="Frobate">
<arg name="foo" type="i" direction="in"/>
<arg name="bar" type="s" direction="out"/>
<arg name="baz" type="a{us}" direction="out"/>
<arg name="0-baz" type="a{us}" direction="out"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
</method>
<method name="Bazify">
@ -16,11 +16,11 @@
<arg name="bar" type="(iiav)" direction="in"/>
</method>
<signal name="Changed">
<arg name="new_value" type="b"/>
<arg name="0-new_value" type="b"/>
</signal>
<signal name="ChangedMulti">
<arg name="new_value1" type="b"/>
<arg name="new_value2" type="y"/>
<arg name="0-new_value2" type="y"/>
</signal>
<property name="Bar" type="y" access="write"/>
</interface>

View File

@ -1,14 +1,33 @@
import os
from dbus_fast import ArgDirection, PropertyAccess, SignatureType
from dbus_fast import (
ArgDirection,
PropertyAccess,
SignatureType,
InvalidMemberNameError,
)
from dbus_fast import introspection as intr
with open(f"{os.path.dirname(__file__)}/data/introspection.xml") as f:
example_data = f.read()
with open(f"{os.path.dirname(__file__)}/data/strict-introspection.xml") as f:
strict_data = f.read()
with open(f"{os.path.dirname(__file__)}/data/sloppy-introspection.xml") as f:
sloppy_data = f.read()
def test_example_introspection_from_xml():
node = intr.Node.parse(example_data)
def test_introspection_from_xml_sloppy():
intr.Node.parse(sloppy_data, validate_property_names=False)
def test_introspection_from_xml_strict():
try:
node = intr.Node.parse(sloppy_data)
except InvalidMemberNameError:
pass
else:
assert False, "Expected an AssertionError"
node = intr.Node.parse(strict_data)
assert len(node.interfaces) == 1
interface = node.interfaces[0]
@ -61,12 +80,12 @@ def test_example_introspection_from_xml():
assert len(changed.args) == 1
new_value = changed.args[0]
assert type(new_value) is intr.Arg
assert new_value.name == "new_value"
assert new_value.name == "0-new_value"
assert new_value.signature == "b"
def test_example_introspection_to_xml():
node = intr.Node.parse(example_data)
node = intr.Node.parse(strict_data)
tree = node.to_xml()
assert tree.tag == "node"
assert tree.attrib.get("name") == "/com/example/sample_object0"
@ -94,7 +113,7 @@ def test_example_introspection_to_xml():
arg = signal[0]
assert arg.tag == "arg"
assert arg.attrib.get("name") == "new_value"
assert arg.attrib.get("name") == "0-new_value"
assert arg.attrib.get("type") == "b"
signal = interface[4]
@ -109,7 +128,7 @@ def test_example_introspection_to_xml():
arg = signal[1]
assert arg.tag == "arg"
assert arg.attrib.get("name") == "new_value2"
assert arg.attrib.get("name") == "0-new_value2"
assert arg.attrib.get("type") == "y"
prop = interface[5]