Skip to content

Commit

Permalink
Fix NodeId parsing for nodes containing semicolons in string identifiers
Browse files Browse the repository at this point in the history
Example:
The node `ns=9;s=Line1.nsuri=MACHINE.NS;s=MACHINE.NS.State.Running` is regularly deconstructed as NamespaceId `9`, Identifier Type `String`, Identifier `Line1.nsuri=MACHINE.NS;s=MACHINE.NS.State.Running`. Previously this was parsed to have the Identifier `MACHINE.NS.State.Running`
  • Loading branch information
Galaxy102 authored and oroulet committed Feb 21, 2024
1 parent 0122a5e commit 2b1edb7
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 2 deletions.
9 changes: 7 additions & 2 deletions asyncua/ua/uatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,8 @@ def _from_string(string):
ntype = None
srv = None
nsu = None
for el in elements:
while elements:
el = elements.pop(0) # consume exactly one part of the node name, left-to-right
if not el:
continue
k, v = el.split("=", 1)
Expand All @@ -543,7 +544,11 @@ def _from_string(string):
identifier = int(v.strip())
elif k == "s":
ntype = NodeIdType.String
identifier = v
# As per https://reference.opcfoundation.org/Core/Part3/v105/docs/8.2.4 and https://reference.opcfoundation.org/Core/Part3/v104/docs/8.2.4,
# strings may contain arbitrary non-control unicode characters, even semicolons and equals.
# We must now consume the whole rest of the identifier.
identifier = String(";".join((v, *elements)))
elements = [] # consume everything immediately
elif k == "g":
ntype = NodeIdType.Guid
identifier = uuid.UUID(f"urn:uuid:{v}")
Expand Down
8 changes: 8 additions & 0 deletions tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from pathlib import Path
from base64 import b64encode
import pytest
from asyncua.ua import NodeId, String, NodeIdType, Int16

from asyncua import Node, ua, uamethod
from asyncua.common import ua_utils
Expand Down Expand Up @@ -2097,3 +2098,10 @@ async def test_sql_injection():
table = "user'"
with pytest.raises(SqlInjectionError) as _:
validate_table_name(table)


async def test_parse_nodeid_name_contains_multiple_dividers():
raw_node_name = "ns=9;s=Line1.nsuri=MACHINE.NS;s=MACHINE.NS.State.Running"
expected_node_id = NodeId(Identifier=String("Line1.nsuri=MACHINE.NS;s=MACHINE.NS.State.Running"), NamespaceIndex=Int16(9), NodeIdType=NodeIdType.String)
got_node_id = NodeId.from_string(string=raw_node_name)
assert got_node_id == expected_node_id

0 comments on commit 2b1edb7

Please sign in to comment.