From cd1851c56b7a974107e2c7852ec3bb810d1f6f4a Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Fri, 18 Aug 2017 08:59:27 -0400 Subject: [PATCH 1/2] Fix pattern in code example in README See also #43. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index b2a8c9c..03c7cc3 100644 --- a/README.rst +++ b/README.rst @@ -39,8 +39,8 @@ constructor: from stix2 import Indicator indicator = Indicator(name="File hash for malware variant", - labels=['malicious-activity'], - pattern='file:hashes.md5 = "d41d8cd98f00b204e9800998ecf8427e"') + labels=["malicious-activity"], + pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']") Certain required attributes of all objects will be set automatically if not provided as keyword arguments: From d4edb8b0bc84e8219f2c1121ea6f50feffc80272 Mon Sep 17 00:00:00 2001 From: clenk Date: Fri, 18 Aug 2017 14:22:57 -0400 Subject: [PATCH 2/2] Validate patterns when creating Indicators --- setup.py | 1 + stix2/properties.py | 16 ++++++++++++++++ stix2/sdo.py | 6 +++--- stix2/test/test_indicator.py | 20 ++++++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index efe754c..5420e04 100644 --- a/setup.py +++ b/setup.py @@ -50,5 +50,6 @@ setup( 'six', 'python-dateutil', 'requests', + 'stix2-patterns', ], ) diff --git a/stix2/properties.py b/stix2/properties.py index f63ec8b..a04294e 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -7,6 +7,8 @@ import uuid from six import string_types, text_type +from stix2patterns.validator import run_validator + from .base import _STIXBase from .exceptions import DictionaryKeyError from .utils import get_dict, parse_into_datetime @@ -370,3 +372,17 @@ class EnumProperty(StringProperty): if value not in self.allowed: raise ValueError("value '%s' is not valid for this enumeration." % value) return self.string_type(value) + + +class PatternProperty(StringProperty): + + def __init__(self, **kwargs): + super(PatternProperty, self).__init__(**kwargs) + + def clean(self, value): + str_value = super(PatternProperty, self).clean(value) + errors = run_validator(str_value) + if errors: + raise ValueError(str(errors[0])) + + return self.string_type(value) diff --git a/stix2/sdo.py b/stix2/sdo.py index 43c8328..86e9f39 100644 --- a/stix2/sdo.py +++ b/stix2/sdo.py @@ -6,8 +6,8 @@ from .base import _STIXBase from .common import COMMON_PROPERTIES, KillChainPhase from .observables import ObservableProperty from .properties import (IDProperty, IntegerProperty, ListProperty, - ReferenceProperty, StringProperty, TimestampProperty, - TypeProperty) + PatternProperty, ReferenceProperty, StringProperty, + TimestampProperty, TypeProperty) from .utils import NOW @@ -77,7 +77,7 @@ class Indicator(_STIXBase): 'labels': ListProperty(StringProperty, required=True), 'name': StringProperty(), 'description': StringProperty(), - 'pattern': StringProperty(required=True), + 'pattern': PatternProperty(required=True), 'valid_from': TimestampProperty(default=lambda: NOW), 'valid_until': TimestampProperty(), 'kill_chain_phases': ListProperty(KillChainPhase), diff --git a/stix2/test/test_indicator.py b/stix2/test/test_indicator.py index 5daa0f6..3a486df 100644 --- a/stix2/test/test_indicator.py +++ b/stix2/test/test_indicator.py @@ -174,3 +174,23 @@ def test_parse_indicator(data): assert idctr.valid_from == dt.datetime(1970, 1, 1, 0, 0, 1, tzinfo=pytz.utc) assert idctr.labels[0] == "malicious-activity" assert idctr.pattern == "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']" + + +def test_invalid_indicator_pattern(): + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + stix2.Indicator( + labels=['malicious-activity'], + pattern="file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e'", + ) + assert excinfo.value.cls == stix2.Indicator + assert excinfo.value.prop_name == 'pattern' + assert 'input is missing square brackets' in excinfo.value.reason + + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + stix2.Indicator( + labels=['malicious-activity'], + pattern='[file:hashes.MD5 = "d41d8cd98f00b204e9800998ecf8427e"]', + ) + assert excinfo.value.cls == stix2.Indicator + assert excinfo.value.prop_name == 'pattern' + assert 'mismatched input' in excinfo.value.reason