Merge branch 'master' into fix_indicator_test
commit
cdde664434
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
|
@ -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]")
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue