Fix typos, add to Property class documentation, small performance

boosts, and let strings and booleans in a ListProperty be handled by
__call__().
stix2.1
clenk 2017-04-24 16:33:59 -04:00
parent 76acd8c0c2
commit fe4c4d78fc
3 changed files with 34 additions and 29 deletions

View File

@ -13,35 +13,36 @@ from .utils import get_dict
from . import exceptions
OBJ_MAP = {
'attack-pattern': AttackPattern,
'campaign': Campaign,
'course-of-action': CourseOfAction,
'identity': Identity,
'indicator': Indicator,
'intrusion-set': IntrusionSet,
'malware': Malware,
'marking-definition': MarkingDefinition,
'observed-data': ObservedData,
'report': Report,
'relationship': Relationship,
'threat-actor': ThreatActor,
'tool': Tool,
'sighting': Sighting,
'vulnerability': Vulnerability,
}
def parse(data):
"""Deserialize a string or file-like object into a STIX object"""
obj = get_dict(data)
obj_map = {
'attack-pattern': AttackPattern,
'campaign': Campaign,
'course-of-action': CourseOfAction,
'identity': Identity,
'indicator': Indicator,
'intrusion-set': IntrusionSet,
'malware': Malware,
'marking-definition': MarkingDefinition,
'observed-data': ObservedData,
'report': Report,
'relationship': Relationship,
'threat-actor': ThreatActor,
'tool': Tool,
'sighting': Sighting,
'vulnerability': Vulnerability,
}
if 'type' not in obj:
# TODO parse external references, kill chain phases, and granular markings
pass
else:
try:
obj_class = obj_map[obj['type']]
obj_class = OBJ_MAP[obj['type']]
return obj_class(**obj)
except KeyError:
# TODO handle custom objects

View File

@ -39,7 +39,7 @@ class TLPMarking(_STIXBase):
class StatementMarking(_STIXBase):
_properties = {
'statement': Property(required=True)
'statement': StringProperty(required=True)
}
def __init__(self, statement=None, **kwargs):

View File

@ -42,9 +42,15 @@ class Property(object):
to use the same default value, so calling now() for each field--
likely several microseconds apart-- does not work.
Subclasses can instead provide a lambda function for `default as a keyword
Subclasses can instead provide a lambda function for `default` as a keyword
argument. `clean` should not be provided as a lambda since lambdas cannot
raise their own exceptions.
When instantiating Properties, `required` and `default` should not be used
together. `default` implies that the field is required in the specification
so this function will be used to supply a value if none is provided.
`required` means that the user must provide this; it is required in the
specification and we can't or don't want to create a default value.
"""
def _default_clean(self, value):
@ -66,8 +72,10 @@ class Property(object):
return value
def __call__(self, value=None):
if value is not None:
return value
"""Used by ListProperty to handle lists that have been defined with
either a class or an instance.
"""
return value
class ListProperty(Property):
@ -76,11 +84,7 @@ class ListProperty(Property):
"""
Contained should be a function which returns an object from the value.
"""
if contained == StringProperty:
self.contained = StringProperty().string_type
elif contained == BooleanProperty:
self.contained = bool
elif inspect.isclass(contained) and issubclass(contained, Property):
if inspect.isclass(contained) and issubclass(contained, Property):
# If it's a class and not an instance, instantiate it so that
# clean() can be called on it, and ListProperty.clean() will
# use __call__ when it appends the item.
@ -191,7 +195,7 @@ class TimestampProperty(Property):
return value
else:
# Add a time component
return dt.datetime.combine(value, dt.time(), tzinfo=pytz.timezone('US/Eastern'))
return dt.datetime.combine(value, dt.time(), tzinfo=pytz.utc)
# value isn't a date or datetime object so assume it's a string
try: