Merge branch 'master' into fix_indicator_test

master
Chris Lenk 2020-03-05 10:51:03 -05:00 committed by GitHub
commit cdde664434
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 43 deletions

View File

@ -53,7 +53,10 @@ def _custom_marking_builder(cls, type, properties, version):
return _CustomMarking return _CustomMarking
def _custom_observable_builder(cls, type, properties, version): def _custom_observable_builder(cls, type, properties, version, id_contrib_props=None):
if id_contrib_props is None:
id_contrib_props = []
class _CustomObservable(cls, _Observable): class _CustomObservable(cls, _Observable):
if not re.match(TYPE_REGEX, type): if not re.match(TYPE_REGEX, type):
@ -98,6 +101,8 @@ def _custom_observable_builder(cls, type, properties, version):
_type = type _type = type
_properties = OrderedDict(properties) _properties = OrderedDict(properties)
if version != '2.0':
_id_contributing_properties = id_contrib_props
def __init__(self, **kwargs): def __init__(self, **kwargs):
_Observable.__init__(self, **kwargs) _Observable.__init__(self, **kwargs)

View File

@ -1,16 +1,12 @@
import importlib import importlib
import inspect import inspect
from antlr4 import CommonTokenStream, InputStream
from antlr4.tree.Trees import Trees
import six
from stix2patterns.exceptions import ParseException from stix2patterns.exceptions import ParseException
from stix2patterns.grammars.STIXPatternLexer import STIXPatternLexer
from stix2patterns.grammars.STIXPatternParser import ( from stix2patterns.grammars.STIXPatternParser import (
STIXPatternParser, TerminalNode, STIXPatternParser, TerminalNode,
) )
from stix2patterns.grammars.STIXPatternVisitor import STIXPatternVisitor from stix2patterns.grammars.STIXPatternVisitor import STIXPatternVisitor
from stix2patterns.validator import STIXPatternErrorListener from stix2patterns.v20.pattern import Pattern
from .patterns import * from .patterns import *
from .patterns import _BooleanExpression from .patterns import _BooleanExpression
@ -328,41 +324,9 @@ class STIXPatternVisitorForSTIX2(STIXPatternVisitor):
def create_pattern_object(pattern, module_suffix="", module_name=""): def create_pattern_object(pattern, module_suffix="", module_name=""):
""" """
Validates a pattern against the STIX Pattern grammar. Error messages are Create a STIX pattern AST from a pattern string.
returned in a list. The test passed if the returned list is empty.
""" """
start = '' pattern_obj = Pattern(pattern)
if isinstance(pattern, six.string_types):
start = pattern[:2]
pattern = InputStream(pattern)
if not start:
start = pattern.readline()[:2]
pattern.seek(0)
parseErrListener = STIXPatternErrorListener()
lexer = STIXPatternLexer(pattern)
# it always adds a console listener by default... remove it.
lexer.removeErrorListeners()
stream = CommonTokenStream(lexer)
parser = STIXPatternParser(stream)
parser.buildParseTrees = True
# it always adds a console listener by default... remove it.
parser.removeErrorListeners()
parser.addErrorListener(parseErrListener)
# To improve error messages, replace "<INVALID>" in the literal
# names with symbolic names. This is a hack, but seemed like
# the simplest workaround.
for i, lit_name in enumerate(parser.literalNames):
if lit_name == u"<INVALID>":
parser.literalNames[i] = parser.symbolicNames[i]
tree = parser.pattern()
builder = STIXPatternVisitorForSTIX2(module_suffix, module_name) builder = STIXPatternVisitorForSTIX2(module_suffix, module_name)
return builder.visit(tree) return pattern_obj.visit(builder)

View File

@ -1,3 +1,5 @@
import uuid
import pytest import pytest
import stix2 import stix2
@ -665,6 +667,76 @@ def test_observed_data_with_custom_observable_object():
assert ob_data.objects['0'].property1 == 'something' assert ob_data.objects['0'].property1 == 'something'
def test_custom_observable_object_det_id_1():
@stix2.v21.CustomObservable(
'x-det-id-observable-1', [
('property1', stix2.properties.StringProperty(required=True)),
('property2', stix2.properties.IntegerProperty()),
], [
'property1',
],
)
class DetIdObs1():
pass
dio_1 = DetIdObs1(property1='I am property1!', property2=42)
dio_2 = DetIdObs1(property1='I am property1!', property2=24)
assert dio_1.property1 == dio_2.property1 == 'I am property1!'
assert dio_1.id == dio_2.id
uuid_obj = uuid.UUID(dio_1.id[-36:])
assert uuid_obj.variant == uuid.RFC_4122
assert uuid_obj.version == 5
dio_3 = DetIdObs1(property1='I am property1!', property2=42)
dio_4 = DetIdObs1(property1='I am also property1!', property2=24)
assert dio_3.property1 == 'I am property1!'
assert dio_4.property1 == 'I am also property1!'
assert dio_3.id != dio_4.id
def test_custom_observable_object_det_id_2():
@stix2.v21.CustomObservable(
'x-det-id-observable-2', [
('property1', stix2.properties.StringProperty(required=True)),
('property2', stix2.properties.IntegerProperty()),
], [
'property1', 'property2',
],
)
class DetIdObs2():
pass
dio_1 = DetIdObs2(property1='I am property1!', property2=42)
dio_2 = DetIdObs2(property1='I am property1!', property2=42)
assert dio_1.property1 == dio_2.property1 == 'I am property1!'
assert dio_1.property2 == dio_2.property2 == 42
assert dio_1.id == dio_2.id
dio_3 = DetIdObs2(property1='I am property1!', property2=42)
dio_4 = DetIdObs2(property1='I am also property1!', property2=42)
assert dio_3.property1 == 'I am property1!'
assert dio_4.property1 == 'I am also property1!'
assert dio_3.property2 == dio_4.property2 == 42
assert dio_3.id != dio_4.id
def test_custom_observable_object_no_id_contrib_props():
@stix2.v21.CustomObservable(
'x-det-id-observable-3', [
('property1', stix2.properties.StringProperty(required=True)),
],
)
class DetIdObs3():
pass
dio = DetIdObs3(property1="I am property1!")
uuid_obj = uuid.UUID(dio.id[-36:])
assert uuid_obj.variant == uuid.RFC_4122
assert uuid_obj.version == 4
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.DomainName, 'x-new-ext', [ stix2.v21.DomainName, 'x-new-ext', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),

View File

@ -1,6 +1,7 @@
import datetime import datetime
import pytest import pytest
from stix2patterns.exceptions import ParseException
import stix2 import stix2
from stix2.pattern_visitor import create_pattern_object from stix2.pattern_visitor import create_pattern_object
@ -515,3 +516,8 @@ def test_list_constant():
def test_parsing_multiple_slashes_quotes(): def test_parsing_multiple_slashes_quotes():
patt_obj = create_pattern_object("[ file:name = 'weird_name\\'' ]") patt_obj = create_pattern_object("[ file:name = 'weird_name\\'' ]")
assert str(patt_obj) == "[file:name = 'weird_name\\'']" assert str(patt_obj) == "[file:name = 'weird_name\\'']"
def test_parse_error():
with pytest.raises(ParseException):
create_pattern_object("[ file: name = 'weirdname]")

View File

@ -966,7 +966,7 @@ class X509Certificate(_Observable):
self._check_at_least_one_property(att_list) self._check_at_least_one_property(att_list)
def CustomObservable(type='x-custom-observable', properties=None): def CustomObservable(type='x-custom-observable', properties=None, id_contrib_props=None):
"""Custom STIX Cyber Observable Object type decorator. """Custom STIX Cyber Observable Object type decorator.
Example: Example:
@ -987,7 +987,7 @@ def CustomObservable(type='x-custom-observable', properties=None):
properties, properties,
[('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=type))], [('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=type))],
])) ]))
return _custom_observable_builder(cls, type, _properties, '2.1') return _custom_observable_builder(cls, type, _properties, '2.1', id_contrib_props)
return wrapper return wrapper