Add required fields to Indicator.
parent
2f8c2780c2
commit
6761d1fdfc
5
setup.py
5
setup.py
|
@ -1,10 +1,15 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
install_requires = [
|
||||||
|
'pytz',
|
||||||
|
]
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='stix2',
|
name='stix2',
|
||||||
description="Produce and consume STIX 2 JSON content",
|
description="Produce and consume STIX 2 JSON content",
|
||||||
version='0.0.1',
|
version='0.0.1',
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
|
install_requires=install_requires,
|
||||||
keywords="stix stix2 json cti cyber threat intelligence",
|
keywords="stix stix2 json cti cyber threat intelligence",
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,54 @@
|
||||||
|
from datetime import datetime
|
||||||
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
|
||||||
|
def format_datetime(dt):
|
||||||
|
# 1. Convert to UTC
|
||||||
|
# 2. Format in isoformat
|
||||||
|
# 3. Strip off "+00:00"
|
||||||
|
# 4. Add "Z"
|
||||||
|
return dt.astimezone(pytz.utc).isoformat()[:-6] + "Z"
|
||||||
|
|
||||||
|
# REQUIRED (all):
|
||||||
|
# - type
|
||||||
|
# - id
|
||||||
|
# - created
|
||||||
|
# - modified
|
||||||
|
|
||||||
|
|
||||||
class Indicator:
|
class Indicator:
|
||||||
|
# REQUIRED (Indicator):
|
||||||
|
# - type
|
||||||
|
# - labels
|
||||||
|
# - pattern
|
||||||
|
# - valid_from
|
||||||
|
required = ['']
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, type='indicator', id=None, created=None, modified=None,
|
||||||
self.id = "indicator--" + str(uuid.uuid4())
|
labels=None, pattern=None, valid_from=None):
|
||||||
|
now = datetime.now(tz=pytz.UTC)
|
||||||
|
|
||||||
|
self.type = type
|
||||||
|
if not id:
|
||||||
|
id = "indicator--" + str(uuid.uuid4())
|
||||||
|
self.id = id
|
||||||
|
self.created = created or now
|
||||||
|
self.modified = modified or now
|
||||||
|
self.labels = labels
|
||||||
|
self.pattern = pattern
|
||||||
|
self.valid_from = valid_from or now
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
# TODO: put keys in specific order. Probably need custom JSON encoder.
|
||||||
|
return json.dumps({
|
||||||
|
'type': self.type,
|
||||||
|
'id': self.id,
|
||||||
|
'created': format_datetime(self.created),
|
||||||
|
'modified': format_datetime(self.modified),
|
||||||
|
'labels': self.labels,
|
||||||
|
'pattern': self.pattern,
|
||||||
|
'valid_from': format_datetime(self.valid_from),
|
||||||
|
}, indent=4, sort_keys=True, separators=(",", ": ")) # Don't include spaces after commas.
|
||||||
|
|
|
@ -1,8 +1,56 @@
|
||||||
"""Tests for the stix2 library"""
|
"""Tests for the stix2 library"""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import pytz
|
||||||
|
|
||||||
import stix2
|
import stix2
|
||||||
|
|
||||||
|
amsterdam = pytz.timezone('Europe/Amsterdam')
|
||||||
|
eastern = pytz.timezone('US/Eastern')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('dt,timestamp', [
|
||||||
|
(datetime.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'),
|
||||||
|
(amsterdam.localize(datetime.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'),
|
||||||
|
(eastern.localize(datetime.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'),
|
||||||
|
(eastern.localize(datetime.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'),
|
||||||
|
])
|
||||||
|
def test_timestamp_formatting(dt, timestamp):
|
||||||
|
assert stix2.format_datetime(dt) == timestamp
|
||||||
|
|
||||||
|
|
||||||
def test_basic_indicator():
|
def test_basic_indicator():
|
||||||
indicator = stix2.Indicator()
|
indicator = stix2.Indicator()
|
||||||
assert indicator.id.startswith("indicator")
|
assert indicator.id.startswith("indicator")
|
||||||
|
|
||||||
|
|
||||||
|
EXPECTED = """{
|
||||||
|
"created": "2017-01-01T00:00:00Z",
|
||||||
|
"id": "indicator--01234567-89ab-cdef-0123-456789abcdef",
|
||||||
|
"labels": [
|
||||||
|
"malicious-activity"
|
||||||
|
],
|
||||||
|
"modified": "2017-01-01T00:00:00Z",
|
||||||
|
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||||
|
"type": "indicator",
|
||||||
|
"valid_from": "1970-01-01T00:00:00Z"
|
||||||
|
}"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_indicator_with_all_required_fields():
|
||||||
|
now = datetime.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)
|
||||||
|
epoch = datetime.datetime(1970, 1, 1, 0, 0, 0, tzinfo=pytz.utc)
|
||||||
|
|
||||||
|
indicator = stix2.Indicator(
|
||||||
|
type="indicator",
|
||||||
|
id="indicator--01234567-89ab-cdef-0123-456789abcdef",
|
||||||
|
created=now,
|
||||||
|
modified=now,
|
||||||
|
labels=['malicious-activity'],
|
||||||
|
pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||||
|
valid_from=epoch,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert str(indicator) == EXPECTED
|
||||||
|
|
Loading…
Reference in New Issue