Merge branch 'parse-cyber-observables' into cyber-observables
						commit
						ae5fb51564
					
				|  | @ -0,0 +1,7 @@ | |||
| [settings] | ||||
| check=1 | ||||
| diff=1 | ||||
| known_third_party=dateutil,pytest,pytz,six | ||||
| known_first_party=stix2 | ||||
| not_skip=__init__.py | ||||
| force_sort_within_sections=1 | ||||
|  | @ -179,7 +179,7 @@ class _STIXBase(collections.Mapping): | |||
|         return self.new_version(revoked=True) | ||||
| 
 | ||||
| 
 | ||||
| class Observable(_STIXBase): | ||||
| class _Observable(_STIXBase): | ||||
| 
 | ||||
|     def __init__(self, **kwargs): | ||||
|         # the constructor might be called independently of an observed data object | ||||
|  | @ -187,10 +187,10 @@ class Observable(_STIXBase): | |||
|             self._STIXBase__valid_refs = kwargs.pop('_valid_refs') | ||||
|         else: | ||||
|             self._STIXBase__valid_refs = [] | ||||
|         super(Observable, self).__init__(**kwargs) | ||||
|         super(_Observable, self).__init__(**kwargs) | ||||
| 
 | ||||
|     def _check_property(self, prop_name, prop, kwargs): | ||||
|         super(Observable, self)._check_property(prop_name, prop, kwargs) | ||||
|         super(_Observable, self)._check_property(prop_name, prop, kwargs) | ||||
|         if prop_name.endswith('_ref') and prop_name in kwargs: | ||||
|             ref = kwargs[prop_name] | ||||
|             if ref not in self._STIXBase__valid_refs: | ||||
|  |  | |||
|  | @ -5,15 +5,15 @@ embedded in Email Message objects, inherit from _STIXBase instead of Observable | |||
| and do not have a '_type' attribute. | ||||
| """ | ||||
| 
 | ||||
| from .base import Observable, _STIXBase | ||||
| from .base import _Observable, _STIXBase | ||||
| from .properties import (BinaryProperty, BooleanProperty, DictionaryProperty, | ||||
|                          EmbeddedObjectProperty, HashesProperty, HexProperty, | ||||
|                          IntegerProperty, ListProperty, | ||||
|                          EmbeddedObjectProperty, EnumProperty, HashesProperty, | ||||
|                          HexProperty, IntegerProperty, ListProperty, | ||||
|                          ObjectReferenceProperty, Property, StringProperty, | ||||
|                          TimestampProperty, TypeProperty) | ||||
| 
 | ||||
| 
 | ||||
| class Artifact(Observable): | ||||
| class Artifact(_Observable): | ||||
|     _type = 'artifact' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -29,7 +29,7 @@ class Artifact(Observable): | |||
|         self._check_properties_dependency(["hashes"], ["url"]) | ||||
| 
 | ||||
| 
 | ||||
| class AutonomousSystem(Observable): | ||||
| class AutonomousSystem(_Observable): | ||||
|     _type = 'autonomous-system' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -39,7 +39,7 @@ class AutonomousSystem(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class Directory(Observable): | ||||
| class Directory(_Observable): | ||||
|     _type = 'directory' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -53,7 +53,7 @@ class Directory(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class DomainName(Observable): | ||||
| class DomainName(_Observable): | ||||
|     _type = 'domain-name' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -62,7 +62,7 @@ class DomainName(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class EmailAddress(Observable): | ||||
| class EmailAddress(_Observable): | ||||
|     _type = 'email-address' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -85,7 +85,7 @@ class EmailMIMEComponent(_STIXBase): | |||
|         self._check_at_least_one_property(["body", "body_raw_ref"]) | ||||
| 
 | ||||
| 
 | ||||
| class EmailMessage(Observable): | ||||
| class EmailMessage(_Observable): | ||||
|     _type = 'email-message' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -111,7 +111,7 @@ class EmailMessage(Observable): | |||
|         # self._dependency(["is_multipart"], ["body"], [False]) | ||||
| 
 | ||||
| 
 | ||||
| class File(Observable): | ||||
| class File(_Observable): | ||||
|     _type = 'file' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -140,7 +140,7 @@ class File(Observable): | |||
|         self._check_at_least_one_property(["hashes", "name"]) | ||||
| 
 | ||||
| 
 | ||||
| class IPv4Address(Observable): | ||||
| class IPv4Address(_Observable): | ||||
|     _type = 'ipv4-addr' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -150,7 +150,7 @@ class IPv4Address(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class IPv6Address(Observable): | ||||
| class IPv6Address(_Observable): | ||||
|     _type = 'ipv6-addr' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -160,7 +160,7 @@ class IPv6Address(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class MACAddress(Observable): | ||||
| class MACAddress(_Observable): | ||||
|     _type = 'mac-addr' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -168,7 +168,7 @@ class MACAddress(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class Mutex(Observable): | ||||
| class Mutex(_Observable): | ||||
|     _type = 'mutex' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -176,7 +176,7 @@ class Mutex(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class NetworkTraffic(Observable): | ||||
| class NetworkTraffic(_Observable): | ||||
|     _type = 'network-traffic' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -205,7 +205,7 @@ class NetworkTraffic(Observable): | |||
|         self._check_at_least_one_property(["src_ref", "dst_ref"]) | ||||
| 
 | ||||
| 
 | ||||
| class Process(Observable): | ||||
| class Process(_Observable): | ||||
|     _type = 'process' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -227,7 +227,7 @@ class Process(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class Software(Observable): | ||||
| class Software(_Observable): | ||||
|     _type = 'software' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -239,7 +239,7 @@ class Software(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class URL(Observable): | ||||
| class URL(_Observable): | ||||
|     _type = 'url' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -247,7 +247,7 @@ class URL(Observable): | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class UserAccount(Observable): | ||||
| class UserAccount(_Observable): | ||||
|     _type = 'user-account' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -273,11 +273,25 @@ class WindowsRegistryValueType(_STIXBase): | |||
|     _properties = { | ||||
|         'name': StringProperty(required=True), | ||||
|         'data': StringProperty(), | ||||
|         'data_type': Property() | ||||
|         'data_type': EnumProperty([ | ||||
|             'REG_NONE', | ||||
|             'REG_SZ', | ||||
|             'REG_EXPAND_SZ', | ||||
|             'REG_BINARY', | ||||
|             'REG_DWORD', | ||||
|             'REG_DWORD_BIG_ENDIAN', | ||||
|             'REG_LINK', | ||||
|             'REG_MULTI_SZ', | ||||
|             'REG_RESOURCE_LIST', | ||||
|             'REG_FULL_RESOURCE_DESCRIPTION', | ||||
|             'REG_RESOURCE_REQUIREMENTS_LIST', | ||||
|             'REG_QWORD', | ||||
|             'REG_INVALID_TYPE', | ||||
|         ]), | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| class WindowsRegistryKey(Observable): | ||||
| class WindowsRegistryKey(_Observable): | ||||
|     _type = 'windows-registry-key' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  | @ -291,8 +305,9 @@ class WindowsRegistryKey(Observable): | |||
| 
 | ||||
|     @property | ||||
|     def values(self): | ||||
|       # Needed because 'values' is a property on collections.Mapping objects | ||||
|         return self._inner['values'] | ||||
| 
 | ||||
|        | ||||
| 
 | ||||
| class X509V3ExtenstionsType(_STIXBase): | ||||
|     _type = 'x509-v3-extensions-type' | ||||
|  | @ -314,9 +329,9 @@ class X509V3ExtenstionsType(_STIXBase): | |||
|         'certificate_policies': StringProperty(), | ||||
|         'policy_mappings': StringProperty(), | ||||
|     } | ||||
|      | ||||
| 
 | ||||
| 
 | ||||
| class X509Certificate(Observable): | ||||
| class X509Certificate(_Observable): | ||||
|     _type = 'x509-certificate' | ||||
|     _properties = { | ||||
|         'type': TypeProperty(_type), | ||||
|  |  | |||
|  | @ -5,10 +5,12 @@ import datetime as dt | |||
| import inspect | ||||
| import re | ||||
| import uuid | ||||
| from six import text_type | ||||
| import pytz | ||||
| 
 | ||||
| from dateutil import parser | ||||
| from .base import Observable, _STIXBase | ||||
| import pytz | ||||
| from six import text_type | ||||
| 
 | ||||
| from .base import _Observable, _STIXBase | ||||
| from .exceptions import DictionaryKeyError | ||||
| 
 | ||||
| 
 | ||||
|  | @ -141,6 +143,7 @@ class StringProperty(Property): | |||
| 
 | ||||
| 
 | ||||
| class TypeProperty(Property): | ||||
| 
 | ||||
|     def __init__(self, type): | ||||
|         super(TypeProperty, self).__init__(fixed=type) | ||||
| 
 | ||||
|  | @ -226,7 +229,7 @@ class ObservableProperty(Property): | |||
|         from .__init__ import parse_observable  # avoid circular import | ||||
|         for key, obj in dictified.items(): | ||||
|             parsed_obj = parse_observable(obj, dictified.keys()) | ||||
|             if not issubclass(type(parsed_obj), Observable): | ||||
|             if not issubclass(type(parsed_obj), _Observable): | ||||
|                 raise ValueError("Objects in an observable property must be " | ||||
|                                  "Cyber Observable Objects") | ||||
|             dictified[key] = parsed_obj | ||||
|  | @ -308,6 +311,7 @@ REF_REGEX = re.compile("^[a-z][a-z-]+[a-z]--[0-9a-fA-F]{8}-[0-9a-fA-F]{4}" | |||
| 
 | ||||
| 
 | ||||
| class ReferenceProperty(Property): | ||||
| 
 | ||||
|     def __init__(self, required=False, type=None): | ||||
|         """ | ||||
|         references sometimes must be to a specific object type | ||||
|  | @ -330,6 +334,7 @@ SELECTOR_REGEX = re.compile("^[a-z0-9_-]{3,250}(\\.(\\[\\d+\\]|[a-z0-9_-]{1,250} | |||
| 
 | ||||
| 
 | ||||
| class SelectorProperty(Property): | ||||
| 
 | ||||
|     def __init__(self, type=None): | ||||
|         # ignore type | ||||
|         super(SelectorProperty, self).__init__() | ||||
|  | @ -345,6 +350,7 @@ class ObjectReferenceProperty(StringProperty): | |||
| 
 | ||||
| 
 | ||||
| class EmbeddedObjectProperty(Property): | ||||
| 
 | ||||
|     def __init__(self, type, required=False): | ||||
|         self.type = type | ||||
|         super(EmbeddedObjectProperty, self).__init__(required, type=type) | ||||
|  | @ -355,3 +361,18 @@ class EmbeddedObjectProperty(Property): | |||
|         elif not isinstance(value, self.type): | ||||
|             raise ValueError("must be of type %s." % self.type.__name__) | ||||
|         return value | ||||
| 
 | ||||
| 
 | ||||
| class EnumProperty(StringProperty): | ||||
| 
 | ||||
|     def __init__(self, allowed, **kwargs): | ||||
|         if type(allowed) is not list: | ||||
|             allowed = list(allowed) | ||||
|         self.allowed = allowed | ||||
|         super(EnumProperty, self).__init__(**kwargs) | ||||
| 
 | ||||
|     def clean(self, value): | ||||
|         value = super(EnumProperty, self).clean(value) | ||||
|         if value not in self.allowed: | ||||
|             raise ValueError("value '%s' is not valid for this enumeration." % value) | ||||
|         return self.string_type(value) | ||||
|  |  | |||
|  | @ -4,8 +4,8 @@ from .base import _STIXBase | |||
| from .common import COMMON_PROPERTIES | ||||
| from .other import KillChainPhase | ||||
| from .properties import (IDProperty, IntegerProperty, ListProperty, | ||||
|                          ObservableProperty, ReferenceProperty, | ||||
|                          StringProperty, TimestampProperty, TypeProperty) | ||||
|                          ObservableProperty, ReferenceProperty, StringProperty, | ||||
|                          TimestampProperty, TypeProperty) | ||||
| from .utils import NOW | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -587,7 +587,7 @@ def test_software_example(): | |||
|     assert s.version == "2002" | ||||
|     assert s.vendor == "Microsoft" | ||||
| 
 | ||||
| 
 | ||||
|      | ||||
| def test_url_example(): | ||||
|     s = stix2.URL(value="https://example.com/research/index.html") | ||||
| 
 | ||||
|  | @ -619,26 +619,23 @@ def test_user_account_example(): | |||
|     assert a.password_last_changed == dt.datetime(2016, 1, 20, 14, 27, 43, tzinfo=pytz.utc) | ||||
|     assert a.account_first_login == dt.datetime(2016, 1, 20, 14, 26, 7, tzinfo=pytz.utc) | ||||
|     assert a.account_last_login == dt.datetime(2016, 7, 22, 16, 8, 28, tzinfo=pytz.utc) | ||||
| 
 | ||||
| 
 | ||||
|      | ||||
|      | ||||
| def test_windows_registry_key_example(): | ||||
|     rk = stix2.WindowsRegistryKey(key="hkey_local_machine\\system\\bar\\foo", | ||||
|                                   values=[{ | ||||
|                                             "name": "Foo", | ||||
|                                             "data": "qwerty", | ||||
|                                             "data_type": "REG_SZ" | ||||
|                                           }, | ||||
|                                           { | ||||
|                                             "name": "Bar", | ||||
|                                             "data": "42", | ||||
|                                             "data_type": "REG_DWORD" | ||||
|                                           }]) | ||||
|     with pytest.raises(ValueError): | ||||
|         v = stix2.WindowsRegistryValueType(name="Foo", | ||||
|                                            data="qwerty", | ||||
|                                            data_type="string") | ||||
| 
 | ||||
|     assert rk.type == "windows-registry-key" | ||||
|     assert rk.key == "hkey_local_machine\\system\\bar\\foo" | ||||
|     assert rk.values[0].name == "Foo" | ||||
|     assert rk.values[0].data == "qwerty" | ||||
|     assert rk.values[0].data_type == "REG_SZ" | ||||
|     v = stix2.WindowsRegistryValueType(name="Foo", | ||||
|                                        data="qwerty", | ||||
|                                        data_type="REG_SZ") | ||||
|     w = stix2.WindowsRegistryKey(key="hkey_local_machine\\system\\bar\\foo", | ||||
|                                  values=[v]) | ||||
|     assert w.key == "hkey_local_machine\\system\\bar\\foo" | ||||
|     assert w.values[0].name == "Foo" | ||||
|     assert w.values[0].data == "qwerty" | ||||
|     assert w.values[0].data_type == "REG_SZ" | ||||
| 
 | ||||
| 
 | ||||
| def test_x509_certificate_example(): | ||||
|  | @ -651,3 +648,4 @@ def test_x509_certificate_example(): | |||
|     assert x509.type == "x509-certificate" | ||||
|     assert x509.issuer == "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com"  # noqa | ||||
|     assert x509.subject == "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org"  # noqa | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,9 +4,9 @@ from stix2.exceptions import DictionaryKeyError | |||
| from stix2.observables import EmailMIMEComponent | ||||
| from stix2.properties import (BinaryProperty, BooleanProperty, | ||||
|                               DictionaryProperty, EmbeddedObjectProperty, | ||||
|                               HashesProperty, HexProperty, IDProperty, | ||||
|                               IntegerProperty, ListProperty, Property, | ||||
|                               ReferenceProperty, StringProperty, | ||||
|                               EnumProperty, HashesProperty, HexProperty, | ||||
|                               IDProperty, IntegerProperty, ListProperty, | ||||
|                               Property, ReferenceProperty, StringProperty, | ||||
|                               TimestampProperty, TypeProperty) | ||||
| 
 | ||||
| from .constants import FAKE_TIME | ||||
|  | @ -247,3 +247,11 @@ def test_embedded_property(): | |||
| 
 | ||||
|     with pytest.raises(ValueError): | ||||
|         emb_prop.clean("string") | ||||
| 
 | ||||
| 
 | ||||
| def test_enum_property(): | ||||
|     enum_prop = EnumProperty(['a', 'b', 'c']) | ||||
|     assert enum_prop.clean('b') | ||||
| 
 | ||||
|     with pytest.raises(ValueError): | ||||
|         enum_prop.clean('z') | ||||
|  |  | |||
|  | @ -3,8 +3,8 @@ | |||
| import datetime as dt | ||||
| import json | ||||
| 
 | ||||
| import pytz | ||||
| from dateutil import parser | ||||
| import pytz | ||||
| 
 | ||||
| # Sentinel value for fields that should be set to the current time. | ||||
| # We can't use the standard 'default' approach, since if there are multiple | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Rich Piazza
						Rich Piazza