handle quoted path components

pull/1/head
Rich Piazza 2020-07-30 15:32:06 -04:00
parent b7a30befdc
commit 8f76a84bbf
4 changed files with 38 additions and 6 deletions

View File

@ -2,6 +2,7 @@
import importlib import importlib
import inspect import inspect
from six import text_type
from stix2patterns.exceptions import ParseException from stix2patterns.exceptions import ParseException
from stix2patterns.grammars.STIXPatternParser import TerminalNode from stix2patterns.grammars.STIXPatternParser import TerminalNode
@ -50,7 +51,7 @@ def check_for_valid_timetamp_syntax(timestamp_string):
def same_boolean_operator(current_op, op_token): def same_boolean_operator(current_op, op_token):
return current_op == op_token.symbol.text return current_op == op_token.getText()
class STIXPatternVisitorForSTIX2(): class STIXPatternVisitorForSTIX2():
@ -260,7 +261,9 @@ class STIXPatternVisitorForSTIX2():
property_path.append(self.instantiate("ListObjectPathComponent", current.property_name, next.getText())) property_path.append(self.instantiate("ListObjectPathComponent", current.property_name, next.getText()))
i += 2 i += 2
elif isinstance(next, IntegerConstant): elif isinstance(next, IntegerConstant):
property_path.append(self.instantiate("ListObjectPathComponent", current.property_name, next.value)) property_path.append(self.instantiate("ListObjectPathComponent",
current.property_name if isinstance(current, BasicObjectPathComponent) else text_type(current),
next.value))
i += 2 i += 2
else: else:
property_path.append(current) property_path.append(current)
@ -275,7 +278,12 @@ class STIXPatternVisitorForSTIX2():
# Visit a parse tree produced by STIXPatternParser#firstPathComponent. # Visit a parse tree produced by STIXPatternParser#firstPathComponent.
def visitFirstPathComponent(self, ctx): def visitFirstPathComponent(self, ctx):
children = self.visitChildren(ctx) children = self.visitChildren(ctx)
step = children[0].getText() first_component = children[0]
# hack for when the first component isn't a TerminalNode (see issue #438)
if isinstance(first_component, TerminalNode):
step = first_component.getText()
else:
step = text_type(first_component)
# if step.endswith("_ref"): # if step.endswith("_ref"):
# return stix2.ReferenceObjectPathComponent(step) # return stix2.ReferenceObjectPathComponent(step)
# else: # else:
@ -294,8 +302,8 @@ class STIXPatternVisitorForSTIX2():
def visitKeyPathStep(self, ctx): def visitKeyPathStep(self, ctx):
children = self.visitChildren(ctx) children = self.visitChildren(ctx)
if isinstance(children[1], StringConstant): if isinstance(children[1], StringConstant):
# special case for hashes # special case for hashes and quoted steps
return children[1].value return children[1]
else: else:
return self.instantiate("BasicObjectPathComponent", children[1].getText(), True) return self.instantiate("BasicObjectPathComponent", children[1].getText(), True)

View File

@ -248,7 +248,10 @@ def make_constant(value):
class _ObjectPathComponent(object): class _ObjectPathComponent(object):
@staticmethod @staticmethod
def create_ObjectPathComponent(component_name): def create_ObjectPathComponent(component_name):
if component_name.endswith("_ref"): # first case is to handle if component_name was quoted
if isinstance(component_name, StringConstant):
return BasicObjectPathComponent(component_name.value, False)
elif component_name.endswith("_ref"):
return ReferenceObjectPathComponent(component_name) return ReferenceObjectPathComponent(component_name)
elif component_name.find("[") != -1: elif component_name.find("[") != -1:
parse1 = component_name.split("[") parse1 = component_name.split("[")

View File

@ -526,6 +526,17 @@ def test_parsing_integer_index():
assert str(patt_obj) == "[a:b[1] = 2]" assert str(patt_obj) == "[a:b[1] = 2]"
# This should never occur, because the first component will always be a property_name, and they should not be quoted.
def test_parsing_quoted_first_path_component():
patt_obj = create_pattern_object("[a:'b'[1]=2]")
assert str(patt_obj) == "[a:'b'[1] = 2]"
def test_parsing_quoted_second_path_component():
patt_obj = create_pattern_object("[a:b.'b'[1]=2]")
assert str(patt_obj) == "[a:b.'b'[1] = 2]"
def test_parsing_illegal_start_stop_qualified_expression(): def test_parsing_illegal_start_stop_qualified_expression():
with pytest.raises(ValueError): with pytest.raises(ValueError):
create_pattern_object("[ipv4-addr:value = '1.2.3.4'] START '2016-06-01' STOP '2017-03-12T08:30:00Z'", version="2.0") create_pattern_object("[ipv4-addr:value = '1.2.3.4'] START '2016-06-01' STOP '2017-03-12T08:30:00Z'", version="2.0")

View File

@ -658,6 +658,16 @@ def test_parsing_integer_index():
patt_obj = create_pattern_object("[a:b[1]=2]") patt_obj = create_pattern_object("[a:b[1]=2]")
assert str(patt_obj) == "[a:b[1] = 2]" assert str(patt_obj) == "[a:b[1] = 2]"
# This should never occur, because the first component will always be a property_name, and they should not be quoted.
def test_parsing_quoted_first_path_component():
patt_obj = create_pattern_object("[a:'b'[1]=2]")
assert str(patt_obj) == "[a:'b'[1] = 2]"
def test_parsing_quoted_second_path_component():
patt_obj = create_pattern_object("[a:b.'b'[1]=2]")
assert str(patt_obj) == "[a:b.'b'[1] = 2]"
def test_parsing_multiple_slashes_quotes(): def test_parsing_multiple_slashes_quotes():
patt_obj = create_pattern_object("[ file:name = 'weird_name\\'' ]", version="2.1") patt_obj = create_pattern_object("[ file:name = 'weird_name\\'' ]", version="2.1")