diff --git a/docs/guide/DataStore, CompositeDataSource, Filters.ipynb b/docs/guide/DataStore, CompositeDataSource, Filters.ipynb index 4614e61..04662cc 100644 --- a/docs/guide/DataStore, CompositeDataSource, Filters.ipynb +++ b/docs/guide/DataStore, CompositeDataSource, Filters.ipynb @@ -255,9 +255,9 @@ ], "metadata": { "kernelspec": { - "display_name": "cti-python-stix2", + "display_name": "Python 3", "language": "python", - "name": "cti-python-stix2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/FileSystem.ipynb b/docs/guide/FileSystem.ipynb index 6a2b17d..9239131 100644 --- a/docs/guide/FileSystem.ipynb +++ b/docs/guide/FileSystem.ipynb @@ -497,9 +497,9 @@ ], "metadata": { "kernelspec": { - "display_name": "cti-python-stix2", + "display_name": "Python 3", "language": "python", - "name": "cti-python-stix2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/Memory.ipynb b/docs/guide/Memory.ipynb index 6fcb399..29daae6 100644 --- a/docs/guide/Memory.ipynb +++ b/docs/guide/Memory.ipynb @@ -256,9 +256,9 @@ ], "metadata": { "kernelspec": { - "display_name": "cti-python-stix2", + "display_name": "Python 3", "language": "python", - "name": "cti-python-stix2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/TAXIICollection.ipynb b/docs/guide/TAXIICollection.ipynb index 1180c74..48b4656 100644 --- a/docs/guide/TAXIICollection.ipynb +++ b/docs/guide/TAXIICollection.ipynb @@ -2387,7 +2387,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "from stix2 import TAXIICollectionSink, ThreatActor\n", @@ -2482,9 +2484,9 @@ ], "metadata": { "kernelspec": { - "display_name": "cti-python-stix2", + "display_name": "Python 3", "language": "python", - "name": "cti-python-stix2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/creating.ipynb b/docs/guide/creating.ipynb index 2c0f132..6cfea7f 100644 --- a/docs/guide/creating.ipynb +++ b/docs/guide/creating.ipynb @@ -869,9 +869,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/custom.ipynb b/docs/guide/custom.ipynb index 0626692..2254fa8 100644 --- a/docs/guide/custom.ipynb +++ b/docs/guide/custom.ipynb @@ -916,9 +916,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/environment.ipynb b/docs/guide/environment.ipynb index d2a0de2..a9184a1 100644 --- a/docs/guide/environment.ipynb +++ b/docs/guide/environment.ipynb @@ -723,9 +723,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/markings.ipynb b/docs/guide/markings.ipynb index 7e512a9..cb8f762 100644 --- a/docs/guide/markings.ipynb +++ b/docs/guide/markings.ipynb @@ -146,14 +146,14 @@ ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "indicator",\n",
-       "    "id": "indicator--aa0a1159-32b8-44d7-ba58-574ab6b9c9af",\n",
-       "    "created": "2017-09-26T23:38:12.161Z",\n",
-       "    "modified": "2017-09-26T23:38:12.161Z",\n",
+       "    "id": "indicator--409a0b15-1108-4251-8aee-a08995976561",\n",
+       "    "created": "2017-10-04T14:42:54.685Z",\n",
+       "    "modified": "2017-10-04T14:42:54.685Z",\n",
        "    "labels": [\n",
        "        "malicious-activity"\n",
        "    ],\n",
        "    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
-       "    "valid_from": "2017-09-26T23:38:12.161492Z",\n",
+       "    "valid_from": "2017-10-04T14:42:54.685184Z",\n",
        "    "object_marking_refs": [\n",
        "        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"\n",
        "    ]\n",
@@ -263,8 +263,8 @@
        ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
        ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "marking-definition",\n",
-       "    "id": "marking-definition--b039cd22-b453-40c7-b9d8-20f8ae1ba29b",\n",
-       "    "created": "2017-09-26T23:38:13.988639Z",\n",
+       "    "id": "marking-definition--030bb5c6-c5eb-4e9c-8e7a-b9aab08ded53",\n",
+       "    "created": "2017-10-04T14:43:04.090873Z",\n",
        "    "definition_type": "statement",\n",
        "    "definition": {\n",
        "        "statement": "Copyright 2017, Example Corp"\n",
@@ -376,16 +376,16 @@
        ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
        ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "indicator",\n",
-       "    "id": "indicator--79913250-0e10-45d2-925d-53ee3747eac5",\n",
-       "    "created": "2017-09-26T23:38:15.669Z",\n",
-       "    "modified": "2017-09-26T23:38:15.669Z",\n",
+       "    "id": "indicator--526cda4e-6745-4cd6-852f-0750c6a79784",\n",
+       "    "created": "2017-10-04T14:43:09.586Z",\n",
+       "    "modified": "2017-10-04T14:43:09.586Z",\n",
        "    "labels": [\n",
        "        "malicious-activity"\n",
        "    ],\n",
        "    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
-       "    "valid_from": "2017-09-26T23:38:15.669626Z",\n",
+       "    "valid_from": "2017-10-04T14:43:09.586133Z",\n",
        "    "object_marking_refs": [\n",
-       "        "marking-definition--b039cd22-b453-40c7-b9d8-20f8ae1ba29b"\n",
+       "        "marking-definition--030bb5c6-c5eb-4e9c-8e7a-b9aab08ded53"\n",
        "    ]\n",
        "}\n",
        "
\n" @@ -484,14 +484,14 @@ ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "indicator",\n",
-       "    "id": "indicator--f96f6de3-184d-4d18-85cd-c1517265b775",\n",
-       "    "created": "2017-09-26T23:38:17.187Z",\n",
-       "    "modified": "2017-09-26T23:38:17.187Z",\n",
+       "    "id": "indicator--1505b789-fcd2-48ee-bea9-3b20627a4abd",\n",
+       "    "created": "2017-10-04T14:43:20.049Z",\n",
+       "    "modified": "2017-10-04T14:43:20.049Z",\n",
        "    "labels": [\n",
        "        "malicious-activity"\n",
        "    ],\n",
        "    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
-       "    "valid_from": "2017-09-26T23:38:17.18725Z",\n",
+       "    "valid_from": "2017-10-04T14:43:20.049166Z",\n",
        "    "object_marking_refs": [\n",
        "        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"\n",
        "    ]\n",
@@ -599,9 +599,9 @@
        ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
        ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "malware",\n",
-       "    "id": "malware--1c57d899-1255-4f08-b084-289296b3aa0d",\n",
-       "    "created": "2017-09-26T23:38:18.729Z",\n",
-       "    "modified": "2017-09-26T23:38:18.729Z",\n",
+       "    "id": "malware--9f8970eb-b398-41b6-b8c8-8a607ad3a2c5",\n",
+       "    "created": "2017-10-04T14:43:26.129Z",\n",
+       "    "modified": "2017-10-04T14:43:26.129Z",\n",
        "    "name": "Poison Ivy",\n",
        "    "description": "A ransomware related to ...",\n",
        "    "labels": [\n",
@@ -609,7 +609,7 @@
        "    ],\n",
        "    "granular_markings": [\n",
        "        {\n",
-       "            "marking_ref": "marking-definition--b039cd22-b453-40c7-b9d8-20f8ae1ba29b",\n",
+       "            "marking_ref": "marking-definition--030bb5c6-c5eb-4e9c-8e7a-b9aab08ded53",\n",
        "            "selectors": [\n",
        "                "description"\n",
        "            ]\n",
@@ -696,12 +696,14 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Both object markings and granular markings can also be added to STIX objects which have already been created. Doing so will create a new version of the object (note the updated ``modified`` time)."
+    "Both object markings and granular markings can also be added to STIX objects which have already been created.\n",
+    "\n",
+    "**Note**: Doing so will create a new version of the object (note the updated ``modified`` time)."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 21,
    "metadata": {},
    "outputs": [
     {
@@ -777,17 +779,17 @@
        ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
        ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "indicator",\n",
-       "    "id": "indicator--aa0a1159-32b8-44d7-ba58-574ab6b9c9af",\n",
-       "    "created": "2017-09-26T23:38:12.161Z",\n",
-       "    "modified": "2017-09-26T23:38:22.548Z",\n",
+       "    "id": "indicator--409a0b15-1108-4251-8aee-a08995976561",\n",
+       "    "created": "2017-10-04T14:42:54.685Z",\n",
+       "    "modified": "2017-10-04T15:03:46.599Z",\n",
        "    "labels": [\n",
        "        "malicious-activity"\n",
        "    ],\n",
        "    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
-       "    "valid_from": "2017-09-26T23:38:12.161492Z",\n",
+       "    "valid_from": "2017-10-04T14:42:54.685184Z",\n",
        "    "object_marking_refs": [\n",
-       "        "marking-definition--b039cd22-b453-40c7-b9d8-20f8ae1ba29b",\n",
-       "        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"\n",
+       "        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82",\n",
+       "        "marking-definition--030bb5c6-c5eb-4e9c-8e7a-b9aab08ded53"\n",
        "    ]\n",
        "}\n",
        "
\n" @@ -796,15 +798,13 @@ "" ] }, - "execution_count": 9, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from stix2.markings import add_markings\n", - "\n", - "indicator4 = add_markings(indicator, marking_definition.id)\n", + "indicator4 = indicator.add_markings(marking_definition)\n", "print(indicator4)" ] }, @@ -817,7 +817,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -893,14 +893,14 @@ ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "indicator",\n",
-       "    "id": "indicator--aa0a1159-32b8-44d7-ba58-574ab6b9c9af",\n",
-       "    "created": "2017-09-26T23:38:12.161Z",\n",
-       "    "modified": "2017-09-26T23:38:24.574Z",\n",
+       "    "id": "indicator--409a0b15-1108-4251-8aee-a08995976561",\n",
+       "    "created": "2017-10-04T14:42:54.685Z",\n",
+       "    "modified": "2017-10-04T15:03:54.290Z",\n",
        "    "labels": [\n",
        "        "malicious-activity"\n",
        "    ],\n",
        "    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
-       "    "valid_from": "2017-09-26T23:38:12.161492Z",\n",
+       "    "valid_from": "2017-10-04T14:42:54.685184Z",\n",
        "    "object_marking_refs": [\n",
        "        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"\n",
        "    ]\n",
@@ -911,15 +911,13 @@
        ""
       ]
      },
-     "execution_count": 10,
+     "execution_count": 22,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "from stix2.markings import remove_markings\n",
-    "\n",
-    "indicator5 = remove_markings(indicator4, marking_definition.id)\n",
+    "indicator5 = indicator4.remove_markings(marking_definition)\n",
     "print(indicator5)"
    ]
   },
@@ -932,7 +930,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 23,
    "metadata": {},
    "outputs": [
     {
@@ -1008,17 +1006,17 @@
        ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
        ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "indicator",\n",
-       "    "id": "indicator--aa0a1159-32b8-44d7-ba58-574ab6b9c9af",\n",
-       "    "created": "2017-09-26T23:38:12.161Z",\n",
-       "    "modified": "2017-09-26T23:38:26.215Z",\n",
+       "    "id": "indicator--409a0b15-1108-4251-8aee-a08995976561",\n",
+       "    "created": "2017-10-04T14:42:54.685Z",\n",
+       "    "modified": "2017-10-04T15:04:04.218Z",\n",
        "    "labels": [\n",
        "        "malicious-activity"\n",
        "    ],\n",
        "    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
-       "    "valid_from": "2017-09-26T23:38:12.161492Z",\n",
+       "    "valid_from": "2017-10-04T14:42:54.685184Z",\n",
        "    "object_marking_refs": [\n",
-       "        "marking-definition--b039cd22-b453-40c7-b9d8-20f8ae1ba29b",\n",
-       "        "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da"\n",
+       "        "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da",\n",
+       "        "marking-definition--030bb5c6-c5eb-4e9c-8e7a-b9aab08ded53"\n",
        "    ]\n",
        "}\n",
        "
\n" @@ -1027,16 +1025,15 @@ "" ] }, - "execution_count": 11, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from stix2 import TLP_GREEN\n", - "from stix2.markings import set_markings\n", "\n", - "indicator6 = set_markings(indicator5, [TLP_GREEN.id, marking_definition.id])\n", + "indicator6 = indicator5.set_markings([TLP_GREEN, marking_definition])\n", "print(indicator6)" ] }, @@ -1125,14 +1122,14 @@ ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
        "    "type": "indicator",\n",
-       "    "id": "indicator--aa0a1159-32b8-44d7-ba58-574ab6b9c9af",\n",
-       "    "created": "2017-09-26T23:38:12.161Z",\n",
-       "    "modified": "2017-09-26T23:38:27.900Z",\n",
+       "    "id": "indicator--409a0b15-1108-4251-8aee-a08995976561",\n",
+       "    "created": "2017-10-04T14:42:54.685Z",\n",
+       "    "modified": "2017-10-04T14:54:39.331Z",\n",
        "    "labels": [\n",
        "        "malicious-activity"\n",
        "    ],\n",
        "    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",\n",
-       "    "valid_from": "2017-09-26T23:38:12.161492Z"\n",
+       "    "valid_from": "2017-10-04T14:42:54.685184Z"\n",
        "}\n",
        "
\n" ], @@ -1146,9 +1143,7 @@ } ], "source": [ - "from stix2.markings import clear_markings\n", - "\n", - "indicator7 = clear_markings(indicator5)\n", + "indicator7 = indicator5.clear_markings()\n", "print(indicator7)" ] }, @@ -1170,32 +1165,57 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "['marking-definition--b039cd22-b453-40c7-b9d8-20f8ae1ba29b',\n", - " 'marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da']" + "['marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da',\n", + " 'marking-definition--030bb5c6-c5eb-4e9c-8e7a-b9aab08ded53']" ] }, - "execution_count": 13, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from stix2.markings import get_markings\n", - "\n", - "get_markings(indicator6)" + "indicator6.get_markings()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "You can also get a list of granular markings by passing a list of selectors to ``get_markings``:" + "To get a list of the granular markings on an object, pass the object and a list of selectors to ``get_markings``:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9']" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "malware.get_markings('name')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also call ``get_markings()`` as a method on the STIX object." ] }, { @@ -1215,36 +1235,14 @@ } ], "source": [ - "get_markings(malware, 'name')" + "malware.get_markings('name')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "You can also check if an object is marked by a specific markings. Again, for granular markings, pass in the selector or list of selectors." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from stix2.markings import is_marked\n", - "\n", - "is_marked(indicator, TLP_AMBER.id)" + "Finally, you may also check if an object is marked by a specific markings. Again, for granular markings, pass in the selector or list of selectors." ] }, { @@ -1264,12 +1262,32 @@ } ], "source": [ - "is_marked(malware, TLP_WHITE.id, 'name')" + "indicator.is_marked(TLP_AMBER.id)" ] }, { "cell_type": "code", "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "malware.is_marked(TLP_WHITE.id, 'name')" + ] + }, + { + "cell_type": "code", + "execution_count": 18, "metadata": { "scrolled": true }, @@ -1280,21 +1298,21 @@ "False" ] }, - "execution_count": 17, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "is_marked(malware, TLP_WHITE.id, 'description')" + "malware.is_marked(TLP_WHITE.id, 'description')" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/parsing.ipynb b/docs/guide/parsing.ipynb index f645740..e991e0c 100644 --- a/docs/guide/parsing.ipynb +++ b/docs/guide/parsing.ipynb @@ -109,9 +109,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/serializing.ipynb b/docs/guide/serializing.ipynb index 8ca4460..8fcc19d 100644 --- a/docs/guide/serializing.ipynb +++ b/docs/guide/serializing.ipynb @@ -178,9 +178,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/docs/guide/versioning.ipynb b/docs/guide/versioning.ipynb index d38ba94..30ceb69 100644 --- a/docs/guide/versioning.ipynb +++ b/docs/guide/versioning.ipynb @@ -322,9 +322,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/stix2/__init__.py b/stix2/__init__.py index 770f8cb..55911a4 100644 --- a/stix2/__init__.py +++ b/stix2/__init__.py @@ -25,6 +25,8 @@ from .common import (TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, MarkingDefinition, StatementMarking, TLPMarking) from .core import Bundle, _register_type, parse from .environment import Environment, ObjectFactory +from .markings import (add_markings, clear_markings, get_markings, is_marked, + remove_markings, set_markings) from .observables import (URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem, CustomExtension, CustomObservable, Directory, DomainName, EmailAddress, EmailMessage, diff --git a/stix2/common.py b/stix2/common.py index bd177fd..602e43f 100644 --- a/stix2/common.py +++ b/stix2/common.py @@ -3,6 +3,7 @@ from collections import OrderedDict from .base import _STIXBase +from .markings import MarkingsMixin from .properties import (HashesProperty, IDProperty, ListProperty, Property, ReferenceProperty, SelectorProperty, StringProperty, TimestampProperty, TypeProperty) @@ -76,7 +77,7 @@ class MarkingProperty(Property): raise ValueError("must be a Statement, TLP Marking or a registered marking.") -class MarkingDefinition(_STIXBase): +class MarkingDefinition(_STIXBase, MarkingsMixin): _type = 'marking-definition' _properties = OrderedDict() _properties.update([ diff --git a/stix2/markings/__init__.py b/stix2/markings/__init__.py index 9194ee1..69f3ace 100644 --- a/stix2/markings/__init__.py +++ b/stix2/markings/__init__.py @@ -224,3 +224,16 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa result = result or object_markings.is_marked(obj, object_marks) return result + + +class MarkingsMixin(): + pass + + +# Note that all of these methods will return a new object because of immutability +MarkingsMixin.get_markings = get_markings +MarkingsMixin.set_markings = set_markings +MarkingsMixin.remove_markings = remove_markings +MarkingsMixin.add_markings = add_markings +MarkingsMixin.clear_markings = clear_markings +MarkingsMixin.is_marked = is_marked diff --git a/stix2/markings/granular_markings.py b/stix2/markings/granular_markings.py index 893428e..3fe3a48 100644 --- a/stix2/markings/granular_markings.py +++ b/stix2/markings/granular_markings.py @@ -90,6 +90,7 @@ def remove_markings(obj, marking, selectors): """ selectors = utils.convert_to_list(selectors) + marking = utils.convert_to_marking_list(marking) utils.validate(obj, selectors) granular_markings = obj.get("granular_markings") @@ -99,12 +100,9 @@ def remove_markings(obj, marking, selectors): granular_markings = utils.expand_markings(granular_markings) - if isinstance(marking, list): - to_remove = [] - for m in marking: - to_remove.append({"marking_ref": m, "selectors": selectors}) - else: - to_remove = [{"marking_ref": marking, "selectors": selectors}] + to_remove = [] + for m in marking: + to_remove.append({"marking_ref": m, "selectors": selectors}) remove = utils.build_granular_marking(to_remove).get("granular_markings") @@ -142,14 +140,12 @@ def add_markings(obj, marking, selectors): """ selectors = utils.convert_to_list(selectors) + marking = utils.convert_to_marking_list(marking) utils.validate(obj, selectors) - if isinstance(marking, list): - granular_marking = [] - for m in marking: - granular_marking.append({"marking_ref": m, "selectors": sorted(selectors)}) - else: - granular_marking = [{"marking_ref": marking, "selectors": sorted(selectors)}] + granular_marking = [] + for m in marking: + granular_marking.append({"marking_ref": m, "selectors": sorted(selectors)}) if obj.get("granular_markings"): granular_marking.extend(obj.get("granular_markings")) @@ -246,7 +242,7 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa raise TypeError("Required argument 'selectors' must be provided") selectors = utils.convert_to_list(selectors) - marking = utils.convert_to_list(marking) + marking = utils.convert_to_marking_list(marking) utils.validate(obj, selectors) granular_markings = obj.get("granular_markings", []) diff --git a/stix2/markings/object_markings.py b/stix2/markings/object_markings.py index ce77966..cb78294 100644 --- a/stix2/markings/object_markings.py +++ b/stix2/markings/object_markings.py @@ -33,7 +33,7 @@ def add_markings(obj, marking): A new version of the given SDO or SRO with specified markings added. """ - marking = utils.convert_to_list(marking) + marking = utils.convert_to_marking_list(marking) object_markings = set(obj.get("object_marking_refs", []) + marking) @@ -57,7 +57,7 @@ def remove_markings(obj, marking): A new version of the given SDO or SRO with specified markings removed. """ - marking = utils.convert_to_list(marking) + marking = utils.convert_to_marking_list(marking) object_markings = obj.get("object_marking_refs", []) @@ -123,7 +123,7 @@ def is_marked(obj, marking=None): provided marking refs match, True is returned. """ - marking = utils.convert_to_list(marking) + marking = utils.convert_to_marking_list(marking) object_markings = obj.get("object_marking_refs", []) if marking: diff --git a/stix2/markings/utils.py b/stix2/markings/utils.py index 6fed976..3024fe8 100644 --- a/stix2/markings/utils.py +++ b/stix2/markings/utils.py @@ -39,6 +39,12 @@ def _validate_selector(obj, selector): return True +def _get_marking_id(marking): + if type(marking).__name__ is 'MarkingDefinition': # avoid circular import + return marking.id + return marking + + def validate(obj, selectors): """Given an SDO or SRO, check that each selector is valid.""" if selectors: @@ -59,6 +65,15 @@ def convert_to_list(data): return [data] +def convert_to_marking_list(data): + """Convert input into a list of marking identifiers.""" + if data is not None: + if isinstance(data, list): + return [_get_marking_id(x) for x in data] + else: + return [_get_marking_id(data)] + + def compress_markings(granular_markings): """Compress granular markings list. diff --git a/stix2/sdo.py b/stix2/sdo.py index cdbb9ca..c3eb619 100644 --- a/stix2/sdo.py +++ b/stix2/sdo.py @@ -6,6 +6,7 @@ import stix2 from .base import _STIXBase from .common import ExternalReference, GranularMarking, KillChainPhase +from .markings import MarkingsMixin from .observables import ObservableProperty from .properties import (BooleanProperty, IDProperty, IntegerProperty, ListProperty, PatternProperty, ReferenceProperty, @@ -13,7 +14,11 @@ from .properties import (BooleanProperty, IDProperty, IntegerProperty, from .utils import NOW -class AttackPattern(_STIXBase): +class STIXDomainObject(_STIXBase, MarkingsMixin): + pass + + +class AttackPattern(STIXDomainObject): _type = 'attack-pattern' _properties = OrderedDict() @@ -34,7 +39,7 @@ class AttackPattern(_STIXBase): ]) -class Campaign(_STIXBase): +class Campaign(STIXDomainObject): _type = 'campaign' _properties = OrderedDict() @@ -58,7 +63,7 @@ class Campaign(_STIXBase): ]) -class CourseOfAction(_STIXBase): +class CourseOfAction(STIXDomainObject): _type = 'course-of-action' _properties = OrderedDict() @@ -78,7 +83,7 @@ class CourseOfAction(_STIXBase): ]) -class Identity(_STIXBase): +class Identity(STIXDomainObject): _type = 'identity' _properties = OrderedDict() @@ -101,7 +106,7 @@ class Identity(_STIXBase): ]) -class Indicator(_STIXBase): +class Indicator(STIXDomainObject): _type = 'indicator' _properties = OrderedDict() @@ -125,7 +130,7 @@ class Indicator(_STIXBase): ]) -class IntrusionSet(_STIXBase): +class IntrusionSet(STIXDomainObject): _type = 'intrusion-set' _properties = OrderedDict() @@ -152,7 +157,7 @@ class IntrusionSet(_STIXBase): ]) -class Malware(_STIXBase): +class Malware(STIXDomainObject): _type = 'malware' _properties = OrderedDict() @@ -173,7 +178,7 @@ class Malware(_STIXBase): ]) -class ObservedData(_STIXBase): +class ObservedData(STIXDomainObject): _type = 'observed-data' _properties = OrderedDict() @@ -195,7 +200,7 @@ class ObservedData(_STIXBase): ]) -class Report(_STIXBase): +class Report(STIXDomainObject): _type = 'report' _properties = OrderedDict() @@ -217,7 +222,7 @@ class Report(_STIXBase): ]) -class ThreatActor(_STIXBase): +class ThreatActor(STIXDomainObject): _type = 'threat-actor' _properties = OrderedDict() @@ -245,7 +250,7 @@ class ThreatActor(_STIXBase): ]) -class Tool(_STIXBase): +class Tool(STIXDomainObject): _type = 'tool' _properties = OrderedDict() @@ -267,7 +272,7 @@ class Tool(_STIXBase): ]) -class Vulnerability(_STIXBase): +class Vulnerability(STIXDomainObject): _type = 'vulnerability' _properties = OrderedDict() @@ -314,7 +319,7 @@ def CustomObject(type='x-custom-type', properties=None): def custom_builder(cls): - class _Custom(cls, _STIXBase): + class _Custom(cls, STIXDomainObject): _type = type _properties = OrderedDict() _properties.update([ diff --git a/stix2/sro.py b/stix2/sro.py index af483bc..4fa0465 100644 --- a/stix2/sro.py +++ b/stix2/sro.py @@ -4,13 +4,18 @@ from collections import OrderedDict from .base import _STIXBase from .common import ExternalReference, GranularMarking +from .markings import MarkingsMixin from .properties import (BooleanProperty, IDProperty, IntegerProperty, ListProperty, ReferenceProperty, StringProperty, TimestampProperty, TypeProperty) from .utils import NOW -class Relationship(_STIXBase): +class STIXRelationshipObject(_STIXBase, MarkingsMixin): + pass + + +class Relationship(STIXRelationshipObject): _type = 'relationship' _properties = OrderedDict() @@ -45,7 +50,7 @@ class Relationship(_STIXBase): super(Relationship, self).__init__(**kwargs) -class Sighting(_STIXBase): +class Sighting(STIXRelationshipObject): _type = 'sighting' _properties = OrderedDict() _properties.update([ diff --git a/stix2/test/test_granular_markings.py b/stix2/test/test_granular_markings.py index e910ad3..f8fc803 100644 --- a/stix2/test/test_granular_markings.py +++ b/stix2/test/test_granular_markings.py @@ -1,7 +1,7 @@ import pytest -from stix2 import Malware, markings +from stix2 import TLP_RED, Malware, markings from .constants import MALWARE_MORE_KWARGS as MALWARE_KWARGS_CONST from .constants import MARKING_IDS @@ -45,6 +45,7 @@ def test_add_marking_mark_one_selector_multiple_refs(): }, ], **MALWARE_KWARGS), + MARKING_IDS[0], ), ( MALWARE_KWARGS, @@ -56,13 +57,26 @@ def test_add_marking_mark_one_selector_multiple_refs(): }, ], **MALWARE_KWARGS), + MARKING_IDS[0], + ), + ( + Malware(**MALWARE_KWARGS), + Malware( + granular_markings=[ + { + "selectors": ["description", "name"], + "marking_ref": TLP_RED.id, + }, + ], + **MALWARE_KWARGS), + TLP_RED, ), ]) def test_add_marking_mark_multiple_selector_one_refs(data): before = data[0] after = data[1] - before = markings.add_markings(before, [MARKING_IDS[0]], ["description", "name"]) + before = markings.add_markings(before, data[2], ["description", "name"]) for m in before["granular_markings"]: assert m in after["granular_markings"] @@ -347,36 +361,42 @@ def test_get_markings_positional_arguments_combinations(data): assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"]) -@pytest.mark.parametrize("before", [ - Malware( - granular_markings=[ - { - "selectors": ["description"], - "marking_ref": MARKING_IDS[0] - }, - { - "selectors": ["description"], - "marking_ref": MARKING_IDS[1] - }, - ], - **MALWARE_KWARGS +@pytest.mark.parametrize("data", [ + ( + Malware( + granular_markings=[ + { + "selectors": ["description"], + "marking_ref": MARKING_IDS[0] + }, + { + "selectors": ["description"], + "marking_ref": MARKING_IDS[1] + }, + ], + **MALWARE_KWARGS + ), + [MARKING_IDS[0], MARKING_IDS[1]], ), - dict( - granular_markings=[ - { - "selectors": ["description"], - "marking_ref": MARKING_IDS[0] - }, - { - "selectors": ["description"], - "marking_ref": MARKING_IDS[1] - }, - ], - **MALWARE_KWARGS + ( + dict( + granular_markings=[ + { + "selectors": ["description"], + "marking_ref": MARKING_IDS[0] + }, + { + "selectors": ["description"], + "marking_ref": MARKING_IDS[1] + }, + ], + **MALWARE_KWARGS + ), + [MARKING_IDS[0], MARKING_IDS[1]], ), ]) -def test_remove_marking_remove_one_selector_with_multiple_refs(before): - before = markings.remove_markings(before, [MARKING_IDS[0], MARKING_IDS[1]], ["description"]) +def test_remove_marking_remove_one_selector_with_multiple_refs(data): + before = markings.remove_markings(data[0], data[1], ["description"]) assert "granular_markings" not in before diff --git a/stix2/test/test_markings.py b/stix2/test/test_markings.py index 0c6069a..456bf92 100644 --- a/stix2/test/test_markings.py +++ b/stix2/test/test_markings.py @@ -241,4 +241,14 @@ def test_marking_wrong_type_construction(): assert str(excinfo.value) == "Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]" -# TODO: Add other examples +def test_campaign_add_markings(): + campaign = stix2.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 = campaign.add_markings(TLP_WHITE) + assert campaign.object_marking_refs[0] == TLP_WHITE.id diff --git a/stix2/test/test_object_markings.py b/stix2/test/test_object_markings.py index 36e8e4d..10949ab 100644 --- a/stix2/test/test_object_markings.py +++ b/stix2/test/test_object_markings.py @@ -1,7 +1,7 @@ import pytest -from stix2 import Malware, exceptions, markings +from stix2 import TLP_AMBER, Malware, exceptions, markings from .constants import FAKE_TIME, MALWARE_ID, MARKING_IDS from .constants import MALWARE_KWARGS as MALWARE_KWARGS_CONST @@ -21,18 +21,26 @@ MALWARE_KWARGS.update({ Malware(**MALWARE_KWARGS), Malware(object_marking_refs=[MARKING_IDS[0]], **MALWARE_KWARGS), + MARKING_IDS[0], ), ( MALWARE_KWARGS, dict(object_marking_refs=[MARKING_IDS[0]], **MALWARE_KWARGS), + MARKING_IDS[0], + ), + ( + Malware(**MALWARE_KWARGS), + Malware(object_marking_refs=[TLP_AMBER.id], + **MALWARE_KWARGS), + TLP_AMBER, ), ]) def test_add_markings_one_marking(data): before = data[0] after = data[1] - before = markings.add_markings(before, MARKING_IDS[0], None) + before = markings.add_markings(before, data[2], None) for m in before["object_marking_refs"]: assert m in after["object_marking_refs"] @@ -280,19 +288,28 @@ def test_remove_markings_object_level(data): **MALWARE_KWARGS), Malware(object_marking_refs=[MARKING_IDS[1]], **MALWARE_KWARGS), + [MARKING_IDS[0], MARKING_IDS[2]], ), ( dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], **MALWARE_KWARGS), dict(object_marking_refs=[MARKING_IDS[1]], **MALWARE_KWARGS), + [MARKING_IDS[0], MARKING_IDS[2]], + ), + ( + Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], TLP_AMBER.id], + **MALWARE_KWARGS), + Malware(object_marking_refs=[MARKING_IDS[1]], + **MALWARE_KWARGS), + [MARKING_IDS[0], TLP_AMBER], ), ]) def test_remove_markings_multiple(data): before = data[0] after = data[1] - before = markings.remove_markings(before, [MARKING_IDS[0], MARKING_IDS[2]], None) + before = markings.remove_markings(before, data[2], None) assert before['object_marking_refs'] == after['object_marking_refs']