1import datetime as dt
2
3import pytest
4import pytz
5
6import stix2
7from stix2.v20 import TLP_WHITE
8
9from .constants import CAMPAIGN_ID, IDENTITY_ID, MARKING_DEFINITION_ID
10
11EXPECTED_TLP_MARKING_DEFINITION = """{
12    "type": "marking-definition",
13    "id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
14    "created": "2017-01-20T00:00:00.000Z",
15    "definition_type": "tlp",
16    "definition": {
17        "tlp": "white"
18    }
19}"""
20
21EXPECTED_STATEMENT_MARKING_DEFINITION = """{
22    "type": "marking-definition",
23    "id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
24    "created": "2017-01-20T00:00:00Z",
25    "definition_type": "statement",
26    "definition": {
27        "statement": "Copyright 2016, Example Corp"
28    }
29}"""
30
31EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING = """{
32    "type": "campaign",
33    "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
34    "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
35    "created": "2016-04-06T20:03:00.000Z",
36    "modified": "2016-04-06T20:03:00.000Z",
37    "name": "Green Group Attacks Against Finance",
38    "description": "Campaign by Green Group against a series of targets in the financial services sector.",
39    "object_marking_refs": [
40        "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9"
41    ]
42}"""
43
44EXPECTED_GRANULAR_MARKING = """{
45    "marking_ref": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
46    "selectors": [
47        "abc",
48        "abc.[23]",
49        "abc.def",
50        "abc.[2].efg"
51    ]
52}"""
53
54EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS = """{
55    "type": "campaign",
56    "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
57    "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
58    "created": "2016-04-06T20:03:00.000Z",
59    "modified": "2016-04-06T20:03:00.000Z",
60    "name": "Green Group Attacks Against Finance",
61    "description": "Campaign by Green Group against a series of targets in the financial services sector.",
62    "granular_markings": [
63        {
64            "marking_ref": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
65            "selectors": [
66                "description"
67            ]
68        }
69    ]
70}"""
71
72
73def test_marking_def_example_with_tlp():
74    assert str(TLP_WHITE) == EXPECTED_TLP_MARKING_DEFINITION
75
76
77def test_marking_def_example_with_statement_positional_argument():
78    marking_definition = stix2.v20.MarkingDefinition(
79        id=MARKING_DEFINITION_ID,
80        created="2017-01-20T00:00:00.000Z",
81        definition_type="statement",
82        definition=stix2.v20.StatementMarking(statement="Copyright 2016, Example Corp"),
83    )
84
85    assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION
86
87
88def test_marking_def_example_with_kwargs_statement():
89    kwargs = dict(statement="Copyright 2016, Example Corp")
90    marking_definition = stix2.v20.MarkingDefinition(
91        id=MARKING_DEFINITION_ID,
92        created="2017-01-20T00:00:00.000Z",
93        definition_type="statement",
94        definition=stix2.v20.StatementMarking(**kwargs),
95    )
96
97    assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION
98
99
100def test_marking_def_invalid_type():
101    with pytest.raises(ValueError):
102        stix2.v20.MarkingDefinition(
103            id=MARKING_DEFINITION_ID,
104            created="2017-01-20T00:00:00.000Z",
105            definition_type="my-definition-type",
106            definition=stix2.v20.StatementMarking("Copyright 2016, Example Corp"),
107        )
108
109
110def test_campaign_with_markings_example():
111    campaign = stix2.v20.Campaign(
112        type='campaign',
113        id=CAMPAIGN_ID,
114        created_by_ref=IDENTITY_ID,
115        created="2016-04-06T20:03:00.000Z",
116        modified="2016-04-06T20:03:00.000Z",
117        name="Green Group Attacks Against Finance",
118        description="Campaign by Green Group against a series of targets in the financial services sector.",
119        object_marking_refs=TLP_WHITE,
120    )
121    assert str(campaign) == EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING
122
123
124def test_granular_example():
125    granular_marking = stix2.v20.GranularMarking(
126        marking_ref=MARKING_DEFINITION_ID,
127        selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"],
128    )
129
130    assert str(granular_marking) == EXPECTED_GRANULAR_MARKING
131
132
133def test_granular_example_with_bad_selector():
134    with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo:
135        stix2.v20.GranularMarking(
136            marking_ref=MARKING_DEFINITION_ID,
137            selectors=["abc[0]"],   # missing "."
138        )
139
140    assert excinfo.value.cls == stix2.v20.GranularMarking
141    assert excinfo.value.prop_name == "selectors"
142    assert excinfo.value.reason == "must adhere to selector syntax."
143    assert str(excinfo.value) == "Invalid value for GranularMarking 'selectors': must adhere to selector syntax."
144
145
146def test_campaign_with_granular_markings_example():
147    campaign = stix2.v20.Campaign(
148        type='campaign',
149        id=CAMPAIGN_ID,
150        created_by_ref=IDENTITY_ID,
151        created="2016-04-06T20:03:00.000Z",
152        modified="2016-04-06T20:03:00.000Z",
153        name="Green Group Attacks Against Finance",
154        description="Campaign by Green Group against a series of targets in the financial services sector.",
155        granular_markings=[
156            stix2.v20.GranularMarking(
157                marking_ref=MARKING_DEFINITION_ID,
158                selectors=["description"],
159            ),
160        ],
161    )
162    assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS
163
164
165@pytest.mark.parametrize(
166    "data", [
167        EXPECTED_TLP_MARKING_DEFINITION,
168        {
169            "id": MARKING_DEFINITION_ID,
170            "type": "marking-definition",
171            "created": "2017-01-20T00:00:00Z",
172            "definition": {
173                "tlp": "white",
174            },
175            "definition_type": "tlp",
176        },
177    ],
178)
179def test_parse_marking_definition(data):
180    gm = stix2.parse(data, version="2.0")
181
182    assert gm.type == 'marking-definition'
183    assert gm.id == MARKING_DEFINITION_ID
184    assert gm.created == dt.datetime(2017, 1, 20, 0, 0, 0, tzinfo=pytz.utc)
185    assert gm.definition.tlp == "white"
186    assert gm.definition_type == "tlp"
187
188
189@stix2.v20.CustomMarking(
190    'x-new-marking-type', [
191        ('property1', stix2.properties.StringProperty(required=True)),
192        ('property2', stix2.properties.IntegerProperty()),
193    ],
194)
195class NewMarking(object):
196    def __init__(self, property2=None, **kwargs):
197        if "property3" in kwargs and not isinstance(kwargs.get("property3"), int):
198            raise TypeError("Must be integer!")
199
200
201def test_registered_custom_marking():
202    nm = NewMarking(property1='something', property2=55)
203
204    marking_def = stix2.v20.MarkingDefinition(
205        id="marking-definition--00000000-0000-4000-8000-000000000012",
206        created="2017-01-22T00:00:00.000Z",
207        definition_type="x-new-marking-type",
208        definition=nm,
209    )
210
211    assert marking_def.type == "marking-definition"
212    assert marking_def.id == "marking-definition--00000000-0000-4000-8000-000000000012"
213    assert marking_def.created == dt.datetime(2017, 1, 22, 0, 0, 0, tzinfo=pytz.utc)
214    assert marking_def.definition.property1 == "something"
215    assert marking_def.definition.property2 == 55
216    assert marking_def.definition_type == "x-new-marking-type"
217
218
219def test_registered_custom_marking_raises_exception():
220    with pytest.raises(TypeError) as excinfo:
221        NewMarking(property1='something', property3='something', allow_custom=True)
222
223    assert str(excinfo.value) == "Must be integer!"
224
225
226def test_not_registered_marking_raises_exception():
227    with pytest.raises(ValueError) as excinfo:
228        # Used custom object on purpose to demonstrate a not-registered marking
229        @stix2.v20.CustomObject(
230            'x-new-marking-type2', [
231                ('property1', stix2.properties.StringProperty(required=True)),
232                ('property2', stix2.properties.IntegerProperty()),
233            ],
234        )
235        class NewObject2(object):
236            def __init__(self, property2=None, **kwargs):
237                return
238
239        no = NewObject2(property1='something', property2=55)
240
241        stix2.v20.MarkingDefinition(
242            id="marking-definition--00000000-0000-4000-8000-000000000012",
243            created="2017-01-22T00:00:00.000Z",
244            definition_type="x-new-marking-type2",
245            definition=no,
246        )
247
248    assert str(excinfo.value) == "definition_type must be a valid marking type"
249
250
251def test_marking_wrong_type_construction():
252    with pytest.raises(ValueError):
253        # Test passing wrong type for properties.
254        @stix2.v20.CustomMarking('x-new-marking-type2', ("a", "b"))
255        class NewObject3(object):
256            pass
257
258
259def test_campaign_add_markings():
260    campaign = stix2.v20.Campaign(
261        id=CAMPAIGN_ID,
262        created_by_ref=IDENTITY_ID,
263        created="2016-04-06T20:03:00Z",
264        modified="2016-04-06T20:03:00Z",
265        name="Green Group Attacks Against Finance",
266        description="Campaign by Green Group against a series of targets in the financial services sector.",
267    )
268    campaign = campaign.add_markings(TLP_WHITE)
269    assert campaign.object_marking_refs[0] == TLP_WHITE.id
270