Add TimestampProperty
parent
168105603b
commit
2e3dfe5d84
1
setup.py
1
setup.py
|
@ -4,6 +4,7 @@ from setuptools import setup, find_packages
|
|||
install_requires = [
|
||||
'pytz',
|
||||
'six',
|
||||
'python-dateutil',
|
||||
]
|
||||
|
||||
setup(
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
from .base import _STIXBase
|
||||
from .properties import (Property, BooleanProperty, ReferenceProperty,
|
||||
StringProperty)
|
||||
StringProperty, TimestampProperty)
|
||||
from .utils import NOW
|
||||
|
||||
COMMON_PROPERTIES = {
|
||||
# 'type' and 'id' should be defined on each individual type
|
||||
'created': Property(default=lambda: NOW),
|
||||
'modified': Property(default=lambda: NOW),
|
||||
'created': TimestampProperty(default=lambda: NOW),
|
||||
'modified': TimestampProperty(default=lambda: NOW),
|
||||
'external_references': Property(),
|
||||
'revoked': BooleanProperty(),
|
||||
'created_by_ref': ReferenceProperty(),
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import re
|
||||
import uuid
|
||||
from six import PY2
|
||||
import datetime as dt
|
||||
import pytz
|
||||
from dateutil import parser
|
||||
|
||||
|
||||
class Property(object):
|
||||
|
@ -194,6 +197,30 @@ class BooleanProperty(Property):
|
|||
raise ValueError("must be a boolean value.")
|
||||
|
||||
|
||||
class TimestampProperty(Property):
|
||||
|
||||
def validate(self, value):
|
||||
if isinstance(value, dt.datetime):
|
||||
return value
|
||||
elif isinstance(value, dt.date):
|
||||
return dt.datetime.combine(value, dt.time())
|
||||
|
||||
try:
|
||||
return parser.parse(value).astimezone(pytz.utc)
|
||||
except ValueError:
|
||||
# Doesn't have timezone info in the string
|
||||
try:
|
||||
return pytz.utc.localize(parser.parse(value))
|
||||
except TypeError:
|
||||
# Unknown format
|
||||
raise ValueError("must be a datetime object, date object, or "
|
||||
"timestamp string in a recognizable format.")
|
||||
except TypeError:
|
||||
# Isn't a string
|
||||
raise ValueError("must be a datetime object, date object, or "
|
||||
"timestamp string.")
|
||||
|
||||
|
||||
REF_REGEX = re.compile("^[a-z][a-z-]+[a-z]--[0-9a-fA-F]{8}-[0-9a-fA-F]{4}"
|
||||
"-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import stix2
|
||||
|
||||
EXPECTED = """{
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"created": "2016-05-12T08:17:27Z",
|
||||
"description": "...",
|
||||
"external_references": [
|
||||
{
|
||||
|
@ -10,7 +10,7 @@ EXPECTED = """{
|
|||
}
|
||||
],
|
||||
"id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27Z",
|
||||
"name": "Spear Phishing",
|
||||
"type": "attack-pattern"
|
||||
}"""
|
||||
|
@ -19,8 +19,8 @@ EXPECTED = """{
|
|||
def test_attack_pattern_example():
|
||||
ap = stix2.AttackPattern(
|
||||
id="attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
created="2016-05-12T08:17:27.000Z",
|
||||
modified="2016-05-12T08:17:27.000Z",
|
||||
created="2016-05-12T08:17:27Z",
|
||||
modified="2016-05-12T08:17:27Z",
|
||||
name="Spear Phishing",
|
||||
external_references=[{
|
||||
"source_name": "capec",
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import stix2
|
||||
|
||||
EXPECTED = """{
|
||||
"created": "2016-04-06T20:03:00.000Z",
|
||||
"created": "2016-04-06T20:03:00Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "Campaign by Green Group against a series of targets in the financial services sector.",
|
||||
"id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"modified": "2016-04-06T20:03:00.000Z",
|
||||
"modified": "2016-04-06T20:03:00Z",
|
||||
"name": "Green Group Attacks Against Finance",
|
||||
"type": "campaign"
|
||||
}"""
|
||||
|
@ -15,8 +15,8 @@ def test_campaign_example():
|
|||
campaign = stix2.Campaign(
|
||||
id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T20:03:00.000Z",
|
||||
modified="2016-04-06T20:03:00.000Z",
|
||||
created="2016-04-06T20:03:00Z",
|
||||
modified="2016-04-06T20:03:00Z",
|
||||
name="Green Group Attacks Against Finance",
|
||||
description="Campaign by Green Group against a series of targets in the financial services sector."
|
||||
)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import stix2
|
||||
|
||||
EXPECTED = """{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created": "2016-04-06T20:03:48Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
|
||||
"id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"modified": "2016-04-06T20:03:48Z",
|
||||
"name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter",
|
||||
"type": "course-of-action"
|
||||
}"""
|
||||
|
@ -15,8 +15,8 @@ def test_course_of_action_example():
|
|||
coa = stix2.CourseOfAction(
|
||||
id="course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T20:03:48.000Z",
|
||||
modified="2016-04-06T20:03:48.000Z",
|
||||
created="2016-04-06T20:03:48Z",
|
||||
modified="2016-04-06T20:03:48Z",
|
||||
name="Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter",
|
||||
description="This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ..."
|
||||
)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import stix2
|
||||
|
||||
EXPECTED = """{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"created": "2015-12-21T19:59:11Z",
|
||||
"id": "identity--311b2d2d-f010-5473-83ec-1edf84858f4c",
|
||||
"identity_class": "individual",
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"modified": "2015-12-21T19:59:11Z",
|
||||
"name": "John Smith",
|
||||
"type": "identity"
|
||||
}"""
|
||||
|
@ -13,8 +13,8 @@ EXPECTED = """{
|
|||
def test_identity_example():
|
||||
report = stix2.Identity(
|
||||
id="identity--311b2d2d-f010-5473-83ec-1edf84858f4c",
|
||||
created="2015-12-21T19:59:11.000Z",
|
||||
modified="2015-12-21T19:59:11.000Z",
|
||||
created="2015-12-21T19:59:11Z",
|
||||
modified="2015-12-21T19:59:11Z",
|
||||
name="John Smith",
|
||||
identity_class="individual",
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@ EXPECTED = """{
|
|||
"aliases": [
|
||||
"Zookeeper"
|
||||
],
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created": "2016-04-06T20:03:48Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "Incidents usually feature a shared TTP of a bobcat being released...",
|
||||
"goals": [
|
||||
|
@ -13,7 +13,7 @@ EXPECTED = """{
|
|||
"damage"
|
||||
],
|
||||
"id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"modified": "2016-04-06T20:03:48Z",
|
||||
"name": "Bobcat Breakin",
|
||||
"type": "intrusion-set"
|
||||
}"""
|
||||
|
@ -23,8 +23,8 @@ def test_intrusion_set_example():
|
|||
intrusion_set = stix2.IntrusionSet(
|
||||
id="intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T20:03:48.000Z",
|
||||
modified="2016-04-06T20:03:48.000Z",
|
||||
created="2016-04-06T20:03:48Z",
|
||||
modified="2016-04-06T20:03:48Z",
|
||||
name="Bobcat Breakin",
|
||||
description="Incidents usually feature a shared TTP of a bobcat being released...",
|
||||
aliases=["Zookeeper"],
|
||||
|
|
|
@ -107,8 +107,8 @@ def test_parse_malware(data):
|
|||
|
||||
assert mal.type == 'malware'
|
||||
assert mal.id == MALWARE_ID
|
||||
assert mal.created == "2016-05-12T08:17:27Z"
|
||||
assert mal.modified == "2016-05-12T08:17:27Z"
|
||||
assert mal.created == dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc)
|
||||
assert mal.modified == dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc)
|
||||
assert mal.labels == ['ransomware']
|
||||
assert mal.name == "Cryptolocker"
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import stix2
|
||||
|
||||
EXPECTED = """{
|
||||
"created": "2016-04-06T19:58:16.000Z",
|
||||
"created": "2016-04-06T19:58:16Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"first_observed": "2015-12-21T19:00:00Z",
|
||||
"id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
"last_observed": "2015-12-21T19:00:00Z",
|
||||
"modified": "2016-04-06T19:58:16.000Z",
|
||||
"modified": "2016-04-06T19:58:16Z",
|
||||
"number_observed": 50,
|
||||
"objects": {
|
||||
"0": {
|
||||
|
@ -21,8 +21,8 @@ def test_observed_data_example():
|
|||
observed_data = stix2.ObservedData(
|
||||
id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T19:58:16.000Z",
|
||||
modified="2016-04-06T19:58:16.000Z",
|
||||
created="2016-04-06T19:58:16Z",
|
||||
modified="2016-04-06T19:58:16Z",
|
||||
first_observed="2015-12-21T19:00:00Z",
|
||||
last_observed="2015-12-21T19:00:00Z",
|
||||
number_observed=50,
|
||||
|
|
|
@ -2,7 +2,8 @@ import pytest
|
|||
|
||||
from stix2.properties import (Property, BooleanProperty, ListProperty,
|
||||
StringProperty, TypeProperty, IDProperty,
|
||||
ReferenceProperty)
|
||||
ReferenceProperty, TimestampProperty)
|
||||
from .constants import FAKE_TIME
|
||||
|
||||
|
||||
def test_property():
|
||||
|
@ -131,3 +132,21 @@ def test_reference_property():
|
|||
assert ref_prop.validate("my-type--3a331bfe-0566-55e1-a4a0-9a2cd355a300")
|
||||
with pytest.raises(ValueError):
|
||||
ref_prop.validate("foo")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
'2017-01-01T12:34:56Z',
|
||||
'2017-01-01 12:34:56',
|
||||
'Jan 1 2017 12:34:56',
|
||||
])
|
||||
def test_timestamp_property_valid(value):
|
||||
ts_prop = TimestampProperty()
|
||||
assert ts_prop.validate(value) == FAKE_TIME
|
||||
|
||||
|
||||
def test_timestamp_property_invalid():
|
||||
ts_prop = TimestampProperty()
|
||||
with pytest.raises(ValueError):
|
||||
ts_prop.validate(1)
|
||||
with pytest.raises(ValueError):
|
||||
ts_prop.validate("someday sometime")
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import stix2
|
||||
|
||||
EXPECTED = """{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"created": "2015-12-21T19:59:11Z",
|
||||
"created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283",
|
||||
"description": "A simple report with an indicator and campaign",
|
||||
"id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3",
|
||||
"labels": [
|
||||
"campaign"
|
||||
],
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"modified": "2015-12-21T19:59:11Z",
|
||||
"name": "The Black Vine Cyberespionage Group",
|
||||
"object_refs": [
|
||||
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
|
@ -24,8 +24,8 @@ def test_report_example():
|
|||
report = stix2.Report(
|
||||
id="report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3",
|
||||
created_by_ref="identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283",
|
||||
created="2015-12-21T19:59:11.000Z",
|
||||
modified="2015-12-21T19:59:11.000Z",
|
||||
created="2015-12-21T19:59:11Z",
|
||||
modified="2015-12-21T19:59:11Z",
|
||||
name="The Black Vine Cyberespionage Group",
|
||||
description="A simple report with an indicator and campaign",
|
||||
published="2016-01-201T17:00:00Z",
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import stix2
|
||||
|
||||
EXPECTED = """{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created": "2016-04-06T20:03:48Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "The Evil Org threat actor group",
|
||||
"id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"labels": [
|
||||
"crime-syndicate"
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"modified": "2016-04-06T20:03:48Z",
|
||||
"name": "Evil Org",
|
||||
"type": "threat-actor"
|
||||
}"""
|
||||
|
@ -18,8 +18,8 @@ def test_threat_actor_example():
|
|||
threat_actor = stix2.ThreatActor(
|
||||
id="threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T20:03:48.000Z",
|
||||
modified="2016-04-06T20:03:48.000Z",
|
||||
created="2016-04-06T20:03:48Z",
|
||||
modified="2016-04-06T20:03:48Z",
|
||||
name="Evil Org",
|
||||
description="The Evil Org threat actor group",
|
||||
labels=["crime-syndicate"],
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import stix2
|
||||
|
||||
EXPECTED = """{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created": "2016-04-06T20:03:48Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"labels": [
|
||||
"remote-access"
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"modified": "2016-04-06T20:03:48Z",
|
||||
"name": "VNC",
|
||||
"type": "tool"
|
||||
}"""
|
||||
|
@ -17,8 +17,8 @@ def test_tool_example():
|
|||
tool = stix2.Tool(
|
||||
id="tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T20:03:48.000Z",
|
||||
modified="2016-04-06T20:03:48.000Z",
|
||||
created="2016-04-06T20:03:48Z",
|
||||
modified="2016-04-06T20:03:48Z",
|
||||
name="VNC",
|
||||
labels=["remote-access"],
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import stix2
|
||||
|
||||
EXPECTED = """{
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"created": "2016-05-12T08:17:27Z",
|
||||
"external_references": [
|
||||
{
|
||||
"external_id": "CVE-2016-1234",
|
||||
|
@ -9,7 +9,7 @@ EXPECTED = """{
|
|||
}
|
||||
],
|
||||
"id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27Z",
|
||||
"name": "CVE-2016-1234",
|
||||
"type": "vulnerability"
|
||||
}"""
|
||||
|
@ -18,8 +18,8 @@ EXPECTED = """{
|
|||
def test_vulnerability_example():
|
||||
vulnerability = stix2.Vulnerability(
|
||||
id="vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
created="2016-05-12T08:17:27.000Z",
|
||||
modified="2016-05-12T08:17:27.000Z",
|
||||
created="2016-05-12T08:17:27Z",
|
||||
modified="2016-05-12T08:17:27Z",
|
||||
name="CVE-2016-1234",
|
||||
external_references=[
|
||||
stix2.ExternalReference(source_name='cve',
|
||||
|
|
Loading…
Reference in New Issue