240 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Python
		
	
	
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| import datetime as dt
 | |
| from io import StringIO
 | |
| 
 | |
| import pytest
 | |
| import pytz
 | |
| 
 | |
| import stix2.serialization
 | |
| import stix2.utils
 | |
| 
 | |
| from .constants import IDENTITY_ID
 | |
| 
 | |
| amsterdam = pytz.timezone('Europe/Amsterdam')
 | |
| eastern = pytz.timezone('US/Eastern')
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     'dttm, timestamp', [
 | |
|         (dt.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'),
 | |
|         (amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'),
 | |
|         (eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'),
 | |
|         (eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'),
 | |
|         (dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'),
 | |
|         (dt.datetime(2017, 7, 1, 0, 0, 0, 1), '2017-07-01T00:00:00.000001Z'),
 | |
|         (stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='millisecond'), '2017-07-01T00:00:00.000Z'),
 | |
|         (stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='second'), '2017-07-01T00:00:00Z'),
 | |
|     ],
 | |
| )
 | |
| def test_timestamp_formatting(dttm, timestamp):
 | |
|     assert stix2.utils.format_datetime(dttm) == timestamp
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     'timestamp, dttm', [
 | |
|         (dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
 | |
|         (dt.date(2017, 1, 1), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
 | |
|         ('2017-01-01T00:00:00Z', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
 | |
|     ],
 | |
| )
 | |
| def test_parse_datetime(timestamp, dttm):
 | |
|     assert stix2.utils.parse_into_datetime(timestamp) == dttm
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     'timestamp, dttm, precision', [
 | |
|         ('2017-01-01T01:02:03.000001Z', dt.datetime(2017, 1, 1, 1, 2, 3, 0, tzinfo=pytz.utc), 'millisecond'),
 | |
|         ('2017-01-01T01:02:03.001Z', dt.datetime(2017, 1, 1, 1, 2, 3, 1000, tzinfo=pytz.utc), 'millisecond'),
 | |
|         ('2017-01-01T01:02:03.1Z', dt.datetime(2017, 1, 1, 1, 2, 3, 100000, tzinfo=pytz.utc), 'millisecond'),
 | |
|         ('2017-01-01T01:02:03.45Z', dt.datetime(2017, 1, 1, 1, 2, 3, 450000, tzinfo=pytz.utc), 'millisecond'),
 | |
|         ('2017-01-01T01:02:03.45Z', dt.datetime(2017, 1, 1, 1, 2, 3, tzinfo=pytz.utc), 'second'),
 | |
|     ],
 | |
| )
 | |
| def test_parse_datetime_precision(timestamp, dttm, precision):
 | |
|     assert stix2.utils.parse_into_datetime(timestamp, precision) == dttm
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     'ts', [
 | |
|         'foobar',
 | |
|         1,
 | |
|     ],
 | |
| )
 | |
| def test_parse_datetime_invalid(ts):
 | |
|     with pytest.raises(ValueError):
 | |
|         stix2.utils.parse_into_datetime('foobar')
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     'data', [
 | |
|         {"a": 1},
 | |
|         '{"a": 1}',
 | |
|         StringIO(u'{"a": 1}'),
 | |
|         [("a", 1,)],
 | |
|     ],
 | |
| )
 | |
| def test_get_dict(data):
 | |
|     assert stix2.utils._get_dict(data)
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     'data', [
 | |
|         1,
 | |
|         [1],
 | |
|         ['a', 1],
 | |
|         "foobar",
 | |
|     ],
 | |
| )
 | |
| def test_get_dict_invalid(data):
 | |
|     with pytest.raises(ValueError):
 | |
|         stix2.utils._get_dict(data)
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     'stix_id, type', [
 | |
|         ('malware--d69c8146-ab35-4d50-8382-6fc80e641d43', 'malware'),
 | |
|         ('intrusion-set--899ce53f-13a0-479b-a0e4-67d46e241542', 'intrusion-set'),
 | |
|     ],
 | |
| )
 | |
| def test_get_type_from_id(stix_id, type):
 | |
|     assert stix2.utils.get_type_from_id(stix_id) == type
 | |
| 
 | |
| 
 | |
| def test_deduplicate(stix_objs1):
 | |
|     unique = stix2.utils.deduplicate(stix_objs1)
 | |
| 
 | |
|     # Only 3 objects are unique
 | |
|     # 2 id's vary
 | |
|     # 2 modified times vary for a particular id
 | |
| 
 | |
|     assert len(unique) == 3
 | |
| 
 | |
|     ids = [obj['id'] for obj in unique]
 | |
|     mods = [obj['modified'] for obj in unique]
 | |
| 
 | |
|     assert "indicator--00000000-0000-4000-8000-000000000001" in ids
 | |
|     assert "indicator--00000000-0000-4000-8000-000000000001" in ids
 | |
|     assert "2017-01-27T13:49:53.935Z" in mods
 | |
|     assert "2017-01-27T13:49:53.936Z" in mods
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     'object, tuple_to_find, expected_index', [
 | |
|         (
 | |
|             stix2.v20.ObservedData(
 | |
|                 id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
 | |
|                 created_by_ref=IDENTITY_ID,
 | |
|                 created="2016-04-06T19:58:16.000Z",
 | |
|                 modified="2016-04-06T19:58:16.000Z",
 | |
|                 first_observed="2015-12-21T19:00:00Z",
 | |
|                 last_observed="2015-12-21T19:00:00Z",
 | |
|                 number_observed=50,
 | |
|                 objects={
 | |
|                     "0": {
 | |
|                         "name": "foo.exe",
 | |
|                         "type": "file",
 | |
|                     },
 | |
|                     "1": {
 | |
|                         "type": "ipv4-addr",
 | |
|                         "value": "198.51.100.3",
 | |
|                     },
 | |
|                     "2": {
 | |
|                         "type": "network-traffic",
 | |
|                         "src_ref": "1",
 | |
|                         "protocols": [
 | |
|                             "tcp",
 | |
|                             "http",
 | |
|                         ],
 | |
|                         "extensions": {
 | |
|                             "http-request-ext": {
 | |
|                                 "request_method": "get",
 | |
|                                 "request_value": "/download.html",
 | |
|                                 "request_version": "http/1.1",
 | |
|                                 "request_header": {
 | |
|                                     "Accept-Encoding": "gzip,deflate",
 | |
|                                     "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113",
 | |
|                                     "Host": "www.example.com",
 | |
|                                 },
 | |
|                             },
 | |
|                         },
 | |
|                     },
 | |
|                 },
 | |
|             ), ('1', {"type": "ipv4-addr", "value": "198.51.100.3"}), 1,
 | |
|         ),
 | |
|         (
 | |
|             {
 | |
|                 "type": "x-example",
 | |
|                 "id": "x-example--d5413db2-c26c-42e0-b0e0-ec800a310bfb",
 | |
|                 "created": "2018-06-11T01:25:22.063Z",
 | |
|                 "modified": "2018-06-11T01:25:22.063Z",
 | |
|                 "dictionary": {
 | |
|                     "key": {
 | |
|                         "key_one": "value",
 | |
|                         "key_two": "value",
 | |
|                     },
 | |
|                 },
 | |
|             }, ('key', {'key_one': 'value', 'key_two': 'value'}), 0,
 | |
|         ),
 | |
|         (
 | |
|             {
 | |
|                 "type": "language-content",
 | |
|                 "id": "language-content--b86bd89f-98bb-4fa9-8cb2-9ad421da981d",
 | |
|                 "created": "2017-02-08T21:31:22.007Z",
 | |
|                 "modified": "2017-02-08T21:31:22.007Z",
 | |
|                 "object_ref": "campaign--12a111f0-b824-4baf-a224-83b80237a094",
 | |
|                 "object_modified": "2017-02-08T21:31:22.007Z",
 | |
|                 "contents": {
 | |
|                     "de": {
 | |
|                         "name": "Bank Angriff 1",
 | |
|                         "description": "Weitere Informationen über Banküberfall",
 | |
|                     },
 | |
|                     "fr": {
 | |
|                         "name": "Attaque Bank 1",
 | |
|                         "description": "Plus d'informations sur la crise bancaire",
 | |
|                     },
 | |
|                 },
 | |
|             }, ('fr', {"name": "Attaque Bank 1", "description": "Plus d'informations sur la crise bancaire"}), 1,
 | |
|         ),
 | |
|     ],
 | |
| )
 | |
| def test_find_property_index(object, tuple_to_find, expected_index):
 | |
|     assert stix2.serialization.find_property_index(
 | |
|         object,
 | |
|         *tuple_to_find
 | |
|     ) == expected_index
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     'dict_value, tuple_to_find, expected_index', [
 | |
|         (
 | |
|             {
 | |
|                 "contents": {
 | |
|                     "de": {
 | |
|                         "name": "Bank Angriff 1",
 | |
|                         "description": "Weitere Informationen über Banküberfall",
 | |
|                     },
 | |
|                     "fr": {
 | |
|                         "name": "Attaque Bank 1",
 | |
|                         "description": "Plus d'informations sur la crise bancaire",
 | |
|                     },
 | |
|                     "es": {
 | |
|                         "name": "Ataque al Banco",
 | |
|                         "description": "Mas informacion sobre el ataque al banco",
 | |
|                     },
 | |
|                 },
 | |
|             }, ('es', {"name": "Ataque al Banco", "description": "Mas informacion sobre el ataque al banco"}), 1,
 | |
|         ),  # Sorted alphabetically
 | |
|         (
 | |
|             {
 | |
|                 'my_list': [
 | |
|                     {"key_one": 1},
 | |
|                     {"key_two": 2},
 | |
|                 ],
 | |
|             }, ('key_one', 1), 0,
 | |
|         ),
 | |
|     ],
 | |
| )
 | |
| def test_iterate_over_values(dict_value, tuple_to_find, expected_index):
 | |
|     assert stix2.serialization._find_property_in_seq(dict_value.values(), *tuple_to_find) == expected_index
 |