Fixed all issues brought up in issue #305 by Chris Lenk
							parent
							
								
									388d95d456
								
							
						
					
					
						commit
						46f1778d04
					
				| 
						 | 
					@ -363,6 +363,10 @@ class DictionaryProperty(Property):
 | 
				
			||||||
                    "underscore (_)"
 | 
					                    "underscore (_)"
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
                raise DictionaryKeyError(k, msg)
 | 
					                raise DictionaryKeyError(k, msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(dictified) < 1:
 | 
				
			||||||
 | 
					            raise ValueError("must not be empty.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return dictified
 | 
					        return dictified
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -381,6 +385,7 @@ HASHES_REGEX = {
 | 
				
			||||||
    "SHA3512": (r"^[a-fA-F0-9]{128}$", "SHA3-512"),
 | 
					    "SHA3512": (r"^[a-fA-F0-9]{128}$", "SHA3-512"),
 | 
				
			||||||
    "SSDEEP": (r"^[a-zA-Z0-9/+:.]{1,128}$", "ssdeep"),
 | 
					    "SSDEEP": (r"^[a-zA-Z0-9/+:.]{1,128}$", "ssdeep"),
 | 
				
			||||||
    "WHIRLPOOL": (r"^[a-fA-F0-9]{128}$", "WHIRLPOOL"),
 | 
					    "WHIRLPOOL": (r"^[a-fA-F0-9]{128}$", "WHIRLPOOL"),
 | 
				
			||||||
 | 
					    "TLSH": (r"^[a-fA-F0-9]{70}$", "TLSH"),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@ EXPECTED_BUNDLE = """{
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
 | 
					            "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
 | 
				
			||||||
            "pattern_type": "stix",
 | 
					            "pattern_type": "stix",
 | 
				
			||||||
 | 
					            "pattern_version": "2.1",
 | 
				
			||||||
            "valid_from": "2017-01-01T12:34:56Z"
 | 
					            "valid_from": "2017-01-01T12:34:56Z"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					@ -61,6 +62,7 @@ EXPECTED_BUNDLE_DICT = {
 | 
				
			||||||
            "modified": "2017-01-01T12:34:56.000Z",
 | 
					            "modified": "2017-01-01T12:34:56.000Z",
 | 
				
			||||||
            "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
 | 
					            "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
 | 
				
			||||||
            "pattern_type": "stix",
 | 
					            "pattern_type": "stix",
 | 
				
			||||||
 | 
					            "pattern_version": "2.1",
 | 
				
			||||||
            "valid_from": "2017-01-01T12:34:56Z",
 | 
					            "valid_from": "2017-01-01T12:34:56Z",
 | 
				
			||||||
            "indicator_types": [
 | 
					            "indicator_types": [
 | 
				
			||||||
                "malicious-activity",
 | 
					                "malicious-activity",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@ EXPECTED_INDICATOR = """{
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
 | 
					    "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
 | 
				
			||||||
    "pattern_type": "stix",
 | 
					    "pattern_type": "stix",
 | 
				
			||||||
 | 
					    "pattern_version": "2.1",
 | 
				
			||||||
    "valid_from": "1970-01-01T00:00:01Z"
 | 
					    "valid_from": "1970-01-01T00:00:01Z"
 | 
				
			||||||
}"""
 | 
					}"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +32,7 @@ EXPECTED_INDICATOR_REPR = "Indicator(" + " ".join("""
 | 
				
			||||||
    indicator_types=['malicious-activity'],
 | 
					    indicator_types=['malicious-activity'],
 | 
				
			||||||
    pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
 | 
					    pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
 | 
				
			||||||
    pattern_type='stix',
 | 
					    pattern_type='stix',
 | 
				
			||||||
 | 
					    pattern_version='2.1',
 | 
				
			||||||
    valid_from='1970-01-01T00:00:01Z'
 | 
					    valid_from='1970-01-01T00:00:01Z'
 | 
				
			||||||
""".split()) + ")"
 | 
					""".split()) + ")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1366,6 +1366,17 @@ def test_x509_certificate_example():
 | 
				
			||||||
    assert x509.subject == "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org"  # noqa
 | 
					    assert x509.subject == "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org"  # noqa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_x509_certificate_error():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with pytest.raises(stix2.exceptions.PropertyPresenceError) as excinfo:
 | 
				
			||||||
 | 
					        stix2.v21.X509Certificate(
 | 
				
			||||||
 | 
					            defanged=True,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert excinfo.value.cls == stix2.v21.X509Certificate
 | 
				
			||||||
 | 
					    assert "X.509 Certificate objects must contain at least one object specific property" in str(excinfo.value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_new_version_with_related_objects():
 | 
					def test_new_version_with_related_objects():
 | 
				
			||||||
    data = stix2.v21.ObservedData(
 | 
					    data = stix2.v21.ObservedData(
 | 
				
			||||||
        first_observed="2016-03-12T12:00:00Z",
 | 
					        first_observed="2016-03-12T12:00:00Z",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,8 @@ import warnings
 | 
				
			||||||
from ..base import _Extension, _Observable, _STIXBase
 | 
					from ..base import _Extension, _Observable, _STIXBase
 | 
				
			||||||
from ..custom import _custom_extension_builder, _custom_observable_builder
 | 
					from ..custom import _custom_extension_builder, _custom_observable_builder
 | 
				
			||||||
from ..exceptions import (
 | 
					from ..exceptions import (
 | 
				
			||||||
    AtLeastOnePropertyError, DependentPropertiesError, STIXDeprecationWarning,
 | 
					    AtLeastOnePropertyError, DependentPropertiesError, PropertyPresenceError,
 | 
				
			||||||
 | 
					    STIXDeprecationWarning,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from ..properties import (
 | 
					from ..properties import (
 | 
				
			||||||
    BinaryProperty, BooleanProperty, CallableValues, DictionaryProperty,
 | 
					    BinaryProperty, BooleanProperty, CallableValues, DictionaryProperty,
 | 
				
			||||||
| 
						 | 
					@ -592,6 +593,18 @@ class SocketExt(_Extension):
 | 
				
			||||||
        ('socket_handle', IntegerProperty()),
 | 
					        ('socket_handle', IntegerProperty()),
 | 
				
			||||||
    ])
 | 
					    ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_object_constraints(self):
 | 
				
			||||||
 | 
					        super(SocketExt, self)._check_object_constraints()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        options = self.get('options')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if options is not None:
 | 
				
			||||||
 | 
					            for key, val in options.items():
 | 
				
			||||||
 | 
					                if key[:3] != "SO_":
 | 
				
			||||||
 | 
					                    raise ValueError("Incorrect options key")
 | 
				
			||||||
 | 
					                if not isinstance(val, int):
 | 
				
			||||||
 | 
					                    raise ValueError("Options value must be an integer")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TCPExt(_Extension):
 | 
					class TCPExt(_Extension):
 | 
				
			||||||
    # TODO: Add link
 | 
					    # TODO: Add link
 | 
				
			||||||
| 
						 | 
					@ -986,6 +999,26 @@ class X509Certificate(_Observable):
 | 
				
			||||||
    ])
 | 
					    ])
 | 
				
			||||||
    _id_contributing_properties = ["hashes", "serial_number"]
 | 
					    _id_contributing_properties = ["hashes", "serial_number"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_object_constraints(self):
 | 
				
			||||||
 | 
					        super(X509Certificate, self)._check_object_constraints()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					                self.get('is_self_signed') is None and
 | 
				
			||||||
 | 
					                self.get('hashes') is None and
 | 
				
			||||||
 | 
					                self.get('version') is None and
 | 
				
			||||||
 | 
					                self.get('serial_number') is None and
 | 
				
			||||||
 | 
					                self.get('signature_algorithm') is None and
 | 
				
			||||||
 | 
					                self.get('issuer') is None and
 | 
				
			||||||
 | 
					                self.get('validity_not_before') is None and
 | 
				
			||||||
 | 
					                self.get('validity_not_after') is None and
 | 
				
			||||||
 | 
					                self.get('subject') is None and
 | 
				
			||||||
 | 
					                self.get('subject_public_key_algorithm') is None and
 | 
				
			||||||
 | 
					                self.get('subject_public_key_modulus') is None and
 | 
				
			||||||
 | 
					                self.get('subject_public_key_exponent') is None and
 | 
				
			||||||
 | 
					                self.get('x509_v3_extensions') is None
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
 | 
					            raise PropertyPresenceError("X.509 Certificate objects must contain at least one object specific property", X509Certificate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def CustomObservable(type='x-custom-observable', properties=None):
 | 
					def CustomObservable(type='x-custom-observable', properties=None):
 | 
				
			||||||
    """Custom STIX Cyber Observable Object type decorator.
 | 
					    """Custom STIX Cyber Observable Object type decorator.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -220,11 +220,16 @@ class Indicator(STIXDomainObject):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        valid_from = self.get('valid_from')
 | 
					        valid_from = self.get('valid_from')
 | 
				
			||||||
        valid_until = self.get('valid_until')
 | 
					        valid_until = self.get('valid_until')
 | 
				
			||||||
 | 
					        pattern_type = self.get('pattern_type')
 | 
				
			||||||
 | 
					        pattern_version = self.get('pattern_version')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if valid_from and valid_until and valid_until <= valid_from:
 | 
					        if valid_from and valid_until and valid_until <= valid_from:
 | 
				
			||||||
            msg = "{0.id} 'valid_until' must be greater than 'valid_from'"
 | 
					            msg = "{0.id} 'valid_until' must be greater than 'valid_from'"
 | 
				
			||||||
            raise ValueError(msg.format(self))
 | 
					            raise ValueError(msg.format(self))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not pattern_version and pattern_type == 'stix':
 | 
				
			||||||
 | 
					            self._inner['pattern_version'] = self.get('spec_version')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Infrastructure(STIXDomainObject):
 | 
					class Infrastructure(STIXDomainObject):
 | 
				
			||||||
    # TODO: Add link
 | 
					    # TODO: Add link
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue