finish 365
parent
844ec2c3bf
commit
f60e4170fd
|
@ -173,7 +173,7 @@ class _STIXBase(Mapping):
|
||||||
for prop_name, prop_value in custom_props.items():
|
for prop_name, prop_value in custom_props.items():
|
||||||
if not re.match(PREFIX_21_REGEX, prop_name):
|
if not re.match(PREFIX_21_REGEX, prop_name):
|
||||||
raise InvalidValueError(self.__class__, prop_name,
|
raise InvalidValueError(self.__class__, prop_name,
|
||||||
reason="Property names must begin with an alpha character.")
|
reason="Property name '%s' must begin with an alpha character." % prop_name)
|
||||||
|
|
||||||
# Remove any keyword arguments whose value is None or [] (i.e. empty list)
|
# Remove any keyword arguments whose value is None or [] (i.e. empty list)
|
||||||
setting_kwargs = {}
|
setting_kwargs = {}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import stix2
|
||||||
from .base import _Observable, _STIXBase
|
from .base import _Observable, _STIXBase
|
||||||
from .exceptions import ParseError
|
from .exceptions import ParseError
|
||||||
from .markings import _MarkingsMixin
|
from .markings import _MarkingsMixin
|
||||||
from .utils import _get_dict, SCO21_EXT_REGEX, TYPE_REGEX
|
from .utils import _get_dict, TYPE_REGEX, PREFIX_21_REGEX, TYPE_21_REGEX
|
||||||
|
|
||||||
STIX2_OBJ_MAPS = {}
|
STIX2_OBJ_MAPS = {}
|
||||||
|
|
||||||
|
@ -230,6 +230,36 @@ def _register_marking(new_marking, version=None):
|
||||||
None, use latest version.
|
None, use latest version.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
type = new_marking._type
|
||||||
|
|
||||||
|
if version == "2.0":
|
||||||
|
if not re.match(TYPE_REGEX, type):
|
||||||
|
raise ValueError(
|
||||||
|
"Invalid marking type name '%s': must only contain the "
|
||||||
|
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." %
|
||||||
|
type,
|
||||||
|
)
|
||||||
|
else: # 2.1+
|
||||||
|
if not re.match(TYPE_21_REGEX, type):
|
||||||
|
raise ValueError(
|
||||||
|
"Invalid marking type name '%s': must only contain the "
|
||||||
|
"characters a-z (lowercase ASCII), 0-9, and hyphen (-) "
|
||||||
|
"and must begin with an a-z character" % type,
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(type) < 3 or len(type) > 250:
|
||||||
|
raise ValueError(
|
||||||
|
"Invalid marking type name '%s': must be between 3 and 250 characters." % type,
|
||||||
|
)
|
||||||
|
|
||||||
|
properties = new_marking._properties
|
||||||
|
|
||||||
|
if version == "2.1":
|
||||||
|
for prop_name, prop_value in properties.items():
|
||||||
|
if not re.match(PREFIX_21_REGEX, prop_name):
|
||||||
|
raise ValueError("Property name '%s' must begin with an alpha character." % prop_name)
|
||||||
|
|
||||||
if version:
|
if version:
|
||||||
v = 'v' + version.replace('.', '')
|
v = 'v' + version.replace('.', '')
|
||||||
else:
|
else:
|
||||||
|
@ -276,6 +306,7 @@ def _register_observable_extension(
|
||||||
obs_class = observable if isinstance(observable, type) else \
|
obs_class = observable if isinstance(observable, type) else \
|
||||||
type(observable)
|
type(observable)
|
||||||
ext_type = new_extension._type
|
ext_type = new_extension._type
|
||||||
|
properties = new_extension._properties
|
||||||
|
|
||||||
if not issubclass(obs_class, _Observable):
|
if not issubclass(obs_class, _Observable):
|
||||||
raise ValueError("'observable' must be a valid Observable class!")
|
raise ValueError("'observable' must be a valid Observable class!")
|
||||||
|
@ -288,7 +319,7 @@ def _register_observable_extension(
|
||||||
ext_type,
|
ext_type,
|
||||||
)
|
)
|
||||||
else: # 2.1+
|
else: # 2.1+
|
||||||
if not re.match(SCO21_EXT_REGEX, ext_type):
|
if not re.match(TYPE_21_REGEX, ext_type):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Invalid extension type name '%s': must only contain the "
|
"Invalid extension type name '%s': must only contain the "
|
||||||
"characters a-z (lowercase ASCII), 0-9, hyphen (-), "
|
"characters a-z (lowercase ASCII), 0-9, hyphen (-), "
|
||||||
|
@ -308,6 +339,11 @@ def _register_observable_extension(
|
||||||
ext_type,
|
ext_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if version == "2.1":
|
||||||
|
for prop_name, prop_value in properties.items():
|
||||||
|
if not re.match(PREFIX_21_REGEX, prop_name):
|
||||||
|
raise ValueError("Property name '%s' must begin with an alpha character." % prop_name)
|
||||||
|
|
||||||
v = 'v' + version.replace('.', '')
|
v = 'v' + version.replace('.', '')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -8,7 +8,7 @@ from .core import (
|
||||||
STIXDomainObject, _register_marking, _register_object,
|
STIXDomainObject, _register_marking, _register_object,
|
||||||
_register_observable, _register_observable_extension,
|
_register_observable, _register_observable_extension,
|
||||||
)
|
)
|
||||||
from .utils import get_class_hierarchy_names, SCO21_TYPE_REGEX, TYPE_REGEX, PREFIX_21_REGEX
|
from .utils import get_class_hierarchy_names, TYPE_21_REGEX, TYPE_REGEX, PREFIX_21_REGEX
|
||||||
|
|
||||||
|
|
||||||
def _custom_object_builder(cls, type, properties, version):
|
def _custom_object_builder(cls, type, properties, version):
|
||||||
|
@ -22,7 +22,7 @@ def _custom_object_builder(cls, type, properties, version):
|
||||||
type,
|
type,
|
||||||
)
|
)
|
||||||
else: # 2.1+
|
else: # 2.1+
|
||||||
if not re.match(SCO21_TYPE_REGEX, type):
|
if not re.match(TYPE_21_REGEX, type):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Invalid type name '%s': must only contain the "
|
"Invalid type name '%s': must only contain the "
|
||||||
"characters a-z (lowercase ASCII), 0-9, and hyphen (-) "
|
"characters a-z (lowercase ASCII), 0-9, and hyphen (-) "
|
||||||
|
@ -40,7 +40,7 @@ def _custom_object_builder(cls, type, properties, version):
|
||||||
if version == "2.1":
|
if version == "2.1":
|
||||||
for prop_name, prop in properties:
|
for prop_name, prop in properties:
|
||||||
if not re.match(PREFIX_21_REGEX, prop_name):
|
if not re.match(PREFIX_21_REGEX, prop_name):
|
||||||
raise ValueError("Property name %s must begin with an alpha character" % prop_name)
|
raise ValueError("Property name '%s' must begin with an alpha character" % prop_name)
|
||||||
|
|
||||||
_type = type
|
_type = type
|
||||||
_properties = OrderedDict(properties)
|
_properties = OrderedDict(properties)
|
||||||
|
@ -55,48 +55,8 @@ def _custom_object_builder(cls, type, properties, version):
|
||||||
|
|
||||||
def _custom_marking_builder(cls, type, properties, version):
|
def _custom_marking_builder(cls, type, properties, version):
|
||||||
|
|
||||||
try:
|
|
||||||
prop_dict = OrderedDict(properties)
|
|
||||||
except TypeError as e:
|
|
||||||
six.raise_from(
|
|
||||||
ValueError(
|
|
||||||
"Marking properties must be dict-like, e.g. a list "
|
|
||||||
"containing tuples. For example, "
|
|
||||||
"[('property1', IntegerProperty())]",
|
|
||||||
),
|
|
||||||
e,
|
|
||||||
)
|
|
||||||
|
|
||||||
class _CustomMarking(cls, _STIXBase):
|
class _CustomMarking(cls, _STIXBase):
|
||||||
|
|
||||||
if version == "2.0":
|
|
||||||
if not re.match(TYPE_REGEX, type):
|
|
||||||
raise ValueError(
|
|
||||||
"Invalid marking type name '%s': must only contain the "
|
|
||||||
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." %
|
|
||||||
type,
|
|
||||||
)
|
|
||||||
else: # 2.1+
|
|
||||||
if not re.match(SCO21_TYPE_REGEX, type):
|
|
||||||
raise ValueError(
|
|
||||||
"Invalid marking type name '%s': must only contain the "
|
|
||||||
"characters a-z (lowercase ASCII), 0-9, and hyphen (-) "
|
|
||||||
"and must begin with an a-z character" % type,
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(type) < 3 or len(type) > 250:
|
|
||||||
raise ValueError(
|
|
||||||
"Invalid marking type name '%s': must be between 3 and 250 characters." % type,
|
|
||||||
)
|
|
||||||
|
|
||||||
if not properties or not isinstance(properties, list):
|
|
||||||
raise ValueError("Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]")
|
|
||||||
|
|
||||||
if version == "2.1 ":
|
|
||||||
for prop_name, prop_value in prop_dict.items():
|
|
||||||
if not re.match(PREFIX_21_REGEX, prop_name):
|
|
||||||
raise ValueError("Property name %s must begin with an alpha character." % prop_name)
|
|
||||||
|
|
||||||
_type = type
|
_type = type
|
||||||
_properties = OrderedDict(properties)
|
_properties = OrderedDict(properties)
|
||||||
|
|
||||||
|
@ -122,7 +82,7 @@ def _custom_observable_builder(cls, type, properties, version, id_contrib_props=
|
||||||
type,
|
type,
|
||||||
)
|
)
|
||||||
else: # 2.1+
|
else: # 2.1+
|
||||||
if not re.match(SCO21_TYPE_REGEX, type):
|
if not re.match(TYPE_21_REGEX, type):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Invalid observable type name '%s': must only contain the "
|
"Invalid observable type name '%s': must only contain the "
|
||||||
"characters a-z (lowercase ASCII), 0-9, and hyphen (-) "
|
"characters a-z (lowercase ASCII), 0-9, and hyphen (-) "
|
||||||
|
@ -153,7 +113,7 @@ def _custom_observable_builder(cls, type, properties, version, id_contrib_props=
|
||||||
# If using STIX2.1 (or newer...), check properties ending in "_ref/s" are ReferenceProperties
|
# If using STIX2.1 (or newer...), check properties ending in "_ref/s" are ReferenceProperties
|
||||||
for prop_name, prop in properties:
|
for prop_name, prop in properties:
|
||||||
if not re.match(PREFIX_21_REGEX, prop_name):
|
if not re.match(PREFIX_21_REGEX, prop_name):
|
||||||
raise ValueError("Property name %s must begin with an alpha character." % prop_name)
|
raise ValueError("Property name '%s' must begin with an alpha character." % prop_name)
|
||||||
elif prop_name.endswith('_ref') and ('ReferenceProperty' not in get_class_hierarchy_names(prop)):
|
elif prop_name.endswith('_ref') and ('ReferenceProperty' not in get_class_hierarchy_names(prop)):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"'%s' is named like a reference property but "
|
"'%s' is named like a reference property but "
|
||||||
|
@ -195,11 +155,6 @@ def _custom_extension_builder(cls, observable, type, properties, version):
|
||||||
|
|
||||||
class _CustomExtension(cls, _Extension):
|
class _CustomExtension(cls, _Extension):
|
||||||
|
|
||||||
if version == "2.1":
|
|
||||||
for prop_name, prop_value in prop_dict.items():
|
|
||||||
if not re.match(PREFIX_21_REGEX, prop_name):
|
|
||||||
raise ValueError("Property name %s must begin with an alpha character." % prop_name)
|
|
||||||
|
|
||||||
_type = type
|
_type = type
|
||||||
_properties = prop_dict
|
_properties = prop_dict
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ import stix2.v21
|
||||||
from ...exceptions import InvalidValueError
|
from ...exceptions import InvalidValueError
|
||||||
from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID
|
from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID
|
||||||
|
|
||||||
|
# Custom Properties in SDOs
|
||||||
|
|
||||||
IDENTITY_CUSTOM_PROP = stix2.v21.Identity(
|
IDENTITY_CUSTOM_PROP = stix2.v21.Identity(
|
||||||
name="John Smith",
|
name="John Smith",
|
||||||
identity_class="individual",
|
identity_class="individual",
|
||||||
|
@ -54,7 +56,7 @@ def test_identity_custom_property():
|
||||||
"7foo": "bar",
|
"7foo": "bar",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert "Property names must begin with an alpha character." in str(excinfo.value)
|
assert "must begin with an alpha character." in str(excinfo.value)
|
||||||
|
|
||||||
identity = stix2.v21.Identity(
|
identity = stix2.v21.Identity(
|
||||||
id=IDENTITY_ID,
|
id=IDENTITY_ID,
|
||||||
|
@ -178,6 +180,7 @@ def test_custom_properties_dict_in_bundled_object():
|
||||||
assert bundle.objects[0].x_foo == "bar"
|
assert bundle.objects[0].x_foo == "bar"
|
||||||
assert '"x_foo": "bar"' in str(bundle)
|
assert '"x_foo": "bar"' in str(bundle)
|
||||||
|
|
||||||
|
# Custom properties in SCOs
|
||||||
|
|
||||||
def test_custom_property_in_observed_data():
|
def test_custom_property_in_observed_data():
|
||||||
artifact = stix2.v21.File(
|
artifact = stix2.v21.File(
|
||||||
|
@ -206,7 +209,7 @@ def test_invalid_custom_property_in_observed_data():
|
||||||
x_foo='bar',
|
x_foo='bar',
|
||||||
)
|
)
|
||||||
|
|
||||||
assert "Property names must begin with an alpha character." in str(excinfo.value)
|
assert "must begin with an alpha character." in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
def test_custom_property_object_in_observable_extension():
|
def test_custom_property_object_in_observable_extension():
|
||||||
|
@ -270,6 +273,7 @@ def test_identity_custom_property_revoke():
|
||||||
identity = IDENTITY_CUSTOM_PROP.revoke()
|
identity = IDENTITY_CUSTOM_PROP.revoke()
|
||||||
assert identity.x_foo == "bar"
|
assert identity.x_foo == "bar"
|
||||||
|
|
||||||
|
# Custom markings
|
||||||
|
|
||||||
def test_identity_custom_property_edit_markings():
|
def test_identity_custom_property_edit_markings():
|
||||||
marking_obj = stix2.v21.MarkingDefinition(
|
marking_obj = stix2.v21.MarkingDefinition(
|
||||||
|
@ -302,7 +306,7 @@ def test_invalid_custom_property_in_marking():
|
||||||
class NewObj():
|
class NewObj():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert "Property names must begin with an alpha character." in str(excinfo.value)
|
assert "must begin with an alpha character." in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
def test_custom_marking_no_init_1():
|
def test_custom_marking_no_init_1():
|
||||||
|
@ -362,6 +366,7 @@ def test_custom_marking_invalid_type_name():
|
||||||
pass # pragma: no cover
|
pass # pragma: no cover
|
||||||
assert "Invalid marking type name '7x-new-marking':" in str(excinfo.value)
|
assert "Invalid marking type name '7x-new-marking':" in str(excinfo.value)
|
||||||
|
|
||||||
|
# Custom Objects
|
||||||
|
|
||||||
@stix2.v21.CustomObject(
|
@stix2.v21.CustomObject(
|
||||||
'x-new-type', [
|
'x-new-type', [
|
||||||
|
@ -492,6 +497,7 @@ def test_parse_unregistered_custom_object_type_w_allow_custom():
|
||||||
custom_obj = stix2.parse(nt_string, version="2.1", allow_custom=True)
|
custom_obj = stix2.parse(nt_string, version="2.1", allow_custom=True)
|
||||||
assert custom_obj["type"] == "x-foobar-observable"
|
assert custom_obj["type"] == "x-foobar-observable"
|
||||||
|
|
||||||
|
# Custom SCOs
|
||||||
|
|
||||||
@stix2.v21.CustomObservable(
|
@stix2.v21.CustomObservable(
|
||||||
'x-new-observable', [
|
'x-new-observable', [
|
||||||
|
@ -559,6 +565,18 @@ def test_custom_observable_object_no_init_2():
|
||||||
assert no2.property1 == 'something'
|
assert no2.property1 == 'something'
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_custom_property_in_custom_observable_object():
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
@stix2.v21.CustomObservable(
|
||||||
|
'x-new-sco', [
|
||||||
|
('5property1', stix2.properties.StringProperty()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewObs(object):
|
||||||
|
pass # pragma: no cover
|
||||||
|
assert "must begin with an alpha character." in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
def test_custom_observable_object_invalid_type_name():
|
def test_custom_observable_object_invalid_type_name():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
@stix2.v21.CustomObservable(
|
@stix2.v21.CustomObservable(
|
||||||
|
@ -826,6 +844,7 @@ def test_custom_observable_object_no_id_contrib_props():
|
||||||
assert uuid_obj.variant == uuid.RFC_4122
|
assert uuid_obj.variant == uuid.RFC_4122
|
||||||
assert uuid_obj.version == 4
|
assert uuid_obj.version == 4
|
||||||
|
|
||||||
|
# Custom Extensions
|
||||||
|
|
||||||
@stix2.v21.CustomExtension(
|
@stix2.v21.CustomExtension(
|
||||||
stix2.v21.DomainName, 'x-new-ext', [
|
stix2.v21.DomainName, 'x-new-ext', [
|
||||||
|
@ -1023,6 +1042,20 @@ def test_custom_extension_no_init_2():
|
||||||
assert ne2.property1 == "foobar"
|
assert ne2.property1 == "foobar"
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_custom_property_in_extension():
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
@stix2.v21.CustomExtension(
|
||||||
|
stix2.v21.DomainName, 'x-new3-ext', [
|
||||||
|
('6property1', stix2.properties.StringProperty(required=True)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
class NewExt():
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert "must begin with an alpha character." in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_observable_with_custom_extension():
|
def test_parse_observable_with_custom_extension():
|
||||||
input_str = """{
|
input_str = """{
|
||||||
"type": "domain-name",
|
"type": "domain-name",
|
||||||
|
|
|
@ -27,8 +27,8 @@ NOW = object()
|
||||||
STIX_UNMOD_PROPERTIES = ['created', 'created_by_ref', 'id', 'type']
|
STIX_UNMOD_PROPERTIES = ['created', 'created_by_ref', 'id', 'type']
|
||||||
|
|
||||||
TYPE_REGEX = re.compile(r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-?$')
|
TYPE_REGEX = re.compile(r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-?$')
|
||||||
SCO21_TYPE_REGEX = re.compile(r'^\-?([a-z][a-z0-9]*)+(-[a-z0-9]+)*\-?$')
|
TYPE_21_REGEX = re.compile(r'^\-?([a-z][a-z0-9]*)+(-[a-z0-9]+)*\-?$')
|
||||||
SCO21_EXT_REGEX = re.compile(r'^\-?([a-z][a-z0-9]*)+(-[a-z0-9]+)*\-ext$')
|
EXT_21_REGEX = re.compile(r'^\-?([a-z][a-z0-9]*)+(-[a-z0-9]+)*\-ext$')
|
||||||
PREFIX_21_REGEX = re.compile(r'^[a-z].*')
|
PREFIX_21_REGEX = re.compile(r'^[a-z].*')
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue