diff --git a/stix2/pattern_visitor.py b/stix2/pattern_visitor.py index f947437..a891e12 100644 --- a/stix2/pattern_visitor.py +++ b/stix2/pattern_visitor.py @@ -3,7 +3,6 @@ import inspect from stix2patterns.exceptions import ParseException from stix2patterns.grammars.STIXPatternParser import TerminalNode -from stix2patterns.grammars.STIXPatternVisitor import STIXPatternVisitor from stix2patterns.v20.grammars.STIXPatternParser import \ STIXPatternParser as STIXPatternParser20 from stix2patterns.v20.grammars.STIXPatternVisitor import \ @@ -102,7 +101,10 @@ class STIXPatternVisitorForSTIX2(): # Visit a parse tree produced by STIXPatternParser#observationExpressionCompound. def visitObservationExpressionCompound(self, ctx): children = self.visitChildren(ctx) - return self.instantiate("ObservationExpression", children[1]) + if isinstance(children[0], TerminalNode) and children[0].symbol.type == self.parser_class.LPAREN: + return self.instantiate("ParentheticalExpression", children[1]) + else: + return self.instantiate("ObservationExpression", children[0]) # Visit a parse tree produced by STIXPatternParser#observationExpressionWithin. def visitObservationExpressionWithin(self, ctx): diff --git a/stix2/patterns.py b/stix2/patterns.py index 2e149be..f0cceb8 100644 --- a/stix2/patterns.py +++ b/stix2/patterns.py @@ -551,7 +551,7 @@ class ObservationExpression(_PatternExpression): self.operand = operand def __str__(self): - return "[%s]" % self.operand + return "%s" % self.operand if isinstance(self.operand, (ObservationExpression, _CompoundObservationExpression)) else "[%s]" % self.operand class _CompoundObservationExpression(_PatternExpression): diff --git a/stix2/test/v21/test_pattern_expressions.py b/stix2/test/v21/test_pattern_expressions.py index 804e88c..f176db7 100644 --- a/stix2/test/v21/test_pattern_expressions.py +++ b/stix2/test/v21/test_pattern_expressions.py @@ -216,6 +216,31 @@ def test_parsing_less_than_or_equal(): assert str(patt_obj) == "[file:size <= 1024]" +def test_parsing_issubset(): + patt_obj = create_pattern_object("[network-traffic:dst_ref.value ISSUBSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']") + assert str(patt_obj) == "[network-traffic:dst_ref.value ISSUBSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']" + + +def test_parsing_issuperset(): + patt_obj = create_pattern_object("[network-traffic:dst_ref.value ISSUPERSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']") + assert str(patt_obj) == "[network-traffic:dst_ref.value ISSUPERSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']" + + +def test_parsing_like(): + patt_obj = create_pattern_object("[directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo']") + assert str(patt_obj) == "[directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo']" + + +def test_parsing_match(): + patt_obj = create_pattern_object("[process:command_line MATCHES '^.+>-add GlobalSign.cer -c -s -r localMachine Root$'] FOLLOWEDBY [process:command_line MATCHES '^.+>-add GlobalSign.cer -c -s -r localMachineTrustedPublisher$'] WITHIN 300 SECONDS") # noqa + assert str(patt_obj) == "[process:command_line MATCHES '^.+>-add GlobalSign.cer -c -s -r localMachine Root$'] FOLLOWEDBY [process:command_line MATCHES '^.+>-add GlobalSign.cer -c -s -r localMachineTrustedPublisher$'] WITHIN 300 SECONDS" + + +def test_parsing_followed_by(): + patt_obj = create_pattern_object("([file:hashes.MD5 = '79054025255fb1a26e4bc422aef54eb4'] FOLLOWEDBY [windows-registry-key:key = 'HKEY_LOCAL_MACHINE\\\\foo\\\\bar']) WITHIN 300 SECONDS") # noqa + assert str(patt_obj) == "([file:hashes.MD5 = '79054025255fb1a26e4bc422aef54eb4'] FOLLOWEDBY [windows-registry-key:key = 'HKEY_LOCAL_MACHINE\\\\foo\\\\bar']) WITHIN 300 SECONDS" # noqa + + def test_not(): exp = stix2.LessThanComparisonExpression( "file:size",