From 34002c4f7cc13d46b2e11a6af117e0c238fbdb27 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Fri, 21 Dec 2018 14:33:59 -0500 Subject: [PATCH 1/6] Fix error when printing WindowsRegistryKey Caused by WindowsRegistryKey having a 'values' property. Fixes #236. --- stix2/test/v20/test_observed_data.py | 2 ++ stix2/test/v21/test_observed_data.py | 2 ++ stix2/v20/observables.py | 15 ++++++++++++++- stix2/v21/observables.py | 15 ++++++++++++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/stix2/test/v20/test_observed_data.py b/stix2/test/v20/test_observed_data.py index 41a80d6..190a1f0 100644 --- a/stix2/test/v20/test_observed_data.py +++ b/stix2/test/v20/test_observed_data.py @@ -1290,6 +1290,8 @@ def test_windows_registry_key_example(): assert w.values[0].name == "Foo" assert w.values[0].data == "qwerty" assert w.values[0].data_type == "REG_SZ" + # ensure no errors in serialization because of 'values' + assert "Foo" in str(w) def test_x509_certificate_example(): diff --git a/stix2/test/v21/test_observed_data.py b/stix2/test/v21/test_observed_data.py index 5a5881a..6d4eda8 100644 --- a/stix2/test/v21/test_observed_data.py +++ b/stix2/test/v21/test_observed_data.py @@ -1264,6 +1264,8 @@ def test_windows_registry_key_example(): assert w.values[0].name == "Foo" assert w.values[0].data == "qwerty" assert w.values[0].data_type == "REG_SZ" + # ensure no errors in serialization because of 'values' + assert "Foo" in str(w) def test_x509_certificate_example(): diff --git a/stix2/v20/observables.py b/stix2/v20/observables.py index 0e7c4a0..a462661 100644 --- a/stix2/v20/observables.py +++ b/stix2/v20/observables.py @@ -706,6 +706,19 @@ class WindowsRegistryValueType(_STIXBase): ]) +class CallableValues(list): + """Wrapper to allow `values()` method on WindowsRegistryKey objects. + Needed because `values` is also a property. + """ + + def __init__(self, parent_instance, *args, **kwargs): + self.parent_instance = parent_instance + super(CallableValues, self).__init__(*args, **kwargs) + + def __call__(self): + return _Observable.values(self.parent_instance) + + class WindowsRegistryKey(_Observable): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. @@ -726,7 +739,7 @@ class WindowsRegistryKey(_Observable): @property def values(self): # Needed because 'values' is a property on collections.Mapping objects - return self._inner['values'] + return CallableValues(self, self._inner['values']) class X509V3ExtenstionsType(_STIXBase): diff --git a/stix2/v21/observables.py b/stix2/v21/observables.py index 1b2251d..92fe36a 100644 --- a/stix2/v21/observables.py +++ b/stix2/v21/observables.py @@ -758,6 +758,19 @@ class WindowsRegistryValueType(_STIXBase): ]) +class CallableValues(list): + """Wrapper to allow `values()` method on WindowsRegistryKey objects. + Needed because `values` is also a property. + """ + + def __init__(self, parent_instance, *args, **kwargs): + self.parent_instance = parent_instance + super(CallableValues, self).__init__(*args, **kwargs) + + def __call__(self): + return _Observable.values(self.parent_instance) + + class WindowsRegistryKey(_Observable): # TODO: Add link """For more detailed information on this object's properties, see @@ -779,7 +792,7 @@ class WindowsRegistryKey(_Observable): @property def values(self): # Needed because 'values' is a property on collections.Mapping objects - return self._inner['values'] + return CallableValues(self, self._inner['values']) class X509V3ExtenstionsType(_STIXBase): From 2966efa4f0418ea605a5cdce6409032a45534d18 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Mon, 7 Jan 2019 11:15:47 -0500 Subject: [PATCH 2/6] Remove dictionary/extension property non-empty req Only bundle.objects and observed-data.objects have a requirement to include at least one item. --- stix2/properties.py | 4 ---- stix2/test/v20/test_observed_data.py | 9 --------- stix2/test/v20/test_properties.py | 1 - stix2/test/v21/test_observed_data.py | 9 --------- stix2/test/v21/test_properties.py | 1 - 5 files changed, 24 deletions(-) diff --git a/stix2/properties.py b/stix2/properties.py index 24549aa..7202f9a 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -291,8 +291,6 @@ class DictionaryProperty(Property): dictified = _get_dict(value) except ValueError: raise ValueError("The dictionary property must contain a dictionary") - if dictified == {}: - raise ValueError("The dictionary property must contain a non-empty dictionary") for k in dictified.keys(): if self.spec_version == '2.0': if len(k) < 3: @@ -498,8 +496,6 @@ class ExtensionsProperty(DictionaryProperty): dictified = copy.deepcopy(dictified) except ValueError: raise ValueError("The extensions property must contain a dictionary") - if dictified == {}: - raise ValueError("The extensions property must contain a non-empty dictionary") v = 'v' + self.spec_version.replace('.', '') diff --git a/stix2/test/v20/test_observed_data.py b/stix2/test/v20/test_observed_data.py index 41a80d6..b922c81 100644 --- a/stix2/test/v20/test_observed_data.py +++ b/stix2/test/v20/test_observed_data.py @@ -1140,15 +1140,6 @@ def test_process_example_windows_process_ext_empty(): assert excinfo.value.properties == sorted(properties_of_extension) -def test_process_example_extensions_empty(): - with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: - stix2.v20.Process(extensions={}) - - assert excinfo.value.cls == stix2.v20.Process - assert excinfo.value.prop_name == 'extensions' - assert 'non-empty dictionary' in excinfo.value.reason - - def test_process_example_with_WindowsProcessExt_Object(): p = stix2.v20.Process(extensions={ "windows-process-ext": stix2.v20.WindowsProcessExt( diff --git a/stix2/test/v20/test_properties.py b/stix2/test/v20/test_properties.py index 24c1c99..e9a513e 100644 --- a/stix2/test/v20/test_properties.py +++ b/stix2/test/v20/test_properties.py @@ -360,7 +360,6 @@ def test_dictionary_property_invalid_key(d): @pytest.mark.parametrize( "d", [ - ({}, "The dictionary property must contain a non-empty dictionary"), # TODO: This error message could be made more helpful. The error is caused # because `json.loads()` doesn't like the *single* quotes around the key # name, even though they are valid in a Python dictionary. While technically diff --git a/stix2/test/v21/test_observed_data.py b/stix2/test/v21/test_observed_data.py index 5a5881a..c859aed 100644 --- a/stix2/test/v21/test_observed_data.py +++ b/stix2/test/v21/test_observed_data.py @@ -1114,15 +1114,6 @@ def test_process_example_windows_process_ext_empty(): assert excinfo.value.properties == sorted(properties_of_extension) -def test_process_example_extensions_empty(): - with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: - stix2.v21.Process(extensions={}) - - assert excinfo.value.cls == stix2.v21.Process - assert excinfo.value.prop_name == 'extensions' - assert 'non-empty dictionary' in excinfo.value.reason - - def test_process_example_with_WindowsProcessExt_Object(): p = stix2.v21.Process(extensions={ "windows-process-ext": stix2.v21.WindowsProcessExt( diff --git a/stix2/test/v21/test_properties.py b/stix2/test/v21/test_properties.py index 611ec5e..298a8df 100644 --- a/stix2/test/v21/test_properties.py +++ b/stix2/test/v21/test_properties.py @@ -369,7 +369,6 @@ def test_dictionary_property_invalid_key(d): @pytest.mark.parametrize( "d", [ - ({}, "The dictionary property must contain a non-empty dictionary"), # TODO: This error message could be made more helpful. The error is caused # because `json.loads()` doesn't like the *single* quotes around the key # name, even though they are valid in a Python dictionary. While technically From ab687d8d0e8e8acef86de1c0014bc7b28ae7bf10 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Mon, 7 Jan 2019 15:22:08 -0500 Subject: [PATCH 3/6] Test empty extension property serialization --- stix2/test/v20/test_observed_data.py | 10 ++++++++++ stix2/test/v21/test_observed_data.py | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/stix2/test/v20/test_observed_data.py b/stix2/test/v20/test_observed_data.py index b922c81..17d732e 100644 --- a/stix2/test/v20/test_observed_data.py +++ b/stix2/test/v20/test_observed_data.py @@ -1140,6 +1140,16 @@ def test_process_example_windows_process_ext_empty(): assert excinfo.value.properties == sorted(properties_of_extension) +def test_process_example_extensions_empty(): + proc = stix2.v20.Process( + pid=314, + name="foobar.exe", + extensions={}, + ) + + assert '{}' in str(proc) + + def test_process_example_with_WindowsProcessExt_Object(): p = stix2.v20.Process(extensions={ "windows-process-ext": stix2.v20.WindowsProcessExt( diff --git a/stix2/test/v21/test_observed_data.py b/stix2/test/v21/test_observed_data.py index c859aed..d3ecde8 100644 --- a/stix2/test/v21/test_observed_data.py +++ b/stix2/test/v21/test_observed_data.py @@ -1114,6 +1114,16 @@ def test_process_example_windows_process_ext_empty(): assert excinfo.value.properties == sorted(properties_of_extension) +def test_process_example_extensions_empty(): + proc = stix2.v20.Process( + pid=314, + name="foobar.exe", + extensions={}, + ) + + assert '{}' in str(proc) + + def test_process_example_with_WindowsProcessExt_Object(): p = stix2.v21.Process(extensions={ "windows-process-ext": stix2.v21.WindowsProcessExt( From 67d3970a507a578aacfdac166028189d5fc9178f Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Tue, 8 Jan 2019 09:35:01 -0500 Subject: [PATCH 4/6] Update test_observed_data.py Change to correct version --- stix2/test/v21/test_observed_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix2/test/v21/test_observed_data.py b/stix2/test/v21/test_observed_data.py index d3ecde8..69b170a 100644 --- a/stix2/test/v21/test_observed_data.py +++ b/stix2/test/v21/test_observed_data.py @@ -1115,7 +1115,7 @@ def test_process_example_windows_process_ext_empty(): def test_process_example_extensions_empty(): - proc = stix2.v20.Process( + proc = stix2.v21.Process( pid=314, name="foobar.exe", extensions={}, From 26a658b7899aa857cdc10e9b3b3ee67c1ed819bd Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Tue, 8 Jan 2019 09:41:53 -0500 Subject: [PATCH 5/6] Update test to v21 --- stix2/test/v21/test_observed_data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stix2/test/v21/test_observed_data.py b/stix2/test/v21/test_observed_data.py index 69b170a..d2aaf52 100644 --- a/stix2/test/v21/test_observed_data.py +++ b/stix2/test/v21/test_observed_data.py @@ -1117,7 +1117,6 @@ def test_process_example_windows_process_ext_empty(): def test_process_example_extensions_empty(): proc = stix2.v21.Process( pid=314, - name="foobar.exe", extensions={}, ) From 1ad64dfc0c134bdf90f714e068513f1b45712d91 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Wed, 9 Jan 2019 10:46:48 -0500 Subject: [PATCH 6/6] Move CallableValues to prevent duplicate code --- stix2/properties.py | 15 ++++++++++++++- stix2/v20/observables.py | 15 +-------------- stix2/v21/observables.py | 15 +-------------- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/stix2/properties.py b/stix2/properties.py index 24549aa..5e1b07f 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -11,7 +11,7 @@ import uuid from six import string_types, text_type from stix2patterns.validator import run_validator -from .base import _STIXBase +from .base import _Observable, _STIXBase from .core import STIX2_OBJ_MAPS, parse, parse_observable from .exceptions import CustomContentError, DictionaryKeyError from .utils import _get_dict, get_class_hierarchy_names, parse_into_datetime @@ -167,6 +167,19 @@ class ListProperty(Property): return result +class CallableValues(list): + """Wrapper to allow `values()` method on WindowsRegistryKey objects. + Needed because `values` is also a property. + """ + + def __init__(self, parent_instance, *args, **kwargs): + self.parent_instance = parent_instance + super(CallableValues, self).__init__(*args, **kwargs) + + def __call__(self): + return _Observable.values(self.parent_instance) + + class StringProperty(Property): def __init__(self, **kwargs): diff --git a/stix2/v20/observables.py b/stix2/v20/observables.py index a462661..55872cd 100644 --- a/stix2/v20/observables.py +++ b/stix2/v20/observables.py @@ -12,7 +12,7 @@ from ..base import _Extension, _Observable, _STIXBase from ..custom import _custom_extension_builder, _custom_observable_builder from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError from ..properties import ( - BinaryProperty, BooleanProperty, DictionaryProperty, + BinaryProperty, BooleanProperty, CallableValues, DictionaryProperty, EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty, HashesProperty, HexProperty, IntegerProperty, ListProperty, ObjectReferenceProperty, StringProperty, TimestampProperty, TypeProperty, @@ -706,19 +706,6 @@ class WindowsRegistryValueType(_STIXBase): ]) -class CallableValues(list): - """Wrapper to allow `values()` method on WindowsRegistryKey objects. - Needed because `values` is also a property. - """ - - def __init__(self, parent_instance, *args, **kwargs): - self.parent_instance = parent_instance - super(CallableValues, self).__init__(*args, **kwargs) - - def __call__(self): - return _Observable.values(self.parent_instance) - - class WindowsRegistryKey(_Observable): """For more detailed information on this object's properties, see `the STIX 2.0 specification `__. diff --git a/stix2/v21/observables.py b/stix2/v21/observables.py index 92fe36a..f383899 100644 --- a/stix2/v21/observables.py +++ b/stix2/v21/observables.py @@ -12,7 +12,7 @@ from ..base import _Extension, _Observable, _STIXBase from ..custom import _custom_extension_builder, _custom_observable_builder from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError from ..properties import ( - BinaryProperty, BooleanProperty, DictionaryProperty, + BinaryProperty, BooleanProperty, CallableValues, DictionaryProperty, EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty, HashesProperty, HexProperty, IntegerProperty, ListProperty, ObjectReferenceProperty, StringProperty, TimestampProperty, TypeProperty, @@ -758,19 +758,6 @@ class WindowsRegistryValueType(_STIXBase): ]) -class CallableValues(list): - """Wrapper to allow `values()` method on WindowsRegistryKey objects. - Needed because `values` is also a property. - """ - - def __init__(self, parent_instance, *args, **kwargs): - self.parent_instance = parent_instance - super(CallableValues, self).__init__(*args, **kwargs) - - def __call__(self): - return _Observable.values(self.parent_instance) - - class WindowsRegistryKey(_Observable): # TODO: Add link """For more detailed information on this object's properties, see