diff --git a/CHANGELOG b/CHANGELOG index 6dcfef9..9911e84 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,17 @@ CHANGELOG ========= +1.1.2 - 2019-02-13 + +* #86 Adds helper function to Location objects to generate a URL to the location in an online map engine. + +1.1.1 - 2019-01-11 + +* #234 Update documentation structure to better navigate between v20/v21 objects +* #232 FileSystemStore now raises an exception if you attempt to overwrite an existing file +* #236 Fix a serialization problem with the WindowsRegistryKey observable object +* #238 Fix a problem with the LanguageContent object not allowing its creation with an empty dictionary + 1.1.0 - 2018-12-11 - Most (if not all) STIX 2.1 SDOs/SROs and core objects have been implemented according to the latest CSD/WD document diff --git a/docs/api/stix2.v20.rst b/docs/api/stix2.v20.rst new file mode 100644 index 0000000..2cbb2e3 --- /dev/null +++ b/docs/api/stix2.v20.rst @@ -0,0 +1,5 @@ +v20 +========= + +.. automodule:: stix2.v20 + :members: \ No newline at end of file diff --git a/docs/api/stix2.v21.rst b/docs/api/stix2.v21.rst new file mode 100644 index 0000000..fc02330 --- /dev/null +++ b/docs/api/stix2.v21.rst @@ -0,0 +1,5 @@ +v21 +========= + +.. automodule:: stix2.v21 + :members: \ No newline at end of file diff --git a/docs/api/stix2.v20.bundle.rst b/docs/api/v20/stix2.v20.bundle.rst similarity index 100% rename from docs/api/stix2.v20.bundle.rst rename to docs/api/v20/stix2.v20.bundle.rst diff --git a/docs/api/stix2.v20.common.rst b/docs/api/v20/stix2.v20.common.rst similarity index 81% rename from docs/api/stix2.v20.common.rst rename to docs/api/v20/stix2.v20.common.rst index 8cec059..0c7a296 100644 --- a/docs/api/stix2.v20.common.rst +++ b/docs/api/v20/stix2.v20.common.rst @@ -2,4 +2,4 @@ common ================ .. automodule:: stix2.v20.common - :members: + :members: \ No newline at end of file diff --git a/docs/api/stix2.v20.observables.rst b/docs/api/v20/stix2.v20.observables.rst similarity index 84% rename from docs/api/stix2.v20.observables.rst rename to docs/api/v20/stix2.v20.observables.rst index 4d9803a..d31f75f 100644 --- a/docs/api/stix2.v20.observables.rst +++ b/docs/api/v20/stix2.v20.observables.rst @@ -2,4 +2,4 @@ observables ===================== .. automodule:: stix2.v20.observables - :members: + :members: \ No newline at end of file diff --git a/docs/api/stix2.v20.sdo.rst b/docs/api/v20/stix2.v20.sdo.rst similarity index 79% rename from docs/api/stix2.v20.sdo.rst rename to docs/api/v20/stix2.v20.sdo.rst index a115d5b..c4c97f8 100644 --- a/docs/api/stix2.v20.sdo.rst +++ b/docs/api/v20/stix2.v20.sdo.rst @@ -2,4 +2,4 @@ sdo ============= .. automodule:: stix2.v20.sdo - :members: + :members: \ No newline at end of file diff --git a/docs/api/stix2.v20.sro.rst b/docs/api/v20/stix2.v20.sro.rst similarity index 79% rename from docs/api/stix2.v20.sro.rst rename to docs/api/v20/stix2.v20.sro.rst index 397cf29..379ed18 100644 --- a/docs/api/stix2.v20.sro.rst +++ b/docs/api/v20/stix2.v20.sro.rst @@ -2,4 +2,4 @@ sro ============= .. automodule:: stix2.v20.sro - :members: + :members: \ No newline at end of file diff --git a/docs/api/stix2.v21.bundle.rst b/docs/api/v21/stix2.v21.bundle.rst similarity index 100% rename from docs/api/stix2.v21.bundle.rst rename to docs/api/v21/stix2.v21.bundle.rst diff --git a/docs/api/stix2.v21.common.rst b/docs/api/v21/stix2.v21.common.rst similarity index 100% rename from docs/api/stix2.v21.common.rst rename to docs/api/v21/stix2.v21.common.rst diff --git a/docs/api/stix2.v21.observables.rst b/docs/api/v21/stix2.v21.observables.rst similarity index 100% rename from docs/api/stix2.v21.observables.rst rename to docs/api/v21/stix2.v21.observables.rst diff --git a/docs/api/stix2.v21.sdo.rst b/docs/api/v21/stix2.v21.sdo.rst similarity index 100% rename from docs/api/stix2.v21.sdo.rst rename to docs/api/v21/stix2.v21.sdo.rst diff --git a/docs/api/stix2.v21.sro.rst b/docs/api/v21/stix2.v21.sro.rst similarity index 100% rename from docs/api/stix2.v21.sro.rst rename to docs/api/v21/stix2.v21.sro.rst diff --git a/docs/guide/creating.ipynb b/docs/guide/creating.ipynb index 058aae3..92a3336 100644 --- a/docs/guide/creating.ipynb +++ b/docs/guide/creating.ipynb @@ -144,12 +144,12 @@ ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "indicator",\n",
-       "    "id": "indicator--548af3be-39d7-4a3e-93c2-1a63cccf8951",\n",
-       "    "created": "2018-04-05T18:32:24.193Z",\n",
-       "    "modified": "2018-04-05T18:32:24.193Z",\n",
+       "    "id": "indicator--2f3d4926-163d-4aef-bcd2-19dea96916ae",\n",
+       "    "created": "2019-05-13T13:14:48.509Z",\n",
+       "    "modified": "2019-05-13T13:14:48.509Z",\n",
        "    "name": "File hash for malware variant",\n",
        "    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
-       "    "valid_from": "2018-04-05T18:32:24.193659Z",\n",
+       "    "valid_from": "2019-05-13T13:14:48.509629Z",\n",
        "    "labels": [\n",
        "        "malicious-activity"\n",
        "    ]\n",
@@ -465,9 +465,9 @@
        ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
        ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "malware",\n",
-       "    "id": "malware--3d7f0c1c-616a-4868-aa7b-150821d2a429",\n",
-       "    "created": "2018-04-05T18:32:46.584Z",\n",
-       "    "modified": "2018-04-05T18:32:46.584Z",\n",
+       "    "id": "malware--1f2aba70-f0ae-49cd-9267-6fcb1e43be67",\n",
+       "    "created": "2019-05-13T13:15:04.698Z",\n",
+       "    "modified": "2019-05-13T13:15:04.698Z",\n",
        "    "name": "Poison Ivy",\n",
        "    "labels": [\n",
        "        "remote-access-trojan"\n",
@@ -498,7 +498,7 @@
    "source": [
     "As with indicators, the ``type``, ``id``, ``created``, and ``modified`` properties will be set automatically if not provided. For Malware objects, the ``labels`` and ``name`` properties must be provided.\n",
     "\n",
-    "You can see the full list of SDO classes [here](../api/stix2.v20.sdo.rst)."
+    "You can see the full list of SDO classes [here](../api/v20/stix2.v20.sdo.rst)."
    ]
   },
   {
@@ -588,12 +588,12 @@
        ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
        ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "relationship",\n",
-       "    "id": "relationship--34ddc7b4-4965-4615-b286-1c8bbaa1e7db",\n",
-       "    "created": "2018-04-05T18:32:49.474Z",\n",
-       "    "modified": "2018-04-05T18:32:49.474Z",\n",
+       "    "id": "relationship--80c174fa-36d1-47c2-9a9d-ce0c636bedcc",\n",
+       "    "created": "2019-05-13T13:15:13.152Z",\n",
+       "    "modified": "2019-05-13T13:15:13.152Z",\n",
        "    "relationship_type": "indicates",\n",
-       "    "source_ref": "indicator--548af3be-39d7-4a3e-93c2-1a63cccf8951",\n",
-       "    "target_ref": "malware--3d7f0c1c-616a-4868-aa7b-150821d2a429"\n",
+       "    "source_ref": "indicator--2f3d4926-163d-4aef-bcd2-19dea96916ae",\n",
+       "    "target_ref": "malware--1f2aba70-f0ae-49cd-9267-6fcb1e43be67"\n",
        "}\n",
        "
\n" ], @@ -700,12 +700,12 @@ ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "relationship",\n",
-       "    "id": "relationship--0a646403-f7e7-4cfd-b945-cab5cde05857",\n",
-       "    "created": "2018-04-05T18:32:51.417Z",\n",
-       "    "modified": "2018-04-05T18:32:51.417Z",\n",
+       "    "id": "relationship--47395d23-dedd-45d4-8db1-c9ffaf44493d",\n",
+       "    "created": "2019-05-13T13:15:16.566Z",\n",
+       "    "modified": "2019-05-13T13:15:16.566Z",\n",
        "    "relationship_type": "indicates",\n",
-       "    "source_ref": "indicator--548af3be-39d7-4a3e-93c2-1a63cccf8951",\n",
-       "    "target_ref": "malware--3d7f0c1c-616a-4868-aa7b-150821d2a429"\n",
+       "    "source_ref": "indicator--2f3d4926-163d-4aef-bcd2-19dea96916ae",\n",
+       "    "target_ref": "malware--1f2aba70-f0ae-49cd-9267-6fcb1e43be67"\n",
        "}\n",
        "
\n" ], @@ -810,26 +810,26 @@ ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "bundle",\n",
-       "    "id": "bundle--f83477e5-f853-47e1-a267-43f3aa1bd5b0",\n",
+       "    "id": "bundle--388c9b2c-936c-420a-baa5-04f48d682a01",\n",
        "    "spec_version": "2.0",\n",
        "    "objects": [\n",
        "        {\n",
        "            "type": "indicator",\n",
-       "            "id": "indicator--548af3be-39d7-4a3e-93c2-1a63cccf8951",\n",
-       "            "created": "2018-04-05T18:32:24.193Z",\n",
-       "            "modified": "2018-04-05T18:32:24.193Z",\n",
+       "            "id": "indicator--2f3d4926-163d-4aef-bcd2-19dea96916ae",\n",
+       "            "created": "2019-05-13T13:14:48.509Z",\n",
+       "            "modified": "2019-05-13T13:14:48.509Z",\n",
        "            "name": "File hash for malware variant",\n",
        "            "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
-       "            "valid_from": "2018-04-05T18:32:24.193659Z",\n",
+       "            "valid_from": "2019-05-13T13:14:48.509629Z",\n",
        "            "labels": [\n",
        "                "malicious-activity"\n",
        "            ]\n",
        "        },\n",
        "        {\n",
        "            "type": "malware",\n",
-       "            "id": "malware--3d7f0c1c-616a-4868-aa7b-150821d2a429",\n",
-       "            "created": "2018-04-05T18:32:46.584Z",\n",
-       "            "modified": "2018-04-05T18:32:46.584Z",\n",
+       "            "id": "malware--1f2aba70-f0ae-49cd-9267-6fcb1e43be67",\n",
+       "            "created": "2019-05-13T13:15:04.698Z",\n",
+       "            "modified": "2019-05-13T13:15:04.698Z",\n",
        "            "name": "Poison Ivy",\n",
        "            "labels": [\n",
        "                "remote-access-trojan"\n",
@@ -837,12 +837,12 @@
        "        },\n",
        "        {\n",
        "            "type": "relationship",\n",
-       "            "id": "relationship--34ddc7b4-4965-4615-b286-1c8bbaa1e7db",\n",
-       "            "created": "2018-04-05T18:32:49.474Z",\n",
-       "            "modified": "2018-04-05T18:32:49.474Z",\n",
+       "            "id": "relationship--80c174fa-36d1-47c2-9a9d-ce0c636bedcc",\n",
+       "            "created": "2019-05-13T13:15:13.152Z",\n",
+       "            "modified": "2019-05-13T13:15:13.152Z",\n",
        "            "relationship_type": "indicates",\n",
-       "            "source_ref": "indicator--548af3be-39d7-4a3e-93c2-1a63cccf8951",\n",
-       "            "target_ref": "malware--3d7f0c1c-616a-4868-aa7b-150821d2a429"\n",
+       "            "source_ref": "indicator--2f3d4926-163d-4aef-bcd2-19dea96916ae",\n",
+       "            "target_ref": "malware--1f2aba70-f0ae-49cd-9267-6fcb1e43be67"\n",
        "        }\n",
        "    ]\n",
        "}\n",
@@ -863,6 +863,249 @@
     "bundle = Bundle(indicator, malware, relationship)\n",
     "print(bundle)"
    ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Creating Cyber Observable References\n",
+    "Cyber Observable Objects have properties that can reference other Cyber Observable Objects. In order to create those references, use the ``_valid_refs`` property as shown in the following examples. It should be noted that ``_valid_refs`` is necessary when creating references to Cyber Observable Objects since some embedded references can only point to certain types, and ``_valid_refs`` helps ensure consistency. \n",
+    "\n",
+    "There are two cases."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "#### Case 1: Specifying the type of the Cyber Observable Objects being referenced\n",
+    "In the following example, the IPv4Address object has its ``resolves_to_refs`` property specified. As per the spec, this property's value must be a list of reference(s) to MACAddress objects. In this case, those references are strings that state the type of the Cyber Observable Object being referenced, and are provided in ``_valid_refs``."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "
{\n",
+       "    "type": "ipv4-addr",\n",
+       "    "value": "177.60.40.7",\n",
+       "    "resolves_to_refs": [\n",
+       "        "1",\n",
+       "        "2"\n",
+       "    ]\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from stix2 import IPv4Address\n", + "\n", + "ip4 = IPv4Address(\n", + " _valid_refs={\"1\": \"mac-addr\", \"2\": \"mac-addr\"},\n", + " value=\"177.60.40.7\",\n", + " resolves_to_refs=[\"1\", \"2\"]\n", + ")\n", + "\n", + "print(ip4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Case 2: Specifying the name of the Cyber Observable Objects being referenced\n", + "The following example is just like the one provided in Case 1 above, with one key difference: instead of using strings to specify the type of the Cyber Observable Objects being referenced in ``_valid_refs``, the referenced Cyber Observable Objects are created beforehand and then their names are provided in ``_valid_refs``." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
{\n",
+       "    "type": "ipv4-addr",\n",
+       "    "value": "177.60.40.7",\n",
+       "    "resolves_to_refs": [\n",
+       "        "1",\n",
+       "        "2"\n",
+       "    ]\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from stix2 import MACAddress\n", + "\n", + "mac_addr_a = MACAddress(value=\"a1:b2:c3:d4:e5:f6\")\n", + "mac_addr_b = MACAddress(value=\"a7:b8:c9:d0:e1:f2\")\n", + "\n", + "ip4_valid_refs = IPv4Address(\n", + " _valid_refs={\"1\": mac_addr_a, \"2\": mac_addr_b},\n", + " value=\"177.60.40.7\",\n", + " resolves_to_refs=[\"1\", \"2\"]\n", + ")\n", + "\n", + "print(ip4_valid_refs)" + ] } ], "metadata": { @@ -881,7 +1124,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.5" + "version": "3.6.7" } }, "nbformat": 4, diff --git a/docs/guide/markings.ipynb b/docs/guide/markings.ipynb index 8230daf..44e023a 100644 --- a/docs/guide/markings.ipynb +++ b/docs/guide/markings.ipynb @@ -1310,6 +1310,212 @@ "source": [ "malware.is_marked(TLP_WHITE.id, 'description')" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Extracting Lang Data Markings or marking-definition Data Markings\n", + "\n", + "If you need a specific kind of marking, you can also filter them using the API. By default the library will get both types of markings by default. You can choose between `lang=True/False` or `marking_ref=True/False` depending on your use-case." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"type\": \"indicator\",\n", + " \"spec_version\": \"2.1\",\n", + " \"id\": \"indicator--634ef462-d6b5-48bc-9d9f-b46a6919227c\",\n", + " \"created\": \"2019-05-03T18:36:44.354Z\",\n", + " \"modified\": \"2019-05-03T18:36:44.354Z\",\n", + " \"description\": \"Una descripcion sobre este indicador\",\n", + " \"indicator_types\": [\n", + " \"malware\"\n", + " ],\n", + " \"pattern\": \"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\",\n", + " \"valid_from\": \"2019-05-03T18:36:44.354443Z\",\n", + " \"object_marking_refs\": [\n", + " \"marking-definition--f88d31f6-486f-44da-b317-01333bde0b82\"\n", + " ],\n", + " \"granular_markings\": [\n", + " {\n", + " \"lang\": \"es\",\n", + " \"selectors\": [\n", + " \"description\"\n", + " ]\n", + " },\n", + " {\n", + " \"marking_ref\": \"marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da\",\n", + " \"selectors\": [\n", + " \"description\"\n", + " ]\n", + " }\n", + " ]\n", + "}\n", + "['es', 'marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da']\n", + "['marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da']\n", + "['es']\n" + ] + } + ], + "source": [ + "from stix2 import v21\n", + "\n", + "v21_indicator = v21.Indicator(\n", + " description=\"Una descripcion sobre este indicador\",\n", + " pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\",\n", + " object_marking_refs=['marking-definition--f88d31f6-486f-44da-b317-01333bde0b82'],\n", + " indicator_types=['malware'],\n", + " granular_markings=[\n", + " {\n", + " 'selectors': ['description'],\n", + " 'lang': 'es'\n", + " },\n", + " {\n", + " 'selectors': ['description'],\n", + " 'marking_ref': 'marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da'\n", + " }\n", + " ]\n", + ")\n", + "print(v21_indicator)\n", + "\n", + "# Gets both lang and marking_ref markings for 'description'\n", + "print(v21_indicator.get_markings('description'))\n", + "\n", + "# Exclude lang markings from results\n", + "print(v21_indicator.get_markings('description', lang=False))\n", + "\n", + "# Exclude marking-definition markings from results\n", + "print(v21_indicator.get_markings('description', marking_ref=False))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this same manner, calls to `clear_markings` and `set_markings` also have the ability to operate in for one or both types of markings." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"type\": \"indicator\",\n", + " \"spec_version\": \"2.1\",\n", + " \"id\": \"indicator--a612665a-2df4-4fd2-851c-7fbb8c92339a\",\n", + " \"created\": \"2019-05-03T19:13:59.010Z\",\n", + " \"modified\": \"2019-05-03T19:15:41.173Z\",\n", + " \"description\": \"Una descripcion sobre este indicador\",\n", + " \"indicator_types\": [\n", + " \"malware\"\n", + " ],\n", + " \"pattern\": \"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\",\n", + " \"valid_from\": \"2019-05-03T19:13:59.010624Z\",\n", + " \"object_marking_refs\": [\n", + " \"marking-definition--f88d31f6-486f-44da-b317-01333bde0b82\"\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "print(v21_indicator.clear_markings(\"description\")) # By default, both types of markings will be removed" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"type\": \"indicator\",\n", + " \"spec_version\": \"2.1\",\n", + " \"id\": \"indicator--982aeb4d-4dd3-4b04-aa50-a1d00c31986c\",\n", + " \"created\": \"2019-05-03T19:19:26.542Z\",\n", + " \"modified\": \"2019-05-03T19:20:51.818Z\",\n", + " \"description\": \"Una descripcion sobre este indicador\",\n", + " \"indicator_types\": [\n", + " \"malware\"\n", + " ],\n", + " \"pattern\": \"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\",\n", + " \"valid_from\": \"2019-05-03T19:19:26.542267Z\",\n", + " \"object_marking_refs\": [\n", + " \"marking-definition--f88d31f6-486f-44da-b317-01333bde0b82\"\n", + " ],\n", + " \"granular_markings\": [\n", + " {\n", + " \"lang\": \"es\",\n", + " \"selectors\": [\n", + " \"description\"\n", + " ]\n", + " }\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "# If lang is False, no lang markings will be removed\n", + "print(v21_indicator.clear_markings(\"description\", lang=False))" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"type\": \"indicator\",\n", + " \"spec_version\": \"2.1\",\n", + " \"id\": \"indicator--de0316d6-38e1-43c2-af4f-649305251864\",\n", + " \"created\": \"2019-05-03T19:40:21.459Z\",\n", + " \"modified\": \"2019-05-03T19:40:26.431Z\",\n", + " \"description\": \"Una descripcion sobre este indicador\",\n", + " \"indicator_types\": [\n", + " \"malware\"\n", + " ],\n", + " \"pattern\": \"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\",\n", + " \"valid_from\": \"2019-05-03T19:40:21.459582Z\",\n", + " \"object_marking_refs\": [\n", + " \"marking-definition--f88d31f6-486f-44da-b317-01333bde0b82\"\n", + " ],\n", + " \"granular_markings\": [\n", + " {\n", + " \"marking_ref\": \"marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da\",\n", + " \"selectors\": [\n", + " \"description\"\n", + " ]\n", + " }\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "# If marking_ref is False, no marking-definition markings will be removed\n", + "print(v21_indicator.clear_markings(\"description\", marking_ref=False))" + ] } ], "metadata": { diff --git a/setup.cfg b/setup.cfg index a1aaca9..ae45560 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.1.0 +current_version = 1.1.2 commit = True tag = True diff --git a/stix2/__init__.py b/stix2/__init__.py index 4498c8b..714bf46 100644 --- a/stix2/__init__.py +++ b/stix2/__init__.py @@ -12,16 +12,8 @@ patterns properties utils - v20.bundle - v20.common - v20.observables - v20.sdo - v20.sro - v21.bundle - v21.common - v21.observables - v21.sdo - v21.sro + v20 + v21 workbench """ diff --git a/stix2/base.py b/stix2/base.py index a6bafff..a9a801e 100644 --- a/stix2/base.py +++ b/stix2/base.py @@ -143,12 +143,12 @@ class _STIXBase(collections.Mapping): if custom_props: self.__allow_custom = True - # Remove any keyword arguments whose value is None + # Remove any keyword arguments whose value is None or [] (i.e. empty list) setting_kwargs = {} props = kwargs.copy() props.update(custom_props) for prop_name, prop_value in props.items(): - if prop_value is not None: + if prop_value is not None and prop_value != []: setting_kwargs[prop_name] = prop_value # Detect any missing required properties @@ -308,7 +308,10 @@ class _Observable(_STIXBase): allowed_types = prop.valid_types try: - ref_type = self._STIXBase__valid_refs[ref] + try: + ref_type = self._STIXBase__valid_refs[ref].type + except AttributeError: + ref_type = self._STIXBase__valid_refs[ref] except TypeError: raise ValueError("'%s' must be created with _valid_refs as a dict, not a list." % self.__class__.__name__) diff --git a/stix2/datastore/__init__.py b/stix2/datastore/__init__.py index 561fe9e..57cb513 100644 --- a/stix2/datastore/__init__.py +++ b/stix2/datastore/__init__.py @@ -420,7 +420,7 @@ class CompositeDataSource(DataSource): """Controller for all the attached DataSources. A user can have a single CompositeDataSource as an interface - the a set of DataSources. When an API call is made to the + to a set of DataSources. When an API call is made to the CompositeDataSource, it is delegated to each of the (real) DataSources that are attached to it. diff --git a/stix2/datastore/filesystem.py b/stix2/datastore/filesystem.py index b4f3d15..0e8bed2 100644 --- a/stix2/datastore/filesystem.py +++ b/stix2/datastore/filesystem.py @@ -1,21 +1,19 @@ """Python STIX2 FileSystem Source/Sink""" -# Temporary while we address TODO statement -from __future__ import print_function - import errno import io import json import os import re import stat -import sys import six from stix2 import v20, v21 from stix2.base import _STIXBase from stix2.core import parse -from stix2.datastore import DataSink, DataSource, DataStoreMixin +from stix2.datastore import ( + DataSink, DataSource, DataSourceError, DataStoreMixin, +) from stix2.datastore.filters import Filter, FilterSet, apply_common_filters from stix2.utils import format_datetime, get_type_from_id, is_marking @@ -544,9 +542,8 @@ class FileSystemSink(DataSink): else: stix_obj = v20.Bundle(stix_obj, allow_custom=self.allow_custom) - # TODO: Better handling of the overwriting case. if os.path.isfile(file_path): - print("Attempted to overwrite file!", file_path, file=sys.stderr) + raise DataSourceError("Attempted to overwrite file (!) at: {}".format(file_path)) else: with io.open(file_path, 'w', encoding=encoding) as f: stix_obj = stix_obj.serialize(pretty=True, encoding=encoding, ensure_ascii=False) diff --git a/stix2/exceptions.py b/stix2/exceptions.py index 231eeb6..f1f1c09 100644 --- a/stix2/exceptions.py +++ b/stix2/exceptions.py @@ -203,3 +203,16 @@ class MarkingNotFoundError(STIXError, AssertionError): def __str__(self): msg = "Marking {0} was not found in {1}!" return msg.format(self.key, self.cls.__class__.__name__) + + +class TLPMarkingDefinitionError(STIXError, AssertionError): + """Marking violation. The marking-definition for TLP MUST follow the mandated instances from the spec.""" + + def __init__(self, user_obj, spec_obj): + super(TLPMarkingDefinitionError, self).__init__() + self.user_obj = user_obj + self.spec_obj = spec_obj + + def __str__(self): + msg = "Marking {0} does not match spec marking {1}!" + return msg.format(self.user_obj, self.spec_obj) diff --git a/stix2/markings/__init__.py b/stix2/markings/__init__.py index 79d1012..6d09f81 100644 --- a/stix2/markings/__init__.py +++ b/stix2/markings/__init__.py @@ -22,7 +22,7 @@ Note: from stix2.markings import granular_markings, object_markings -def get_markings(obj, selectors=None, inherited=False, descendants=False): +def get_markings(obj, selectors=None, inherited=False, descendants=False, marking_ref=True, lang=True): """ Get all markings associated to the field(s) specified by selectors. @@ -30,10 +30,13 @@ def get_markings(obj, selectors=None, inherited=False, descendants=False): obj: An SDO or SRO object. selectors: string or list of selectors strings relative to the SDO or SRO in which the properties appear. - inherited: If True, include object level markings and granular markings - inherited relative to the properties. - descendants: If True, include granular markings applied to any children - relative to the properties. + inherited (bool): If True, include object level markings and granular + markings inherited relative to the properties. + descendants (bool): If True, include granular markings applied to any + children relative to the properties. + marking_ref (bool): If False, excludes markings that use + ``marking_ref`` property. + lang (bool): If False, excludes markings that use ``lang`` property. Returns: list: Marking identifiers that matched the selectors expression. @@ -51,6 +54,8 @@ def get_markings(obj, selectors=None, inherited=False, descendants=False): selectors, inherited, descendants, + marking_ref, + lang, ) if inherited: @@ -59,7 +64,7 @@ def get_markings(obj, selectors=None, inherited=False, descendants=False): return list(set(results)) -def set_markings(obj, marking, selectors=None): +def set_markings(obj, marking, selectors=None, marking_ref=True, lang=True): """ Remove all markings associated with selectors and appends a new granular marking. Refer to `clear_markings` and `add_markings` for details. @@ -70,6 +75,10 @@ def set_markings(obj, marking, selectors=None): properties selected by `selectors`. selectors: string or list of selectors strings relative to the SDO or SRO in which the properties appear. + marking_ref (bool): If False, markings that use the ``marking_ref`` + property will not be removed. + lang (bool): If False, markings that use the ``lang`` property + will not be removed. Returns: A new version of the given SDO or SRO with specified markings removed @@ -83,7 +92,7 @@ def set_markings(obj, marking, selectors=None): if selectors is None: return object_markings.set_markings(obj, marking) else: - return granular_markings.set_markings(obj, marking, selectors) + return granular_markings.set_markings(obj, marking, selectors, marking_ref, lang) def remove_markings(obj, marking, selectors=None): @@ -144,7 +153,7 @@ def add_markings(obj, marking, selectors=None): return granular_markings.add_markings(obj, marking, selectors) -def clear_markings(obj, selectors=None): +def clear_markings(obj, selectors=None, marking_ref=True, lang=True): """ Remove all markings associated with the selectors. @@ -152,6 +161,10 @@ def clear_markings(obj, selectors=None): obj: An SDO or SRO object. selectors: string or list of selectors strings relative to the SDO or SRO in which the field(s) appear(s). + marking_ref (bool): If False, markings that use the ``marking_ref`` + property will not be removed. + lang (bool): If False, markings that use the ``lang`` property + will not be removed. Raises: InvalidSelectorError: If `selectors` fail validation. @@ -169,7 +182,7 @@ def clear_markings(obj, selectors=None): if selectors is None: return object_markings.clear_markings(obj) else: - return granular_markings.clear_markings(obj, selectors) + return granular_markings.clear_markings(obj, selectors, marking_ref, lang) def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=False): @@ -182,10 +195,11 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa properties selected by `selectors`. selectors: string or list of selectors strings relative to the SDO or SRO in which the field(s) appear(s). - inherited: If True, include object level markings and granular markings - inherited to determine if the properties is/are marked. - descendants: If True, include granular markings applied to any children - of the given selector to determine if the properties is/are marked. + inherited (bool): If True, include object level markings and granular + markings inherited to determine if the properties is/are marked. + descendants (bool): If True, include granular markings applied to any + children of the given selector to determine if the properties + is/are marked. Returns: bool: True if ``selectors`` is found on internal SDO or SRO collection. @@ -228,7 +242,7 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa return result -class _MarkingsMixin(): +class _MarkingsMixin(object): pass diff --git a/stix2/markings/granular_markings.py b/stix2/markings/granular_markings.py index 09c3d37..5456f83 100644 --- a/stix2/markings/granular_markings.py +++ b/stix2/markings/granular_markings.py @@ -2,10 +2,10 @@ from stix2 import exceptions from stix2.markings import utils -from stix2.utils import new_version +from stix2.utils import is_marking, new_version -def get_markings(obj, selectors, inherited=False, descendants=False): +def get_markings(obj, selectors, inherited=False, descendants=False, marking_ref=True, lang=True): """ Get all granular markings associated to with the properties. @@ -13,10 +13,13 @@ def get_markings(obj, selectors, inherited=False, descendants=False): obj: An SDO or SRO object. selectors: string or list of selector strings relative to the SDO or SRO in which the properties appear. - inherited: If True, include markings inherited relative to the + inherited (bool): If True, include markings inherited relative to the properties. - descendants: If True, include granular markings applied to any children - relative to the properties. + descendants (bool): If True, include granular markings applied to any + children relative to the properties. + marking_ref (bool): If False, excludes markings that use + ``marking_ref`` property. + lang (bool): If False, excludes markings that use ``lang`` property. Raises: InvalidSelectorError: If `selectors` fail validation. @@ -43,13 +46,18 @@ def get_markings(obj, selectors, inherited=False, descendants=False): (user_selector.startswith(marking_selector) and inherited), # Catch inherited selectors. (marking_selector.startswith(user_selector) and descendants), ]): # Catch descendants selectors - refs = marking.get('marking_ref', []) - results.update([refs]) + ref = marking.get('marking_ref') + lng = marking.get('lang') + + if ref and marking_ref: + results.add(ref) + if lng and lang: + results.add(lng) return list(results) -def set_markings(obj, marking, selectors): +def set_markings(obj, marking, selectors, marking_ref=True, lang=True): """ Remove all granular markings associated with selectors and append a new granular marking. Refer to `clear_markings` and `add_markings` for details. @@ -60,19 +68,25 @@ def set_markings(obj, marking, selectors): SRO in which the properties appear. marking: identifier or list of marking identifiers that apply to the properties selected by `selectors`. + marking_ref (bool): If False, markings that use the ``marking_ref`` + property will not be removed. + lang (bool): If False, markings that use the ``lang`` property + will not be removed. Returns: A new version of the given SDO or SRO with specified markings removed and new ones added. """ - obj = clear_markings(obj, selectors) + obj = clear_markings(obj, selectors, marking_ref, lang) return add_markings(obj, marking, selectors) def remove_markings(obj, marking, selectors): """ - Remove a granular marking from the granular_markings collection. + Remove a granular marking from the granular_markings collection. The method + makes a best-effort attempt to distinguish between a marking-definition + or language granular marking. Args: obj: An SDO or SRO object. @@ -103,7 +117,10 @@ def remove_markings(obj, marking, selectors): to_remove = [] for m in marking: - to_remove.append({'marking_ref': m, 'selectors': selectors}) + if is_marking(m): + to_remove.append({'marking_ref': m, 'selectors': selectors}) + else: + to_remove.append({'lang': m, 'selectors': selectors}) remove = utils.build_granular_marking(to_remove).get('granular_markings') @@ -124,7 +141,9 @@ def remove_markings(obj, marking, selectors): def add_markings(obj, marking, selectors): """ - Append a granular marking to the granular_markings collection. + Append a granular marking to the granular_markings collection. The method + makes a best-effort attempt to distinguish between a marking-definition + or language granular marking. Args: obj: An SDO or SRO object. @@ -146,7 +165,10 @@ def add_markings(obj, marking, selectors): granular_marking = [] for m in marking: - granular_marking.append({'marking_ref': m, 'selectors': sorted(selectors)}) + if is_marking(m): + granular_marking.append({'marking_ref': m, 'selectors': sorted(selectors)}) + else: + granular_marking.append({'lang': m, 'selectors': sorted(selectors)}) if obj.get('granular_markings'): granular_marking.extend(obj.get('granular_markings')) @@ -156,7 +178,7 @@ def add_markings(obj, marking, selectors): return new_version(obj, granular_markings=granular_marking, allow_custom=True) -def clear_markings(obj, selectors): +def clear_markings(obj, selectors, marking_ref=True, lang=True): """ Remove all granular markings associated with the selectors. @@ -164,6 +186,10 @@ def clear_markings(obj, selectors): obj: An SDO or SRO object. selectors: string or list of selectors strings relative to the SDO or SRO in which the properties appear. + marking_ref (bool): If False, markings that use the ``marking_ref`` + property will not be removed. + lang (bool): If False, markings that use the ``lang`` property + will not be removed. Raises: InvalidSelectorError: If `selectors` fail validation. @@ -184,11 +210,12 @@ def clear_markings(obj, selectors): granular_markings = utils.expand_markings(granular_markings) - sdo = utils.build_granular_marking( - [{'selectors': selectors, 'marking_ref': 'N/A'}], - ) + granular_dict = utils.build_granular_marking([ + {'selectors': selectors, 'marking_ref': 'N/A'}, + {'selectors': selectors, 'lang': 'N/A'}, + ]) - clear = sdo.get('granular_markings', []) + clear = granular_dict.get('granular_markings', []) if not any( clear_selector in sdo_selectors.get('selectors', []) @@ -201,10 +228,13 @@ def clear_markings(obj, selectors): for granular_marking in granular_markings: for s in selectors: if s in granular_marking.get('selectors', []): - marking_refs = granular_marking.get('marking_ref') + ref = granular_marking.get('marking_ref') + lng = granular_marking.get('lang') - if marking_refs: + if ref and marking_ref: granular_marking['marking_ref'] = '' + if lng and lang: + granular_marking['lang'] = '' granular_markings = utils.compress_markings(granular_markings) @@ -222,11 +252,12 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa obj: An SDO or SRO object. marking: identifier or list of marking identifiers that apply to the properties selected by `selectors`. - selectors: string or list of selectors strings relative to the SDO or - SRO in which the properties appear. - inherited: If True, return markings inherited from the given selector. - descendants: If True, return granular markings applied to any children - of the given selector. + selectors (bool): string or list of selectors strings relative to the + SDO or SRO in which the properties appear. + inherited (bool): If True, return markings inherited from the given + selector. + descendants (bool): If True, return granular markings applied to any + children of the given selector. Raises: InvalidSelectorError: If `selectors` fail validation. @@ -262,9 +293,12 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa (marking_selector.startswith(user_selector) and descendants), ]): # Catch descendants selectors marking_ref = granular_marking.get('marking_ref', '') + lang = granular_marking.get('lang', '') if marking and any(x == marking_ref for x in marking): markings.update([marking_ref]) + if marking and any(x == lang for x in marking): + markings.update([lang]) marked = True diff --git a/stix2/markings/utils.py b/stix2/markings/utils.py index d8bbf1d..b1c103b 100644 --- a/stix2/markings/utils.py +++ b/stix2/markings/utils.py @@ -4,7 +4,7 @@ import collections import six -from stix2 import exceptions +from stix2 import exceptions, utils def _evaluate_expression(obj, selector): @@ -121,10 +121,15 @@ def compress_markings(granular_markings): if granular_marking.get('marking_ref'): map_[granular_marking.get('marking_ref')].update(granular_marking.get('selectors')) + if granular_marking.get('lang'): + map_[granular_marking.get('lang')].update(granular_marking.get('selectors')) + compressed = \ [ - {'marking_ref': marking_ref, 'selectors': sorted(selectors)} - for marking_ref, selectors in six.iteritems(map_) + {'marking_ref': item, 'selectors': sorted(selectors)} + if utils.is_marking(item) else + {'lang': item, 'selectors': sorted(selectors)} + for item, selectors in six.iteritems(map_) ] return compressed @@ -174,13 +179,22 @@ def expand_markings(granular_markings): for marking in granular_markings: selectors = marking.get('selectors') marking_ref = marking.get('marking_ref') + lang = marking.get('lang') - expanded.extend( - [ - {'marking_ref': marking_ref, 'selectors': [selector]} - for selector in selectors - ], - ) + if marking_ref: + expanded.extend( + [ + {'marking_ref': marking_ref, 'selectors': [selector]} + for selector in selectors + ], + ) + if lang: + expanded.extend( + [ + {'lang': lang, 'selectors': [selector]} + for selector in selectors + ], + ) return expanded @@ -240,3 +254,81 @@ def iterpath(obj, path=None): path.pop() path.pop() + + +def check_tlp_marking(marking_obj, spec_version): + # Specific TLP Marking validation case. + + if marking_obj["definition_type"] == "tlp": + color = marking_obj["definition"]["tlp"] + + if color == "white": + if spec_version == '2.0': + w = ( + '{"created": "2017-01-20T00:00:00.000Z", "definition": {"tlp": "white"}, "definition_type": "tlp",' + ' "id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", "type": "marking-definition"}' + ) + else: + w = ( + '{"created": "2017-01-20T00:00:00.000Z", "definition": {"tlp": "white"}, "definition_type": "tlp",' + ' "id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", "type": "marking-definition",' + ' "spec_version": "2.1"}' + ) + if marking_obj["id"] != "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9": + raise exceptions.TLPMarkingDefinitionError(marking_obj["id"], w) + elif utils.format_datetime(marking_obj["created"]) != "2017-01-20T00:00:00.000Z": + raise exceptions.TLPMarkingDefinitionError(utils.format_datetime(marking_obj["created"]), w) + + elif color == "green": + if spec_version == '2.0': + g = ( + '{"created": "2017-01-20T00:00:00.000Z", "definition": {"tlp": "green"}, "definition_type": "tlp",' + ' "id": "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da", "type": "marking-definition"}' + ) + else: + g = ( + '{"created": "2017-01-20T00:00:00.000Z", "definition": {"tlp": "green"}, "definition_type": "tlp",' + ' "id": "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da", "type": "marking-definition",' + ' "spec_version": "2.1"}' + ) + if marking_obj["id"] != "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da": + raise exceptions.TLPMarkingDefinitionError(marking_obj["id"], g) + elif utils.format_datetime(marking_obj["created"]) != "2017-01-20T00:00:00.000Z": + raise exceptions.TLPMarkingDefinitionError(utils.format_datetime(marking_obj["created"]), g) + + elif color == "amber": + if spec_version == '2.0': + a = ( + '{"created": "2017-01-20T00:00:00.000Z", "definition": {"tlp": "amber"}, "definition_type": "tlp",' + ' "id": "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82", "type": "marking-definition"}' + ) + else: + a = ( + '{"created": "2017-01-20T00:00:00.000Z", "definition": {"tlp": "amber"}, "definition_type": "tlp",' + ' "id": "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82", "type": "marking-definition",' + ' "spec_version": "2.1"}' + ) + if marking_obj["id"] != "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82": + raise exceptions.TLPMarkingDefinitionError(marking_obj["id"], a) + elif utils.format_datetime(marking_obj["created"]) != "2017-01-20T00:00:00.000Z": + raise exceptions.TLPMarkingDefinitionError(utils.format_datetime(marking_obj["created"]), a) + + elif color == "red": + if spec_version == '2.0': + r = ( + '{"created": "2017-01-20T00:00:00.000Z", "definition": {"tlp": "red"}, "definition_type": "tlp",' + ' "id": "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed", "type": "marking-definition"}' + ) + else: + r = ( + '{"created": "2017-01-20T00:00:00.000Z", "definition": {"tlp": "red"}, "definition_type": "tlp",' + ' "id": "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed", "type": "marking-definition",' + ' "spec_version": "2.1"}' + ) + if marking_obj["id"] != "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed": + raise exceptions.TLPMarkingDefinitionError(marking_obj["id"], r) + elif utils.format_datetime(marking_obj["created"]) != "2017-01-20T00:00:00.000Z": + raise exceptions.TLPMarkingDefinitionError(utils.format_datetime(marking_obj["created"]), r) + + else: + raise exceptions.TLPMarkingDefinitionError(marking_obj["id"], "Does not match any TLP Marking definition") diff --git a/stix2/properties.py b/stix2/properties.py index 8e0066c..4e2f5f6 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -13,7 +13,7 @@ from stix2patterns.validator import run_validator import stix2 -from .base import _STIXBase +from .base import _Observable, _STIXBase from .core import STIX2_OBJ_MAPS, parse, parse_observable from .exceptions import CustomContentError, DictionaryKeyError from .utils import _get_dict, get_class_hierarchy_names, parse_into_datetime @@ -208,14 +208,28 @@ class ListProperty(Property): return result +class CallableValues(list): + """Wrapper to allow `values()` method on WindowsRegistryKey objects. + Needed because `values` is also a property. + """ + + def __init__(self, parent_instance, *args, **kwargs): + self.parent_instance = parent_instance + super(CallableValues, self).__init__(*args, **kwargs) + + def __call__(self): + return _Observable.values(self.parent_instance) + + class StringProperty(Property): def __init__(self, **kwargs): - self.string_type = text_type super(StringProperty, self).__init__(**kwargs) def clean(self, value): - return self.string_type(value) + if not isinstance(value, string_types): + return text_type(value) + return value class TypeProperty(Property): @@ -330,8 +344,6 @@ class DictionaryProperty(Property): dictified = _get_dict(value) except ValueError: raise ValueError("The dictionary property must contain a dictionary") - if dictified == {}: - raise ValueError("The dictionary property must contain a non-empty dictionary") for k in dictified.keys(): if self.spec_version == '2.0': if len(k) < 3: @@ -466,21 +478,22 @@ class EnumProperty(StringProperty): super(EnumProperty, self).__init__(**kwargs) def clean(self, value): - value = super(EnumProperty, self).clean(value) - if value not in self.allowed: - raise ValueError("value '{}' is not valid for this enumeration.".format(value)) - return self.string_type(value) + cleaned_value = super(EnumProperty, self).clean(value) + if cleaned_value not in self.allowed: + raise ValueError("value '{}' is not valid for this enumeration.".format(cleaned_value)) + + return cleaned_value class PatternProperty(StringProperty): def clean(self, value): - str_value = super(PatternProperty, self).clean(value) - errors = run_validator(str_value) + cleaned_value = super(PatternProperty, self).clean(value) + errors = run_validator(cleaned_value) if errors: raise ValueError(str(errors[0])) - return self.string_type(value) + return cleaned_value class ObservableProperty(Property): @@ -536,8 +549,6 @@ class ExtensionsProperty(DictionaryProperty): dictified = copy.deepcopy(dictified) except ValueError: raise ValueError("The extensions property must contain a dictionary") - if dictified == {}: - raise ValueError("The extensions property must contain a non-empty dictionary") v = 'v' + self.spec_version.replace('.', '') diff --git a/stix2/test/v20/constants.py b/stix2/test/v20/constants.py index 8d439f1..37b9da2 100644 --- a/stix2/test/v20/constants.py +++ b/stix2/test/v20/constants.py @@ -50,7 +50,7 @@ CAMPAIGN_KWARGS = dict( CAMPAIGN_MORE_KWARGS = dict( type='campaign', id=CAMPAIGN_ID, - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:00.000Z", modified="2016-04-06T20:03:00.000Z", name="Green Group Attacks Against Finance", diff --git a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--0a3ead4e-6d47-4ccb-854c-a6a4f9d96b22/20170531213019735010.json b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--0a3ead4e-6d47-4ccb-854c-a6a4f9d96b22/20170531213019735010.json index 47dd5f8..98521dc 100644 --- a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--0a3ead4e-6d47-4ccb-854c-a6a4f9d96b22/20170531213019735010.json +++ b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--0a3ead4e-6d47-4ccb-854c-a6a4f9d96b22/20170531213019735010.json @@ -2,7 +2,7 @@ "id": "bundle--f68640b4-0cdc-42ae-b176-def1754a1ea0", "objects": [ { - "created": "2017-05-31T21:30:19.73501Z", + "created": "2017-05-31T21:30:19.735Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Credential dumping is the process of obtaining account login and password information from the operating system and software. Credentials can be used to perform Windows Credential Editor, Mimikatz, and gsecdump. These tools are in use by both professional security testers and adversaries.\n\nPlaintext passwords can be obtained using tools such as Mimikatz to extract passwords stored by the Local Security Authority (LSA). If smart cards are used to authenticate to a domain using a personal identification number (PIN), then that PIN is also cached as a result and may be dumped.Mimikatz access the LSA Subsystem Service (LSASS) process by opening the process, locating the LSA secrets key, and decrypting the sections in memory where credential details are stored. Credential dumpers may also use methods for reflective DLL Injection to reduce potential indicators of malicious activity.\n\nNTLM hash dumpers open the Security Accounts Manager (SAM) on the local file system (%SystemRoot%/system32/config/SAM) or create a dump of the Registry SAM key to access stored account password hashes. Some hash dumpers will open the local file system as a device and parse to the SAM table to avoid file access defenses. Others will make an in-memory copy of the SAM table before reading hashes. Detection of compromised Legitimate Credentials in-use by adversaries may help as well. \n\nOn Windows 8.1 and Windows Server 2012 R2, monitor Windows Logs for LSASS.exe creation to verify that LSASS started as a protected process.\n\nMonitor processes and command-line arguments for program execution that may be indicative of credential dumping. Remote access tools may contain built-in features or incorporate existing tools like Mimikatz. PowerShell scripts also exist that contain credential dumping functionality, such as PowerSploit's Invoke-Mimikatz module,[[Citation: Powersploit]] which may require additional logging features to be configured in the operating system to collect necessary information for analysis.\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: API monitoring, Process command-line parameters, Process monitoring, PowerShell logs", "external_references": [ @@ -29,7 +29,7 @@ "phase_name": "credential-access" } ], - "modified": "2017-05-31T21:30:19.73501Z", + "modified": "2017-05-31T21:30:19.735Z", "name": "Credential Dumping", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b/20170531213026496201.json b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b/20170531213026496201.json index 13f900f..da4e238 100644 --- a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b/20170531213026496201.json +++ b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b/20170531213026496201.json @@ -2,7 +2,7 @@ "id": "bundle--b07d6fd6-7cc5-492d-a1eb-9ba956b329d5", "objects": [ { - "created": "2017-05-31T21:30:26.496201Z", + "created": "2017-05-31T21:30:26.496Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Rootkits are programs that hide the existence of malware by intercepting and modifying operating system API calls that supply system information. Rootkits or rootkit enabling functionality may reside at the user or kernel level in the operating system or lower, to include a Hypervisor, Master Boot Record, or the Basic Input/Output System.[[Citation: Wikipedia Rootkit]]\n\nAdversaries may use rootkits to hide the presence of programs, files, network connections, services, drivers, and other system components.\n\nDetection: Some rootkit protections may be built into anti-virus or operating system software. There are dedicated rootkit detection tools that look for specific types of rootkit behavior. Monitor for the existence of unrecognized DLLs, devices, services, and changes to the MBR.[[Citation: Wikipedia Rootkit]]\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: BIOS, MBR, System calls", "external_references": [ @@ -24,7 +24,7 @@ "phase_name": "defense-evasion" } ], - "modified": "2017-05-31T21:30:26.496201Z", + "modified": "2017-05-31T21:30:26.496Z", "name": "Rootkit", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--774a3188-6ba9-4dc4-879d-d54ee48a5ce9/20170531213029458940.json b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--774a3188-6ba9-4dc4-879d-d54ee48a5ce9/20170531213029458940.json index db57e2c..1c8e76c 100644 --- a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--774a3188-6ba9-4dc4-879d-d54ee48a5ce9/20170531213029458940.json +++ b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--774a3188-6ba9-4dc4-879d-d54ee48a5ce9/20170531213029458940.json @@ -2,7 +2,7 @@ "id": "bundle--1a854c96-639e-4771-befb-e7b960a65974", "objects": [ { - "created": "2017-05-31T21:30:29.45894Z", + "created": "2017-05-31T21:30:29.458Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Data, such as sensitive documents, may be exfiltrated through the use of automated processing or Scripting after being gathered during Exfiltration Over Command and Control Channel and Exfiltration Over Alternative Protocol.\n\nDetection: Monitor process file access patterns and network behavior. Unrecognized processes or scripts that appear to be traversing file systems and sending network traffic may be suspicious.\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: File monitoring, Process monitoring, Process use of network", "external_references": [ @@ -19,7 +19,7 @@ "phase_name": "exfiltration" } ], - "modified": "2017-05-31T21:30:29.45894Z", + "modified": "2017-05-31T21:30:29.458Z", "name": "Automated Exfiltration", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475/20170531213045139269.json b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475/20170531213045139269.json index d48092d..c4f2436 100644 --- a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475/20170531213045139269.json +++ b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475/20170531213045139269.json @@ -2,7 +2,7 @@ "id": "bundle--33e3e33a-38b8-4a37-9455-5b8c82d3b10a", "objects": [ { - "created": "2017-05-31T21:30:45.139269Z", + "created": "2017-05-31T21:30:45.139Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Adversaries may attempt to get a listing of network connections to or from the compromised system.\nUtilities and commands that acquire this information include netstat, \"net use,\" and \"net session\" with Net.\n\nDetection: System and network discovery techniques normally occur throughout an operation as an adversary learns the environment. Data and events should not be viewed in isolation, but as part of a chain of behavior that could lead to other activities, such as Windows Management Instrumentation and PowerShell.\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: Process command-line parameters, Process monitoring", "external_references": [ @@ -19,7 +19,7 @@ "phase_name": "discovery" } ], - "modified": "2017-05-31T21:30:45.139269Z", + "modified": "2017-05-31T21:30:45.139Z", "name": "Local Network Connections Discovery", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--ae676644-d2d2-41b7-af7e-9bed1b55898c/20170531213041022897.json b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--ae676644-d2d2-41b7-af7e-9bed1b55898c/20170531213041022897.json index 031419e..1a64591 100644 --- a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--ae676644-d2d2-41b7-af7e-9bed1b55898c/20170531213041022897.json +++ b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--ae676644-d2d2-41b7-af7e-9bed1b55898c/20170531213041022897.json @@ -2,7 +2,7 @@ "id": "bundle--a87938c5-cc1e-4e06-a8a3-b10243ae397d", "objects": [ { - "created": "2017-05-31T21:30:41.022897Z", + "created": "2017-05-31T21:30:41.022Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Sensitive data can be collected from remote systems via shared network drives (host shared directory, network file server, etc.) that are accessible from the current system prior to cmd may be used to gather information.\n\nDetection: Monitor processes and command-line arguments for actions that could be taken to collect files from a network share. Remote access tools with built-in features may interact directly with the Windows API to gather data. Data may also be acquired through Windows system management tools such as Windows Management Instrumentation and PowerShell.\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: File monitoring, Process monitoring, Process command-line parameters", "external_references": [ @@ -19,7 +19,7 @@ "phase_name": "collection" } ], - "modified": "2017-05-31T21:30:41.022897Z", + "modified": "2017-05-31T21:30:41.022Z", "name": "Data from Network Shared Drive", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a/20170531213032662702.json b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a/20170531213032662702.json index 67c380c..e968c1f 100644 --- a/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a/20170531213032662702.json +++ b/stix2/test/v20/stix2_data/attack-pattern/attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a/20170531213032662702.json @@ -2,7 +2,7 @@ "id": "bundle--5ddaeff9-eca7-4094-9e65-4f53da21a444", "objects": [ { - "created": "2017-05-31T21:30:32.662702Z", + "created": "2017-05-31T21:30:32.662Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Adversaries may attempt to make an executable or file difficult to discover or analyze by encrypting, encoding, or otherwise obfuscating its contents on the system.\n\nDetection: Detection of file obfuscation is difficult unless artifacts are left behind by the obfuscation process that are uniquely detectable with a signature. If detection of the obfuscation itself is not possible, it may be possible to detect the malicious activity that caused the obfuscated file (for example, the method that was used to write, read, or modify the file on the file system).\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: Network protocol analysis, Process use of network, Binary file metadata, File monitoring, Malware reverse engineering", "external_references": [ @@ -19,7 +19,7 @@ "phase_name": "defense-evasion" } ], - "modified": "2017-05-31T21:30:32.662702Z", + "modified": "2017-05-31T21:30:32.662Z", "name": "Obfuscated Files or Information", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/course-of-action/course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f/20170531213026495974.json b/stix2/test/v20/stix2_data/course-of-action/course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f/20170531213026495974.json index 541ede1..9a7e4f5 100644 --- a/stix2/test/v20/stix2_data/course-of-action/course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f/20170531213026495974.json +++ b/stix2/test/v20/stix2_data/course-of-action/course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f/20170531213026495974.json @@ -2,11 +2,11 @@ "id": "bundle--a42d26fe-c938-4074-a1b3-50d852e6f0bd", "objects": [ { - "created": "2017-05-31T21:30:26.495974Z", + "created": "2017-05-31T21:30:26.495Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Identify potentially malicious software that may contain rootkit functionality, and audit and/or block it by using whitelisting[[CiteRef::Beechey 2010]] tools, like AppLocker,[[CiteRef::Windows Commands JPCERT]][[CiteRef::NSA MS AppLocker]] or Software Restriction Policies[[CiteRef::Corio 2008]] where appropriate.[[CiteRef::TechNet Applocker vs SRP]]", "id": "course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f", - "modified": "2017-05-31T21:30:26.495974Z", + "modified": "2017-05-31T21:30:26.495Z", "name": "Rootkit Mitigation", "type": "course-of-action" } diff --git a/stix2/test/v20/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd/20170531213041022744.json b/stix2/test/v20/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd/20170531213041022744.json index 669aae5..902cf1b 100644 --- a/stix2/test/v20/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd/20170531213041022744.json +++ b/stix2/test/v20/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd/20170531213041022744.json @@ -1,9 +1,9 @@ { - "created": "2017-05-31T21:30:41.022744Z", + "created": "2017-05-31T21:30:41.022Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Identify unnecessary system utilities or potentially malicious software that may be used to collect data from a network share, and audit and/or block them by using whitelisting[[CiteRef::Beechey 2010]] tools, like AppLocker,[[CiteRef::Windows Commands JPCERT]][[CiteRef::NSA MS AppLocker]] or Software Restriction Policies[[CiteRef::Corio 2008]] where appropriate.[[CiteRef::TechNet Applocker vs SRP]]", "id": "course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd", - "modified": "2017-05-31T21:30:41.022744Z", + "modified": "2017-05-31T21:30:41.022Z", "name": "Data from Network Shared Drive Mitigation", "type": "course-of-action" } diff --git a/stix2/test/v20/stix2_data/identity/identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5/20170601000000000000.json b/stix2/test/v20/stix2_data/identity/identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5/20170601000000000000.json index d110a09..9b86896 100644 --- a/stix2/test/v20/stix2_data/identity/identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5/20170601000000000000.json +++ b/stix2/test/v20/stix2_data/identity/identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5/20170601000000000000.json @@ -2,10 +2,10 @@ "id": "bundle--81884287-2548-47fc-a997-39489ddd5462", "objects": [ { - "created": "2017-06-01T00:00:00Z", + "created": "2017-06-01T00:00:00.000Z", "id": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "identity_class": "organization", - "modified": "2017-06-01T00:00:00Z", + "modified": "2017-06-01T00:00:00.000Z", "name": "The MITRE Corporation", "type": "identity" } diff --git a/stix2/test/v20/stix2_data/intrusion-set/intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064/20170531213149412497.json b/stix2/test/v20/stix2_data/intrusion-set/intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064/20170531213149412497.json index 648ed94..b1adad5 100644 --- a/stix2/test/v20/stix2_data/intrusion-set/intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064/20170531213149412497.json +++ b/stix2/test/v20/stix2_data/intrusion-set/intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064/20170531213149412497.json @@ -10,7 +10,7 @@ "PinkPanther", "Black Vine" ], - "created": "2017-05-31T21:31:49.412497Z", + "created": "2017-05-31T21:31:49.412Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Deep Panda is a suspected Chinese threat group known to target many industries, including government, defense, financial, and telecommunications.Deep Panda.Deep Panda also appears to be known as Black Vine based on the attribution of both group names to the Anthem intrusion.[[Citation: Symantec Black Vine]]", "external_references": [ @@ -41,7 +41,7 @@ } ], "id": "intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064", - "modified": "2017-05-31T21:31:49.412497Z", + "modified": "2017-05-31T21:31:49.412Z", "name": "Deep Panda", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/intrusion-set/intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a/20170531213153197755.json b/stix2/test/v20/stix2_data/intrusion-set/intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a/20170531213153197755.json index bf3daa6..db2e43e 100644 --- a/stix2/test/v20/stix2_data/intrusion-set/intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a/20170531213153197755.json +++ b/stix2/test/v20/stix2_data/intrusion-set/intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a/20170531213153197755.json @@ -5,7 +5,7 @@ "aliases": [ "DragonOK" ], - "created": "2017-05-31T21:31:53.197755Z", + "created": "2017-05-31T21:31:53.197Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "DragonOK is a threat group that has targeted Japanese organizations with phishing emails. Due to overlapping TTPs, including similar custom tools, DragonOK is thought to have a direct or indirect relationship with the threat group Moafee. [[Citation: Operation Quantum Entanglement]][[Citation: Symbiotic APT Groups]] It is known to use a variety of malware, including Sysget/HelloBridge, PlugX, PoisonIvy, FormerFirstRat, NFlog, and NewCT. [[Citation: New DragonOK]]", "external_references": [ @@ -31,7 +31,7 @@ } ], "id": "intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a", - "modified": "2017-05-31T21:31:53.197755Z", + "modified": "2017-05-31T21:31:53.197Z", "name": "DragonOK", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json b/stix2/test/v20/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json index c60200b..63f6f55 100644 --- a/stix2/test/v20/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json +++ b/stix2/test/v20/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json @@ -2,7 +2,7 @@ "id": "bundle--f64de948-7067-4534-8018-85f03d470625", "objects": [ { - "created": "2017-05-31T21:32:58.226477Z", + "created": "2017-05-31T21:32:58.226Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Rover is malware suspected of being used for espionage purposes. It was used in 2015 in a targeted email sent to an Indian Ambassador to Afghanistan.[[Citation: Palo Alto Rover]]", "external_references": [ @@ -21,7 +21,7 @@ "labels": [ "malware" ], - "modified": "2017-05-31T21:32:58.226477Z", + "modified": "2017-05-31T21:32:58.226Z", "name": "Rover", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json b/stix2/test/v20/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json index 50c8a5d..f354e6c 100644 --- a/stix2/test/v20/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json +++ b/stix2/test/v20/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json @@ -2,7 +2,7 @@ "id": "bundle--c633942b-545c-4c87-91b7-9fe5740365e0", "objects": [ { - "created": "2017-05-31T21:33:26.565056Z", + "created": "2017-05-31T21:33:26.565Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "RTM is custom malware written in Delphi. It is used by the group of the same name (RTM).[[Citation: ESET RTM Feb 2017]]", "external_references": [ @@ -21,7 +21,7 @@ "labels": [ "malware" ], - "modified": "2017-05-31T21:33:26.565056Z", + "modified": "2017-05-31T21:33:26.565Z", "name": "RTM", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json b/stix2/test/v20/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json index 224f6a9..efbd6ca 100644 --- a/stix2/test/v20/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json +++ b/stix2/test/v20/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json @@ -2,7 +2,7 @@ "id": "bundle--09ce4338-8741-4fcf-9738-d216c8e40974", "objects": [ { - "created": "2017-05-31T21:32:48.482655Z", + "created": "2017-05-31T21:32:48.482Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Sakula is a remote access tool (RAT) that first surfaced in 2012 and was used in intrusions throughout 2015.[[Citation: Dell Sakula]]\n\nAliases: Sakula, Sakurel, VIPER", "external_references": [ @@ -21,7 +21,7 @@ "labels": [ "malware" ], - "modified": "2017-05-31T21:32:48.482655Z", + "modified": "2017-05-31T21:32:48.482Z", "name": "Sakula", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json b/stix2/test/v20/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json index 3e1c870..4d57db5 100644 --- a/stix2/test/v20/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json +++ b/stix2/test/v20/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json @@ -2,7 +2,7 @@ "id": "bundle--611947ce-ae3b-4fdb-b297-aed8eab22e4f", "objects": [ { - "created": "2017-05-31T21:32:15.263882Z", + "created": "2017-05-31T21:32:15.263Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "PoisonIvy is a popular remote access tool (RAT) that has been used by many groups.[[Citation: FireEye Poison Ivy]]\n\nAliases: PoisonIvy, Poison Ivy", "external_references": [ @@ -21,7 +21,7 @@ "labels": [ "malware" ], - "modified": "2017-05-31T21:32:15.263882Z", + "modified": "2017-05-31T21:32:15.263Z", "name": "PoisonIvy", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/relationship/relationship--0d4a7788-7f3b-4df8-a498-31a38003c883/20170531213327182784.json b/stix2/test/v20/stix2_data/relationship/relationship--0d4a7788-7f3b-4df8-a498-31a38003c883/20170531213327182784.json index 0f4a32a..22d3fc9 100644 --- a/stix2/test/v20/stix2_data/relationship/relationship--0d4a7788-7f3b-4df8-a498-31a38003c883/20170531213327182784.json +++ b/stix2/test/v20/stix2_data/relationship/relationship--0d4a7788-7f3b-4df8-a498-31a38003c883/20170531213327182784.json @@ -2,10 +2,10 @@ "id": "bundle--7e715462-dd9d-40b9-968a-10ef0ecf126d", "objects": [ { - "created": "2017-05-31T21:33:27.182784Z", + "created": "2017-05-31T21:33:27.182Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--0d4a7788-7f3b-4df8-a498-31a38003c883", - "modified": "2017-05-31T21:33:27.182784Z", + "modified": "2017-05-31T21:33:27.182Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v20/stix2_data/relationship/relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227/20170531213327082801.json b/stix2/test/v20/stix2_data/relationship/relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227/20170531213327082801.json index e5e1e87..68a8c8f 100644 --- a/stix2/test/v20/stix2_data/relationship/relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227/20170531213327082801.json +++ b/stix2/test/v20/stix2_data/relationship/relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227/20170531213327082801.json @@ -2,10 +2,10 @@ "id": "bundle--a53eef35-abfc-4bcd-b84e-a048f7b4a9bf", "objects": [ { - "created": "2017-05-31T21:33:27.082801Z", + "created": "2017-05-31T21:33:27.082Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227", - "modified": "2017-05-31T21:33:27.082801Z", + "modified": "2017-05-31T21:33:27.082Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v20/stix2_data/relationship/relationship--1e91cd45-a725-4965-abe3-700694374432/20170531213327018782.json b/stix2/test/v20/stix2_data/relationship/relationship--1e91cd45-a725-4965-abe3-700694374432/20170531213327018782.json index 9651425..1d5112d 100644 --- a/stix2/test/v20/stix2_data/relationship/relationship--1e91cd45-a725-4965-abe3-700694374432/20170531213327018782.json +++ b/stix2/test/v20/stix2_data/relationship/relationship--1e91cd45-a725-4965-abe3-700694374432/20170531213327018782.json @@ -2,10 +2,10 @@ "id": "bundle--0b9f6412-314f-44e3-8779-9738c9578ef5", "objects": [ { - "created": "2017-05-31T21:33:27.018782Z", + "created": "2017-05-31T21:33:27.018Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--1e91cd45-a725-4965-abe3-700694374432", - "modified": "2017-05-31T21:33:27.018782Z", + "modified": "2017-05-31T21:33:27.018Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v20/stix2_data/relationship/relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e/20170531213327100701.json b/stix2/test/v20/stix2_data/relationship/relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e/20170531213327100701.json index 7e355fc..671f905 100644 --- a/stix2/test/v20/stix2_data/relationship/relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e/20170531213327100701.json +++ b/stix2/test/v20/stix2_data/relationship/relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e/20170531213327100701.json @@ -2,10 +2,10 @@ "id": "bundle--6d5b04a8-efb2-4179-990e-74f1dcc76e0c", "objects": [ { - "created": "2017-05-31T21:33:27.100701Z", + "created": "2017-05-31T21:33:27.100Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e", - "modified": "2017-05-31T21:33:27.100701Z", + "modified": "2017-05-31T21:33:27.100Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v20/stix2_data/relationship/relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1/20170531213327143973.json b/stix2/test/v20/stix2_data/relationship/relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1/20170531213327143973.json index f537309..5392ff8 100644 --- a/stix2/test/v20/stix2_data/relationship/relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1/20170531213327143973.json +++ b/stix2/test/v20/stix2_data/relationship/relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1/20170531213327143973.json @@ -2,10 +2,10 @@ "id": "bundle--a7efc025-040d-49c7-bf97-e5a1120ecacc", "objects": [ { - "created": "2017-05-31T21:33:27.143973Z", + "created": "2017-05-31T21:33:27.143Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1", - "modified": "2017-05-31T21:33:27.143973Z", + "modified": "2017-05-31T21:33:27.143Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v20/stix2_data/relationship/relationship--592d0c31-e61f-495e-a60e-70d7be59a719/20170531213327021562.json b/stix2/test/v20/stix2_data/relationship/relationship--592d0c31-e61f-495e-a60e-70d7be59a719/20170531213327021562.json index 47008f0..d91e48c 100644 --- a/stix2/test/v20/stix2_data/relationship/relationship--592d0c31-e61f-495e-a60e-70d7be59a719/20170531213327021562.json +++ b/stix2/test/v20/stix2_data/relationship/relationship--592d0c31-e61f-495e-a60e-70d7be59a719/20170531213327021562.json @@ -2,10 +2,10 @@ "id": "bundle--9f013d47-7704-41c2-9749-23d0d94af94d", "objects": [ { - "created": "2017-05-31T21:33:27.021562Z", + "created": "2017-05-31T21:33:27.021Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--592d0c31-e61f-495e-a60e-70d7be59a719", - "modified": "2017-05-31T21:33:27.021562Z", + "modified": "2017-05-31T21:33:27.021Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v20/stix2_data/relationship/relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1/20170531213327044387.json b/stix2/test/v20/stix2_data/relationship/relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1/20170531213327044387.json index d697277..21cd833 100644 --- a/stix2/test/v20/stix2_data/relationship/relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1/20170531213327044387.json +++ b/stix2/test/v20/stix2_data/relationship/relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1/20170531213327044387.json @@ -2,10 +2,10 @@ "id": "bundle--15167b24-4cee-4c96-a140-32a6c37df4b4", "objects": [ { - "created": "2017-05-31T21:33:27.044387Z", + "created": "2017-05-31T21:33:27.044Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1", - "modified": "2017-05-31T21:33:27.044387Z", + "modified": "2017-05-31T21:33:27.044Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v20/stix2_data/relationship/relationship--8797579b-e3be-4209-a71b-255a4d08243d/20170531213327051532.json b/stix2/test/v20/stix2_data/relationship/relationship--8797579b-e3be-4209-a71b-255a4d08243d/20170531213327051532.json index d7f2ff7..ef0ad24 100644 --- a/stix2/test/v20/stix2_data/relationship/relationship--8797579b-e3be-4209-a71b-255a4d08243d/20170531213327051532.json +++ b/stix2/test/v20/stix2_data/relationship/relationship--8797579b-e3be-4209-a71b-255a4d08243d/20170531213327051532.json @@ -2,10 +2,10 @@ "id": "bundle--ff845dca-7036-416f-aae0-95030994c49f", "objects": [ { - "created": "2017-05-31T21:33:27.051532Z", + "created": "2017-05-31T21:33:27.051Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--8797579b-e3be-4209-a71b-255a4d08243d", - "modified": "2017-05-31T21:33:27.051532Z", + "modified": "2017-05-31T21:33:27.051Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v20/stix2_data/tool/tool--03342581-f790-4f03-ba41-e82e67392e23/20170531213231601148.json b/stix2/test/v20/stix2_data/tool/tool--03342581-f790-4f03-ba41-e82e67392e23/20170531213231601148.json index 9d47880..02df113 100644 --- a/stix2/test/v20/stix2_data/tool/tool--03342581-f790-4f03-ba41-e82e67392e23/20170531213231601148.json +++ b/stix2/test/v20/stix2_data/tool/tool--03342581-f790-4f03-ba41-e82e67392e23/20170531213231601148.json @@ -2,7 +2,7 @@ "id": "bundle--d8826afc-1561-4362-a4e3-05a4c2c3ac3c", "objects": [ { - "created": "2017-05-31T21:32:31.601148Z", + "created": "2017-05-31T21:32:31.601Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "The Net utility is a component of the Windows operating system. It is used in command-line operations for control of users, groups, services, and network connections.Net has a great deal of functionality,[[Citation: Savill 1999]] much of which is useful for an adversary, such as gathering system and network information for [[Discovery]], moving laterally through [[Windows admin shares]] using net use commands, and interacting with services.\n\nAliases: Net, net.exe", "external_references": [ @@ -26,7 +26,7 @@ "labels": [ "tool" ], - "modified": "2017-05-31T21:32:31.601148Z", + "modified": "2017-05-31T21:32:31.601Z", "name": "Net", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/stix2_data/tool/tool--242f3da3-4425-4d11-8f5c-b842886da966/20170531213212684914.json b/stix2/test/v20/stix2_data/tool/tool--242f3da3-4425-4d11-8f5c-b842886da966/20170531213212684914.json index 281888e..2480a80 100644 --- a/stix2/test/v20/stix2_data/tool/tool--242f3da3-4425-4d11-8f5c-b842886da966/20170531213212684914.json +++ b/stix2/test/v20/stix2_data/tool/tool--242f3da3-4425-4d11-8f5c-b842886da966/20170531213212684914.json @@ -2,7 +2,7 @@ "id": "bundle--7dbde18f-6f14-4bf0-8389-505c89d6d5a6", "objects": [ { - "created": "2017-05-31T21:32:12.684914Z", + "created": "2017-05-31T21:32:12.684Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Windows Credential Editor is a password dumping tool.[[Citation: Amplia WCE]]\n\nAliases: Windows Credential Editor, WCE", "external_references": [ @@ -21,7 +21,7 @@ "labels": [ "tool" ], - "modified": "2017-05-31T21:32:12.684914Z", + "modified": "2017-05-31T21:32:12.684Z", "name": "Windows Credential Editor", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v20/test_attack_pattern.py b/stix2/test/v20/test_attack_pattern.py index f071d3a..8d35e52 100644 --- a/stix2/test/v20/test_attack_pattern.py +++ b/stix2/test/v20/test_attack_pattern.py @@ -25,7 +25,7 @@ EXPECTED = """{ def test_attack_pattern_example(): ap = stix2.v20.AttackPattern( - id="attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + id=ATTACK_PATTERN_ID, created="2016-05-12T08:17:27.000Z", modified="2016-05-12T08:17:27.000Z", name="Spear Phishing", @@ -44,7 +44,7 @@ def test_attack_pattern_example(): EXPECTED, { "type": "attack-pattern", - "id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + "id": ATTACK_PATTERN_ID, "created": "2016-05-12T08:17:27.000Z", "modified": "2016-05-12T08:17:27.000Z", "description": "...", @@ -74,11 +74,43 @@ def test_parse_attack_pattern(data): def test_attack_pattern_invalid_labels(): with pytest.raises(stix2.exceptions.InvalidValueError): stix2.v20.AttackPattern( - id="attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + id=ATTACK_PATTERN_ID, created="2016-05-12T08:17:27Z", modified="2016-05-12T08:17:27Z", name="Spear Phishing", labels=1, ) + +def test_overly_precise_timestamps(): + ap = stix2.v20.AttackPattern( + id=ATTACK_PATTERN_ID, + created="2016-05-12T08:17:27.0000342Z", + modified="2016-05-12T08:17:27.000287Z", + name="Spear Phishing", + external_references=[{ + "source_name": "capec", + "external_id": "CAPEC-163", + }], + description="...", + ) + + assert str(ap) == EXPECTED + + +def test_less_precise_timestamps(): + ap = stix2.v20.AttackPattern( + id=ATTACK_PATTERN_ID, + created="2016-05-12T08:17:27.00Z", + modified="2016-05-12T08:17:27.0Z", + name="Spear Phishing", + external_references=[{ + "source_name": "capec", + "external_id": "CAPEC-163", + }], + description="...", + ) + + assert str(ap) == EXPECTED + # TODO: Add other examples diff --git a/stix2/test/v20/test_bundle.py b/stix2/test/v20/test_bundle.py index 907f632..57c189e 100644 --- a/stix2/test/v20/test_bundle.py +++ b/stix2/test/v20/test_bundle.py @@ -4,6 +4,8 @@ import pytest import stix2 +from .constants import IDENTITY_ID + EXPECTED_BUNDLE = """{ "type": "bundle", "id": "bundle--00000000-0000-4000-8000-000000000007", @@ -185,7 +187,7 @@ def test_parse_unknown_type(): "id": "other--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "created": "2016-04-06T20:03:00Z", "modified": "2016-04-06T20:03:00Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "description": "Campaign by Green Group against a series of targets in the financial services sector.", "name": "Green Group Attacks Against Finance", } @@ -234,3 +236,100 @@ def test_bundle_with_different_spec_objects(): stix2.v20.Bundle(objects=data) assert "Spec version 2.0 bundles don't yet support containing objects of a different spec version." in str(excinfo.value) + + +def test_bundle_obj_id_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + mal_list = bundle.get_obj("malware--00000000-0000-4000-8000-000000000003") + assert bundle.objects[1] == mal_list[0] + assert len(mal_list) == 1 + + +@pytest.mark.parametrize( + "bundle_data", [{ + "type": "bundle", + "id": "bundle--00000000-0000-4000-8000-000000000007", + "spec_version": "2.0", + "objects": [ + { + "type": "indicator", + "id": "indicator--00000000-0000-4000-8000-000000000001", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", + "valid_from": "2017-01-01T12:34:56Z", + "labels": [ + "malicious-activity", + ], + }, + { + "type": "malware", + "id": "malware--00000000-0000-4000-8000-000000000003", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "name": "Cryptolocker1", + "labels": [ + "ransomware", + ], + }, + { + "type": "malware", + "id": "malware--00000000-0000-4000-8000-000000000003", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-12-21T12:34:56.000Z", + "name": "CryptolockerOne", + "labels": [ + "ransomware", + ], + }, + { + "type": "relationship", + "id": "relationship--00000000-0000-4000-8000-000000000005", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "relationship_type": "indicates", + "source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", + "target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", + }, + ], + }], +) +def test_bundle_objs_ids_found(bundle_data): + bundle = stix2.parse(bundle_data) + + mal_list = bundle.get_obj("malware--00000000-0000-4000-8000-000000000003") + assert bundle.objects[1] == mal_list[0] + assert bundle.objects[2] == mal_list[1] + assert len(mal_list) == 2 + + +def test_bundle_getitem_overload_property_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + assert bundle.type == "bundle" + assert bundle['type'] == "bundle" + + +def test_bundle_getitem_overload_obj_id_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + mal_list = bundle["malware--00000000-0000-4000-8000-000000000003"] + assert bundle.objects[1] == mal_list[0] + assert len(mal_list) == 1 + + +def test_bundle_obj_id_not_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + with pytest.raises(KeyError) as excinfo: + bundle.get_obj('non existent') + assert "does not match the id property of any of the bundle" in str(excinfo.value) + + +def test_bundle_getitem_overload_obj_id_not_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + with pytest.raises(KeyError) as excinfo: + bundle['non existent'] + assert "neither a property on the bundle nor does it match the id property" in str(excinfo.value) diff --git a/stix2/test/v20/test_campaign.py b/stix2/test/v20/test_campaign.py index 57dbfd2..0d4a202 100644 --- a/stix2/test/v20/test_campaign.py +++ b/stix2/test/v20/test_campaign.py @@ -5,12 +5,12 @@ import pytz import stix2 -from .constants import CAMPAIGN_ID +from .constants import CAMPAIGN_ID, CAMPAIGN_MORE_KWARGS, IDENTITY_ID EXPECTED = """{ "type": "campaign", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "name": "Green Group Attacks Against Finance", @@ -19,14 +19,7 @@ EXPECTED = """{ def test_campaign_example(): - campaign = stix2.v20.Campaign( - id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", - 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.", - ) + campaign = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS) assert str(campaign) == EXPECTED @@ -36,10 +29,10 @@ def test_campaign_example(): EXPECTED, { "type": "campaign", - "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "id": CAMPAIGN_ID, "created": "2016-04-06T20:03:00Z", "modified": "2016-04-06T20:03:00Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "description": "Campaign by Green Group against a series of targets in the financial services sector.", "name": "Green Group Attacks Against Finance", }, @@ -52,7 +45,7 @@ def test_parse_campaign(data): assert cmpn.id == CAMPAIGN_ID assert cmpn.created == dt.datetime(2016, 4, 6, 20, 3, 0, tzinfo=pytz.utc) assert cmpn.modified == dt.datetime(2016, 4, 6, 20, 3, 0, tzinfo=pytz.utc) - assert cmpn.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert cmpn.created_by_ref == IDENTITY_ID assert cmpn.description == "Campaign by Green Group against a series of targets in the financial services sector." assert cmpn.name == "Green Group Attacks Against Finance" diff --git a/stix2/test/v20/test_core.py b/stix2/test/v20/test_core.py index 017344f..c2056b8 100644 --- a/stix2/test/v20/test_core.py +++ b/stix2/test/v20/test_core.py @@ -3,6 +3,8 @@ import pytest import stix2 from stix2 import core, exceptions +from .constants import IDENTITY_ID + BUNDLE = { "type": "bundle", "spec_version": "2.0", @@ -96,7 +98,7 @@ def test_register_marking_with_no_version(): def test_register_observable_with_version(): observed_data = stix2.v20.ObservedData( id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + 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", @@ -134,7 +136,7 @@ def test_register_observable_with_version(): def test_register_observable_extension_with_version(): observed_data = stix2.v20.ObservedData( id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + 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", diff --git a/stix2/test/v20/test_course_of_action.py b/stix2/test/v20/test_course_of_action.py index d1c0fb7..f648907 100644 --- a/stix2/test/v20/test_course_of_action.py +++ b/stix2/test/v20/test_course_of_action.py @@ -5,12 +5,12 @@ import pytz import stix2 -from .constants import COURSE_OF_ACTION_ID +from .constants import COURSE_OF_ACTION_ID, IDENTITY_ID EXPECTED = """{ "type": "course-of-action", "id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", @@ -20,8 +20,8 @@ EXPECTED = """{ def test_course_of_action_example(): coa = stix2.v20.CourseOfAction( - id="course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=COURSE_OF_ACTION_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", name="Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", @@ -36,9 +36,9 @@ def test_course_of_action_example(): EXPECTED, { "created": "2016-04-06T20:03:48.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "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", + "id": COURSE_OF_ACTION_ID, "modified": "2016-04-06T20:03:48.000Z", "name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", "type": "course-of-action", @@ -52,7 +52,7 @@ def test_parse_course_of_action(data): assert coa.id == COURSE_OF_ACTION_ID assert coa.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) assert coa.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) - assert coa.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert coa.created_by_ref == IDENTITY_ID assert coa.description == "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ..." assert coa.name == "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter" diff --git a/stix2/test/v20/test_custom.py b/stix2/test/v20/test_custom.py index 40ffa88..32632b9 100644 --- a/stix2/test/v20/test_custom.py +++ b/stix2/test/v20/test_custom.py @@ -2,7 +2,7 @@ import pytest import stix2 -from .constants import FAKE_TIME, MARKING_DEFINITION_ID +from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID IDENTITY_CUSTOM_PROP = stix2.v20.Identity( name="John Smith", @@ -15,7 +15,7 @@ IDENTITY_CUSTOM_PROP = stix2.v20.Identity( def test_identity_custom_property(): with pytest.raises(ValueError) as excinfo: stix2.v20.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -26,7 +26,7 @@ def test_identity_custom_property(): with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo: stix2.v20.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -39,7 +39,7 @@ def test_identity_custom_property(): assert "Unexpected properties for Identity" in str(excinfo.value) identity = stix2.v20.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -54,7 +54,7 @@ def test_identity_custom_property(): def test_identity_custom_property_invalid(): with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo: stix2.v20.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -68,7 +68,7 @@ def test_identity_custom_property_invalid(): def test_identity_custom_property_allowed(): identity = stix2.v20.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -127,7 +127,7 @@ def test_custom_properties_object_in_bundled_object(): def test_custom_property_dict_in_bundled_object(): custom_identity = { 'type': 'identity', - 'id': 'identity--311b2d2d-f010-4473-83ec-1edf84858f4c', + 'id': IDENTITY_ID, 'created': '2015-12-21T19:59:11Z', 'name': 'John Smith', 'identity_class': 'individual', @@ -144,7 +144,7 @@ def test_custom_property_dict_in_bundled_object(): def test_custom_properties_dict_in_bundled_object(): custom_identity = { 'type': 'identity', - 'id': 'identity--311b2d2d-f010-4473-83ec-1edf84858f4c', + 'id': IDENTITY_ID, 'created': '2015-12-21T19:59:11Z', 'name': 'John Smith', 'identity_class': 'individual', diff --git a/stix2/test/v20/test_datastore_filesystem.py b/stix2/test/v20/test_datastore_filesystem.py index 84a3034..25de37e 100644 --- a/stix2/test/v20/test_datastore_filesystem.py +++ b/stix2/test/v20/test_datastore_filesystem.py @@ -9,6 +9,7 @@ import pytest import pytz import stix2 +from stix2.datastore import DataSourceError from stix2.datastore.filesystem import ( AuthSet, _find_search_optimizations, _get_matching_dir_entries, _timestamp2filename, @@ -420,8 +421,37 @@ def test_filesystem_sink_add_objects_list(fs_sink, fs_source): os.remove(camp7filepath) +def test_filesystem_attempt_stix_file_overwrite(fs_store): + # add python stix object + camp8 = stix2.v20.Campaign( + name="George Washington", + objective="Create an awesome country", + aliases=["Georgey"], + ) + + fs_store.add(camp8) + + camp8_r = fs_store.get(camp8.id) + assert camp8_r.id == camp8_r.id + assert camp8_r.name == camp8.name + + filepath = os.path.join( + FS_PATH, "campaign", camp8_r.id, + _timestamp2filename(camp8_r.modified) + ".json", + ) + + # Now attempt to overwrite the existing file + with pytest.raises(DataSourceError) as excinfo: + fs_store.add(camp8) + assert "Attempted to overwrite file" in str(excinfo) + + os.remove(filepath) + + def test_filesystem_sink_marking(fs_sink): marking = stix2.v20.MarkingDefinition( + id="marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da", + created="2017-01-20T00:00:00.000Z", definition_type="tlp", definition=stix2.v20.TLPMarking(tlp="green"), ) @@ -555,6 +585,8 @@ def test_filesystem_store_add_invalid_object(fs_store): def test_filesystem_store_add_marking(fs_store): marking = stix2.v20.MarkingDefinition( + id="marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da", + created="2017-01-20T00:00:00.000Z", definition_type="tlp", definition=stix2.v20.TLPMarking(tlp="green"), ) diff --git a/stix2/test/v20/test_datastore_memory.py b/stix2/test/v20/test_datastore_memory.py index 495652b..fba96dd 100644 --- a/stix2/test/v20/test_datastore_memory.py +++ b/stix2/test/v20/test_datastore_memory.py @@ -275,13 +275,13 @@ def test_memory_store_object_creator_of_present(mem_store): camp = Campaign( name="Scipio Africanus", objective="Defeat the Carthaginians", - created_by_ref="identity--e4196283-7420-4277-a7a3-d57f61ef1389", + created_by_ref=IDENTITY_ID, x_empire="Roman", allow_custom=True, ) iden = Identity( - id="identity--e4196283-7420-4277-a7a3-d57f61ef1389", + id=IDENTITY_ID, name="Foo Corp.", identity_class="corporation", ) diff --git a/stix2/test/v20/test_identity.py b/stix2/test/v20/test_identity.py index 4a88a8a..750c6f2 100644 --- a/stix2/test/v20/test_identity.py +++ b/stix2/test/v20/test_identity.py @@ -19,7 +19,7 @@ EXPECTED = """{ def test_identity_example(): identity = stix2.v20.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11.000Z", modified="2015-12-21T19:59:11.000Z", name="John Smith", @@ -34,7 +34,7 @@ def test_identity_example(): EXPECTED, { "created": "2015-12-21T19:59:11.000Z", - "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + "id": IDENTITY_ID, "identity_class": "individual", "modified": "2015-12-21T19:59:11.000Z", "name": "John Smith", diff --git a/stix2/test/v20/test_indicator.py b/stix2/test/v20/test_indicator.py index 5194142..b2836e5 100644 --- a/stix2/test/v20/test_indicator.py +++ b/stix2/test/v20/test_indicator.py @@ -151,7 +151,7 @@ def test_created_modified_time_are_identical_by_default(): EXPECTED_INDICATOR, { "type": "indicator", - "id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", + "id": INDICATOR_ID, "created": "2017-01-01T00:00:01Z", "modified": "2017-01-01T00:00:01Z", "labels": [ diff --git a/stix2/test/v20/test_intrusion_set.py b/stix2/test/v20/test_intrusion_set.py index bf4a7d5..69b336e 100644 --- a/stix2/test/v20/test_intrusion_set.py +++ b/stix2/test/v20/test_intrusion_set.py @@ -5,12 +5,12 @@ import pytz import stix2 -from .constants import INTRUSION_SET_ID +from .constants import IDENTITY_ID, INTRUSION_SET_ID EXPECTED = """{ "type": "intrusion-set", "id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "Bobcat Breakin", @@ -28,8 +28,8 @@ EXPECTED = """{ def test_intrusion_set_example(): intrusion_set = stix2.v20.IntrusionSet( - id="intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=INTRUSION_SET_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", name="Bobcat Breakin", @@ -49,14 +49,14 @@ def test_intrusion_set_example(): "Zookeeper", ], "created": "2016-04-06T20:03:48.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "description": "Incidents usually feature a shared TTP of a bobcat being released...", "goals": [ "acquisition-theft", "harassment", "damage", ], - "id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29", + "id": INTRUSION_SET_ID, "modified": "2016-04-06T20:03:48.000Z", "name": "Bobcat Breakin", "type": "intrusion-set", diff --git a/stix2/test/v20/test_malware.py b/stix2/test/v20/test_malware.py index 844c7d9..900a4b9 100644 --- a/stix2/test/v20/test_malware.py +++ b/stix2/test/v20/test_malware.py @@ -35,6 +35,22 @@ def test_malware_with_all_required_properties(): assert str(mal) == EXPECTED_MALWARE +def test_malware_with_empty_optional_field(): + now = dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc) + + mal = stix2.v20.Malware( + type="malware", + id=MALWARE_ID, + created=now, + modified=now, + labels=["ransomware"], + name="Cryptolocker", + external_references=[], + ) + + assert str(mal) == EXPECTED_MALWARE + + def test_malware_autogenerated_properties(malware): assert malware.type == 'malware' assert malware.id == 'malware--00000000-0000-4000-8000-000000000001' @@ -108,7 +124,7 @@ def test_invalid_kwarg_to_malware(): EXPECTED_MALWARE, { "type": "malware", - "id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", + "id": MALWARE_ID, "created": "2016-05-12T08:17:27.000Z", "modified": "2016-05-12T08:17:27.000Z", "labels": ["ransomware"], diff --git a/stix2/test/v20/test_marking_definition.py b/stix2/test/v20/test_marking_definition.py new file mode 100644 index 0000000..20575fa --- /dev/null +++ b/stix2/test/v20/test_marking_definition.py @@ -0,0 +1,133 @@ + +import pytest + +from stix2 import exceptions +from stix2.v20 import ( + TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, MarkingDefinition, TLPMarking, +) + + +def test_bad_id_marking_tlp_white(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--4c9faac1-3558-43d2-919e-95c88d3bc332', + definition_type='tlp', + definition=TLPMarking(tlp='white'), + ) + + +def test_bad_id_marking_tlp_green(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--93023361-d3cf-4666-bca2-8c017948dc3d', + definition_type='tlp', + definition=TLPMarking(tlp='green'), + ) + + +def test_bad_id_marking_tlp_amber(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--05e32101-a940-42ba-8fe9-39283b999ce4', + definition_type='tlp', + definition=TLPMarking(tlp='amber'), + ) + + +def test_bad_id_marking_tlp_red(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--9eceb00c-c158-43f4-87f8-1e3648de17e2', + definition_type='tlp', + definition=TLPMarking(tlp='red'), + ) + + +def test_bad_created_marking_tlp_white(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9', + definition_type='tlp', + definition=TLPMarking(tlp='white'), + ) + + +def test_bad_created_marking_tlp_green(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da', + definition_type='tlp', + definition=TLPMarking(tlp='green'), + ) + + +def test_bad_created_marking_tlp_amber(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--f88d31f6-486f-44da-b317-01333bde0b82', + definition_type='tlp', + definition=TLPMarking(tlp='amber'), + ) + + +def test_bad_created_marking_tlp_red(): + with pytest.raises(exceptions.TLPMarkingDefinitionError) as excinfo: + MarkingDefinition( + id='marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed', + definition_type='tlp', + definition=TLPMarking(tlp='red'), + ) + + assert "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed" in str(excinfo.value) + + +def test_successful_tlp_white(): + white = MarkingDefinition( + id='marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9', + created='2017-01-20T00:00:00.000Z', + definition_type='tlp', + definition=TLPMarking(tlp='white'), + ) + + assert white.serialize(sort_keys=True) == TLP_WHITE.serialize(sort_keys=True) + + +def test_successful_tlp_green(): + green = MarkingDefinition( + id='marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da', + created='2017-01-20T00:00:00.000Z', + definition_type='tlp', + definition=TLPMarking(tlp='green'), + ) + + assert green.serialize(sort_keys=True) == TLP_GREEN.serialize(sort_keys=True) + + +def test_successful_tlp_amber(): + amber = MarkingDefinition( + id='marking-definition--f88d31f6-486f-44da-b317-01333bde0b82', + created='2017-01-20T00:00:00.000Z', + definition_type='tlp', + definition=TLPMarking(tlp='amber'), + ) + + assert amber.serialize(sort_keys=True) == TLP_AMBER.serialize(sort_keys=True) + + +def test_successful_tlp_red(): + red = MarkingDefinition( + id='marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed', + created='2017-01-20T00:00:00.000Z', + definition_type='tlp', + definition=TLPMarking(tlp='red'), + ) + + assert red.serialize(sort_keys=True) == TLP_RED.serialize(sort_keys=True) + + +def test_unknown_tlp_marking(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + definition_type='tlp', + definition=TLPMarking(tlp='gray'), + ) diff --git a/stix2/test/v20/test_markings.py b/stix2/test/v20/test_markings.py index cbf1f5b..b34ef43 100644 --- a/stix2/test/v20/test_markings.py +++ b/stix2/test/v20/test_markings.py @@ -6,7 +6,7 @@ import pytz import stix2 from stix2.v20 import TLP_WHITE -from .constants import MARKING_DEFINITION_ID +from .constants import CAMPAIGN_ID, IDENTITY_ID, MARKING_DEFINITION_ID EXPECTED_TLP_MARKING_DEFINITION = """{ "type": "marking-definition", @@ -31,7 +31,7 @@ EXPECTED_STATEMENT_MARKING_DEFINITION = """{ EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING = """{ "type": "campaign", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "name": "Green Group Attacks Against Finance", @@ -54,7 +54,7 @@ EXPECTED_GRANULAR_MARKING = """{ EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS = """{ "type": "campaign", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "name": "Green Group Attacks Against Finance", @@ -76,7 +76,7 @@ def test_marking_def_example_with_tlp(): def test_marking_def_example_with_statement_positional_argument(): marking_definition = stix2.v20.MarkingDefinition( - id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + id=MARKING_DEFINITION_ID, created="2017-01-20T00:00:00.000Z", definition_type="statement", definition=stix2.v20.StatementMarking(statement="Copyright 2016, Example Corp"), @@ -88,7 +88,7 @@ def test_marking_def_example_with_statement_positional_argument(): def test_marking_def_example_with_kwargs_statement(): kwargs = dict(statement="Copyright 2016, Example Corp") marking_definition = stix2.v20.MarkingDefinition( - id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + id=MARKING_DEFINITION_ID, created="2017-01-20T00:00:00.000Z", definition_type="statement", definition=stix2.v20.StatementMarking(**kwargs), @@ -100,7 +100,7 @@ def test_marking_def_example_with_kwargs_statement(): def test_marking_def_invalid_type(): with pytest.raises(ValueError): stix2.v20.MarkingDefinition( - id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + id=MARKING_DEFINITION_ID, created="2017-01-20T00:00:00.000Z", definition_type="my-definition-type", definition=stix2.v20.StatementMarking("Copyright 2016, Example Corp"), @@ -109,10 +109,11 @@ def test_marking_def_invalid_type(): def test_campaign_with_markings_example(): campaign = stix2.v20.Campaign( - id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", - created="2016-04-06T20:03:00Z", - modified="2016-04-06T20:03:00Z", + type='campaign', + id=CAMPAIGN_ID, + created_by_ref=IDENTITY_ID, + created="2016-04-06T20:03:00.000Z", + modified="2016-04-06T20:03:00.000Z", name="Green Group Attacks Against Finance", description="Campaign by Green Group against a series of targets in the financial services sector.", object_marking_refs=TLP_WHITE, @@ -122,7 +123,7 @@ def test_campaign_with_markings_example(): def test_granular_example(): granular_marking = stix2.v20.GranularMarking( - marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + marking_ref=MARKING_DEFINITION_ID, selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"], ) @@ -132,7 +133,7 @@ def test_granular_example(): def test_granular_example_with_bad_selector(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v20.GranularMarking( - marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + marking_ref=MARKING_DEFINITION_ID, selectors=["abc[0]"], # missing "." ) @@ -144,15 +145,16 @@ def test_granular_example_with_bad_selector(): def test_campaign_with_granular_markings_example(): campaign = stix2.v20.Campaign( - id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", - created="2016-04-06T20:03:00Z", - modified="2016-04-06T20:03:00Z", + type='campaign', + id=CAMPAIGN_ID, + created_by_ref=IDENTITY_ID, + created="2016-04-06T20:03:00.000Z", + modified="2016-04-06T20:03:00.000Z", name="Green Group Attacks Against Finance", description="Campaign by Green Group against a series of targets in the financial services sector.", granular_markings=[ stix2.v20.GranularMarking( - marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + marking_ref=MARKING_DEFINITION_ID, selectors=["description"], ), ], @@ -164,7 +166,7 @@ def test_campaign_with_granular_markings_example(): "data", [ EXPECTED_TLP_MARKING_DEFINITION, { - "id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + "id": MARKING_DEFINITION_ID, "type": "marking-definition", "created": "2017-01-20T00:00:00Z", "definition": { @@ -258,8 +260,8 @@ def test_marking_wrong_type_construction(): def test_campaign_add_markings(): campaign = stix2.v20.Campaign( - id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=CAMPAIGN_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:00Z", modified="2016-04-06T20:03:00Z", name="Green Group Attacks Against Finance", diff --git a/stix2/test/v20/test_object_markings.py b/stix2/test/v20/test_object_markings.py index 495c45a..156c42d 100644 --- a/stix2/test/v20/test_object_markings.py +++ b/stix2/test/v20/test_object_markings.py @@ -107,7 +107,6 @@ def test_add_markings_combination(): "data", [ ([""]), (""), - ([]), ([MARKING_IDS[0], 456]), ], ) @@ -576,7 +575,6 @@ def test_set_marking(): @pytest.mark.parametrize( "data", [ - ([]), ([""]), (""), ([MARKING_IDS[4], 687]), diff --git a/stix2/test/v20/test_observed_data.py b/stix2/test/v20/test_observed_data.py index cbdd394..95daf22 100644 --- a/stix2/test/v20/test_observed_data.py +++ b/stix2/test/v20/test_observed_data.py @@ -6,7 +6,7 @@ import pytz import stix2 -from .constants import OBSERVED_DATA_ID +from .constants import IDENTITY_ID, OBSERVED_DATA_ID OBJECTS_REGEX = re.compile('\"objects\": {(?:.*?)(?:(?:[^{]*?)|(?:{[^{]*?}))*}', re.DOTALL) @@ -14,7 +14,7 @@ OBJECTS_REGEX = re.compile('\"objects\": {(?:.*?)(?:(?:[^{]*?)|(?:{[^{]*?}))*}', EXPECTED = """{ "type": "observed-data", "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T19:58:16.000Z", "modified": "2016-04-06T19:58:16.000Z", "first_observed": "2015-12-21T19:00:00Z", @@ -31,8 +31,8 @@ EXPECTED = """{ def test_observed_data_example(): observed_data = stix2.v20.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -52,7 +52,7 @@ def test_observed_data_example(): EXPECTED_WITH_REF = """{ "type": "observed-data", "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T19:58:16.000Z", "modified": "2016-04-06T19:58:16.000Z", "first_observed": "2015-12-21T19:00:00Z", @@ -76,8 +76,8 @@ EXPECTED_WITH_REF = """{ def test_observed_data_example_with_refs(): observed_data = stix2.v20.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -102,8 +102,8 @@ def test_observed_data_example_with_refs(): def test_observed_data_example_with_bad_refs(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v20.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -130,8 +130,8 @@ def test_observed_data_example_with_bad_refs(): def test_observed_data_example_with_non_dictionary(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v20.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -148,8 +148,8 @@ def test_observed_data_example_with_non_dictionary(): def test_observed_data_example_with_empty_dictionary(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v20.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -168,9 +168,9 @@ def test_observed_data_example_with_empty_dictionary(): EXPECTED, { "type": "observed-data", - "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", + "id": OBSERVED_DATA_ID, "created": "2016-04-06T19:58:16.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "first_observed": "2015-12-21T19:00:00Z", "last_observed": "2015-12-21T19:00:00Z", "modified": "2016-04-06T19:58:16.000Z", @@ -193,7 +193,7 @@ def test_parse_observed_data(data): assert odata.modified == dt.datetime(2016, 4, 6, 19, 58, 16, tzinfo=pytz.utc) assert odata.first_observed == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc) assert odata.last_observed == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc) - assert odata.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert odata.created_by_ref == IDENTITY_ID assert odata.objects["0"].type == "file" @@ -533,7 +533,7 @@ def test_parse_basic_tcp_traffic_with_error(data): EXPECTED_PROCESS_OD = """{ "created": "2016-04-06T19:58:16.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "first_observed": "2015-12-21T19:00:00Z", "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", "last_observed": "2015-12-21T19:00:00Z", @@ -563,8 +563,8 @@ EXPECTED_PROCESS_OD = """{ def test_observed_data_with_process_example(): observed_data = stix2.v20.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -960,6 +960,24 @@ def test_ip4_address_example(): assert ip4.resolves_to_refs == ["4", "5"] +def test_ip4_address_valid_refs(): + mac1 = stix2.v20.MACAddress( + value="a1:b2:c3:d4:e5:f6", + ) + mac2 = stix2.v20.MACAddress( + value="a7:b8:c9:d0:e1:f2", + ) + + ip4 = stix2.v20.IPv4Address( + _valid_refs={"1": mac1, "2": mac2}, + value="177.60.40.7", + resolves_to_refs=["1", "2"], + ) + + assert ip4.value == "177.60.40.7" + assert ip4.resolves_to_refs == ["1", "2"] + + def test_ip4_address_example_cidr(): ip4 = stix2.v20.IPv4Address(value="198.51.100.0/24") @@ -1141,12 +1159,13 @@ def test_process_example_windows_process_ext_empty(): def test_process_example_extensions_empty(): - with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: - stix2.v20.Process(extensions={}) + proc = stix2.v20.Process( + pid=314, + name="foobar.exe", + extensions={}, + ) - assert excinfo.value.cls == stix2.v20.Process - assert excinfo.value.prop_name == 'extensions' - assert 'non-empty dictionary' in excinfo.value.reason + assert '{}' in str(proc) def test_process_example_with_WindowsProcessExt_Object(): @@ -1290,6 +1309,8 @@ def test_windows_registry_key_example(): assert w.values[0].name == "Foo" assert w.values[0].data == "qwerty" assert w.values[0].data_type == "REG_SZ" + # ensure no errors in serialization because of 'values' + assert "Foo" in str(w) def test_x509_certificate_example(): diff --git a/stix2/test/v20/test_pickle.py b/stix2/test/v20/test_pickle.py index 6c65d8f..416341c 100644 --- a/stix2/test/v20/test_pickle.py +++ b/stix2/test/v20/test_pickle.py @@ -2,13 +2,15 @@ import pickle import stix2 +from .constants import IDENTITY_ID + def test_pickling(): """ Ensure a pickle/unpickle cycle works okay. """ identity = stix2.v20.Identity( - id="identity--d66cb89d-5228-4983-958c-fa84ef75c88c", + id=IDENTITY_ID, name="alice", description="this is a pickle test", identity_class="some_class", diff --git a/stix2/test/v20/test_properties.py b/stix2/test/v20/test_properties.py index 4305e57..04a26f4 100644 --- a/stix2/test/v20/test_properties.py +++ b/stix2/test/v20/test_properties.py @@ -369,7 +369,6 @@ def test_dictionary_property_invalid_key(d): @pytest.mark.parametrize( "d", [ - ({}, "The dictionary property must contain a non-empty dictionary"), # TODO: This error message could be made more helpful. The error is caused # because `json.loads()` doesn't like the *single* quotes around the key # name, even though they are valid in a Python dictionary. While technically diff --git a/stix2/test/v20/test_relationship.py b/stix2/test/v20/test_relationship.py index 4dc1de8..a0fccf4 100644 --- a/stix2/test/v20/test_relationship.py +++ b/stix2/test/v20/test_relationship.py @@ -142,12 +142,12 @@ def test_create_relationship_with_positional_args(indicator, malware): EXPECTED_RELATIONSHIP, { "created": "2016-04-06T20:06:37Z", - "id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301", + "id": RELATIONSHIP_ID, "modified": "2016-04-06T20:06:37Z", - "relationship_type": "indicates", - "source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", - "target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", "type": "relationship", + "relationship_type": "indicates", + "source_ref": INDICATOR_ID, + "target_ref": MALWARE_ID, }, ], ) @@ -159,5 +159,5 @@ def test_parse_relationship(data): assert rel.created == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) assert rel.modified == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) assert rel.relationship_type == "indicates" - assert rel.source_ref == "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7" - assert rel.target_ref == "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e" + assert rel.source_ref == INDICATOR_ID + assert rel.target_ref == MALWARE_ID diff --git a/stix2/test/v20/test_report.py b/stix2/test/v20/test_report.py index fc4f288..53707ce 100644 --- a/stix2/test/v20/test_report.py +++ b/stix2/test/v20/test_report.py @@ -5,21 +5,24 @@ import pytz import stix2 -from .constants import INDICATOR_KWARGS, REPORT_ID +from .constants import ( + CAMPAIGN_ID, IDENTITY_ID, INDICATOR_ID, INDICATOR_KWARGS, RELATIONSHIP_ID, + REPORT_ID, +) EXPECTED = """{ "type": "report", "id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", - "created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2015-12-21T19:59:11.000Z", "modified": "2015-12-21T19:59:11.000Z", "name": "The Black Vine Cyberespionage Group", "description": "A simple report with an indicator and campaign", "published": "2016-01-20T17:00:00Z", "object_refs": [ - "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" + "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", + "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "relationship--df7c87eb-75d2-4948-af81-9d49d246f301" ], "labels": [ "campaign" @@ -29,8 +32,8 @@ EXPECTED = """{ def test_report_example(): report = stix2.v20.Report( - id="report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", - created_by_ref="identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + id=REPORT_ID, + created_by_ref=IDENTITY_ID, created="2015-12-21T19:59:11.000Z", modified="2015-12-21T19:59:11.000Z", name="The Black Vine Cyberespionage Group", @@ -38,9 +41,9 @@ def test_report_example(): published="2016-01-20T17:00:00Z", labels=["campaign"], object_refs=[ - "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + INDICATOR_ID, + CAMPAIGN_ID, + RELATIONSHIP_ID, ], ) @@ -49,8 +52,8 @@ def test_report_example(): def test_report_example_objects_in_object_refs(): report = stix2.v20.Report( - id="report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", - created_by_ref="identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + id=REPORT_ID, + created_by_ref=IDENTITY_ID, created="2015-12-21T19:59:11.000Z", modified="2015-12-21T19:59:11.000Z", name="The Black Vine Cyberespionage Group", @@ -58,9 +61,9 @@ def test_report_example_objects_in_object_refs(): published="2016-01-20T17:00:00Z", labels=["campaign"], object_refs=[ - stix2.v20.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS), - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + stix2.v20.Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS), + CAMPAIGN_ID, + RELATIONSHIP_ID, ], ) @@ -70,8 +73,8 @@ def test_report_example_objects_in_object_refs(): def test_report_example_objects_in_object_refs_with_bad_id(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v20.Report( - id="report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", - created_by_ref="identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + id=REPORT_ID, + created_by_ref=IDENTITY_ID, created="2015-12-21T19:59:11.000Z", modified="2015-12-21T19:59:11.000Z", name="The Black Vine Cyberespionage Group", @@ -79,9 +82,9 @@ def test_report_example_objects_in_object_refs_with_bad_id(): published="2016-01-20T17:00:00Z", labels=["campaign"], object_refs=[ - stix2.v20.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS), + stix2.v20.Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS), "campaign-83422c77-904c-4dc1-aff5-5c38f3a2c55c", # the "bad" id, missing a "-" - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + RELATIONSHIP_ID, ], ) @@ -94,18 +97,18 @@ def test_report_example_objects_in_object_refs_with_bad_id(): EXPECTED, { "created": "2015-12-21T19:59:11.000Z", - "created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + "created_by_ref": IDENTITY_ID, "description": "A simple report with an indicator and campaign", - "id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", + "id": REPORT_ID, "labels": [ "campaign", ], "modified": "2015-12-21T19:59:11.000Z", "name": "The Black Vine Cyberespionage Group", "object_refs": [ - "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + INDICATOR_ID, + CAMPAIGN_ID, + RELATIONSHIP_ID, ], "published": "2016-01-20T17:00:00Z", "type": "report", @@ -119,11 +122,11 @@ def test_parse_report(data): assert rept.id == REPORT_ID assert rept.created == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) assert rept.modified == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) - assert rept.created_by_ref == "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283" + assert rept.created_by_ref == IDENTITY_ID assert rept.object_refs == [ - "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + INDICATOR_ID, + CAMPAIGN_ID, + RELATIONSHIP_ID, ] assert rept.description == "A simple report with an indicator and campaign" assert rept.labels == ["campaign"] diff --git a/stix2/test/v20/test_sighting.py b/stix2/test/v20/test_sighting.py index f1d40c5..6bad63c 100644 --- a/stix2/test/v20/test_sighting.py +++ b/stix2/test/v20/test_sighting.py @@ -5,7 +5,7 @@ import pytz import stix2 -from .constants import INDICATOR_ID, SIGHTING_ID, SIGHTING_KWARGS +from .constants import IDENTITY_ID, INDICATOR_ID, SIGHTING_ID, SIGHTING_KWARGS EXPECTED_SIGHTING = """{ "type": "sighting", @@ -14,7 +14,7 @@ EXPECTED_SIGHTING = """{ "modified": "2016-04-06T20:06:37.000Z", "sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "where_sighted_refs": [ - "identity--8cc7afd6-5455-4d2b-a736-e614ee631d99" + "identity--311b2d2d-f010-4473-83ec-1edf84858f4c" ] }""" @@ -39,7 +39,7 @@ def test_sighting_all_required_properties(): created=now, modified=now, sighting_of_ref=INDICATOR_ID, - where_sighted_refs=["identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"], + where_sighted_refs=[IDENTITY_ID], ) assert str(s) == EXPECTED_SIGHTING @@ -90,12 +90,12 @@ def test_create_sighting_from_objects_rather_than_ids(malware): # noqa: F811 EXPECTED_SIGHTING, { "created": "2016-04-06T20:06:37Z", - "id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb", + "id": SIGHTING_ID, "modified": "2016-04-06T20:06:37Z", "sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "type": "sighting", "where_sighted_refs": [ - "identity--8cc7afd6-5455-4d2b-a736-e614ee631d99", + IDENTITY_ID, ], }, ], @@ -107,5 +107,5 @@ def test_parse_sighting(data): assert sighting.id == SIGHTING_ID assert sighting.created == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) assert sighting.modified == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) - assert sighting.sighting_of_ref == "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7" - assert sighting.where_sighted_refs == ["identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"] + assert sighting.sighting_of_ref == INDICATOR_ID + assert sighting.where_sighted_refs == [IDENTITY_ID] diff --git a/stix2/test/v20/test_threat_actor.py b/stix2/test/v20/test_threat_actor.py index f7ef843..854e77a 100644 --- a/stix2/test/v20/test_threat_actor.py +++ b/stix2/test/v20/test_threat_actor.py @@ -5,12 +5,12 @@ import pytz import stix2 -from .constants import THREAT_ACTOR_ID +from .constants import IDENTITY_ID, THREAT_ACTOR_ID EXPECTED = """{ "type": "threat-actor", "id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "Evil Org", @@ -23,13 +23,13 @@ EXPECTED = """{ def test_threat_actor_example(): threat_actor = stix2.v20.ThreatActor( - id="threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=THREAT_ACTOR_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", - name="Evil Org", description="The Evil Org threat actor group", labels=["crime-syndicate"], + name="Evil Org", ) assert str(threat_actor) == EXPECTED @@ -40,13 +40,11 @@ def test_threat_actor_example(): EXPECTED, { "created": "2016-04-06T20:03:48.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "description": "The Evil Org threat actor group", - "id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "labels": [ - "crime-syndicate", - ], + "id": THREAT_ACTOR_ID, "modified": "2016-04-06T20:03:48.000Z", + "labels": ["crime-syndicate"], "name": "Evil Org", "type": "threat-actor", }, @@ -59,7 +57,7 @@ def test_parse_threat_actor(data): assert actor.id == THREAT_ACTOR_ID assert actor.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) assert actor.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) - assert actor.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert actor.created_by_ref == IDENTITY_ID assert actor.description == "The Evil Org threat actor group" assert actor.name == "Evil Org" assert actor.labels == ["crime-syndicate"] diff --git a/stix2/test/v20/test_tool.py b/stix2/test/v20/test_tool.py index e0c7082..435b85e 100644 --- a/stix2/test/v20/test_tool.py +++ b/stix2/test/v20/test_tool.py @@ -5,12 +5,12 @@ import pytz import stix2 -from .constants import TOOL_ID +from .constants import IDENTITY_ID, TOOL_ID EXPECTED = """{ "type": "tool", "id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "VNC", @@ -22,7 +22,7 @@ EXPECTED = """{ EXPECTED_WITH_REVOKED = """{ "type": "tool", "id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "VNC", @@ -35,12 +35,12 @@ EXPECTED_WITH_REVOKED = """{ def test_tool_example(): tool = stix2.v20.Tool( - id="tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=TOOL_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", - name="VNC", labels=["remote-access"], + name="VNC", ) assert str(tool) == EXPECTED @@ -51,12 +51,10 @@ def test_tool_example(): EXPECTED, { "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", - ], + "created_by_ref": IDENTITY_ID, + "id": TOOL_ID, "modified": "2016-04-06T20:03:48Z", + "labels": ["remote-access"], "name": "VNC", "type": "tool", }, @@ -69,7 +67,7 @@ def test_parse_tool(data): assert tool.id == TOOL_ID assert tool.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) assert tool.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) - assert tool.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert tool.created_by_ref == IDENTITY_ID assert tool.labels == ["remote-access"] assert tool.name == "VNC" @@ -82,12 +80,12 @@ def test_tool_no_workbench_wrappers(): def test_tool_serialize_with_defaults(): tool = stix2.v20.Tool( - id="tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=TOOL_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", - name="VNC", labels=["remote-access"], + name="VNC", ) assert tool.serialize(pretty=True, include_optional_defaults=True) == EXPECTED_WITH_REVOKED diff --git a/stix2/test/v20/test_utils.py b/stix2/test/v20/test_utils.py index 1aa85b1..ee011c1 100644 --- a/stix2/test/v20/test_utils.py +++ b/stix2/test/v20/test_utils.py @@ -8,6 +8,8 @@ import pytz import stix2.utils +from .constants import IDENTITY_ID + amsterdam = pytz.timezone('Europe/Amsterdam') eastern = pytz.timezone('US/Eastern') @@ -123,7 +125,7 @@ def test_deduplicate(stix_objs1): ( stix2.v20.ObservedData( id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + 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", diff --git a/stix2/test/v20/test_vulnerability.py b/stix2/test/v20/test_vulnerability.py index 7ce05ef..5a69d82 100644 --- a/stix2/test/v20/test_vulnerability.py +++ b/stix2/test/v20/test_vulnerability.py @@ -24,7 +24,7 @@ EXPECTED = """{ def test_vulnerability_example(): vulnerability = stix2.v20.Vulnerability( - id="vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + id=VULNERABILITY_ID, created="2016-05-12T08:17:27.000Z", modified="2016-05-12T08:17:27.000Z", name="CVE-2016-1234", @@ -50,7 +50,7 @@ def test_vulnerability_example(): "source_name": "cve", }, ], - "id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + "id": VULNERABILITY_ID, "modified": "2016-05-12T08:17:27Z", "name": "CVE-2016-1234", "type": "vulnerability", diff --git a/stix2/test/v21/constants.py b/stix2/test/v21/constants.py index e03c610..b0ba1ef 100644 --- a/stix2/test/v21/constants.py +++ b/stix2/test/v21/constants.py @@ -31,6 +31,12 @@ MARKING_IDS = [ "marking-definition--68520ae2-fefe-43a9-84ee-2c2a934d2c7d", "marking-definition--2802dfb1-1019-40a8-8848-68d0ec0e417f", ] +MARKING_LANGS = [ + "en", + "es", + "de", + "ja", +] RELATIONSHIP_IDS = [ 'relationship--06520621-5352-4e6a-b976-e8fa3d437ffd', 'relationship--181c9c09-43e6-45dd-9374-3bec192f05ef', @@ -53,7 +59,7 @@ CAMPAIGN_MORE_KWARGS = dict( type='campaign', spec_version='2.1', id=CAMPAIGN_ID, - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:00.000Z", modified="2016-04-06T20:03:00.000Z", name="Green Group Attacks Against Finance", diff --git a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--0a3ead4e-6d47-4ccb-854c-a6a4f9d96b22/20170531213019735010.json b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--0a3ead4e-6d47-4ccb-854c-a6a4f9d96b22/20170531213019735010.json index ccbe2cc..f9fdf75 100644 --- a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--0a3ead4e-6d47-4ccb-854c-a6a4f9d96b22/20170531213019735010.json +++ b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--0a3ead4e-6d47-4ccb-854c-a6a4f9d96b22/20170531213019735010.json @@ -2,7 +2,7 @@ "id": "bundle--f68640b4-0cdc-42ae-b176-def1754a1ea0", "objects": [ { - "created": "2017-05-31T21:30:19.73501Z", + "created": "2017-05-31T21:30:19.735Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Credential dumping is the process of obtaining account login and password information from the operating system and software. Credentials can be used to perform Windows Credential Editor, Mimikatz, and gsecdump. These tools are in use by both professional security testers and adversaries.\n\nPlaintext passwords can be obtained using tools such as Mimikatz to extract passwords stored by the Local Security Authority (LSA). If smart cards are used to authenticate to a domain using a personal identification number (PIN), then that PIN is also cached as a result and may be dumped.Mimikatz access the LSA Subsystem Service (LSASS) process by opening the process, locating the LSA secrets key, and decrypting the sections in memory where credential details are stored. Credential dumpers may also use methods for reflective DLL Injection to reduce potential indicators of malicious activity.\n\nNTLM hash dumpers open the Security Accounts Manager (SAM) on the local file system (%SystemRoot%/system32/config/SAM) or create a dump of the Registry SAM key to access stored account password hashes. Some hash dumpers will open the local file system as a device and parse to the SAM table to avoid file access defenses. Others will make an in-memory copy of the SAM table before reading hashes. Detection of compromised Legitimate Credentials in-use by adversaries may help as well. \n\nOn Windows 8.1 and Windows Server 2012 R2, monitor Windows Logs for LSASS.exe creation to verify that LSASS started as a protected process.\n\nMonitor processes and command-line arguments for program execution that may be indicative of credential dumping. Remote access tools may contain built-in features or incorporate existing tools like Mimikatz. PowerShell scripts also exist that contain credential dumping functionality, such as PowerSploit's Invoke-Mimikatz module,[[Citation: Powersploit]] which may require additional logging features to be configured in the operating system to collect necessary information for analysis.\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: API monitoring, Process command-line parameters, Process monitoring, PowerShell logs", "external_references": [ @@ -29,7 +29,7 @@ "phase_name": "credential-access" } ], - "modified": "2017-05-31T21:30:19.73501Z", + "modified": "2017-05-31T21:30:19.735Z", "name": "Credential Dumping", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b/20170531213026496201.json b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b/20170531213026496201.json index c36831e..abc6725 100644 --- a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b/20170531213026496201.json +++ b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b/20170531213026496201.json @@ -2,7 +2,7 @@ "id": "bundle--b07d6fd6-7cc5-492d-a1eb-9ba956b329d5", "objects": [ { - "created": "2017-05-31T21:30:26.496201Z", + "created": "2017-05-31T21:30:26.496Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Rootkits are programs that hide the existence of malware by intercepting and modifying operating system API calls that supply system information. Rootkits or rootkit enabling functionality may reside at the user or kernel level in the operating system or lower, to include a Hypervisor, Master Boot Record, or the Basic Input/Output System.[[Citation: Wikipedia Rootkit]]\n\nAdversaries may use rootkits to hide the presence of programs, files, network connections, services, drivers, and other system components.\n\nDetection: Some rootkit protections may be built into anti-virus or operating system software. There are dedicated rootkit detection tools that look for specific types of rootkit behavior. Monitor for the existence of unrecognized DLLs, devices, services, and changes to the MBR.[[Citation: Wikipedia Rootkit]]\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: BIOS, MBR, System calls", "external_references": [ @@ -24,7 +24,7 @@ "phase_name": "defense-evasion" } ], - "modified": "2017-05-31T21:30:26.496201Z", + "modified": "2017-05-31T21:30:26.496Z", "name": "Rootkit", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--774a3188-6ba9-4dc4-879d-d54ee48a5ce9/20170531213029458940.json b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--774a3188-6ba9-4dc4-879d-d54ee48a5ce9/20170531213029458940.json index 0504875..4bde369 100644 --- a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--774a3188-6ba9-4dc4-879d-d54ee48a5ce9/20170531213029458940.json +++ b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--774a3188-6ba9-4dc4-879d-d54ee48a5ce9/20170531213029458940.json @@ -2,7 +2,7 @@ "id": "bundle--1a854c96-639e-4771-befb-e7b960a65974", "objects": [ { - "created": "2017-05-31T21:30:29.45894Z", + "created": "2017-05-31T21:30:29.458Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Data, such as sensitive documents, may be exfiltrated through the use of automated processing or Scripting after being gathered during Exfiltration Over Command and Control Channel and Exfiltration Over Alternative Protocol.\n\nDetection: Monitor process file access patterns and network behavior. Unrecognized processes or scripts that appear to be traversing file systems and sending network traffic may be suspicious.\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: File monitoring, Process monitoring, Process use of network", "external_references": [ @@ -19,7 +19,7 @@ "phase_name": "exfiltration" } ], - "modified": "2017-05-31T21:30:29.45894Z", + "modified": "2017-05-31T21:30:29.458Z", "name": "Automated Exfiltration", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475/20170531213045139269.json b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475/20170531213045139269.json index 2e3b622..582a935 100644 --- a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475/20170531213045139269.json +++ b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475/20170531213045139269.json @@ -2,7 +2,7 @@ "id": "bundle--33e3e33a-38b8-4a37-9455-5b8c82d3b10a", "objects": [ { - "created": "2017-05-31T21:30:45.139269Z", + "created": "2017-05-31T21:30:45.139Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Adversaries may attempt to get a listing of network connections to or from the compromised system.\nUtilities and commands that acquire this information include netstat, \"net use,\" and \"net session\" with Net.\n\nDetection: System and network discovery techniques normally occur throughout an operation as an adversary learns the environment. Data and events should not be viewed in isolation, but as part of a chain of behavior that could lead to other activities, such as Windows Management Instrumentation and PowerShell.\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: Process command-line parameters, Process monitoring", "external_references": [ @@ -19,7 +19,7 @@ "phase_name": "discovery" } ], - "modified": "2017-05-31T21:30:45.139269Z", + "modified": "2017-05-31T21:30:45.139Z", "name": "Local Network Connections Discovery", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--ae676644-d2d2-41b7-af7e-9bed1b55898c/20170531213041022897.json b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--ae676644-d2d2-41b7-af7e-9bed1b55898c/20170531213041022897.json index 8819fcb..8827c4b 100644 --- a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--ae676644-d2d2-41b7-af7e-9bed1b55898c/20170531213041022897.json +++ b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--ae676644-d2d2-41b7-af7e-9bed1b55898c/20170531213041022897.json @@ -2,7 +2,7 @@ "id": "bundle--a87938c5-cc1e-4e06-a8a3-b10243ae397d", "objects": [ { - "created": "2017-05-31T21:30:41.022897Z", + "created": "2017-05-31T21:30:41.022Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Sensitive data can be collected from remote systems via shared network drives (host shared directory, network file server, etc.) that are accessible from the current system prior to cmd may be used to gather information.\n\nDetection: Monitor processes and command-line arguments for actions that could be taken to collect files from a network share. Remote access tools with built-in features may interact directly with the Windows API to gather data. Data may also be acquired through Windows system management tools such as Windows Management Instrumentation and PowerShell.\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: File monitoring, Process monitoring, Process command-line parameters", "external_references": [ @@ -19,7 +19,7 @@ "phase_name": "collection" } ], - "modified": "2017-05-31T21:30:41.022897Z", + "modified": "2017-05-31T21:30:41.022Z", "name": "Data from Network Shared Drive", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a/20170531213032662702.json b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a/20170531213032662702.json index 7d2b58e..219ce46 100644 --- a/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a/20170531213032662702.json +++ b/stix2/test/v21/stix2_data/attack-pattern/attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a/20170531213032662702.json @@ -2,7 +2,7 @@ "id": "bundle--5ddaeff9-eca7-4094-9e65-4f53da21a444", "objects": [ { - "created": "2017-05-31T21:30:32.662702Z", + "created": "2017-05-31T21:30:32.662Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Adversaries may attempt to make an executable or file difficult to discover or analyze by encrypting, encoding, or otherwise obfuscating its contents on the system.\n\nDetection: Detection of file obfuscation is difficult unless artifacts are left behind by the obfuscation process that are uniquely detectable with a signature. If detection of the obfuscation itself is not possible, it may be possible to detect the malicious activity that caused the obfuscated file (for example, the method that was used to write, read, or modify the file on the file system).\n\nPlatforms: Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows XP, Windows 7, Windows 8, Windows Server 2003 R2, Windows Server 2008 R2, Windows Server 2012 R2, Windows Vista, Windows 8.1\n\nData Sources: Network protocol analysis, Process use of network, Binary file metadata, File monitoring, Malware reverse engineering", "external_references": [ @@ -19,7 +19,7 @@ "phase_name": "defense-evasion" } ], - "modified": "2017-05-31T21:30:32.662702Z", + "modified": "2017-05-31T21:30:32.662Z", "name": "Obfuscated Files or Information", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/course-of-action/course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f/20170531213026495974.json b/stix2/test/v21/stix2_data/course-of-action/course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f/20170531213026495974.json index 3117103..b59ae52 100644 --- a/stix2/test/v21/stix2_data/course-of-action/course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f/20170531213026495974.json +++ b/stix2/test/v21/stix2_data/course-of-action/course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f/20170531213026495974.json @@ -2,11 +2,11 @@ "id": "bundle--a42d26fe-c938-4074-a1b3-50d852e6f0bd", "objects": [ { - "created": "2017-05-31T21:30:26.495974Z", + "created": "2017-05-31T21:30:26.495Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Identify potentially malicious software that may contain rootkit functionality, and audit and/or block it by using whitelisting[[CiteRef::Beechey 2010]] tools, like AppLocker,[[CiteRef::Windows Commands JPCERT]][[CiteRef::NSA MS AppLocker]] or Software Restriction Policies[[CiteRef::Corio 2008]] where appropriate.[[CiteRef::TechNet Applocker vs SRP]]", "id": "course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f", - "modified": "2017-05-31T21:30:26.495974Z", + "modified": "2017-05-31T21:30:26.495Z", "name": "Rootkit Mitigation", "spec_version": "2.1", "type": "course-of-action" diff --git a/stix2/test/v21/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd/20170531213041022744.json b/stix2/test/v21/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd/20170531213041022744.json index dcc5b0d..1c05407 100644 --- a/stix2/test/v21/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd/20170531213041022744.json +++ b/stix2/test/v21/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd/20170531213041022744.json @@ -1,9 +1,9 @@ { - "created": "2017-05-31T21:30:41.022744Z", + "created": "2017-05-31T21:30:41.022Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Identify unnecessary system utilities or potentially malicious software that may be used to collect data from a network share, and audit and/or block them by using whitelisting[[CiteRef::Beechey 2010]] tools, like AppLocker,[[CiteRef::Windows Commands JPCERT]][[CiteRef::NSA MS AppLocker]] or Software Restriction Policies[[CiteRef::Corio 2008]] where appropriate.[[CiteRef::TechNet Applocker vs SRP]]", "id": "course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd", - "modified": "2017-05-31T21:30:41.022744Z", + "modified": "2017-05-31T21:30:41.022Z", "name": "Data from Network Shared Drive Mitigation", "spec_version": "2.1", "type": "course-of-action" diff --git a/stix2/test/v21/stix2_data/identity/identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5/20170601000000000000.json b/stix2/test/v21/stix2_data/identity/identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5/20170601000000000000.json index 368273d..e235745 100644 --- a/stix2/test/v21/stix2_data/identity/identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5/20170601000000000000.json +++ b/stix2/test/v21/stix2_data/identity/identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5/20170601000000000000.json @@ -2,10 +2,10 @@ "id": "bundle--81884287-2548-47fc-a997-39489ddd5462", "objects": [ { - "created": "2017-06-01T00:00:00Z", + "created": "2017-06-01T00:00:00.000Z", "id": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "identity_class": "organization", - "modified": "2017-06-01T00:00:00Z", + "modified": "2017-06-01T00:00:00.000Z", "name": "The MITRE Corporation", "spec_version": "2.1", "type": "identity" diff --git a/stix2/test/v21/stix2_data/intrusion-set/intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064/20170531213149412497.json b/stix2/test/v21/stix2_data/intrusion-set/intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064/20170531213149412497.json index b8372aa..c7947e8 100644 --- a/stix2/test/v21/stix2_data/intrusion-set/intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064/20170531213149412497.json +++ b/stix2/test/v21/stix2_data/intrusion-set/intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064/20170531213149412497.json @@ -10,7 +10,7 @@ "PinkPanther", "Black Vine" ], - "created": "2017-05-31T21:31:49.412497Z", + "created": "2017-05-31T21:31:49.412Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Deep Panda is a suspected Chinese threat group known to target many industries, including government, defense, financial, and telecommunications.Deep Panda.Deep Panda also appears to be known as Black Vine based on the attribution of both group names to the Anthem intrusion.[[Citation: Symantec Black Vine]]", "external_references": [ @@ -41,7 +41,7 @@ } ], "id": "intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064", - "modified": "2017-05-31T21:31:49.412497Z", + "modified": "2017-05-31T21:31:49.412Z", "name": "Deep Panda", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/intrusion-set/intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a/20170531213153197755.json b/stix2/test/v21/stix2_data/intrusion-set/intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a/20170531213153197755.json index 2fe46f1..b48a477 100644 --- a/stix2/test/v21/stix2_data/intrusion-set/intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a/20170531213153197755.json +++ b/stix2/test/v21/stix2_data/intrusion-set/intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a/20170531213153197755.json @@ -5,7 +5,7 @@ "aliases": [ "DragonOK" ], - "created": "2017-05-31T21:31:53.197755Z", + "created": "2017-05-31T21:31:53.197Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "DragonOK is a threat group that has targeted Japanese organizations with phishing emails. Due to overlapping TTPs, including similar custom tools, DragonOK is thought to have a direct or indirect relationship with the threat group Moafee. [[Citation: Operation Quantum Entanglement]][[Citation: Symbiotic APT Groups]] It is known to use a variety of malware, including Sysget/HelloBridge, PlugX, PoisonIvy, FormerFirstRat, NFlog, and NewCT. [[Citation: New DragonOK]]", "external_references": [ @@ -31,7 +31,7 @@ } ], "id": "intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a", - "modified": "2017-05-31T21:31:53.197755Z", + "modified": "2017-05-31T21:31:53.197Z", "name": "DragonOK", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json index 8ea538e..1bedc5b 100644 --- a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json +++ b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json @@ -2,7 +2,7 @@ "id": "bundle--f64de948-7067-4534-8018-85f03d470625", "objects": [ { - "created": "2017-05-31T21:32:58.226477Z", + "created": "2017-05-31T21:32:58.226Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Rover is malware suspected of being used for espionage purposes. It was used in 2015 in a targeted email sent to an Indian Ambassador to Afghanistan.[[Citation: Palo Alto Rover]]", "external_references": [ @@ -21,7 +21,7 @@ "malware_types": [ "malware" ], - "modified": "2017-05-31T21:32:58.226477Z", + "modified": "2017-05-31T21:32:58.226Z", "name": "Rover", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json b/stix2/test/v21/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json index 9f51a11..0b7c01e 100644 --- a/stix2/test/v21/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json +++ b/stix2/test/v21/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json @@ -2,7 +2,7 @@ "id": "bundle--c633942b-545c-4c87-91b7-9fe5740365e0", "objects": [ { - "created": "2017-05-31T21:33:26.565056Z", + "created": "2017-05-31T21:33:26.565Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "RTM is custom malware written in Delphi. It is used by the group of the same name (RTM).[[Citation: ESET RTM Feb 2017]]", "external_references": [ @@ -21,7 +21,7 @@ "malware_types": [ "malware" ], - "modified": "2017-05-31T21:33:26.565056Z", + "modified": "2017-05-31T21:33:26.565Z", "name": "RTM", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json b/stix2/test/v21/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json index 2808866..195c973 100644 --- a/stix2/test/v21/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json +++ b/stix2/test/v21/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json @@ -2,7 +2,7 @@ "id": "bundle--09ce4338-8741-4fcf-9738-d216c8e40974", "objects": [ { - "created": "2017-05-31T21:32:48.482655Z", + "created": "2017-05-31T21:32:48.482Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Sakula is a remote access tool (RAT) that first surfaced in 2012 and was used in intrusions throughout 2015.[[Citation: Dell Sakula]]\n\nAliases: Sakula, Sakurel, VIPER", "external_references": [ @@ -21,7 +21,7 @@ "malware_types": [ "malware" ], - "modified": "2017-05-31T21:32:48.482655Z", + "modified": "2017-05-31T21:32:48.482Z", "name": "Sakula", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json b/stix2/test/v21/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json index 3e1c870..4d57db5 100644 --- a/stix2/test/v21/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json +++ b/stix2/test/v21/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json @@ -2,7 +2,7 @@ "id": "bundle--611947ce-ae3b-4fdb-b297-aed8eab22e4f", "objects": [ { - "created": "2017-05-31T21:32:15.263882Z", + "created": "2017-05-31T21:32:15.263Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "PoisonIvy is a popular remote access tool (RAT) that has been used by many groups.[[Citation: FireEye Poison Ivy]]\n\nAliases: PoisonIvy, Poison Ivy", "external_references": [ @@ -21,7 +21,7 @@ "labels": [ "malware" ], - "modified": "2017-05-31T21:32:15.263882Z", + "modified": "2017-05-31T21:32:15.263Z", "name": "PoisonIvy", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/relationship/relationship--0d4a7788-7f3b-4df8-a498-31a38003c883/20170531213327182784.json b/stix2/test/v21/stix2_data/relationship/relationship--0d4a7788-7f3b-4df8-a498-31a38003c883/20170531213327182784.json index 915b126..b428b3b 100644 --- a/stix2/test/v21/stix2_data/relationship/relationship--0d4a7788-7f3b-4df8-a498-31a38003c883/20170531213327182784.json +++ b/stix2/test/v21/stix2_data/relationship/relationship--0d4a7788-7f3b-4df8-a498-31a38003c883/20170531213327182784.json @@ -2,10 +2,10 @@ "id": "bundle--7e715462-dd9d-40b9-968a-10ef0ecf126d", "objects": [ { - "created": "2017-05-31T21:33:27.182784Z", + "created": "2017-05-31T21:33:27.182Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--0d4a7788-7f3b-4df8-a498-31a38003c883", - "modified": "2017-05-31T21:33:27.182784Z", + "modified": "2017-05-31T21:33:27.182Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v21/stix2_data/relationship/relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227/20170531213327082801.json b/stix2/test/v21/stix2_data/relationship/relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227/20170531213327082801.json index 478ca3a..ca0d1f0 100644 --- a/stix2/test/v21/stix2_data/relationship/relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227/20170531213327082801.json +++ b/stix2/test/v21/stix2_data/relationship/relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227/20170531213327082801.json @@ -2,10 +2,10 @@ "id": "bundle--a53eef35-abfc-4bcd-b84e-a048f7b4a9bf", "objects": [ { - "created": "2017-05-31T21:33:27.082801Z", + "created": "2017-05-31T21:33:27.082Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--0e55ee98-0c6d-43d4-b424-b18a0036b227", - "modified": "2017-05-31T21:33:27.082801Z", + "modified": "2017-05-31T21:33:27.082Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v21/stix2_data/relationship/relationship--1e91cd45-a725-4965-abe3-700694374432/20170531213327018782.json b/stix2/test/v21/stix2_data/relationship/relationship--1e91cd45-a725-4965-abe3-700694374432/20170531213327018782.json index 2ea9d22..5087f28 100644 --- a/stix2/test/v21/stix2_data/relationship/relationship--1e91cd45-a725-4965-abe3-700694374432/20170531213327018782.json +++ b/stix2/test/v21/stix2_data/relationship/relationship--1e91cd45-a725-4965-abe3-700694374432/20170531213327018782.json @@ -2,10 +2,10 @@ "id": "bundle--0b9f6412-314f-44e3-8779-9738c9578ef5", "objects": [ { - "created": "2017-05-31T21:33:27.018782Z", + "created": "2017-05-31T21:33:27.018Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--1e91cd45-a725-4965-abe3-700694374432", - "modified": "2017-05-31T21:33:27.018782Z", + "modified": "2017-05-31T21:33:27.018Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v21/stix2_data/relationship/relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e/20170531213327100701.json b/stix2/test/v21/stix2_data/relationship/relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e/20170531213327100701.json index d0a2a50..6d73f52 100644 --- a/stix2/test/v21/stix2_data/relationship/relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e/20170531213327100701.json +++ b/stix2/test/v21/stix2_data/relationship/relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e/20170531213327100701.json @@ -2,10 +2,10 @@ "id": "bundle--6d5b04a8-efb2-4179-990e-74f1dcc76e0c", "objects": [ { - "created": "2017-05-31T21:33:27.100701Z", + "created": "2017-05-31T21:33:27.100Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--3a3084f9-0302-4fd5-9b8a-e0db10f5345e", - "modified": "2017-05-31T21:33:27.100701Z", + "modified": "2017-05-31T21:33:27.100Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v21/stix2_data/relationship/relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1/20170531213327143973.json b/stix2/test/v21/stix2_data/relationship/relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1/20170531213327143973.json index 0ff1d5a..5d4594c 100644 --- a/stix2/test/v21/stix2_data/relationship/relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1/20170531213327143973.json +++ b/stix2/test/v21/stix2_data/relationship/relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1/20170531213327143973.json @@ -2,10 +2,10 @@ "id": "bundle--a7efc025-040d-49c7-bf97-e5a1120ecacc", "objects": [ { - "created": "2017-05-31T21:33:27.143973Z", + "created": "2017-05-31T21:33:27.143Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--3a3ed0b2-0c38-441f-ac40-53b873e545d1", - "modified": "2017-05-31T21:33:27.143973Z", + "modified": "2017-05-31T21:33:27.143Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v21/stix2_data/relationship/relationship--592d0c31-e61f-495e-a60e-70d7be59a719/20170531213327021562.json b/stix2/test/v21/stix2_data/relationship/relationship--592d0c31-e61f-495e-a60e-70d7be59a719/20170531213327021562.json index 640be0c..c18ade2 100644 --- a/stix2/test/v21/stix2_data/relationship/relationship--592d0c31-e61f-495e-a60e-70d7be59a719/20170531213327021562.json +++ b/stix2/test/v21/stix2_data/relationship/relationship--592d0c31-e61f-495e-a60e-70d7be59a719/20170531213327021562.json @@ -2,10 +2,10 @@ "id": "bundle--9f013d47-7704-41c2-9749-23d0d94af94d", "objects": [ { - "created": "2017-05-31T21:33:27.021562Z", + "created": "2017-05-31T21:33:27.021Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--592d0c31-e61f-495e-a60e-70d7be59a719", - "modified": "2017-05-31T21:33:27.021562Z", + "modified": "2017-05-31T21:33:27.021Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v21/stix2_data/relationship/relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1/20170531213327044387.json b/stix2/test/v21/stix2_data/relationship/relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1/20170531213327044387.json index 41be9df..d7a1fc2 100644 --- a/stix2/test/v21/stix2_data/relationship/relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1/20170531213327044387.json +++ b/stix2/test/v21/stix2_data/relationship/relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1/20170531213327044387.json @@ -2,10 +2,10 @@ "id": "bundle--15167b24-4cee-4c96-a140-32a6c37df4b4", "objects": [ { - "created": "2017-05-31T21:33:27.044387Z", + "created": "2017-05-31T21:33:27.044Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1", - "modified": "2017-05-31T21:33:27.044387Z", + "modified": "2017-05-31T21:33:27.044Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v21/stix2_data/relationship/relationship--8797579b-e3be-4209-a71b-255a4d08243d/20170531213327051532.json b/stix2/test/v21/stix2_data/relationship/relationship--8797579b-e3be-4209-a71b-255a4d08243d/20170531213327051532.json index ce33f67..f406224 100644 --- a/stix2/test/v21/stix2_data/relationship/relationship--8797579b-e3be-4209-a71b-255a4d08243d/20170531213327051532.json +++ b/stix2/test/v21/stix2_data/relationship/relationship--8797579b-e3be-4209-a71b-255a4d08243d/20170531213327051532.json @@ -2,10 +2,10 @@ "id": "bundle--ff845dca-7036-416f-aae0-95030994c49f", "objects": [ { - "created": "2017-05-31T21:33:27.051532Z", + "created": "2017-05-31T21:33:27.051Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "id": "relationship--8797579b-e3be-4209-a71b-255a4d08243d", - "modified": "2017-05-31T21:33:27.051532Z", + "modified": "2017-05-31T21:33:27.051Z", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], diff --git a/stix2/test/v21/stix2_data/tool/tool--03342581-f790-4f03-ba41-e82e67392e23/20170531213231601148.json b/stix2/test/v21/stix2_data/tool/tool--03342581-f790-4f03-ba41-e82e67392e23/20170531213231601148.json index 103e8ec..a8a9455 100644 --- a/stix2/test/v21/stix2_data/tool/tool--03342581-f790-4f03-ba41-e82e67392e23/20170531213231601148.json +++ b/stix2/test/v21/stix2_data/tool/tool--03342581-f790-4f03-ba41-e82e67392e23/20170531213231601148.json @@ -2,7 +2,7 @@ "id": "bundle--d8826afc-1561-4362-a4e3-05a4c2c3ac3c", "objects": [ { - "created": "2017-05-31T21:32:31.601148Z", + "created": "2017-05-31T21:32:31.601Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "The Net utility is a component of the Windows operating system. It is used in command-line operations for control of users, groups, services, and network connections.Net has a great deal of functionality,[[Citation: Savill 1999]] much of which is useful for an adversary, such as gathering system and network information for [[Discovery]], moving laterally through [[Windows admin shares]] using net use commands, and interacting with services.\n\nAliases: Net, net.exe", "external_references": [ @@ -26,7 +26,7 @@ "tool_types": [ "tool" ], - "modified": "2017-05-31T21:32:31.601148Z", + "modified": "2017-05-31T21:32:31.601Z", "name": "Net", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/stix2_data/tool/tool--242f3da3-4425-4d11-8f5c-b842886da966/20170531213212684914.json b/stix2/test/v21/stix2_data/tool/tool--242f3da3-4425-4d11-8f5c-b842886da966/20170531213212684914.json index 32ea7ba..b3c9451 100644 --- a/stix2/test/v21/stix2_data/tool/tool--242f3da3-4425-4d11-8f5c-b842886da966/20170531213212684914.json +++ b/stix2/test/v21/stix2_data/tool/tool--242f3da3-4425-4d11-8f5c-b842886da966/20170531213212684914.json @@ -2,7 +2,7 @@ "id": "bundle--7dbde18f-6f14-4bf0-8389-505c89d6d5a6", "objects": [ { - "created": "2017-05-31T21:32:12.684914Z", + "created": "2017-05-31T21:32:12.684Z", "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", "description": "Windows Credential Editor is a password dumping tool.[[Citation: Amplia WCE]]\n\nAliases: Windows Credential Editor, WCE", "external_references": [ @@ -21,7 +21,7 @@ "tool_types": [ "tool" ], - "modified": "2017-05-31T21:32:12.684914Z", + "modified": "2017-05-31T21:32:12.684Z", "name": "Windows Credential Editor", "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" diff --git a/stix2/test/v21/test_attack_pattern.py b/stix2/test/v21/test_attack_pattern.py index 9c13a12..165581c 100644 --- a/stix2/test/v21/test_attack_pattern.py +++ b/stix2/test/v21/test_attack_pattern.py @@ -26,7 +26,7 @@ EXPECTED = """{ def test_attack_pattern_example(): ap = stix2.v21.AttackPattern( - id="attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + id=ATTACK_PATTERN_ID, created="2016-05-12T08:17:27.000Z", modified="2016-05-12T08:17:27.000Z", name="Spear Phishing", @@ -46,7 +46,7 @@ def test_attack_pattern_example(): { "type": "attack-pattern", "spec_version": "2.1", - "id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + "id": ATTACK_PATTERN_ID, "created": "2016-05-12T08:17:27.000Z", "modified": "2016-05-12T08:17:27.000Z", "description": "...", @@ -77,11 +77,44 @@ def test_parse_attack_pattern(data): def test_attack_pattern_invalid_labels(): with pytest.raises(stix2.exceptions.InvalidValueError): stix2.v21.AttackPattern( - id="attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + id=ATTACK_PATTERN_ID, created="2016-05-12T08:17:27Z", modified="2016-05-12T08:17:27Z", name="Spear Phishing", labels=1, ) + +def test_overly_precise_timestamps(): + ap = stix2.v21.AttackPattern( + id=ATTACK_PATTERN_ID, + created="2016-05-12T08:17:27.0000342Z", + modified="2016-05-12T08:17:27.000287Z", + name="Spear Phishing", + external_references=[{ + "source_name": "capec", + "external_id": "CAPEC-163", + }], + description="...", + ) + + assert str(ap) == EXPECTED + + +def test_less_precise_timestamps(): + ap = stix2.v21.AttackPattern( + id=ATTACK_PATTERN_ID, + created="2016-05-12T08:17:27.00Z", + modified="2016-05-12T08:17:27.0Z", + name="Spear Phishing", + external_references=[{ + "source_name": "capec", + "external_id": "CAPEC-163", + }], + description="...", + ) + + assert str(ap) == EXPECTED + + # TODO: Add other examples diff --git a/stix2/test/v21/test_bundle.py b/stix2/test/v21/test_bundle.py index 86c2d00..47d0a7a 100644 --- a/stix2/test/v21/test_bundle.py +++ b/stix2/test/v21/test_bundle.py @@ -4,6 +4,8 @@ import pytest import stix2 +from .constants import IDENTITY_ID + EXPECTED_BUNDLE = """{ "type": "bundle", "id": "bundle--00000000-0000-4000-8000-000000000007", @@ -190,7 +192,7 @@ def test_parse_unknown_type(): "id": "other--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "created": "2016-04-06T20:03:00Z", "modified": "2016-04-06T20:03:00Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "description": "Campaign by Green Group against a series of targets in the financial services sector.", "name": "Green Group Attacks Against Finance", } @@ -205,3 +207,103 @@ def test_stix_object_property(): identity = stix2.v21.Identity(name="test", identity_class="individual") assert prop.clean(identity) is identity + + +def test_bundle_obj_id_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + mal_list = bundle.get_obj("malware--00000000-0000-4000-8000-000000000003") + assert bundle.objects[1] == mal_list[0] + assert len(mal_list) == 1 + + +@pytest.mark.parametrize( + "bundle_data", [{ + "type": "bundle", + "id": "bundle--00000000-0000-4000-8000-000000000007", + "objects": [ + { + "type": "indicator", + "spec_version": "2.1", + "id": "indicator--00000000-0000-4000-8000-000000000001", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "indicator_types": [ + "malicious-activity", + ], + "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", + "valid_from": "2017-01-01T12:34:56Z", + }, + { + "type": "malware", + "spec_version": "2.1", + "id": "malware--00000000-0000-4000-8000-000000000003", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "name": "Cryptolocker1", + "malware_types": [ + "ransomware", + ], + }, + { + "type": "malware", + "spec_version": "2.1", + "id": "malware--00000000-0000-4000-8000-000000000003", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-12-21T12:34:56.000Z", + "name": "CryptolockerOne", + "malware_types": [ + "ransomware", + ], + }, + { + "type": "relationship", + "spec_version": "2.1", + "id": "relationship--00000000-0000-4000-8000-000000000005", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "relationship_type": "indicates", + "source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", + "target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", + }, + ], + }], +) +def test_bundle_objs_ids_found(bundle_data): + bundle = stix2.parse(bundle_data) + + mal_list = bundle.get_obj("malware--00000000-0000-4000-8000-000000000003") + assert bundle.objects[1] == mal_list[0] + assert bundle.objects[2] == mal_list[1] + assert len(mal_list) == 2 + + +def test_bundle_getitem_overload_property_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + assert bundle.type == "bundle" + assert bundle['type'] == "bundle" + + +def test_bundle_getitem_overload_obj_id_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + mal_list = bundle["malware--00000000-0000-4000-8000-000000000003"] + assert bundle.objects[1] == mal_list[0] + assert len(mal_list) == 1 + + +def test_bundle_obj_id_not_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + with pytest.raises(KeyError) as excinfo: + bundle.get_obj('non existent') + assert "does not match the id property of any of the bundle" in str(excinfo.value) + + +def test_bundle_getitem_overload_obj_id_not_found(): + bundle = stix2.parse(EXPECTED_BUNDLE) + + with pytest.raises(KeyError) as excinfo: + bundle['non existent'] + assert "neither a property on the bundle nor does it match the id property" in str(excinfo.value) diff --git a/stix2/test/v21/test_campaign.py b/stix2/test/v21/test_campaign.py index ad7e753..10f5d7b 100644 --- a/stix2/test/v21/test_campaign.py +++ b/stix2/test/v21/test_campaign.py @@ -5,13 +5,13 @@ import pytz import stix2 -from .constants import CAMPAIGN_ID +from .constants import CAMPAIGN_ID, CAMPAIGN_MORE_KWARGS, IDENTITY_ID EXPECTED = """{ "type": "campaign", "spec_version": "2.1", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "name": "Green Group Attacks Against Finance", @@ -21,12 +21,7 @@ EXPECTED = """{ def test_campaign_example(): campaign = stix2.v21.Campaign( - id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", - 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.", + **CAMPAIGN_MORE_KWARGS ) assert str(campaign) == EXPECTED @@ -38,10 +33,10 @@ def test_campaign_example(): { "type": "campaign", "spec_version": "2.1", - "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "id": CAMPAIGN_ID, "created": "2016-04-06T20:03:00Z", "modified": "2016-04-06T20:03:00Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "description": "Campaign by Green Group against a series of targets in the financial services sector.", "name": "Green Group Attacks Against Finance", }, @@ -55,7 +50,7 @@ def test_parse_campaign(data): assert cmpn.id == CAMPAIGN_ID assert cmpn.created == dt.datetime(2016, 4, 6, 20, 3, 0, tzinfo=pytz.utc) assert cmpn.modified == dt.datetime(2016, 4, 6, 20, 3, 0, tzinfo=pytz.utc) - assert cmpn.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert cmpn.created_by_ref == IDENTITY_ID assert cmpn.description == "Campaign by Green Group against a series of targets in the financial services sector." assert cmpn.name == "Green Group Attacks Against Finance" diff --git a/stix2/test/v21/test_core.py b/stix2/test/v21/test_core.py index 19aa275..bf45f32 100644 --- a/stix2/test/v21/test_core.py +++ b/stix2/test/v21/test_core.py @@ -3,6 +3,8 @@ import pytest import stix2 from stix2 import core, exceptions +from .constants import IDENTITY_ID, OBSERVED_DATA_ID + BUNDLE = { "type": "bundle", "id": "bundle--00000000-0000-4000-8000-000000000007", @@ -98,8 +100,8 @@ def test_register_marking_with_no_version(): def test_register_observable_with_default_version(): observed_data = stix2.v21.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -136,8 +138,8 @@ def test_register_observable_with_default_version(): def test_register_observable_extension_with_default_version(): observed_data = stix2.v21.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", diff --git a/stix2/test/v21/test_course_of_action.py b/stix2/test/v21/test_course_of_action.py index 5354d59..b86471a 100644 --- a/stix2/test/v21/test_course_of_action.py +++ b/stix2/test/v21/test_course_of_action.py @@ -6,13 +6,13 @@ import pytz import stix2 import stix2.exceptions -from .constants import COURSE_OF_ACTION_ID +from .constants import COURSE_OF_ACTION_ID, IDENTITY_ID EXPECTED = """{ "type": "course-of-action", "spec_version": "2.1", "id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", @@ -29,8 +29,8 @@ EXPECTED = """{ def test_course_of_action_example(): coa = stix2.v21.CourseOfAction( - id="course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=COURSE_OF_ACTION_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", name="Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", @@ -48,9 +48,9 @@ def test_course_of_action_example(): EXPECTED, { "created": "2016-04-06T20:03:48.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "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", + "id": COURSE_OF_ACTION_ID, "modified": "2016-04-06T20:03:48.000Z", "name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", "spec_version": "2.1", @@ -69,7 +69,7 @@ def test_parse_course_of_action(data): assert coa.id == COURSE_OF_ACTION_ID assert coa.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) assert coa.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) - assert coa.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert coa.created_by_ref == IDENTITY_ID assert coa.description == "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ..." assert coa.name == "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter" assert coa.action_type == "textual:text/plain" diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index 295520e..6e1e585 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -3,7 +3,7 @@ import pytest import stix2 import stix2.base -from .constants import FAKE_TIME, MARKING_DEFINITION_ID +from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID IDENTITY_CUSTOM_PROP = stix2.v21.Identity( name="John Smith", @@ -16,7 +16,7 @@ IDENTITY_CUSTOM_PROP = stix2.v21.Identity( def test_identity_custom_property(): with pytest.raises(ValueError) as excinfo: stix2.v21.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -27,7 +27,7 @@ def test_identity_custom_property(): with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo: stix2.v21.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -40,7 +40,7 @@ def test_identity_custom_property(): assert "Unexpected properties for Identity" in str(excinfo.value) identity = stix2.v21.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -55,7 +55,7 @@ def test_identity_custom_property(): def test_identity_custom_property_invalid(): with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo: stix2.v21.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -69,7 +69,7 @@ def test_identity_custom_property_invalid(): def test_identity_custom_property_allowed(): identity = stix2.v21.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11Z", modified="2015-12-21T19:59:11Z", name="John Smith", @@ -130,7 +130,7 @@ def test_custom_property_dict_in_bundled_object(): custom_identity = { 'type': 'identity', 'spec_version': '2.1', - 'id': 'identity--311b2d2d-f010-4473-83ec-1edf84858f4c', + 'id': IDENTITY_ID, 'created': '2015-12-21T19:59:11Z', 'name': 'John Smith', 'identity_class': 'individual', @@ -148,7 +148,7 @@ def test_custom_properties_dict_in_bundled_object(): custom_identity = { 'type': 'identity', 'spec_version': '2.1', - 'id': 'identity--311b2d2d-f010-4473-83ec-1edf84858f4c', + 'id': IDENTITY_ID, 'created': '2015-12-21T19:59:11Z', 'name': 'John Smith', 'identity_class': 'individual', diff --git a/stix2/test/v21/test_datastore_filesystem.py b/stix2/test/v21/test_datastore_filesystem.py index 2404f3f..34b1088 100644 --- a/stix2/test/v21/test_datastore_filesystem.py +++ b/stix2/test/v21/test_datastore_filesystem.py @@ -421,6 +421,8 @@ def test_filesystem_sink_add_objects_list(fs_sink, fs_source): def test_filesystem_sink_marking(fs_sink): marking = stix2.v21.MarkingDefinition( + id="marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da", + created="2017-01-20T00:00:00.000Z", definition_type="tlp", definition=stix2.v21.TLPMarking(tlp="green"), ) @@ -554,6 +556,8 @@ def test_filesystem_store_add_invalid_object(fs_store): def test_filesystem_store_add_marking(fs_store): marking = stix2.v21.MarkingDefinition( + id="marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da", + created="2017-01-20T00:00:00.000Z", definition_type="tlp", definition=stix2.v21.TLPMarking(tlp="green"), ) diff --git a/stix2/test/v21/test_datastore_filters.py b/stix2/test/v21/test_datastore_filters.py index 466d304..4b9878a 100644 --- a/stix2/test/v21/test_datastore_filters.py +++ b/stix2/test/v21/test_datastore_filters.py @@ -4,6 +4,8 @@ from stix2 import parse from stix2.datastore.filters import Filter, apply_common_filters from stix2.utils import STIXdatetime, parse_into_datetime +from .constants import OBSERVED_DATA_ID + stix_objs = [ { "created": "2017-01-27T13:49:53.997Z", @@ -72,7 +74,7 @@ stix_objs = [ { "type": "observed-data", "spec_version": "2.1", - "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", + "id": OBSERVED_DATA_ID, "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T19:58:16.000Z", "modified": "2016-04-06T19:58:16.000Z", @@ -444,7 +446,7 @@ def test_filters7(stix_objs2, real_stix_objs2): obsvd_data_obj = { "type": "observed-data", "spec_version": "2.1", - "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", + "id": OBSERVED_DATA_ID, "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T19:58:16.000Z", "modified": "2016-04-06T19:58:16.000Z", diff --git a/stix2/test/v21/test_datastore_memory.py b/stix2/test/v21/test_datastore_memory.py index eb30f07..b69d4d6 100644 --- a/stix2/test/v21/test_datastore_memory.py +++ b/stix2/test/v21/test_datastore_memory.py @@ -282,13 +282,13 @@ def test_memory_store_object_creator_of_present(mem_store): camp = Campaign( name="Scipio Africanus", objective="Defeat the Carthaginians", - created_by_ref="identity--e4196283-7420-4277-a7a3-d57f61ef1389", + created_by_ref=IDENTITY_ID, x_empire="Roman", allow_custom=True, ) iden = Identity( - id="identity--e4196283-7420-4277-a7a3-d57f61ef1389", + id=IDENTITY_ID, name="Foo Corp.", identity_class="corporation", ) diff --git a/stix2/test/v21/test_granular_markings.py b/stix2/test/v21/test_granular_markings.py index 9f7234e..e178f86 100644 --- a/stix2/test/v21/test_granular_markings.py +++ b/stix2/test/v21/test_granular_markings.py @@ -5,7 +5,7 @@ from stix2.exceptions import MarkingNotFoundError from stix2.v21 import TLP_RED, Malware from .constants import MALWARE_MORE_KWARGS as MALWARE_KWARGS_CONST -from .constants import MARKING_IDS +from .constants import MARKING_IDS, MARKING_LANGS """Tests for the Data Markings API.""" @@ -111,6 +111,37 @@ def test_add_marking_mark_multiple_selector_multiple_refs(): assert m in after["granular_markings"] +def test_add_marking_mark_multiple_selector_multiple_refs_mixed(): + before = Malware( + **MALWARE_KWARGS + ) + after = Malware( + granular_markings=[ + { + "selectors": ["description", "name"], + "marking_ref": MARKING_IDS[0], + }, + { + "selectors": ["description", "name"], + "marking_ref": MARKING_IDS[1], + }, + { + "selectors": ["description", "name"], + "lang": MARKING_LANGS[0], + }, + { + "selectors": ["description", "name"], + "lang": MARKING_LANGS[1], + }, + ], + **MALWARE_KWARGS + ) + before = markings.add_markings(before, [MARKING_IDS[0], MARKING_IDS[1], MARKING_LANGS[0], MARKING_LANGS[1]], ["description", "name"]) + + for m in before["granular_markings"]: + assert m in after["granular_markings"] + + def test_add_marking_mark_another_property_same_marking(): before = Malware( granular_markings=[ @@ -376,6 +407,98 @@ def test_get_markings_positional_arguments_combinations(data): assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"]) +GET_MARKINGS_TEST_DATA_LANGS = { + "a": 333, + "b": "value", + "c": [ + 17, + "list value", + { + "g": "nested", + "h": 45, + }, + ], + "x": { + "y": [ + "hello", + 88, + ], + "z": { + "foo1": "bar", + "foo2": 65, + }, + }, + "granular_markings": [ + { + "marking_ref": "m1", + "selectors": ["a"], + }, + { + "marking_ref": "m2", + "selectors": ["c"], + }, + { + "marking_ref": "m3", + "selectors": ["c.[1]"], + }, + { + "marking_ref": "m4", + "selectors": ["c.[2]"], + }, + { + "marking_ref": "m5", + "selectors": ["c.[2].g"], + }, + { + "marking_ref": "m6", + "selectors": ["x"], + }, + { + "lang": "l7", + "selectors": ["x.y"], + }, + { + "marking_ref": "m8", + "selectors": ["x.y.[1]"], + }, + { + "lang": "l9", + "selectors": ["x.z"], + }, + { + "marking_ref": "m9", + "selectors": ["x.z"], + }, + { + "marking_ref": "m10", + "selectors": ["x.z.foo2"], + }, + ], +} + + +@pytest.mark.parametrize("data", [GET_MARKINGS_TEST_DATA_LANGS]) +def test_get_markings_multiple_selectors_langs(data): + """Test multiple selectors return combination of markings.""" + total = markings.get_markings(data, ["x.y", "x.z"]) + xy_markings = markings.get_markings(data, ["x.y"]) + xz_markings = markings.get_markings(data, ["x.z"]) + + assert set(xy_markings).issubset(total) + assert set(xz_markings).issubset(total) + assert set(xy_markings).union(xz_markings).issuperset(total) + + +@pytest.mark.parametrize("data", [GET_MARKINGS_TEST_DATA_LANGS]) +def test_get_markings_multiple_selectors_with_options(data): + """Test multiple selectors return combination of markings.""" + total = markings.get_markings(data, ["x.y", "x.z"], lang=False) + xz_markings = markings.get_markings(data, ["x.z"], marking_ref=False) + + assert len(total) == 1 + assert len(xz_markings) == 1 + + @pytest.mark.parametrize( "data", [ ( @@ -455,6 +578,38 @@ def test_remove_marking_mark_one_selector_from_multiple_ones(): assert m in after["granular_markings"] +def test_remove_marking_mark_one_selector_from_multiple_ones_mixed(): + after = Malware( + granular_markings=[ + { + "selectors": ["description"], + "marking_ref": MARKING_IDS[0], + }, + { + "selectors": ["description"], + "lang": MARKING_LANGS[0], + }, + ], + **MALWARE_KWARGS + ) + before = Malware( + granular_markings=[ + { + "selectors": ["description", "modified"], + "marking_ref": MARKING_IDS[0], + }, + { + "selectors": ["description", "modified"], + "lang": MARKING_LANGS[0], + }, + ], + **MALWARE_KWARGS + ) + before = markings.remove_markings(before, [MARKING_IDS[0], MARKING_LANGS[0]], ["modified"]) + for m in before["granular_markings"]: + assert m in after["granular_markings"] + + def test_remove_marking_mark_one_selector_markings_from_multiple_ones(): after = Malware( granular_markings=[ @@ -592,6 +747,10 @@ IS_MARKED_TEST_DATA = [ "selectors": ["malware_types", "description"], "marking_ref": MARKING_IDS[3], }, + { + "selectors": ["name"], + "lang": MARKING_LANGS[1], + }, ], **MALWARE_KWARGS ), @@ -609,6 +768,10 @@ IS_MARKED_TEST_DATA = [ "selectors": ["malware_types", "description"], "marking_ref": MARKING_IDS[3], }, + { + "selectors": ["name"], + "lang": MARKING_LANGS[1], + }, ], **MALWARE_KWARGS ), @@ -620,6 +783,7 @@ def test_is_marked_smoke(data): """Smoke test is_marked call does not fail.""" assert markings.is_marked(data, selectors=["description"]) assert markings.is_marked(data, selectors=["modified"]) is False + assert markings.is_marked(data, selectors=["name"]) @pytest.mark.parametrize( @@ -666,6 +830,7 @@ def test_is_marked_valid_selector_and_refs(data): """Test that a valid selector returns True when marking_refs match.""" assert markings.is_marked(data, [MARKING_IDS[1]], ["description"]) assert markings.is_marked(data, [MARKING_IDS[1]], ["modified"]) is False + assert markings.is_marked(data, [MARKING_LANGS[1]], ["name"]) @pytest.mark.parametrize("data", IS_MARKED_TEST_DATA) @@ -870,6 +1035,28 @@ def test_set_marking_mark_one_selector_multiple_refs(): assert m in after["granular_markings"] +def test_set_marking_mark_one_selector_multiple_lang_refs(): + before = Malware( + **MALWARE_KWARGS + ) + after = Malware( + granular_markings=[ + { + "selectors": ["description"], + "lang": MARKING_LANGS[0], + }, + { + "selectors": ["description"], + "lang": MARKING_LANGS[1], + }, + ], + **MALWARE_KWARGS + ) + before = markings.set_markings(before, [MARKING_LANGS[0], MARKING_LANGS[1]], ["description"]) + for m in before["granular_markings"]: + assert m in after["granular_markings"] + + def test_set_marking_mark_multiple_selector_one_refs(): before = Malware( granular_markings=[ @@ -894,6 +1081,38 @@ def test_set_marking_mark_multiple_selector_one_refs(): assert m in after["granular_markings"] +def test_set_marking_mark_multiple_mixed_markings(): + before = Malware( + granular_markings=[ + { + "selectors": ["description", "modified"], + "marking_ref": MARKING_IDS[1], + }, + { + "selectors": ["description", "modified"], + "lang": MARKING_LANGS[2], + }, + ], + **MALWARE_KWARGS + ) + after = Malware( + granular_markings=[ + { + "selectors": ["description", "modified"], + "marking_ref": MARKING_IDS[2], + }, + { + "selectors": ["description", "modified"], + "lang": MARKING_LANGS[3], + }, + ], + **MALWARE_KWARGS + ) + before = markings.set_markings(before, [MARKING_IDS[2], MARKING_LANGS[3]], ["description", "modified"]) + for m in before["granular_markings"]: + assert m in after["granular_markings"] + + def test_set_marking_mark_multiple_selector_multiple_refs_from_none(): before = Malware( **MALWARE_KWARGS diff --git a/stix2/test/v21/test_identity.py b/stix2/test/v21/test_identity.py index da99de4..9d17723 100644 --- a/stix2/test/v21/test_identity.py +++ b/stix2/test/v21/test_identity.py @@ -20,7 +20,7 @@ EXPECTED = """{ def test_identity_example(): identity = stix2.v21.Identity( - id="identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + id=IDENTITY_ID, created="2015-12-21T19:59:11.000Z", modified="2015-12-21T19:59:11.000Z", name="John Smith", @@ -35,7 +35,7 @@ def test_identity_example(): EXPECTED, { "created": "2015-12-21T19:59:11.000Z", - "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + "id": IDENTITY_ID, "identity_class": "individual", "modified": "2015-12-21T19:59:11.000Z", "name": "John Smith", diff --git a/stix2/test/v21/test_indicator.py b/stix2/test/v21/test_indicator.py index a54ea62..49bc6e0 100644 --- a/stix2/test/v21/test_indicator.py +++ b/stix2/test/v21/test_indicator.py @@ -155,7 +155,7 @@ def test_created_modified_time_are_identical_by_default(): EXPECTED_INDICATOR, { "type": "indicator", - "id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", + "id": INDICATOR_ID, "created": "2017-01-01T00:00:01Z", "modified": "2017-01-01T00:00:01Z", "indicator_types": [ diff --git a/stix2/test/v21/test_intrusion_set.py b/stix2/test/v21/test_intrusion_set.py index d87780c..778eda7 100644 --- a/stix2/test/v21/test_intrusion_set.py +++ b/stix2/test/v21/test_intrusion_set.py @@ -5,13 +5,13 @@ import pytz import stix2 -from .constants import INTRUSION_SET_ID +from .constants import IDENTITY_ID, INTRUSION_SET_ID EXPECTED = """{ "type": "intrusion-set", "spec_version": "2.1", "id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "Bobcat Breakin", @@ -29,8 +29,8 @@ EXPECTED = """{ def test_intrusion_set_example(): intrusion_set = stix2.v21.IntrusionSet( - id="intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=INTRUSION_SET_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", name="Bobcat Breakin", @@ -50,14 +50,14 @@ def test_intrusion_set_example(): "Zookeeper", ], "created": "2016-04-06T20:03:48.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "description": "Incidents usually feature a shared TTP of a bobcat being released...", "goals": [ "acquisition-theft", "harassment", "damage", ], - "id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29", + "id": INTRUSION_SET_ID, "modified": "2016-04-06T20:03:48.000Z", "name": "Bobcat Breakin", "spec_version": "2.1", diff --git a/stix2/test/v21/test_location.py b/stix2/test/v21/test_location.py index 62fd9e0..c734334 100644 --- a/stix2/test/v21/test_location.py +++ b/stix2/test/v21/test_location.py @@ -50,7 +50,6 @@ def test_location_with_some_required_properties(): now = dt.datetime(2016, 4, 6, 20, 3, 0, tzinfo=pytz.utc) loc = stix2.v21.Location( - type="location", id=LOCATION_ID, created=now, modified=now, @@ -69,7 +68,7 @@ def test_location_with_some_required_properties(): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "region": "north-america", @@ -94,7 +93,7 @@ def test_parse_location(data): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "latitude": 90.01, @@ -103,7 +102,7 @@ def test_parse_location(data): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "latitude": -90.1, @@ -123,7 +122,7 @@ def test_location_bad_latitude(data): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "latitude": 80, @@ -132,7 +131,7 @@ def test_location_bad_latitude(data): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "latitude": 80, @@ -152,7 +151,7 @@ def test_location_bad_longitude(data): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "longitude": 175.7, @@ -161,7 +160,7 @@ def test_location_bad_longitude(data): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "latitude": 80, @@ -181,7 +180,7 @@ def test_location_properties_missing_when_precision_is_present(data): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "latitude": 18.468842, @@ -203,7 +202,7 @@ def test_location_negative_precision(data): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "latitude": 18.468842, @@ -215,7 +214,7 @@ def test_location_negative_precision(data): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "longitude": 160.7, @@ -238,7 +237,7 @@ def test_location_latitude_dependency_missing(data, msg): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "latitude": 18.468842, @@ -249,7 +248,7 @@ def test_location_latitude_dependency_missing(data, msg): { "type": "location", "spec_version": "2.1", - "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", + "id": LOCATION_ID, "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "longitude": 160.7, @@ -263,3 +262,100 @@ def test_location_lat_or_lon_dependency_missing(data, msg): stix2.parse(data) assert msg in str(excinfo.value) + + +def test_google_map_url_long_lat_provided(): + expected_url = "https://www.google.com/maps/search/?api=1&query=41.862401%2C-87.616001" + + loc = stix2.v21.Location( + latitude=41.862401, + longitude=-87.616001, + ) + + loc_url = loc.to_maps_url() + assert loc_url == expected_url + + +def test_google_map_url_multiple_props_no_long_lat_provided(): + expected_url = "https://www.google.com/maps/search/?api=1&query=1410+Museum+Campus+Drive%2C+Chicago%2C+IL+60605%2CUnited+States+of+America%2CNorth+America" + now = dt.datetime(2019, 2, 7, 12, 34, 56, tzinfo=pytz.utc) + + loc = stix2.v21.Location( + type="location", + id=LOCATION_ID, + created=now, + modified=now, + region="North America", + country="United States of America", + street_address="1410 Museum Campus Drive, Chicago, IL 60605", + ) + + loc_url = loc.to_maps_url() + assert loc_url == expected_url + + +def test_google_map_url_multiple_props_and_long_lat_provided(): + expected_url = "https://www.google.com/maps/search/?api=1&query=41.862401%2C-87.616001" + + loc = stix2.v21.Location( + region="North America", + country="United States of America", + street_address="1410 Museum Campus Drive, Chicago, IL 60605", + latitude=41.862401, + longitude=-87.616001, + ) + + loc_url = loc.to_maps_url() + assert loc_url == expected_url + + +def test_map_url_invalid_map_engine_provided(): + loc = stix2.v21.Location( + latitude=41.862401, + longitude=-87.616001, + ) + + with pytest.raises(ValueError) as excinfo: + loc.to_maps_url("Fake Maps") + + assert "is not a valid or currently-supported map engine" in str(excinfo.value) + + +def test_bing_map_url_long_lat_provided(): + expected_url = "https://bing.com/maps/default.aspx?where1=41.862401%2C-87.616001&lvl=16" + + loc = stix2.v21.Location( + latitude=41.862401, + longitude=-87.616001, + ) + + loc_url = loc.to_maps_url("Bing Maps") + assert loc_url == expected_url + + +def test_bing_map_url_multiple_props_no_long_lat_provided(): + expected_url = "https://bing.com/maps/default.aspx?where1=1410+Museum+Campus+Drive%2C+Chicago%2C+IL+60605%2CUnited+States+of+America%2CNorth+America&lvl=16" + + loc = stix2.v21.Location( + region="North America", + country="United States of America", + street_address="1410 Museum Campus Drive, Chicago, IL 60605", + ) + + loc_url = loc.to_maps_url("Bing Maps") + assert loc_url == expected_url + + +def test_bing_map_url_multiple_props_and_long_lat_provided(): + expected_url = "https://bing.com/maps/default.aspx?where1=41.862401%2C-87.616001&lvl=16" + + loc = stix2.v21.Location( + region="North America", + country="United States of America", + street_address="1410 Museum Campus Drive, Chicago, IL 60605", + latitude=41.862401, + longitude=-87.616001, + ) + + loc_url = loc.to_maps_url("Bing Maps") + assert loc_url == expected_url diff --git a/stix2/test/v21/test_malware.py b/stix2/test/v21/test_malware.py index 3ae96d9..c55bfa9 100644 --- a/stix2/test/v21/test_malware.py +++ b/stix2/test/v21/test_malware.py @@ -110,7 +110,7 @@ def test_invalid_kwarg_to_malware(): { "type": "malware", "spec_version": "2.1", - "id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", + "id": MALWARE_ID, "created": "2016-05-12T08:17:27.000Z", "modified": "2016-05-12T08:17:27.000Z", "malware_types": ["ransomware"], diff --git a/stix2/test/v21/test_marking_definition.py b/stix2/test/v21/test_marking_definition.py new file mode 100644 index 0000000..c497e99 --- /dev/null +++ b/stix2/test/v21/test_marking_definition.py @@ -0,0 +1,133 @@ + +import pytest + +from stix2 import exceptions +from stix2.v21 import ( + TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, MarkingDefinition, TLPMarking, +) + + +def test_bad_id_marking_tlp_white(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--4c9faac1-3558-43d2-919e-95c88d3bc332', + definition_type='tlp', + definition=TLPMarking(tlp='white'), + ) + + +def test_bad_id_marking_tlp_green(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--93023361-d3cf-4666-bca2-8c017948dc3d', + definition_type='tlp', + definition=TLPMarking(tlp='green'), + ) + + +def test_bad_id_marking_tlp_amber(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--05e32101-a940-42ba-8fe9-39283b999ce4', + definition_type='tlp', + definition=TLPMarking(tlp='amber'), + ) + + +def test_bad_id_marking_tlp_red(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--9eceb00c-c158-43f4-87f8-1e3648de17e2', + definition_type='tlp', + definition=TLPMarking(tlp='red'), + ) + + +def test_bad_created_marking_tlp_white(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9', + definition_type='tlp', + definition=TLPMarking(tlp='white'), + ) + + +def test_bad_created_marking_tlp_green(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da', + definition_type='tlp', + definition=TLPMarking(tlp='green'), + ) + + +def test_bad_created_marking_tlp_amber(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + id='marking-definition--f88d31f6-486f-44da-b317-01333bde0b82', + definition_type='tlp', + definition=TLPMarking(tlp='amber'), + ) + + +def test_bad_created_marking_tlp_red(): + with pytest.raises(exceptions.TLPMarkingDefinitionError) as excinfo: + MarkingDefinition( + id='marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed', + definition_type='tlp', + definition=TLPMarking(tlp='red'), + ) + + assert "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed" in str(excinfo.value) + + +def test_successful_tlp_white(): + white = MarkingDefinition( + id='marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9', + created='2017-01-20T00:00:00.000Z', + definition_type='tlp', + definition=TLPMarking(tlp='white'), + ) + + assert white.serialize(sort_keys=True) == TLP_WHITE.serialize(sort_keys=True) + + +def test_successful_tlp_green(): + green = MarkingDefinition( + id='marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da', + created='2017-01-20T00:00:00.000Z', + definition_type='tlp', + definition=TLPMarking(tlp='green'), + ) + + assert green.serialize(sort_keys=True) == TLP_GREEN.serialize(sort_keys=True) + + +def test_successful_tlp_amber(): + amber = MarkingDefinition( + id='marking-definition--f88d31f6-486f-44da-b317-01333bde0b82', + created='2017-01-20T00:00:00.000Z', + definition_type='tlp', + definition=TLPMarking(tlp='amber'), + ) + + assert amber.serialize(sort_keys=True) == TLP_AMBER.serialize(sort_keys=True) + + +def test_successful_tlp_red(): + red = MarkingDefinition( + id='marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed', + created='2017-01-20T00:00:00.000Z', + definition_type='tlp', + definition=TLPMarking(tlp='red'), + ) + + assert red.serialize(sort_keys=True) == TLP_RED.serialize(sort_keys=True) + + +def test_unknown_tlp_marking(): + with pytest.raises(exceptions.TLPMarkingDefinitionError): + MarkingDefinition( + definition_type='tlp', + definition=TLPMarking(tlp='gray'), + ) diff --git a/stix2/test/v21/test_markings.py b/stix2/test/v21/test_markings.py index 7782236..bd247e6 100644 --- a/stix2/test/v21/test_markings.py +++ b/stix2/test/v21/test_markings.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + import datetime as dt import pytest @@ -6,7 +8,7 @@ import pytz import stix2 from stix2.v21 import TLP_WHITE -from .constants import MARKING_DEFINITION_ID +from .constants import IDENTITY_ID, MARKING_DEFINITION_ID EXPECTED_TLP_MARKING_DEFINITION = """{ "type": "marking-definition", @@ -34,7 +36,7 @@ EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING = """{ "type": "campaign", "spec_version": "2.1", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "name": "Green Group Attacks Against Finance", @@ -54,11 +56,11 @@ EXPECTED_GRANULAR_MARKING = """{ ] }""" -EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS = """{ +EXPECTED_CAMPAIGN_WITH_GRANULAR_REF_MARKINGS = """{ "type": "campaign", "spec_version": "2.1", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:00.000Z", "modified": "2016-04-06T20:03:00.000Z", "name": "Green Group Attacks Against Finance", @@ -74,13 +76,34 @@ EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS = """{ }""" +EXPECTED_CAMPAIGN_WITH_GRANULAR_LANG_MARKINGS = u"""{ + "type": "campaign", + "spec_version": "2.1", + "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", + "created": "2016-04-06T20:03:00.000Z", + "modified": "2016-04-06T20:03:00.000Z", + "name": "Bank Attack", + "description": "Weitere Informationen über Banküberfall", + "lang": "en", + "granular_markings": [ + { + "lang": "de", + "selectors": [ + "description" + ] + } + ] +}""" + + def test_marking_def_example_with_tlp(): assert str(TLP_WHITE) == EXPECTED_TLP_MARKING_DEFINITION def test_marking_def_example_with_statement_positional_argument(): marking_definition = stix2.v21.MarkingDefinition( - id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + id=MARKING_DEFINITION_ID, created="2017-01-20T00:00:00.000Z", definition_type="statement", definition=stix2.StatementMarking(statement="Copyright 2016, Example Corp"), @@ -92,7 +115,7 @@ def test_marking_def_example_with_statement_positional_argument(): def test_marking_def_example_with_kwargs_statement(): kwargs = dict(statement="Copyright 2016, Example Corp") marking_definition = stix2.v21.MarkingDefinition( - id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + id=MARKING_DEFINITION_ID, created="2017-01-20T00:00:00.000Z", definition_type="statement", definition=stix2.StatementMarking(**kwargs), @@ -104,7 +127,7 @@ def test_marking_def_example_with_kwargs_statement(): def test_marking_def_invalid_type(): with pytest.raises(ValueError): stix2.v21.MarkingDefinition( - id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + id=MARKING_DEFINITION_ID, created="2017-01-20T00:00:00.000Z", definition_type="my-definition-type", definition=stix2.StatementMarking("Copyright 2016, Example Corp"), @@ -114,7 +137,7 @@ def test_marking_def_invalid_type(): def test_campaign_with_markings_example(): campaign = stix2.v21.Campaign( id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:00Z", modified="2016-04-06T20:03:00Z", name="Green Group Attacks Against Finance", @@ -126,7 +149,7 @@ def test_campaign_with_markings_example(): def test_granular_example(): granular_marking = stix2.v21.GranularMarking( - marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + marking_ref=MARKING_DEFINITION_ID, selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"], ) @@ -136,7 +159,7 @@ def test_granular_example(): def test_granular_example_with_bad_selector(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v21.GranularMarking( - marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + marking_ref=MARKING_DEFINITION_ID, selectors=["abc[0]"], # missing "." ) @@ -149,26 +172,26 @@ def test_granular_example_with_bad_selector(): def test_campaign_with_granular_markings_example(): campaign = stix2.v21.Campaign( id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + created_by_ref=IDENTITY_ID, 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.", granular_markings=[ stix2.v21.GranularMarking( - marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + marking_ref=MARKING_DEFINITION_ID, selectors=["description"], ), ], ) - assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS + assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_REF_MARKINGS @pytest.mark.parametrize( "data", [ EXPECTED_TLP_MARKING_DEFINITION, { - "id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", + "id": MARKING_DEFINITION_ID, "spec_version": "2.1", "type": "marking-definition", "created": "2017-01-20T00:00:00Z", @@ -265,7 +288,7 @@ def test_marking_wrong_type_construction(): def test_campaign_add_markings(): campaign = stix2.v21.Campaign( id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:00Z", modified="2016-04-06T20:03:00Z", name="Green Group Attacks Against Finance", @@ -273,3 +296,26 @@ def test_campaign_add_markings(): ) campaign = campaign.add_markings(TLP_WHITE) assert campaign.object_marking_refs[0] == TLP_WHITE.id + + +def test_campaign_with_granular_lang_markings_example(): + campaign = stix2.v21.Campaign( + id="campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + created_by_ref=IDENTITY_ID, + created="2016-04-06T20:03:00Z", + modified="2016-04-06T20:03:00Z", + name="Bank Attack", + lang="en", + description="Weitere Informationen über Banküberfall", + granular_markings=[ + stix2.v21.GranularMarking( + lang="de", + selectors=["description"], + ), + ], + ) + + # In order to provide the same representation, we need to disable escaping + # in json.dumps(). https://docs.python.org/3/library/json.html#json.dumps + # or https://docs.python.org/2/library/json.html#json.dumps + assert campaign.serialize(pretty=True, ensure_ascii=False) == EXPECTED_CAMPAIGN_WITH_GRANULAR_LANG_MARKINGS diff --git a/stix2/test/v21/test_note.py b/stix2/test/v21/test_note.py index a9807e8..47a191e 100644 --- a/stix2/test/v21/test_note.py +++ b/stix2/test/v21/test_note.py @@ -84,7 +84,7 @@ def test_note_with_required_properties(): { "type": "note", "spec_version": "2.1", - "id": "note--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + "id": NOTE_ID, "created": "2016-05-12T08:17:27.000Z", "modified": "2016-05-12T08:17:27.000Z", "abstract": "Tracking Team Note#1", @@ -93,7 +93,7 @@ def test_note_with_required_properties(): "John Doe", ], "object_refs": [ - "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + CAMPAIGN_ID, ], "external_references": [ { diff --git a/stix2/test/v21/test_object_markings.py b/stix2/test/v21/test_object_markings.py index d43aad5..7b19d4f 100644 --- a/stix2/test/v21/test_object_markings.py +++ b/stix2/test/v21/test_object_markings.py @@ -106,7 +106,6 @@ def test_add_markings_combination(): "data", [ ([""]), (""), - ([]), ([MARKING_IDS[0], 456]), ], ) @@ -575,7 +574,6 @@ def test_set_marking(): @pytest.mark.parametrize( "data", [ - ([]), ([""]), (""), ([MARKING_IDS[4], 687]), diff --git a/stix2/test/v21/test_observed_data.py b/stix2/test/v21/test_observed_data.py index 8dd4487..09e6a67 100644 --- a/stix2/test/v21/test_observed_data.py +++ b/stix2/test/v21/test_observed_data.py @@ -7,7 +7,7 @@ import pytz import stix2 import stix2.exceptions -from .constants import OBSERVED_DATA_ID +from .constants import IDENTITY_ID, OBSERVED_DATA_ID OBJECTS_REGEX = re.compile('\"objects\": {(?:.*?)(?:(?:[^{]*?)|(?:{[^{]*?}))*}', re.DOTALL) @@ -16,7 +16,7 @@ EXPECTED = """{ "type": "observed-data", "spec_version": "2.1", "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T19:58:16.000Z", "modified": "2016-04-06T19:58:16.000Z", "first_observed": "2015-12-21T19:00:00Z", @@ -33,8 +33,8 @@ EXPECTED = """{ def test_observed_data_example(): observed_data = stix2.v21.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -55,7 +55,7 @@ EXPECTED_WITH_REF = """{ "type": "observed-data", "spec_version": "2.1", "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T19:58:16.000Z", "modified": "2016-04-06T19:58:16.000Z", "first_observed": "2015-12-21T19:00:00Z", @@ -79,8 +79,8 @@ EXPECTED_WITH_REF = """{ def test_observed_data_example_with_refs(): observed_data = stix2.v21.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -166,8 +166,8 @@ def test_observed_data_object_constraint(): def test_observed_data_example_with_bad_refs(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v21.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -194,8 +194,8 @@ def test_observed_data_example_with_bad_refs(): def test_observed_data_example_with_non_dictionary(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v21.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -212,8 +212,8 @@ def test_observed_data_example_with_non_dictionary(): def test_observed_data_example_with_empty_dictionary(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v21.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -233,9 +233,9 @@ def test_observed_data_example_with_empty_dictionary(): { "type": "observed-data", "spec_version": "2.1", - "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", + "id": OBSERVED_DATA_ID, "created": "2016-04-06T19:58:16.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "first_observed": "2015-12-21T19:00:00Z", "last_observed": "2015-12-21T19:00:00Z", "modified": "2016-04-06T19:58:16.000Z", @@ -259,7 +259,7 @@ def test_parse_observed_data(data): assert odata.modified == dt.datetime(2016, 4, 6, 19, 58, 16, tzinfo=pytz.utc) assert odata.first_observed == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc) assert odata.last_observed == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc) - assert odata.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert odata.created_by_ref == IDENTITY_ID assert odata.objects["0"].type == "file" @@ -599,7 +599,7 @@ def test_parse_basic_tcp_traffic_with_error(data): EXPECTED_PROCESS_OD = """{ "created": "2016-04-06T19:58:16.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "first_observed": "2015-12-21T19:00:00Z", "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", "last_observed": "2015-12-21T19:00:00Z", @@ -627,8 +627,8 @@ EXPECTED_PROCESS_OD = """{ def test_observed_data_with_process_example(): observed_data = stix2.v21.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=OBSERVED_DATA_ID, + 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", @@ -1002,6 +1002,24 @@ def test_ip4_address_example(): assert ip4.resolves_to_refs == ["4", "5"] +def test_ip4_address_valid_refs(): + mac1 = stix2.v21.MACAddress( + value="a1:b2:c3:d4:e5:f6", + ) + mac2 = stix2.v21.MACAddress( + value="a7:b8:c9:d0:e1:f2", + ) + + ip4 = stix2.v21.IPv4Address( + _valid_refs={"1": mac1, "2": mac2}, + value="177.60.40.7", + resolves_to_refs=["1", "2"], + ) + + assert ip4.value == "177.60.40.7" + assert ip4.resolves_to_refs == ["1", "2"] + + def test_ip4_address_example_cidr(): ip4 = stix2.v21.IPv4Address(value="198.51.100.0/24") @@ -1177,12 +1195,12 @@ def test_process_example_windows_process_ext_empty(): def test_process_example_extensions_empty(): - with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: - stix2.v21.Process(extensions={}) + proc = stix2.v21.Process( + pid=314, + extensions={}, + ) - assert excinfo.value.cls == stix2.v21.Process - assert excinfo.value.prop_name == 'extensions' - assert 'non-empty dictionary' in excinfo.value.reason + assert '{}' in str(proc) def test_process_example_with_WindowsProcessExt_Object(): @@ -1326,6 +1344,8 @@ def test_windows_registry_key_example(): assert w.values[0].name == "Foo" assert w.values[0].data == "qwerty" assert w.values[0].data_type == "REG_SZ" + # ensure no errors in serialization because of 'values' + assert "Foo" in str(w) def test_x509_certificate_example(): diff --git a/stix2/test/v21/test_opinion.py b/stix2/test/v21/test_opinion.py index 79e97ca..b2f6dc0 100644 --- a/stix2/test/v21/test_opinion.py +++ b/stix2/test/v21/test_opinion.py @@ -66,7 +66,7 @@ def test_opinion_with_required_properties(): { "type": "opinion", "spec_version": "2.1", - "id": "opinion--b01efc25-77b4-4003-b18b-f6e24b5cd9f7", + "id": OPINION_ID, "created": "2016-05-12T08:17:27.000Z", "modified": "2016-05-12T08:17:27.000Z", "explanation": EXPLANATION, diff --git a/stix2/test/v21/test_pickle.py b/stix2/test/v21/test_pickle.py index 0dc1c4c..faef4c4 100644 --- a/stix2/test/v21/test_pickle.py +++ b/stix2/test/v21/test_pickle.py @@ -2,13 +2,15 @@ import pickle import stix2 +from .constants import IDENTITY_ID + def test_pickling(): """ Ensure a pickle/unpickle cycle works okay. """ identity = stix2.v21.Identity( - id="identity--d66cb89d-5228-4983-958c-fa84ef75c88c", + id=IDENTITY_ID, name="alice", description="this is a pickle test", identity_class="some_class", diff --git a/stix2/test/v21/test_properties.py b/stix2/test/v21/test_properties.py index 3e4ee92..557e419 100644 --- a/stix2/test/v21/test_properties.py +++ b/stix2/test/v21/test_properties.py @@ -373,7 +373,6 @@ def test_dictionary_property_invalid_key(d): @pytest.mark.parametrize( "d", [ - ({}, "The dictionary property must contain a non-empty dictionary"), # TODO: This error message could be made more helpful. The error is caused # because `json.loads()` doesn't like the *single* quotes around the key # name, even though they are valid in a Python dictionary. While technically @@ -455,6 +454,11 @@ def test_enum_property_valid(value): assert enum_prop.clean('b') +def test_enum_property_clean(): + enum_prop = EnumProperty(['1']) + assert enum_prop.clean(1) == '1' + + def test_enum_property_invalid(): enum_prop = EnumProperty(['a', 'b', 'c']) with pytest.raises(ValueError): diff --git a/stix2/test/v21/test_relationship.py b/stix2/test/v21/test_relationship.py index 0ec3e08..386e24b 100644 --- a/stix2/test/v21/test_relationship.py +++ b/stix2/test/v21/test_relationship.py @@ -162,11 +162,11 @@ def test_create_relationship_with_positional_args(indicator, malware): EXPECTED_RELATIONSHIP, { "created": "2016-04-06T20:06:37Z", - "id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301", + "id": RELATIONSHIP_ID, "modified": "2016-04-06T20:06:37Z", "relationship_type": "indicates", - "source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", - "target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", + "source_ref": INDICATOR_ID, + "target_ref": MALWARE_ID, "spec_version": "2.1", "type": "relationship", }, @@ -181,19 +181,19 @@ def test_parse_relationship(data): assert rel.created == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) assert rel.modified == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) assert rel.relationship_type == "indicates" - assert rel.source_ref == "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7" - assert rel.target_ref == "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e" + assert rel.source_ref == INDICATOR_ID + assert rel.target_ref == MALWARE_ID @pytest.mark.parametrize( "data", [ { "created": "2016-04-06T20:06:37Z", - "id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301", + "id": RELATIONSHIP_ID, "modified": "2016-04-06T20:06:37Z", "relationship_type": "indicates", - "source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", - "target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", + "source_ref": INDICATOR_ID, + "target_ref": MALWARE_ID, "start_time": "2018-04-06T20:06:37Z", "stop_time": "2016-04-06T20:06:37Z", "spec_version": "2.1", diff --git a/stix2/test/v21/test_report.py b/stix2/test/v21/test_report.py index 8b7ee78..e54e11d 100644 --- a/stix2/test/v21/test_report.py +++ b/stix2/test/v21/test_report.py @@ -5,13 +5,16 @@ import pytz import stix2 -from .constants import INDICATOR_KWARGS, REPORT_ID +from .constants import ( + CAMPAIGN_ID, IDENTITY_ID, INDICATOR_ID, INDICATOR_KWARGS, RELATIONSHIP_ID, + REPORT_ID, +) EXPECTED = """{ "type": "report", "spec_version": "2.1", "id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", - "created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2015-12-21T19:59:11.000Z", "modified": "2015-12-21T19:59:11.000Z", "name": "The Black Vine Cyberespionage Group", @@ -21,17 +24,17 @@ EXPECTED = """{ ], "published": "2016-01-20T17:00:00Z", "object_refs": [ - "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" + "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", + "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "relationship--df7c87eb-75d2-4948-af81-9d49d246f301" ] }""" def test_report_example(): report = stix2.v21.Report( - id="report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", - created_by_ref="identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + id=REPORT_ID, + created_by_ref=IDENTITY_ID, created="2015-12-21T19:59:11.000Z", modified="2015-12-21T19:59:11.000Z", name="The Black Vine Cyberespionage Group", @@ -39,9 +42,9 @@ def test_report_example(): published="2016-01-20T17:00:00Z", report_types=["campaign"], object_refs=[ - "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + INDICATOR_ID, + CAMPAIGN_ID, + RELATIONSHIP_ID, ], ) @@ -50,8 +53,8 @@ def test_report_example(): def test_report_example_objects_in_object_refs(): report = stix2.v21.Report( - id="report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", - created_by_ref="identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + id=REPORT_ID, + created_by_ref=IDENTITY_ID, created="2015-12-21T19:59:11.000Z", modified="2015-12-21T19:59:11.000Z", name="The Black Vine Cyberespionage Group", @@ -59,9 +62,9 @@ def test_report_example_objects_in_object_refs(): published="2016-01-20T17:00:00Z", report_types=["campaign"], object_refs=[ - stix2.v21.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS), - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + stix2.v21.Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS), + CAMPAIGN_ID, + RELATIONSHIP_ID, ], ) @@ -71,8 +74,8 @@ def test_report_example_objects_in_object_refs(): def test_report_example_objects_in_object_refs_with_bad_id(): with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: stix2.v21.Report( - id="report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", - created_by_ref="identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + id=REPORT_ID, + created_by_ref=IDENTITY_ID, created="2015-12-21T19:59:11.000Z", modified="2015-12-21T19:59:11.000Z", name="The Black Vine Cyberespionage Group", @@ -80,9 +83,9 @@ def test_report_example_objects_in_object_refs_with_bad_id(): published="2016-01-20T17:00:00Z", report_types=["campaign"], object_refs=[ - stix2.v21.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS), + stix2.v21.Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS), "campaign-83422c77-904c-4dc1-aff5-5c38f3a2c55c", # the "bad" id, missing a "-" - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + RELATIONSHIP_ID, ], ) @@ -95,18 +98,18 @@ def test_report_example_objects_in_object_refs_with_bad_id(): EXPECTED, { "created": "2015-12-21T19:59:11.000Z", - "created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + "created_by_ref": IDENTITY_ID, "description": "A simple report with an indicator and campaign", - "id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", + "id": REPORT_ID, "report_types": [ "campaign", ], "modified": "2015-12-21T19:59:11.000Z", "name": "The Black Vine Cyberespionage Group", "object_refs": [ - "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + INDICATOR_ID, + CAMPAIGN_ID, + RELATIONSHIP_ID, ], "published": "2016-01-20T17:00:00Z", "spec_version": "2.1", @@ -122,11 +125,11 @@ def test_parse_report(data): assert rept.id == REPORT_ID assert rept.created == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) assert rept.modified == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) - assert rept.created_by_ref == "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283" + assert rept.created_by_ref == IDENTITY_ID assert rept.object_refs == [ - "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", - "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", - "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a", + INDICATOR_ID, + CAMPAIGN_ID, + RELATIONSHIP_ID, ] assert rept.description == "A simple report with an indicator and campaign" assert rept.report_types == ["campaign"] diff --git a/stix2/test/v21/test_sighting.py b/stix2/test/v21/test_sighting.py index cfdc7ea..0493b71 100644 --- a/stix2/test/v21/test_sighting.py +++ b/stix2/test/v21/test_sighting.py @@ -5,7 +5,7 @@ import pytz import stix2 -from .constants import INDICATOR_ID, SIGHTING_ID, SIGHTING_KWARGS +from .constants import IDENTITY_ID, INDICATOR_ID, SIGHTING_ID, SIGHTING_KWARGS EXPECTED_SIGHTING = """{ "type": "sighting", @@ -15,7 +15,7 @@ EXPECTED_SIGHTING = """{ "modified": "2016-04-06T20:06:37.000Z", "sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "where_sighted_refs": [ - "identity--8cc7afd6-5455-4d2b-a736-e614ee631d99" + "identity--311b2d2d-f010-4473-83ec-1edf84858f4c" ] }""" @@ -41,7 +41,7 @@ def test_sighting_all_required_properties(): created=now, modified=now, sighting_of_ref=INDICATOR_ID, - where_sighted_refs=["identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"], + where_sighted_refs=[IDENTITY_ID], ) assert str(s) == EXPECTED_SIGHTING @@ -94,13 +94,13 @@ def test_create_sighting_from_objects_rather_than_ids(malware): # noqa: F811 EXPECTED_SIGHTING, { "created": "2016-04-06T20:06:37Z", - "id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb", + "id": SIGHTING_ID, "modified": "2016-04-06T20:06:37Z", "sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "spec_version": "2.1", "type": "sighting", "where_sighted_refs": [ - "identity--8cc7afd6-5455-4d2b-a736-e614ee631d99", + IDENTITY_ID, ], }, ], @@ -113,5 +113,5 @@ def test_parse_sighting(data): assert sighting.id == SIGHTING_ID assert sighting.created == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) assert sighting.modified == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) - assert sighting.sighting_of_ref == "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7" - assert sighting.where_sighted_refs == ["identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"] + assert sighting.sighting_of_ref == INDICATOR_ID + assert sighting.where_sighted_refs == [IDENTITY_ID] diff --git a/stix2/test/v21/test_threat_actor.py b/stix2/test/v21/test_threat_actor.py index a7a29f8..5468731 100644 --- a/stix2/test/v21/test_threat_actor.py +++ b/stix2/test/v21/test_threat_actor.py @@ -5,13 +5,13 @@ import pytz import stix2 -from .constants import THREAT_ACTOR_ID +from .constants import IDENTITY_ID, THREAT_ACTOR_ID EXPECTED = """{ "type": "threat-actor", "spec_version": "2.1", "id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "Evil Org", @@ -24,8 +24,8 @@ EXPECTED = """{ def test_threat_actor_example(): threat_actor = stix2.v21.ThreatActor( - id="threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=THREAT_ACTOR_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", name="Evil Org", @@ -41,9 +41,9 @@ def test_threat_actor_example(): EXPECTED, { "created": "2016-04-06T20:03:48.000Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": IDENTITY_ID, "description": "The Evil Org threat actor group", - "id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "id": THREAT_ACTOR_ID, "threat_actor_types": [ "crime-syndicate", ], @@ -62,7 +62,7 @@ def test_parse_threat_actor(data): assert actor.id == THREAT_ACTOR_ID assert actor.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) assert actor.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) - assert actor.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert actor.created_by_ref == IDENTITY_ID assert actor.description == "The Evil Org threat actor group" assert actor.name == "Evil Org" assert actor.threat_actor_types == ["crime-syndicate"] diff --git a/stix2/test/v21/test_tool.py b/stix2/test/v21/test_tool.py index 9258a23..6a7d89c 100644 --- a/stix2/test/v21/test_tool.py +++ b/stix2/test/v21/test_tool.py @@ -5,13 +5,13 @@ import pytz import stix2 -from .constants import TOOL_ID +from .constants import IDENTITY_ID, TOOL_ID EXPECTED = """{ "type": "tool", "spec_version": "2.1", "id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "VNC", @@ -24,7 +24,7 @@ EXPECTED_WITH_REVOKED = """{ "type": "tool", "spec_version": "2.1", "id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "created_by_ref": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2016-04-06T20:03:48.000Z", "modified": "2016-04-06T20:03:48.000Z", "name": "VNC", @@ -37,8 +37,8 @@ EXPECTED_WITH_REVOKED = """{ def test_tool_example(): tool = stix2.v21.Tool( - id="tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=TOOL_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", name="VNC", @@ -53,8 +53,8 @@ def test_tool_example(): EXPECTED, { "created": "2016-04-06T20:03:48Z", - "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", - "id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "created_by_ref": IDENTITY_ID, + "id": TOOL_ID, "tool_types": [ "remote-access", ], @@ -73,7 +73,7 @@ def test_parse_tool(data): assert tool.id == TOOL_ID assert tool.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) assert tool.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) - assert tool.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert tool.created_by_ref == IDENTITY_ID assert tool.tool_types == ["remote-access"] assert tool.name == "VNC" @@ -86,8 +86,8 @@ def test_tool_no_workbench_wrappers(): def test_tool_serialize_with_defaults(): tool = stix2.v21.Tool( - id="tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + id=TOOL_ID, + created_by_ref=IDENTITY_ID, created="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z", name="VNC", diff --git a/stix2/test/v21/test_utils.py b/stix2/test/v21/test_utils.py index 96a06d3..dec3294 100644 --- a/stix2/test/v21/test_utils.py +++ b/stix2/test/v21/test_utils.py @@ -8,6 +8,8 @@ import pytz import stix2.utils +from .constants import IDENTITY_ID + amsterdam = pytz.timezone('Europe/Amsterdam') eastern = pytz.timezone('US/Eastern') @@ -123,7 +125,7 @@ def test_deduplicate(stix_objs1): ( stix2.v21.ObservedData( id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + 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", diff --git a/stix2/test/v21/test_vulnerability.py b/stix2/test/v21/test_vulnerability.py index 9c618e5..ee63a0e 100644 --- a/stix2/test/v21/test_vulnerability.py +++ b/stix2/test/v21/test_vulnerability.py @@ -25,7 +25,7 @@ EXPECTED = """{ def test_vulnerability_example(): vulnerability = stix2.v21.Vulnerability( - id="vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + id=VULNERABILITY_ID, created="2016-05-12T08:17:27.000Z", modified="2016-05-12T08:17:27.000Z", name="CVE-2016-1234", @@ -51,7 +51,7 @@ def test_vulnerability_example(): "source_name": "cve", }, ], - "id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + "id": VULNERABILITY_ID, "modified": "2016-05-12T08:17:27Z", "name": "CVE-2016-1234", "spec_version": "2.1", diff --git a/stix2/v20/__init__.py b/stix2/v20/__init__.py index bef7d66..4d0a98f 100644 --- a/stix2/v20/__init__.py +++ b/stix2/v20/__init__.py @@ -1,4 +1,16 @@ -"""STIX 2.0 API Objects.""" +"""STIX 2.0 API Objects. + +.. autosummary:: + :toctree: v20 + + bundle + common + observables + sdo + sro + +| +""" # flake8: noqa diff --git a/stix2/v20/bundle.py b/stix2/v20/bundle.py index fe6b62e..9e0b313 100644 --- a/stix2/v20/bundle.py +++ b/stix2/v20/bundle.py @@ -35,3 +35,21 @@ class Bundle(_STIXBase): self._properties['objects'].contained.allow_custom = kwargs.get('allow_custom', False) super(Bundle, self).__init__(**kwargs) + + def get_obj(self, obj_uuid): + if "objects" in self._inner: + found_objs = [elem for elem in self.objects if elem.id == obj_uuid] + if found_objs == []: + raise KeyError("'%s' does not match the id property of any of the bundle's objects" % obj_uuid) + return found_objs + else: + raise KeyError("There are no objects in this empty bundle") + + def __getitem__(self, key): + try: + return super(Bundle, self).__getitem__(key) + except KeyError: + try: + return self.get_obj(key) + except KeyError: + raise KeyError("'%s' is neither a property on the bundle nor does it match the id property of any of the bundle's objects" % key) diff --git a/stix2/v20/common.py b/stix2/v20/common.py index b8149a2..c2dedfb 100644 --- a/stix2/v20/common.py +++ b/stix2/v20/common.py @@ -6,6 +6,7 @@ import copy from ..base import _STIXBase from ..custom import _custom_marking_builder from ..markings import _MarkingsMixin +from ..markings.utils import check_tlp_marking from ..properties import ( HashesProperty, IDProperty, ListProperty, Property, ReferenceProperty, SelectorProperty, StringProperty, TimestampProperty, TypeProperty, @@ -134,6 +135,14 @@ class MarkingDefinition(_STIXBase, _MarkingsMixin): super(MarkingDefinition, self).__init__(**kwargs) + def _check_object_constraints(self): + super(MarkingDefinition, self)._check_object_constraints() + check_tlp_marking(self, '2.0') + + def serialize(self, pretty=False, include_optional_defaults=False, **kwargs): + check_tlp_marking(self, '2.0') + return super(MarkingDefinition, self).serialize(pretty, include_optional_defaults, **kwargs) + OBJ_MAP_MARKING = { 'tlp': TLPMarking, diff --git a/stix2/v20/observables.py b/stix2/v20/observables.py index ba28214..dc2b4aa 100644 --- a/stix2/v20/observables.py +++ b/stix2/v20/observables.py @@ -12,7 +12,7 @@ from ..base import _Extension, _Observable, _STIXBase from ..custom import _custom_extension_builder, _custom_observable_builder from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError from ..properties import ( - BinaryProperty, BooleanProperty, DictionaryProperty, + BinaryProperty, BooleanProperty, CallableValues, DictionaryProperty, EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty, HashesProperty, HexProperty, IntegerProperty, ListProperty, ObjectReferenceProperty, StringProperty, TimestampProperty, TypeProperty, @@ -726,7 +726,7 @@ class WindowsRegistryKey(_Observable): @property def values(self): # Needed because 'values' is a property on collections.Mapping objects - return self._inner['values'] + return CallableValues(self, self._inner['values']) class X509V3ExtenstionsType(_STIXBase): diff --git a/stix2/v21/__init__.py b/stix2/v21/__init__.py index 4a8fe29..c1caae4 100644 --- a/stix2/v21/__init__.py +++ b/stix2/v21/__init__.py @@ -1,4 +1,16 @@ -"""STIX 2.1 API Objects.""" +"""STIX 2.1 API Objects. + +.. autosummary:: + :toctree: v21 + + bundle + common + observables + sdo + sro + +| +""" # flake8: noqa diff --git a/stix2/v21/bundle.py b/stix2/v21/bundle.py index c84058e..4ebd96c 100644 --- a/stix2/v21/bundle.py +++ b/stix2/v21/bundle.py @@ -33,3 +33,21 @@ class Bundle(_STIXBase): self._properties['objects'].contained.allow_custom = kwargs.get('allow_custom', False) super(Bundle, self).__init__(**kwargs) + + def get_obj(self, obj_uuid): + if "objects" in self._inner: + found_objs = [elem for elem in self.objects if elem.id == obj_uuid] + if found_objs == []: + raise KeyError("'%s' does not match the id property of any of the bundle's objects" % obj_uuid) + return found_objs + else: + raise KeyError("There are no objects in this empty bundle") + + def __getitem__(self, key): + try: + return super(Bundle, self).__getitem__(key) + except KeyError: + try: + return self.get_obj(key) + except KeyError: + raise KeyError("'%s' is neither a property on the bundle nor does it match the id property of any of the bundle's objects" % key) diff --git a/stix2/v21/common.py b/stix2/v21/common.py index 110529e..f85bf88 100644 --- a/stix2/v21/common.py +++ b/stix2/v21/common.py @@ -6,6 +6,7 @@ import copy from ..base import _STIXBase from ..custom import _custom_marking_builder from ..markings import _MarkingsMixin +from ..markings.utils import check_tlp_marking from ..properties import ( BooleanProperty, DictionaryProperty, HashesProperty, IDProperty, IntegerProperty, ListProperty, Property, ReferenceProperty, @@ -174,6 +175,14 @@ class MarkingDefinition(_STIXBase, _MarkingsMixin): super(MarkingDefinition, self).__init__(**kwargs) + def _check_object_constraints(self): + super(MarkingDefinition, self)._check_object_constraints() + check_tlp_marking(self, '2.1') + + def serialize(self, pretty=False, include_optional_defaults=False, **kwargs): + check_tlp_marking(self, '2.1') + return super(MarkingDefinition, self).serialize(pretty, include_optional_defaults, **kwargs) + OBJ_MAP_MARKING = { 'tlp': TLPMarking, diff --git a/stix2/v21/observables.py b/stix2/v21/observables.py index 1b2251d..f383899 100644 --- a/stix2/v21/observables.py +++ b/stix2/v21/observables.py @@ -12,7 +12,7 @@ from ..base import _Extension, _Observable, _STIXBase from ..custom import _custom_extension_builder, _custom_observable_builder from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError from ..properties import ( - BinaryProperty, BooleanProperty, DictionaryProperty, + BinaryProperty, BooleanProperty, CallableValues, DictionaryProperty, EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty, HashesProperty, HexProperty, IntegerProperty, ListProperty, ObjectReferenceProperty, StringProperty, TimestampProperty, TypeProperty, @@ -779,7 +779,7 @@ class WindowsRegistryKey(_Observable): @property def values(self): # Needed because 'values' is a property on collections.Mapping objects - return self._inner['values'] + return CallableValues(self, self._inner['values']) class X509V3ExtenstionsType(_STIXBase): diff --git a/stix2/v21/sdo.py b/stix2/v21/sdo.py index 46ce231..522aeda 100644 --- a/stix2/v21/sdo.py +++ b/stix2/v21/sdo.py @@ -3,6 +3,8 @@ from collections import OrderedDict import itertools +from six.moves.urllib.parse import quote_plus + from ..core import STIXDomainObject from ..custom import _custom_object_builder from ..properties import ( @@ -275,6 +277,56 @@ class Location(STIXDomainObject): self._check_properties_dependency(['latitude'], ['longitude']) self._check_properties_dependency(['longitude'], ['latitude']) + def to_maps_url(self, map_engine="Google Maps"): + """Return URL to this location in an online map engine. + + Google Maps is the default, but Bing maps are also supported. + + Args: + map_engine (str): Which map engine to find the location in + + Returns: + The URL of the location in the given map engine. + + """ + params = [] + + latitude = self.get('latitude', None) + longitude = self.get('longitude', None) + if latitude is not None and longitude is not None: + params.extend([str(latitude), str(longitude)]) + else: + properties = ['street_address', 'city', 'country', 'region', 'administrative_area', 'postal_code'] + params = [self.get(prop) for prop in properties if self.get(prop) is not None] + + return self._to_maps_url_dispatcher(map_engine, params) + + def _to_maps_url_dispatcher(self, map_engine, params): + if map_engine == "Google Maps": + return self._to_google_maps_url(params) + elif map_engine == "Bing Maps": + return self._to_bing_maps_url(params) + else: + raise ValueError(map_engine + " is not a valid or currently-supported map engine") + + def _to_google_maps_url(self, params): + url_base = "https://www.google.com/maps/search/?api=1&query=" + url_ending = params[0] + for i in range(1, len(params)): + url_ending = url_ending + "," + params[i] + + final_url = url_base + quote_plus(url_ending) + return final_url + + def _to_bing_maps_url(self, params): + url_base = "https://bing.com/maps/default.aspx?where1=" + url_ending = params[0] + for i in range(1, len(params)): + url_ending = url_ending + "," + params[i] + + final_url = url_base + quote_plus(url_ending) + "&lvl=16" # level 16 zoom so long/lat searches shown more clearly + return final_url + class Malware(STIXDomainObject): # TODO: Add link diff --git a/stix2/version.py b/stix2/version.py index 6849410..72f26f5 100644 --- a/stix2/version.py +++ b/stix2/version.py @@ -1 +1 @@ -__version__ = "1.1.0" +__version__ = "1.1.2"