Merge pull request #468 from oasis-open/dev-extensions-proposal

Extensions Support
pull/1/head
Rich Piazza 2021-07-07 16:10:01 -04:00 committed by GitHub
commit 3ce193aca6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
92 changed files with 2874 additions and 1028 deletions

View File

@ -39,7 +39,7 @@ be set automatically if not provided as keyword arguments.
pattern_type="stix", pattern_type="stix",
pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']") pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']")
To parse a STIX JSON string into a Python STIX object, use ``parse()``: To parse a STIX JSON string into a Python STIX object, use ``parse()``. To serialize a STIX object, use ``serialize()``:
.. code-block:: python .. code-block:: python
@ -61,15 +61,15 @@ To parse a STIX JSON string into a Python STIX object, use ``parse()``:
"valid_from": "2017-09-26T23:33:39.829952Z" "valid_from": "2017-09-26T23:33:39.829952Z"
}""") }""")
print(indicator) print(indicator.serialize(pretty=True))
For more in-depth documentation, please see `https://stix2.readthedocs.io/ <https://stix2.readthedocs.io/>`__. For more in-depth documentation, please see `https://stix2.readthedocs.io/ <https://stix2.readthedocs.io/>`__.
STIX 2 Technical Specification Support STIX 2 Technical Specification Support
-------------------------------------- --------------------------------------
This version of cti-python-stix2 brings support to `STIX Version 2.1 <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html>`__ This version of cti-python-stix2 brings support to `STIX Version 2.1 <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html>`__
published on 20 March 2020 currently at the Committee Specification (CS) level. published on 25 January 2021 currently at the Committee Specification (CS) 02 level.
The stix2 Python library supports multiple versions of the STIX 2 Technical The stix2 Python library supports multiple versions of the STIX 2 Technical
Specification. The library will be updated to support new Committee Specification. The library will be updated to support new Committee

View File

@ -27,7 +27,7 @@ the repository on GitHub and clone your fork instead of the main repo:
git clone https://github.com/yourusername/cti-python-stix2.git git clone https://github.com/yourusername/cti-python-stix2.git
2. Install develoment-related dependencies: 2. Install development-related dependencies:
.. prompt:: bash .. prompt:: bash
@ -107,7 +107,7 @@ run:
then look at the resulting report in ``htmlcov/index.html``. then look at the resulting report in ``htmlcov/index.html``.
All commits pushed to the ``master`` branch or submitted as a pull request are All commits pushed to the ``master`` branch or submitted as a pull request are
tested with `Travis-CI <https://travis-ci.org/oasis-open/cti-python-stix2>`_ tested with `GitHub Actions <https://github.com/oasis-open/cti-python-stix2/actions>`_
automatically. automatically.
Adding a dependency Adding a dependency

View File

@ -173,7 +173,7 @@
"indicator = Indicator(name=\"File hash for malware variant\",\n", "indicator = Indicator(name=\"File hash for malware variant\",\n",
" pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\",\n", " pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\",\n",
" pattern_type=\"stix\")\n", " pattern_type=\"stix\")\n",
"print(indicator)" "print(indicator.serialize(pretty=True))"
] ]
}, },
{ {
@ -503,7 +503,7 @@
"\n", "\n",
"malware = Malware(name=\"Poison Ivy\",\n", "malware = Malware(name=\"Poison Ivy\",\n",
" is_family=False)\n", " is_family=False)\n",
"print(malware)" "print(malware.serialize(pretty=True))"
] ]
}, },
{ {
@ -627,7 +627,7 @@
"relationship = Relationship(relationship_type='indicates',\n", "relationship = Relationship(relationship_type='indicates',\n",
" source_ref=indicator.id,\n", " source_ref=indicator.id,\n",
" target_ref=malware.id)\n", " target_ref=malware.id)\n",
"print(relationship)" "print(relationship.serialize(pretty=True))"
] ]
}, },
{ {
@ -736,7 +736,7 @@
], ],
"source": [ "source": [
"relationship2 = Relationship(indicator, 'indicates', malware)\n", "relationship2 = Relationship(indicator, 'indicates', malware)\n",
"print(relationship2)" "print(relationship2.serialize(pretty=True))"
] ]
}, },
{ {
@ -876,7 +876,7 @@
"from stix2 import Bundle\n", "from stix2 import Bundle\n",
"\n", "\n",
"bundle = Bundle(indicator, malware, relationship)\n", "bundle = Bundle(indicator, malware, relationship)\n",
"print(bundle)" "print(bundle.serialize(pretty=True))"
] ]
}, },
{ {
@ -993,7 +993,7 @@
" resolves_to_refs=[\"mac-addr--43f380fd-37c6-476d-8643-60849bf9240e\"]\n", " resolves_to_refs=[\"mac-addr--43f380fd-37c6-476d-8643-60849bf9240e\"]\n",
")\n", ")\n",
"\n", "\n",
"print(ip4)" "print(ip4.serialize(pretty=True))"
] ]
}, },
{ {
@ -1111,7 +1111,7 @@
" resolves_to_refs=[mac_addr_a.id, mac_addr_b.id]\n", " resolves_to_refs=[mac_addr_a.id, mac_addr_b.id]\n",
")\n", ")\n",
"\n", "\n",
"print(ip4_valid_refs)" "print(ip4_valid_refs.serialize(pretty=True))"
] ]
} }
], ],

View File

@ -201,7 +201,7 @@
" custom_properties={\n", " custom_properties={\n",
" \"x_foo\": \"bar\"\n", " \"x_foo\": \"bar\"\n",
" })\n", " })\n",
"print(identity)" "print(identity.serialize(pretty=True))"
] ]
}, },
{ {
@ -313,7 +313,7 @@
" identity_class=\"individual\",\n", " identity_class=\"individual\",\n",
" x_foo=\"bar\",\n", " x_foo=\"bar\",\n",
" allow_custom=True)\n", " allow_custom=True)\n",
"print(identity2)" "print(identity2.serialize(pretty=True))"
] ]
}, },
{ {
@ -533,7 +533,7 @@
], ],
"source": [ "source": [
"identity4 = identity3.new_version(x_foo=None)\n", "identity4 = identity3.new_version(x_foo=None)\n",
"print(identity4)" "print(identity4.serialize(pretty=True))"
] ]
}, },
{ {
@ -671,7 +671,7 @@
"source": [ "source": [
"animal = Animal(species=\"lion\",\n", "animal = Animal(species=\"lion\",\n",
" animal_class=\"mammal\")\n", " animal_class=\"mammal\")\n",
"print(animal)" "print(animal.serialize(pretty=True))"
] ]
}, },
{ {
@ -956,7 +956,7 @@
"\n", "\n",
"new_observable = NewObservable(a_property=\"something\",\n", "new_observable = NewObservable(a_property=\"something\",\n",
" property_2=10)\n", " property_2=10)\n",
"print(new_observable)" "print(new_observable.serialize(pretty=True))"
] ]
}, },
{ {
@ -1458,13 +1458,13 @@
" pass\n", " pass\n",
"\n", "\n",
"new_observable_a = NewObservable2(a_property=\"A property\", property_2=2000)\n", "new_observable_a = NewObservable2(a_property=\"A property\", property_2=2000)\n",
"print(new_observable_a)\n", "print(new_observable_a.serialize(pretty=True))\n",
"\n", "\n",
"new_observable_b = NewObservable2(a_property=\"A property\", property_2=3000)\n", "new_observable_b = NewObservable2(a_property=\"A property\", property_2=3000)\n",
"print(new_observable_b)\n", "print(new_observable_b.serialize(pretty=True))\n",
"\n", "\n",
"new_observable_c = NewObservable2(a_property=\"A different property\", property_2=3000)\n", "new_observable_c = NewObservable2(a_property=\"A different property\", property_2=3000)\n",
"print(new_observable_c)" "print(new_observable_c.serialize(pretty=True))"
] ]
}, },
{ {
@ -1588,7 +1588,7 @@
"\n", "\n",
"new_ext = NewExtension(property1=\"something\",\n", "new_ext = NewExtension(property1=\"something\",\n",
" property2=10)\n", " property2=10)\n",
"print(new_ext)" "print(new_ext.serialize(pretty=True))"
] ]
}, },
{ {

View File

@ -332,11 +332,11 @@
"\n", "\n",
"# get an object that is only in the filesystem\n", "# get an object that is only in the filesystem\n",
"intrusion_set = cs.get('intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a')\n", "intrusion_set = cs.get('intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a')\n",
"print(intrusion_set)\n", "print(intrusion_set.serialize(pretty=True))\n",
"\n", "\n",
"# get an object that is only in the TAXII collection\n", "# get an object that is only in the TAXII collection\n",
"ind = cs.get('indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7')\n", "ind = cs.get('indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7')\n",
"print(ind)" "print(ind.serialize(pretty=True))"
] ]
}, },
{ {
@ -593,7 +593,7 @@
} }
], ],
"source": [ "source": [
"print(mem.creator_of(mal))" "print(mem.creator_of(mal).serialize(pretty=True))"
] ]
}, },
{ {

View File

@ -225,7 +225,7 @@
} }
], ],
"source": [ "source": [
"print(env.get(\"indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7\"))" "print(env.get(\"indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7\").serialize(pretty=True))"
] ]
}, },
{ {
@ -360,7 +360,7 @@
"ind = factory.create(Indicator,\n", "ind = factory.create(Indicator,\n",
" pattern_type=\"stix\",\n", " pattern_type=\"stix\",\n",
" pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n", " pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n",
"print(ind)" "print(ind.serialize(pretty=True))"
] ]
}, },
{ {
@ -486,7 +486,7 @@
" created_by_ref=None,\n", " created_by_ref=None,\n",
" pattern_type=\"stix\",\n", " pattern_type=\"stix\",\n",
" pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n", " pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n",
"print(ind2)" "print(ind2.serialize(pretty=True))"
] ]
}, },
{ {
@ -593,7 +593,7 @@
" created_by_ref=\"identity--962cabe5-f7f3-438a-9169-585a8c971d12\",\n", " created_by_ref=\"identity--962cabe5-f7f3-438a-9169-585a8c971d12\",\n",
" pattern_type=\"stix\",\n", " pattern_type=\"stix\",\n",
" pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n", " pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n",
"print(ind3)" "print(ind3.serialize(pretty=True))"
] ]
}, },
{ {
@ -712,7 +712,7 @@
" pattern_type=\"stix\",\n", " pattern_type=\"stix\",\n",
" pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n", " pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n",
"environ.add(i)\n", "environ.add(i)\n",
"print(environ.get(i.id))" "print(environ.get(i.id).serialize(pretty=True))"
] ]
} }
], ],

930
docs/guide/extensions.ipynb Normal file
View File

@ -0,0 +1,930 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"nbsphinx": "hidden"
},
"outputs": [],
"source": [
"# Delete this cell to re-enable tracebacks\n",
"import sys\n",
"ipython = get_ipython()\n",
"\n",
"def hide_traceback(exc_tuple=None, filename=None, tb_offset=None,\n",
" exception_only=False, running_compiled_code=False):\n",
" etype, value, tb = sys.exc_info()\n",
" value.__cause__ = None # suppress chained exceptions\n",
" return ipython._showtraceback(etype, value, ipython.InteractiveTB.get_exception_only(etype, value))\n",
"\n",
"ipython.showtraceback = hide_traceback"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"nbsphinx": "hidden"
},
"outputs": [],
"source": [
"# JSON output syntax highlighting\n",
"from __future__ import print_function\n",
"from pygments import highlight\n",
"from pygments.lexers import JsonLexer, TextLexer\n",
"from pygments.formatters import HtmlFormatter\n",
"from IPython.display import display, HTML\n",
"from IPython.core.interactiveshell import InteractiveShell\n",
"\n",
"InteractiveShell.ast_node_interactivity = \"all\"\n",
"\n",
"def json_print(inpt):\n",
" string = str(inpt)\n",
" formatter = HtmlFormatter()\n",
" if string[0] == '{':\n",
" lexer = JsonLexer()\n",
" else:\n",
" lexer = TextLexer()\n",
" return HTML('<style type=\"text/css\">{}</style>{}'.format(\n",
" formatter.get_style_defs('.highlight'),\n",
" highlight(string, lexer, formatter)))\n",
"\n",
"globals()['print'] = json_print"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## STIX Extensions\n",
"\n",
"This page is specific for the STIX Extensions mechanism defined in STIX 2.1 CS 02. For the deprecated STIX Customization mechanisms see the [Custom](custom.ipynb) section.\n",
"\n",
"### Top Level Property Extensions\n",
"\n",
"The example below shows how to create an `indicator` object with a `top-level-property-extension`. "
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style type=\"text/css\">pre { line-height: 125%; margin: 0; }\n",
"td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
"span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
".highlight .hll { background-color: #ffffcc }\n",
".highlight { background: #f8f8f8; }\n",
".highlight .c { color: #408080; font-style: italic } /* Comment */\n",
".highlight .err { border: 1px solid #FF0000 } /* Error */\n",
".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n",
".highlight .o { color: #666666 } /* Operator */\n",
".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n",
".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
".highlight .gd { color: #A00000 } /* Generic.Deleted */\n",
".highlight .ge { font-style: italic } /* Generic.Emph */\n",
".highlight .gr { color: #FF0000 } /* Generic.Error */\n",
".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
".highlight .gi { color: #00A000 } /* Generic.Inserted */\n",
".highlight .go { color: #888888 } /* Generic.Output */\n",
".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
".highlight .gs { font-weight: bold } /* Generic.Strong */\n",
".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
".highlight .gt { color: #0044DD } /* Generic.Traceback */\n",
".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n",
".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
".highlight .kt { color: #B00040 } /* Keyword.Type */\n",
".highlight .m { color: #666666 } /* Literal.Number */\n",
".highlight .s { color: #BA2121 } /* Literal.String */\n",
".highlight .na { color: #7D9029 } /* Name.Attribute */\n",
".highlight .nb { color: #008000 } /* Name.Builtin */\n",
".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
".highlight .no { color: #880000 } /* Name.Constant */\n",
".highlight .nd { color: #AA22FF } /* Name.Decorator */\n",
".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
".highlight .nf { color: #0000FF } /* Name.Function */\n",
".highlight .nl { color: #A0A000 } /* Name.Label */\n",
".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
".highlight .nv { color: #19177C } /* Name.Variable */\n",
".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n",
".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n",
".highlight .mf { color: #666666 } /* Literal.Number.Float */\n",
".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n",
".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n",
".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n",
".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n",
".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n",
".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n",
".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
".highlight .sx { color: #008000 } /* Literal.String.Other */\n",
".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n",
".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n",
".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n",
".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n",
".highlight .vc { color: #19177C } /* Name.Variable.Class */\n",
".highlight .vg { color: #19177C } /* Name.Variable.Global */\n",
".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n",
".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;extension-definition&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;spec_version&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2.1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;created_by_ref&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;identity--11b76a96-5d2b-45e0-8a5a-f6994f370731&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;created&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2014-02-20T09:16:08.000Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;modified&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2014-02-20T09:16:08.000Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;New SDO 1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;description&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;This schema adds two properties to a STIX object at the toplevel&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;schema&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;https://www.example.com/schema-foo-1a/v1/&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;version&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;1.2.1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;extension_types&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n",
" <span class=\"s2\">&quot;toplevel-property-extension&quot;</span>\n",
" <span class=\"p\">],</span>\n",
" <span class=\"nt\">&quot;extension_properties&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n",
" <span class=\"s2\">&quot;toxicity&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"s2\">&quot;rank&quot;</span>\n",
" <span class=\"p\">]</span>\n",
"<span class=\"p\">}</span>\n",
"</pre></div>\n"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"<style type=\"text/css\">pre { line-height: 125%; margin: 0; }\n",
"td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
"span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
".highlight .hll { background-color: #ffffcc }\n",
".highlight { background: #f8f8f8; }\n",
".highlight .c { color: #408080; font-style: italic } /* Comment */\n",
".highlight .err { border: 1px solid #FF0000 } /* Error */\n",
".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n",
".highlight .o { color: #666666 } /* Operator */\n",
".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n",
".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
".highlight .gd { color: #A00000 } /* Generic.Deleted */\n",
".highlight .ge { font-style: italic } /* Generic.Emph */\n",
".highlight .gr { color: #FF0000 } /* Generic.Error */\n",
".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
".highlight .gi { color: #00A000 } /* Generic.Inserted */\n",
".highlight .go { color: #888888 } /* Generic.Output */\n",
".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
".highlight .gs { font-weight: bold } /* Generic.Strong */\n",
".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
".highlight .gt { color: #0044DD } /* Generic.Traceback */\n",
".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n",
".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
".highlight .kt { color: #B00040 } /* Keyword.Type */\n",
".highlight .m { color: #666666 } /* Literal.Number */\n",
".highlight .s { color: #BA2121 } /* Literal.String */\n",
".highlight .na { color: #7D9029 } /* Name.Attribute */\n",
".highlight .nb { color: #008000 } /* Name.Builtin */\n",
".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
".highlight .no { color: #880000 } /* Name.Constant */\n",
".highlight .nd { color: #AA22FF } /* Name.Decorator */\n",
".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
".highlight .nf { color: #0000FF } /* Name.Function */\n",
".highlight .nl { color: #A0A000 } /* Name.Label */\n",
".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
".highlight .nv { color: #19177C } /* Name.Variable */\n",
".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n",
".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n",
".highlight .mf { color: #666666 } /* Literal.Number.Float */\n",
".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n",
".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n",
".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n",
".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n",
".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n",
".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n",
".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
".highlight .sx { color: #008000 } /* Literal.String.Other */\n",
".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n",
".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n",
".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n",
".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n",
".highlight .vc { color: #19177C } /* Name.Variable.Class */\n",
".highlight .vg { color: #19177C } /* Name.Variable.Global */\n",
".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n",
".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;indicator&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;spec_version&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2.1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;created&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2014-02-20T09:16:08.989Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;modified&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2014-02-20T09:16:08.989Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;File hash for Poison Ivy variant&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;description&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;This file hash indicates that a sample of Poison Ivy is present.&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;pattern&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;[file:hashes.&#39;SHA-256&#39; = &#39;ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c&#39;]&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;pattern_type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;stix&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;pattern_version&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2.1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;valid_from&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2014-02-20T09:00:00Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;labels&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n",
" <span class=\"s2\">&quot;malicious-activity&quot;</span>\n",
" <span class=\"p\">],</span>\n",
" <span class=\"nt\">&quot;extensions&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension_type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;toplevel-property-extension&quot;</span>\n",
" <span class=\"p\">}</span>\n",
" <span class=\"p\">},</span>\n",
" <span class=\"nt\">&quot;rank&quot;</span><span class=\"p\">:</span> <span class=\"mi\">5</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;toxicity&quot;</span><span class=\"p\">:</span> <span class=\"mi\">8</span>\n",
"<span class=\"p\">}</span>\n",
"</pre></div>\n"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import stix2\n",
"\n",
"extension_definition1 = stix2.v21.ExtensionDefinition(\n",
" id=\"extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8\",\n",
" created_by_ref=\"identity--11b76a96-5d2b-45e0-8a5a-f6994f370731\",\n",
" created=\"2014-02-20T09:16:08.000Z\",\n",
" modified=\"2014-02-20T09:16:08.000Z\",\n",
" name=\"New SDO 1\",\n",
" description=\"This schema adds two properties to a STIX object at the toplevel\",\n",
" schema=\"https://www.example.com/schema-foo-1a/v1/\",\n",
" version=\"1.2.1\",\n",
" extension_types=[\"toplevel-property-extension\"],\n",
" extension_properties=[\n",
" \"toxicity\",\n",
" \"rank\",\n",
" ],\n",
")\n",
"\n",
"indicator = stix2.v21.Indicator(\n",
" id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c',\n",
" created='2014-02-20T09:16:08.989000Z',\n",
" modified='2014-02-20T09:16:08.989000Z',\n",
" name='File hash for Poison Ivy variant',\n",
" description='This file hash indicates that a sample of Poison Ivy is present.',\n",
" labels=[\n",
" 'malicious-activity',\n",
" ],\n",
" rank=5,\n",
" toxicity=8,\n",
" pattern='[file:hashes.\\'SHA-256\\' = \\'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c\\']',\n",
" pattern_type='stix',\n",
" valid_from='2014-02-20T09:00:00.000000Z',\n",
" extensions={\n",
" extension_definition1.id : {\n",
" 'extension_type': 'toplevel-property-extension',\n",
" },\n",
" }\n",
")\n",
"\n",
"print(extension_definition1.serialize(pretty=True))\n",
"print(indicator.serialize(pretty=True))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Using CustomExtension decorator\n",
"\n",
"However, in order to prevent repetitive instantiation of the same extension, the `@CustomExtension` decorator can be used to register the `extension-definition` with stix2. Use the `extension_type` class variable to define what kind of extension it is. Then its id can be passed into objects that use this extension."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style type=\"text/css\">pre { line-height: 125%; margin: 0; }\n",
"td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
"span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
".highlight .hll { background-color: #ffffcc }\n",
".highlight { background: #f8f8f8; }\n",
".highlight .c { color: #408080; font-style: italic } /* Comment */\n",
".highlight .err { border: 1px solid #FF0000 } /* Error */\n",
".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n",
".highlight .o { color: #666666 } /* Operator */\n",
".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n",
".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
".highlight .gd { color: #A00000 } /* Generic.Deleted */\n",
".highlight .ge { font-style: italic } /* Generic.Emph */\n",
".highlight .gr { color: #FF0000 } /* Generic.Error */\n",
".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
".highlight .gi { color: #00A000 } /* Generic.Inserted */\n",
".highlight .go { color: #888888 } /* Generic.Output */\n",
".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
".highlight .gs { font-weight: bold } /* Generic.Strong */\n",
".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
".highlight .gt { color: #0044DD } /* Generic.Traceback */\n",
".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n",
".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
".highlight .kt { color: #B00040 } /* Keyword.Type */\n",
".highlight .m { color: #666666 } /* Literal.Number */\n",
".highlight .s { color: #BA2121 } /* Literal.String */\n",
".highlight .na { color: #7D9029 } /* Name.Attribute */\n",
".highlight .nb { color: #008000 } /* Name.Builtin */\n",
".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
".highlight .no { color: #880000 } /* Name.Constant */\n",
".highlight .nd { color: #AA22FF } /* Name.Decorator */\n",
".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
".highlight .nf { color: #0000FF } /* Name.Function */\n",
".highlight .nl { color: #A0A000 } /* Name.Label */\n",
".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
".highlight .nv { color: #19177C } /* Name.Variable */\n",
".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n",
".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n",
".highlight .mf { color: #666666 } /* Literal.Number.Float */\n",
".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n",
".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n",
".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n",
".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n",
".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n",
".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n",
".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
".highlight .sx { color: #008000 } /* Literal.String.Other */\n",
".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n",
".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n",
".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n",
".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n",
".highlight .vc { color: #19177C } /* Name.Variable.Class */\n",
".highlight .vg { color: #19177C } /* Name.Variable.Global */\n",
".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n",
".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;indicator&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;spec_version&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2.1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;created&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2014-02-20T09:16:08.989Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;modified&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2014-02-20T09:16:08.989Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;File hash for Poison Ivy variant&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;description&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;This file hash indicates that a sample of Poison Ivy is present.&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;pattern&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;[file:hashes.&#39;SHA-256&#39; = &#39;ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c&#39;]&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;pattern_type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;stix&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;pattern_version&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2.1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;valid_from&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2014-02-20T09:00:00Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;labels&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n",
" <span class=\"s2\">&quot;malicious-activity&quot;</span>\n",
" <span class=\"p\">],</span>\n",
" <span class=\"nt\">&quot;extensions&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension_type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;toplevel-property-extension&quot;</span>\n",
" <span class=\"p\">}</span>\n",
" <span class=\"p\">},</span>\n",
" <span class=\"nt\">&quot;rank&quot;</span><span class=\"p\">:</span> <span class=\"mi\">5</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;toxicity&quot;</span><span class=\"p\">:</span> <span class=\"mi\">8</span>\n",
"<span class=\"p\">}</span>\n",
"</pre></div>\n"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"TOPLEVEL_EXTENSION_DEFINITION_ID = 'extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8'\n",
"\n",
"@stix2.v21.CustomExtension(\n",
" TOPLEVEL_EXTENSION_DEFINITION_ID, [\n",
" ('rank', stix2.properties.IntegerProperty(required=True)),\n",
" ('toxicity', stix2.properties.IntegerProperty(required=True)),\n",
" ],\n",
")\n",
"class ExtensionTopLevel:\n",
" extension_type = 'toplevel-property-extension'\n",
"\n",
"indicator = stix2.v21.Indicator(\n",
" id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c',\n",
" created='2014-02-20T09:16:08.989000Z',\n",
" modified='2014-02-20T09:16:08.989000Z',\n",
" name='File hash for Poison Ivy variant',\n",
" description='This file hash indicates that a sample of Poison Ivy is present.',\n",
" labels=[\n",
" 'malicious-activity',\n",
" ],\n",
" rank=5,\n",
" toxicity=8,\n",
" pattern='[file:hashes.\\'SHA-256\\' = \\'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c\\']',\n",
" pattern_type='stix',\n",
" valid_from='2014-02-20T09:00:00.000000Z',\n",
" extensions={\n",
" TOPLEVEL_EXTENSION_DEFINITION_ID : {\n",
" 'extension_type': 'toplevel-property-extension',\n",
" },\n",
" }\n",
")\n",
"\n",
"print(indicator.serialize(pretty=True))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Using CustomObservable for Extension Definition\n",
"\n",
"Similarly, when registering new objects via `@CustomObservable` you can pass the `extension-definition` id that defines this new SCO. \n",
"\n",
"---\n",
"**Note:**\n",
"Creating an instance of an extension-definition object **does not** mean it is registered in the library. Please use the appropriate decorator for this step: `@CustomExtension`, `@CustomObject`, `@CustomObservable`, `@CustomMarking`\n",
"\n",
"---"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style type=\"text/css\">pre { line-height: 125%; margin: 0; }\n",
"td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
"span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
".highlight .hll { background-color: #ffffcc }\n",
".highlight { background: #f8f8f8; }\n",
".highlight .c { color: #408080; font-style: italic } /* Comment */\n",
".highlight .err { border: 1px solid #FF0000 } /* Error */\n",
".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n",
".highlight .o { color: #666666 } /* Operator */\n",
".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n",
".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
".highlight .gd { color: #A00000 } /* Generic.Deleted */\n",
".highlight .ge { font-style: italic } /* Generic.Emph */\n",
".highlight .gr { color: #FF0000 } /* Generic.Error */\n",
".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
".highlight .gi { color: #00A000 } /* Generic.Inserted */\n",
".highlight .go { color: #888888 } /* Generic.Output */\n",
".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
".highlight .gs { font-weight: bold } /* Generic.Strong */\n",
".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
".highlight .gt { color: #0044DD } /* Generic.Traceback */\n",
".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n",
".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
".highlight .kt { color: #B00040 } /* Keyword.Type */\n",
".highlight .m { color: #666666 } /* Literal.Number */\n",
".highlight .s { color: #BA2121 } /* Literal.String */\n",
".highlight .na { color: #7D9029 } /* Name.Attribute */\n",
".highlight .nb { color: #008000 } /* Name.Builtin */\n",
".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
".highlight .no { color: #880000 } /* Name.Constant */\n",
".highlight .nd { color: #AA22FF } /* Name.Decorator */\n",
".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
".highlight .nf { color: #0000FF } /* Name.Function */\n",
".highlight .nl { color: #A0A000 } /* Name.Label */\n",
".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
".highlight .nv { color: #19177C } /* Name.Variable */\n",
".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n",
".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n",
".highlight .mf { color: #666666 } /* Literal.Number.Float */\n",
".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n",
".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n",
".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n",
".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n",
".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n",
".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n",
".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
".highlight .sx { color: #008000 } /* Literal.String.Other */\n",
".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n",
".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n",
".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n",
".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n",
".highlight .vc { color: #19177C } /* Name.Variable.Class */\n",
".highlight .vg { color: #19177C } /* Name.Variable.Global */\n",
".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n",
".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;my-favorite-sco&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;spec_version&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2.1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;my-favorite-sco--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;This is the name of my favorite SCO&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;some_network_protocol_field&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;value&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;extensions&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension-definition--150c1738-28c9-44d0-802d-70523218240b&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension_type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;new-sco&quot;</span>\n",
" <span class=\"p\">}</span>\n",
" <span class=\"p\">}</span>\n",
"<span class=\"p\">}</span>\n",
"</pre></div>\n"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"@stix2.v21.CustomObservable(\n",
" 'my-favorite-sco', [\n",
" ('name', stix2.properties.StringProperty(required=True)),\n",
" ('some_network_protocol_field', stix2.properties.StringProperty(required=True)),\n",
" ], ['name', 'some_network_protocol_field'], 'extension-definition--150c1738-28c9-44d0-802d-70523218240b',\n",
")\n",
"class MyFavSCO:\n",
" pass\n",
"\n",
"my_favorite_sco = MyFavSCO(\n",
" id='my-favorite-sco--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874',\n",
" name='This is the name of my favorite SCO',\n",
" some_network_protocol_field='value',\n",
")\n",
"\n",
"print(my_favorite_sco.serialize(pretty=True))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Using CustomMarking for Extension Definition\n",
"\n",
"The example below shows the use for MarkingDefinition extensions. Currently this is only supported as a `property-extension`. Now, as another option to building the `extensions` as a dictionary, it can also be built with objects as shown below by extracting the registered class."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style type=\"text/css\">pre { line-height: 125%; margin: 0; }\n",
"td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
"span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
".highlight .hll { background-color: #ffffcc }\n",
".highlight { background: #f8f8f8; }\n",
".highlight .c { color: #408080; font-style: italic } /* Comment */\n",
".highlight .err { border: 1px solid #FF0000 } /* Error */\n",
".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n",
".highlight .o { color: #666666 } /* Operator */\n",
".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n",
".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
".highlight .gd { color: #A00000 } /* Generic.Deleted */\n",
".highlight .ge { font-style: italic } /* Generic.Emph */\n",
".highlight .gr { color: #FF0000 } /* Generic.Error */\n",
".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
".highlight .gi { color: #00A000 } /* Generic.Inserted */\n",
".highlight .go { color: #888888 } /* Generic.Output */\n",
".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
".highlight .gs { font-weight: bold } /* Generic.Strong */\n",
".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
".highlight .gt { color: #0044DD } /* Generic.Traceback */\n",
".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n",
".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
".highlight .kt { color: #B00040 } /* Keyword.Type */\n",
".highlight .m { color: #666666 } /* Literal.Number */\n",
".highlight .s { color: #BA2121 } /* Literal.String */\n",
".highlight .na { color: #7D9029 } /* Name.Attribute */\n",
".highlight .nb { color: #008000 } /* Name.Builtin */\n",
".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
".highlight .no { color: #880000 } /* Name.Constant */\n",
".highlight .nd { color: #AA22FF } /* Name.Decorator */\n",
".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
".highlight .nf { color: #0000FF } /* Name.Function */\n",
".highlight .nl { color: #A0A000 } /* Name.Label */\n",
".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
".highlight .nv { color: #19177C } /* Name.Variable */\n",
".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n",
".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n",
".highlight .mf { color: #666666 } /* Literal.Number.Float */\n",
".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n",
".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n",
".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n",
".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n",
".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n",
".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n",
".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
".highlight .sx { color: #008000 } /* Literal.String.Other */\n",
".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n",
".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n",
".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n",
".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n",
".highlight .vc { color: #19177C } /* Name.Variable.Class */\n",
".highlight .vg { color: #19177C } /* Name.Variable.Global */\n",
".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n",
".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;marking-definition&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;spec_version&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2.1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;marking-definition--28417f9f-1963-4e7f-914d-233f8fd4829f&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;created&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2021-03-31T21:54:46.652069Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;This is the name of my favorite Marking&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;extensions&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension_type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;property-extension&quot;</span>\n",
" <span class=\"p\">}</span>\n",
" <span class=\"p\">}</span>\n",
"<span class=\"p\">}</span>\n",
"</pre></div>\n"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from stix2 import registry\n",
"\n",
"MARKING_EXTENSION_ID = 'extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff'\n",
"\n",
"@stix2.v21.CustomMarking(\n",
" 'my-favorite-marking', [\n",
" ('some_marking_field', stix2.properties.StringProperty(required=True)),\n",
" ], MARKING_EXTENSION_ID,\n",
")\n",
"class MyFavMarking:\n",
" pass\n",
"\n",
"ext_class = registry.class_for_type(MARKING_EXTENSION_ID, '2.1')\n",
"\n",
"my_favorite_marking = MyFavMarking(\n",
" name='This is the name of my favorite Marking',\n",
" extensions={\n",
" MARKING_EXTENSION_ID: ext_class(some_marking_field='value')\n",
" }\n",
")\n",
"\n",
"print(my_favorite_marking.serialize(pretty=True))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Using CustomObject for Extension Definition\n",
"\n",
"Similar to the examples above, the same can be done for SDOs and SROs."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style type=\"text/css\">pre { line-height: 125%; margin: 0; }\n",
"td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }\n",
"td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
"span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }\n",
".highlight .hll { background-color: #ffffcc }\n",
".highlight { background: #f8f8f8; }\n",
".highlight .c { color: #408080; font-style: italic } /* Comment */\n",
".highlight .err { border: 1px solid #FF0000 } /* Error */\n",
".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n",
".highlight .o { color: #666666 } /* Operator */\n",
".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n",
".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
".highlight .gd { color: #A00000 } /* Generic.Deleted */\n",
".highlight .ge { font-style: italic } /* Generic.Emph */\n",
".highlight .gr { color: #FF0000 } /* Generic.Error */\n",
".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
".highlight .gi { color: #00A000 } /* Generic.Inserted */\n",
".highlight .go { color: #888888 } /* Generic.Output */\n",
".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
".highlight .gs { font-weight: bold } /* Generic.Strong */\n",
".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
".highlight .gt { color: #0044DD } /* Generic.Traceback */\n",
".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n",
".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
".highlight .kt { color: #B00040 } /* Keyword.Type */\n",
".highlight .m { color: #666666 } /* Literal.Number */\n",
".highlight .s { color: #BA2121 } /* Literal.String */\n",
".highlight .na { color: #7D9029 } /* Name.Attribute */\n",
".highlight .nb { color: #008000 } /* Name.Builtin */\n",
".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
".highlight .no { color: #880000 } /* Name.Constant */\n",
".highlight .nd { color: #AA22FF } /* Name.Decorator */\n",
".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
".highlight .nf { color: #0000FF } /* Name.Function */\n",
".highlight .nl { color: #A0A000 } /* Name.Label */\n",
".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
".highlight .nv { color: #19177C } /* Name.Variable */\n",
".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n",
".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n",
".highlight .mf { color: #666666 } /* Literal.Number.Float */\n",
".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n",
".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n",
".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n",
".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n",
".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n",
".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n",
".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
".highlight .sx { color: #008000 } /* Literal.String.Other */\n",
".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n",
".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n",
".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n",
".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n",
".highlight .vc { color: #19177C } /* Name.Variable.Class */\n",
".highlight .vg { color: #19177C } /* Name.Variable.Global */\n",
".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n",
".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n",
".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;my-favorite-sro&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;spec_version&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2.1&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;my-favorite-sro--d6306d62-c08d-4d78-baf7-11e7a4c9bc36&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;created&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2021-03-31T22:43:42.807698Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;modified&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2021-03-31T22:43:42.807698Z&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;My First SRO&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;some_source_ref&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;identity--b1da8c3e-34d8-470f-9d2b-392e275f1f7d&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;some_target_ref&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;identity--1ddfed54-e8cd-49c9-9c7d-8d1b03c94685&quot;</span><span class=\"p\">,</span>\n",
" <span class=\"nt\">&quot;extensions&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension-definition--e96690a5-dc13-4f27-99dd-0f2188ad74ce&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n",
" <span class=\"nt\">&quot;extension_type&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;new-sro&quot;</span>\n",
" <span class=\"p\">}</span>\n",
" <span class=\"p\">}</span>\n",
"<span class=\"p\">}</span>\n",
"</pre></div>\n"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"invalid_refs = ['bundle', 'language-content', 'marking-definition', 'relationship', 'sighting', 'foobar']\n",
"\n",
"@stix2.v21.CustomObject(\n",
" 'my-favorite-sro', [\n",
" ('name', stix2.properties.StringProperty(required=False)),\n",
" ('some_source_ref', stix2.properties.ReferenceProperty(invalid_types=invalid_refs, spec_version='2.1', required=True)),\n",
" ('some_target_ref', stix2.properties.ReferenceProperty(invalid_types=invalid_refs, spec_version='2.1', required=True)),\n",
" ], extension_name='extension-definition--e96690a5-dc13-4f27-99dd-0f2188ad74ce', is_sdo=False,\n",
")\n",
"class MyFavSRO:\n",
" pass\n",
"\n",
"\n",
"my_favorite_sro = MyFavSRO(\n",
" name=\"My First SRO\",\n",
" some_source_ref=\"identity--b1da8c3e-34d8-470f-9d2b-392e275f1f7d\",\n",
" some_target_ref=\"identity--1ddfed54-e8cd-49c9-9c7d-8d1b03c94685\",\n",
")\n",
"\n",
"print(my_favorite_sro.serialize(pretty=True))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -262,7 +262,7 @@
"mal = fs.get(\"malware--92ec0cbd-2c30-44a2-b270-73f4ec949841\")\n", "mal = fs.get(\"malware--92ec0cbd-2c30-44a2-b270-73f4ec949841\")\n",
"\n", "\n",
"# for visual purposes\n", "# for visual purposes\n",
"print(mal)" "print(mal.serialize(pretty=True))"
] ]
}, },
{ {

File diff suppressed because it is too large Load Diff

View File

@ -187,7 +187,7 @@
"mem.add(ind)\n", "mem.add(ind)\n",
"\n", "\n",
"# for visual purposes\n", "# for visual purposes\n",
"print(mem.get(ind.id))\n" "print(mem.get(ind.id).serialize(pretty=True))\n"
] ]
}, },
{ {
@ -304,7 +304,7 @@
"mem.add([ind2,ind3, mal])\n", "mem.add([ind2,ind3, mal])\n",
"\n", "\n",
"# for visual purposes\n", "# for visual purposes\n",
"print(mem.get(ind3.id))" "print(mem.get(ind3.id).serialize(pretty=True))"
] ]
}, },
{ {
@ -412,7 +412,7 @@
"from stix2 import Filter\n", "from stix2 import Filter\n",
"\n", "\n",
"mal = mem.query([Filter(\"malware_types\",\"=\", \"rootkit\")])[0]\n", "mal = mem.query([Filter(\"malware_types\",\"=\", \"rootkit\")])[0]\n",
"print(mal)" "print(mal.serialize(pretty=True))"
] ]
}, },
{ {
@ -533,7 +533,7 @@
"report = mem_2.get(\"malware--6cee28b8-4d42-4e72-bd77-ea47897672c0\")\n", "report = mem_2.get(\"malware--6cee28b8-4d42-4e72-bd77-ea47897672c0\")\n",
"\n", "\n",
"# for visual purposes\n", "# for visual purposes\n",
"print(report)" "print(report.serialize(pretty=True))"
] ]
} }
], ],

View File

@ -282,7 +282,7 @@
"\n", "\n",
"obj = parse(input_string)\n", "obj = parse(input_string)\n",
"print(type(obj))\n", "print(type(obj))\n",
"print(obj)" "print(obj.serialize(pretty=True))"
] ]
}, },
{ {
@ -483,7 +483,7 @@
"\n", "\n",
"obj = parse(input_dict)\n", "obj = parse(input_dict)\n",
"print(type(obj))\n", "print(type(obj))\n",
"print(obj)" "print(obj.serialize(pretty=True))"
] ]
}, },
{ {
@ -677,7 +677,7 @@
"\n", "\n",
"obj = parse(file_handle)\n", "obj = parse(file_handle)\n",
"print(type(obj))\n", "print(type(obj))\n",
"print(obj)" "print(obj.serialize(pretty=True))"
] ]
}, },
{ {

View File

@ -1502,7 +1502,7 @@
"\n", "\n",
"ece14 = ObservationExpression(EqualityComparisonExpression(ObjectPath(\"file\", [\"name\"]), \"$$t00rzch$$.elf\"))\n", "ece14 = ObservationExpression(EqualityComparisonExpression(ObjectPath(\"file\", [\"name\"]), \"$$t00rzch$$.elf\"))\n",
"ind = Indicator(name=\"Cryptotorch\", pattern_type=\"stix\", pattern=ece14)\n", "ind = Indicator(name=\"Cryptotorch\", pattern_type=\"stix\", pattern=ece14)\n",
"print(ind)" "print(ind.serialize(pretty=True))"
] ]
} }
], ],
@ -1522,7 +1522,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.9.0a6" "version": "3.9.2"
} }
}, },
"nbformat": 4, "nbformat": 4,

View File

@ -173,14 +173,21 @@
" pattern_type=\"stix\",\n", " pattern_type=\"stix\",\n",
" pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n", " pattern=\"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\")\n",
"\n", "\n",
"print(str(indicator))" "print(indicator.serialize(pretty=True))"
] ]
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"However, the string representation can be slow, as it sorts properties to be in a more readable order. If you need performance and don't care about the human-readability of the output, use the object's `serialize()` function:" "---\n",
"**New in 3.0.0:** \n",
"\n",
"Calling `str()` on a STIX object will call `serialize()` without any formatting options. The change was made to address the performance penalty induced by unknowingly calling with the pretty formatted option. As shown above, to get the same effect as `str()` had in past versions of the library, use the method directly and pass in the pretty argument `serialize(pretty=True)`.\n",
"\n",
"---\n",
"\n",
"However, the pretty formatted string representation can be slow, as it sorts properties to be in a more readable order. If you need performance and don't care about the human-readability of the output, use the object's `serialize()` function to pass in any arguments `json.dump()` would understand:"
] ]
}, },
{ {
@ -384,13 +391,6 @@
"source": [ "source": [
"print(indicator.serialize(indent=4))" "print(indicator.serialize(indent=4))"
] ]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The only difference between this and the string representation from using `str()` is that this will not sort the keys. This works because the keyword arguments are passed to `json.dumps()` internally."
]
} }
], ],
"metadata": { "metadata": {

View File

@ -557,10 +557,10 @@
"stix_obj_versions = tc_source.all_versions(\"indicator--6770298f-0fd8-471a-ab8c-1c658a46574e\")\n", "stix_obj_versions = tc_source.all_versions(\"indicator--6770298f-0fd8-471a-ab8c-1c658a46574e\")\n",
"\n", "\n",
"#for visual purposes\n", "#for visual purposes\n",
"print(stix_obj)\n", "print(stix_obj.serialize(pretty=True))\n",
"print(\"-------\")\n", "print(\"-------\")\n",
"for so in stix_obj_versions:\n", "for so in stix_obj_versions:\n",
" print(so)\n" " print(so.serialize(pretty=True))\n"
] ]
}, },
{ {
@ -959,7 +959,7 @@
"\n", "\n",
"#for visual purposes\n", "#for visual purposes\n",
"for indicator in indicators:\n", "for indicator in indicators:\n",
" print(indicator)" " print(indicator.serialize(pretty=True))"
] ]
}, },
{ {
@ -1113,7 +1113,7 @@
"# TAXIICollectionStore\n", "# TAXIICollectionStore\n",
"stix_obj2 = tc_source.get(\"malware--c0931cc6-c75e-47e5-9036-78fabc95d4ec\")\n", "stix_obj2 = tc_source.get(\"malware--c0931cc6-c75e-47e5-9036-78fabc95d4ec\")\n",
"\n", "\n",
"print(stix_obj2)" "print(stix_obj2.serialize(pretty=True))"
] ]
}, },
{ {

View File

@ -356,7 +356,7 @@
" \"pattern\": \"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\",\n", " \"pattern\": \"[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']\",\n",
" \"valid_from\": \"2017-09-26T23:33:39.829952Z\"\n", " \"valid_from\": \"2017-09-26T23:33:39.829952Z\"\n",
"}\"\"\", version=\"2.0\")\n", "}\"\"\", version=\"2.0\")\n",
"print(indicator)" "print(indicator.serialize(pretty=True))"
] ]
}, },
{ {

View File

@ -185,7 +185,7 @@
"\n", "\n",
"indicator2 = indicator.new_version(name=\"File hash for Foobar malware\",\n", "indicator2 = indicator.new_version(name=\"File hash for Foobar malware\",\n",
" labels=[\"malicious-activity\"])\n", " labels=[\"malicious-activity\"])\n",
"print(indicator2)" "print(indicator2.serialize(pretty=True))"
] ]
}, },
{ {
@ -326,7 +326,7 @@
], ],
"source": [ "source": [
"indicator3 = indicator.new_version(description=None)\n", "indicator3 = indicator.new_version(description=None)\n",
"print(indicator3)" "print(indicator3.serialize(pretty=True))"
] ]
}, },
{ {
@ -443,7 +443,7 @@
], ],
"source": [ "source": [
"indicator4 = indicator3.revoke()\n", "indicator4 = indicator3.revoke()\n",
"print(indicator4)" "print(indicator4.serialize(pretty=True))"
] ]
} }
], ],

View File

@ -506,7 +506,7 @@
"source": [ "source": [
"for i in indicators():\n", "for i in indicators():\n",
" for obj in i.related():\n", " for obj in i.related():\n",
" print(obj)" " print(obj.serialize(pretty=True))"
] ]
}, },
{ {
@ -621,7 +621,7 @@
"source": [ "source": [
"malware = get('malware--c0931cc6-c75e-47e5-9036-78fabc95d4ec')\n", "malware = get('malware--c0931cc6-c75e-47e5-9036-78fabc95d4ec')\n",
"indicator = malware.related(filters=Filter('type', '=', 'indicator'))\n", "indicator = malware.related(filters=Filter('type', '=', 'indicator'))\n",
"print(indicator[0])" "print(indicator[0].serialize(pretty=True))"
] ]
}, },
{ {

View File

@ -24,7 +24,7 @@ To accomplish these goals, and to incorporate lessons learned while developing
where users would create an object and then assign attributes to it, in where users would create an object and then assign attributes to it, in
``stix2`` all properties must be provided when creating the object. ``stix2`` all properties must be provided when creating the object.
2. Where necessary, library objects should act like ``dict``'s. When treated as 2. Where necessary, library objects should act like ``dict``'s. When treated as
a ``str``, the JSON reprentation of the object should be used. a ``str``, the JSON representation of the object should be used.
3. Core Python data types (including numeric types, ``datetime``) should be used 3. Core Python data types (including numeric types, ``datetime``) should be used
when appropriate, and serialized to the correct format in JSON as specified when appropriate, and serialized to the correct format in JSON as specified
in the STIX 2 spec. in the STIX 2 spec.

View File

@ -1,4 +1,4 @@
from taxii2client import Collection from taxii2client.v21 import Collection
import stix2 import stix2
@ -8,7 +8,7 @@ import stix2
def main(): def main():
collection = Collection( collection = Collection(
"http://127.0.0.1:5000/trustgroup1/collections/52892447-4d7e-4f70-b94d-d7f22742ff63/", "http://127.0.0.1:5000/trustgroup1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/",
user="admin", password="Password0", user="admin", password="Password0",
) )
@ -16,12 +16,12 @@ def main():
taxii = stix2.TAXIICollectionSource(collection) taxii = stix2.TAXIICollectionSource(collection)
# get (url watch indicator) # get (url watch indicator)
indicator_fw = taxii.get("indicator--00000000-0000-4000-8000-000000000001") indicator_fw = taxii.get("indicator--6770298f-0fd8-471a-ab8c-1c658a46574e")
print("\n\n-------Queried for Indicator - got:") print("\n\n-------Queried for Indicator - got:")
print(indicator_fw.serialize(indent=4)) print(indicator_fw.serialize(indent=4))
# all versions (url watch indicator - currently two) # all versions (url watch indicator - currently two)
indicator_fw_versions = taxii.all_versions("indicator--00000000-0000-4000-8000-000000000001") indicator_fw_versions = taxii.all_versions("indicator--6770298f-0fd8-471a-ab8c-1c658a46574e")
print("\n\n------Queried for indicator (all_versions()) - got:") print("\n\n------Queried for indicator (all_versions()) - got:")
for indicator in indicator_fw_versions: for indicator in indicator_fw_versions:
print(indicator.serialize(indent=4)) print(indicator.serialize(indent=4))

View File

@ -1,5 +1,7 @@
"""Base classes for type definitions in the STIX2 library.""" """Base classes for type definitions in the STIX2 library."""
import collections
import collections.abc
import copy import copy
import itertools import itertools
import re import re
@ -17,23 +19,12 @@ from .exceptions import (
) )
from .markings import _MarkingsMixin from .markings import _MarkingsMixin
from .markings.utils import validate from .markings.utils import validate
from .serialization import ( from .registry import class_for_type
STIXJSONEncoder, STIXJSONIncludeOptionalDefaultsEncoder, fp_serialize, from .serialization import STIXJSONEncoder, fp_serialize, serialize
serialize,
)
from .utils import NOW, PREFIX_21_REGEX, get_timestamp from .utils import NOW, PREFIX_21_REGEX, get_timestamp
from .versioning import new_version as _new_version from .versioning import new_version as _new_version
from .versioning import revoke as _revoke from .versioning import revoke as _revoke
try:
from collections.abc import Mapping
except ImportError:
from collections import Mapping
# TODO: Remove STIXJSONEncoder, STIXJSONIncludeOptionalDefaultsEncoder, serialize from __all__ on next major release.
# Kept for backwards compatibility.
__all__ = ['STIXJSONEncoder', 'STIXJSONIncludeOptionalDefaultsEncoder', '_STIXBase', 'serialize']
DEFAULT_ERROR = "{type} must have {property}='{expected}'." DEFAULT_ERROR = "{type} must have {property}='{expected}'."
SCO_DET_ID_NAMESPACE = uuid.UUID("00abedb4-aa42-466c-9c01-fed23315a9b7") SCO_DET_ID_NAMESPACE = uuid.UUID("00abedb4-aa42-466c-9c01-fed23315a9b7")
@ -42,19 +33,9 @@ def get_required_properties(properties):
return (k for k, v in properties.items() if v.required) return (k for k, v in properties.items() if v.required)
class _STIXBase(Mapping): class _STIXBase(collections.abc.Mapping):
"""Base class for STIX object types""" """Base class for STIX object types"""
def object_properties(self):
props = set(self._properties.keys())
custom_props = list(set(self._inner.keys()) - props)
custom_props.sort()
all_properties = list(self._properties.keys())
all_properties.extend(custom_props) # Any custom properties to the bottom
return all_properties
def _check_property(self, prop_name, prop, kwargs, allow_custom): def _check_property(self, prop_name, prop, kwargs, allow_custom):
if prop_name not in kwargs: if prop_name not in kwargs:
if hasattr(prop, 'default'): if hasattr(prop, 'default'):
@ -80,7 +61,7 @@ class _STIXBase(Mapping):
return has_custom return has_custom
# interproperty constraint methods # inter-property constraint methods
def _check_mutually_exclusive_properties(self, list_of_properties, at_least_one=True): def _check_mutually_exclusive_properties(self, list_of_properties, at_least_one=True):
current_properties = self.properties_populated() current_properties = self.properties_populated()
@ -89,20 +70,34 @@ class _STIXBase(Mapping):
if count > 1 or (at_least_one and count == 0): if count > 1 or (at_least_one and count == 0):
raise MutuallyExclusivePropertiesError(self.__class__, list_of_properties) raise MutuallyExclusivePropertiesError(self.__class__, list_of_properties)
def _check_at_least_one_property(self, list_of_properties=None): def _check_at_least_one_property(self, properties_checked=None):
if not list_of_properties: """
list_of_properties = sorted(list(self.__class__._properties.keys())) Check whether one or more of the given properties are present.
:param properties_checked: An iterable of the names of the properties
of interest, or None to check against a default list. The default
list includes all properties defined on the object, with some
hard-coded exceptions.
:raises AtLeastOnePropertyError: If none of the given properties are
present.
"""
if properties_checked is None:
property_exceptions = {"extensions", "type"}
if isinstance(self, _Observable): if isinstance(self, _Observable):
props_to_remove = ["type", "id", "defanged", "spec_version"] property_exceptions |= {"id", "defanged", "spec_version"}
else:
props_to_remove = ["type"]
list_of_properties = [prop for prop in list_of_properties if prop not in props_to_remove] properties_checked = self._properties.keys() - property_exceptions
current_properties = self.properties_populated()
list_of_properties_populated = set(list_of_properties).intersection(current_properties)
if list_of_properties and (not list_of_properties_populated or list_of_properties_populated == set(['extensions'])): elif not isinstance(properties_checked, set):
raise AtLeastOnePropertyError(self.__class__, list_of_properties) properties_checked = set(properties_checked)
if properties_checked:
properties_checked_assigned = properties_checked & self.keys()
if not properties_checked_assigned:
raise AtLeastOnePropertyError(
self.__class__, properties_checked,
)
def _check_properties_dependency(self, list_of_properties, list_of_dependent_properties): def _check_properties_dependency(self, list_of_properties, list_of_dependent_properties):
failed_dependency_pairs = [] failed_dependency_pairs = []
@ -123,20 +118,49 @@ class _STIXBase(Mapping):
# Use the same timestamp for any auto-generated datetimes # Use the same timestamp for any auto-generated datetimes
self.__now = get_timestamp() self.__now = get_timestamp()
# Detect any keyword arguments not allowed for a specific type
custom_props = kwargs.pop('custom_properties', {}) custom_props = kwargs.pop('custom_properties', {})
if custom_props and not isinstance(custom_props, dict): if custom_props and not isinstance(custom_props, dict):
raise ValueError("'custom_properties' must be a dictionary") raise ValueError("'custom_properties' must be a dictionary")
extra_kwargs = kwargs.keys() - self._properties.keys() # Detect any keyword arguments representing customization.
if extra_kwargs and not allow_custom: # In STIX 2.1, this is complicated by "toplevel-property-extension"
raise ExtraPropertiesError(cls, extra_kwargs) # type extensions, which can add extra properties which are *not*
# considered custom.
extensions = kwargs.get("extensions")
registered_toplevel_extension_props = {}
has_unregistered_toplevel_extension = False
if extensions:
for ext_id, ext in extensions.items():
if ext.get("extension_type") == "toplevel-property-extension":
registered_ext_class = class_for_type(
ext_id, "2.1", "extensions",
)
if registered_ext_class:
registered_toplevel_extension_props.update(
registered_ext_class._toplevel_properties,
)
else:
has_unregistered_toplevel_extension = True
if has_unregistered_toplevel_extension:
# Must assume all extras are extension properties, not custom.
custom_kwargs = set()
else:
# All toplevel property extensions (if any) have been
# registered. So we can tell what their properties are and
# treat only those as not custom.
custom_kwargs = kwargs.keys() - self._properties.keys() \
- registered_toplevel_extension_props.keys()
if custom_kwargs and not allow_custom:
raise ExtraPropertiesError(cls, custom_kwargs)
if custom_props: if custom_props:
# loophole for custom_properties... # loophole for custom_properties...
allow_custom = True allow_custom = True
all_custom_prop_names = extra_kwargs | custom_props.keys() - \ all_custom_prop_names = (custom_kwargs | custom_props.keys()) - \
self._properties.keys() self._properties.keys()
if all_custom_prop_names: if all_custom_prop_names:
if not isinstance(self, stix2.v20._STIXBase20): if not isinstance(self, stix2.v20._STIXBase20):
@ -147,30 +171,52 @@ class _STIXBase(Mapping):
reason="Property name '%s' must begin with an alpha character." % prop_name, reason="Property name '%s' must begin with an alpha character." % prop_name,
) )
# Remove any keyword arguments whose value is None or [] (i.e. empty list) # defined_properties = all properties defined on this type, plus all
setting_kwargs = { # properties defined on this instance as a result of toplevel property
k: v # extensions.
for k, v in itertools.chain(kwargs.items(), custom_props.items()) defined_properties = collections.ChainMap(
if v is not None and v != [] self._properties, registered_toplevel_extension_props,
} )
assigned_properties = collections.ChainMap(kwargs, custom_props)
# Establish property order: spec-defined, toplevel extension, custom.
toplevel_extension_props = registered_toplevel_extension_props.keys() \
| (kwargs.keys() - self._properties.keys() - custom_kwargs)
property_order = itertools.chain(
self._properties,
toplevel_extension_props,
sorted(all_custom_prop_names),
)
setting_kwargs = {}
has_custom = bool(all_custom_prop_names)
for prop_name in property_order:
prop_val = assigned_properties.get(prop_name)
if prop_val not in (None, []):
setting_kwargs[prop_name] = prop_val
prop = defined_properties.get(prop_name)
if prop:
temp_custom = self._check_property(
prop_name, prop, setting_kwargs, allow_custom,
)
has_custom = has_custom or temp_custom
# Detect any missing required properties # Detect any missing required properties
required_properties = set(get_required_properties(self._properties)) required_properties = set(
missing_kwargs = required_properties - set(setting_kwargs) get_required_properties(defined_properties),
)
missing_kwargs = required_properties - setting_kwargs.keys()
if missing_kwargs: if missing_kwargs:
raise MissingPropertiesError(cls, missing_kwargs) raise MissingPropertiesError(cls, missing_kwargs)
has_custom = bool(all_custom_prop_names)
for prop_name, prop_metadata in self._properties.items():
temp_custom = self._check_property(
prop_name, prop_metadata, setting_kwargs, allow_custom,
)
has_custom = has_custom or temp_custom
# Cache defaulted optional properties for serialization # Cache defaulted optional properties for serialization
defaulted = [] defaulted = []
for name, prop in self._properties.items(): for name, prop in defined_properties.items():
try: try:
if ( if (
not prop.required and not hasattr(prop, '_fixed_value') and not prop.required and not hasattr(prop, '_fixed_value') and
@ -231,14 +277,12 @@ class _STIXBase(Mapping):
super(_STIXBase, self).__setattr__(name, value) super(_STIXBase, self).__setattr__(name, value)
def __str__(self): def __str__(self):
return self.serialize(pretty=True) # Note: use .serialize() or fp_serialize() directly if specific formatting options are needed.
return self.serialize()
def __repr__(self): def __repr__(self):
props = [(k, self[k]) for k in self.object_properties() if self.get(k)] props = ', '.join([f"{k}={self[k]!r}" for k in self])
return '{0}({1})'.format( return f'{self.__class__.__name__}({props})'
self.__class__.__name__,
', '.join(['{0!s}={1!r}'.format(k, v) for k, v in props]),
)
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
# Assume: we can ignore the memo argument, because no object will ever contain the same sub-object multiple times. # Assume: we can ignore the memo argument, because no object will ever contain the same sub-object multiple times.
@ -334,21 +378,8 @@ class _Observable(_STIXBase):
def __init__(self, **kwargs): def __init__(self, **kwargs):
# the constructor might be called independently of an observed data object # the constructor might be called independently of an observed data object
self._STIXBase__valid_refs = kwargs.pop('_valid_refs', []) self._STIXBase__valid_refs = kwargs.pop('_valid_refs', [])
self._properties['extensions'].allow_custom = kwargs.get('allow_custom', False)
super(_Observable, self).__init__(**kwargs) super(_Observable, self).__init__(**kwargs)
if 'id' not in kwargs and not isinstance(self, stix2.v20._Observable):
# Specific to 2.1+ observables: generate a deterministic ID
id_ = self._generate_id()
# Spec says fall back to UUIDv4 if no contributing properties were
# given. That's what already happened (the following is actually
# overwriting the default uuidv4), so nothing to do here.
if id_ is not None:
# Can't assign to self (we're immutable), so slip the ID in
# more sneakily.
self._inner["id"] = id_
def _check_ref(self, ref, prop, prop_name): def _check_ref(self, ref, prop, prop_name):
""" """
Only for checking `*_ref` or `*_refs` properties in spec_version 2.0 Only for checking `*_ref` or `*_refs` properties in spec_version 2.0
@ -481,7 +512,7 @@ def _make_json_serializable(value):
json_value = value # default assumption json_value = value # default assumption
if isinstance(value, Mapping): if isinstance(value, collections.abc.Mapping):
json_value = { json_value = {
k: _make_json_serializable(v) k: _make_json_serializable(v)
for k, v in value.items() for k, v in value.items()

View File

@ -1,9 +1,10 @@
from collections import OrderedDict from collections import OrderedDict
from .base import _cls_init from .base import _cls_init
from .properties import EnumProperty
from .registration import ( from .registration import (
_register_marking, _register_object, _register_observable, _get_extension_class, _register_extension, _register_marking,
_register_observable_extension, _register_object, _register_observable,
) )
@ -29,6 +30,11 @@ def _custom_object_builder(cls, type, properties, version, base_class):
def __init__(self, **kwargs): def __init__(self, **kwargs):
base_class.__init__(self, **kwargs) base_class.__init__(self, **kwargs)
_cls_init(cls, self, kwargs) _cls_init(cls, self, kwargs)
ext = getattr(self, 'with_extension', None)
if ext and version != '2.0':
if 'extensions' not in self._inner:
self._inner['extensions'] = {}
self._inner['extensions'][ext] = _get_extension_class(ext, version)()
_CustomObject.__name__ = cls.__name__ _CustomObject.__name__ = cls.__name__
@ -47,6 +53,11 @@ def _custom_marking_builder(cls, type, properties, version, base_class):
def __init__(self, **kwargs): def __init__(self, **kwargs):
base_class.__init__(self, **kwargs) base_class.__init__(self, **kwargs)
_cls_init(cls, self, kwargs) _cls_init(cls, self, kwargs)
ext = getattr(self, 'with_extension', None)
if ext and version != '2.0':
if 'extensions' not in self._inner:
self._inner['extensions'] = {}
self._inner['extensions'][ext] = _get_extension_class(ext, version)()
_CustomMarking.__name__ = cls.__name__ _CustomMarking.__name__ = cls.__name__
@ -70,6 +81,11 @@ def _custom_observable_builder(cls, type, properties, version, base_class, id_co
def __init__(self, **kwargs): def __init__(self, **kwargs):
base_class.__init__(self, **kwargs) base_class.__init__(self, **kwargs)
_cls_init(cls, self, kwargs) _cls_init(cls, self, kwargs)
ext = getattr(self, 'with_extension', None)
if ext and version != '2.0':
if 'extensions' not in self._inner:
self._inner['extensions'] = {}
self._inner['extensions'][ext] = _get_extension_class(ext, version)()
_CustomObservable.__name__ = cls.__name__ _CustomObservable.__name__ = cls.__name__
@ -77,13 +93,47 @@ def _custom_observable_builder(cls, type, properties, version, base_class, id_co
return _CustomObservable return _CustomObservable
def _custom_extension_builder(cls, observable, type, properties, version, base_class): def _custom_extension_builder(cls, type, properties, version, base_class):
prop_dict = _get_properties_dict(properties)
properties = _get_properties_dict(properties)
toplevel_properties = None
# Auto-create an "extension_type" property from the class attribute, if
# it exists. How to treat the other properties which were given depends on
# the extension type.
extension_type = getattr(cls, "extension_type", None)
if extension_type:
# I suppose I could also go with a plain string property, since the
# value is fixed... but an enum property seems more true to the
# property's semantics. Also, I can't import a vocab module for the
# enum values without circular import errors. :(
extension_type_prop = EnumProperty(
[
"new-sdo", "new-sco", "new-sro", "property-extension",
"toplevel-property-extension",
],
required=False,
fixed=extension_type,
)
nested_properties = {
"extension_type": extension_type_prop,
}
if extension_type == "toplevel-property-extension":
toplevel_properties = properties
else:
nested_properties.update(properties)
else:
nested_properties = properties
class _CustomExtension(cls, base_class): class _CustomExtension(cls, base_class):
_type = type _type = type
_properties = prop_dict _properties = nested_properties
if extension_type == "toplevel-property-extension":
_toplevel_properties = toplevel_properties
def __init__(self, **kwargs): def __init__(self, **kwargs):
base_class.__init__(self, **kwargs) base_class.__init__(self, **kwargs)
@ -91,5 +141,5 @@ def _custom_extension_builder(cls, observable, type, properties, version, base_c
_CustomExtension.__name__ = cls.__name__ _CustomExtension.__name__ = cls.__name__
_register_observable_extension(observable, _CustomExtension, version=version) _register_extension(_CustomExtension, version=version)
return _CustomExtension return _CustomExtension

View File

@ -257,7 +257,7 @@ def iterpath(obj, path=None):
def check_tlp_marking(marking_obj, spec_version): def check_tlp_marking(marking_obj, spec_version):
# Specific TLP Marking validation case. # Specific TLP Marking validation case.
if marking_obj["definition_type"] == "tlp": if marking_obj.get("definition_type", "") == "tlp":
color = marking_obj["definition"]["tlp"] color = marking_obj["definition"]["tlp"]
if color == "white": if color == "white":

View File

@ -86,6 +86,14 @@ def dict_to_stix2(stix_dict, allow_custom=False, version=None):
# flag allows for unknown custom objects too, but will not # flag allows for unknown custom objects too, but will not
# be parsed into STIX object, returned as is # be parsed into STIX object, returned as is
return stix_dict return stix_dict
for key_id, ext_def in stix_dict.get('extensions', {}).items():
if (
key_id.startswith('extension-definition--') and
'property-extension' not in ext_def.get('extension_type', '')
):
# prevents ParseError for unregistered objects when
# allow_custom=False and the extension defines a new object
return stix_dict
raise ParseError("Can't parse unknown object type '%s'! For custom types, use the CustomObject decorator." % obj_type) raise ParseError("Can't parse unknown object type '%s'! For custom types, use the CustomObject decorator." % obj_type)
return obj_class(allow_custom=allow_custom, **stix_dict) return obj_class(allow_custom=allow_custom, **stix_dict)

View File

@ -56,7 +56,7 @@ class TimestampConstant(_Constant):
class IntegerConstant(_Constant): class IntegerConstant(_Constant):
"""Pattern interger constant """Pattern integer constant
Args: Args:
value (int): integer value value (int): integer value
@ -265,7 +265,7 @@ class BasicObjectPathComponent(_ObjectPathComponent):
"""Basic object path component (for an observation or expression) """Basic object path component (for an observation or expression)
By "Basic", implies that the object path component is not a By "Basic", implies that the object path component is not a
list, object reference or futher referenced property, i.e. terminal list, object reference or further referenced property, i.e. terminal
component component
Args: Args:

View File

@ -2,6 +2,7 @@
import base64 import base64
import binascii import binascii
import collections.abc
import copy import copy
import inspect import inspect
import re import re
@ -13,20 +14,15 @@ import stix2.hashes
from .base import _STIXBase from .base import _STIXBase
from .exceptions import CustomContentError, DictionaryKeyError, STIXError from .exceptions import CustomContentError, DictionaryKeyError, STIXError
from .parsing import parse, parse_observable from .parsing import parse, parse_observable
from .registry import STIX2_OBJ_MAPS from .registry import class_for_type
from .utils import ( from .utils import (
STIXTypeClass, _get_dict, get_class_hierarchy_names, get_type_from_id, STIXTypeClass, _get_dict, get_class_hierarchy_names, get_type_from_id,
is_object, is_stix_type, parse_into_datetime, to_enum, is_object, is_stix_type, parse_into_datetime, to_enum,
) )
from .version import DEFAULT_VERSION from .version import DEFAULT_VERSION
try: TYPE_REGEX = re.compile(r'^-?[a-z0-9]+(-[a-z0-9]+)*-?$')
from collections.abc import Mapping TYPE_21_REGEX = re.compile(r'^([a-z][a-z0-9]*)+([a-z0-9-]+)*-?$')
except ImportError:
from collections import Mapping
TYPE_REGEX = re.compile(r'^\-?[a-z0-9]+(-[a-z0-9]+)*\-?$')
TYPE_21_REGEX = re.compile(r'^([a-z][a-z0-9]*)+(-[a-z0-9]+)*\-?$')
ERROR_INVALID_ID = ( ERROR_INVALID_ID = (
"not a valid STIX identifier, must match <object-type>--<UUID>: {}" "not a valid STIX identifier, must match <object-type>--<UUID>: {}"
) )
@ -125,7 +121,7 @@ class Property(object):
creating an object with that property. No default value exists for creating an object with that property. No default value exists for
these properties. (Default: ``False``) these properties. (Default: ``False``)
fixed: This provides a constant default value. Users are free to fixed: This provides a constant default value. Users are free to
provide this value explicity when constructing an object (which provide this value explicitly when constructing an object (which
allows you to copy **all** values from an existing object to a new allows you to copy **all** values from an existing object to a new
object), but if the user provides a value other than the ``fixed`` object), but if the user provides a value other than the ``fixed``
value, it will raise an error. This is semantically equivalent to value, it will raise an error. This is semantically equivalent to
@ -184,7 +180,7 @@ class Property(object):
if required and default: if required and default:
raise STIXError( raise STIXError(
"Cant't use 'required' and 'default' together. 'required'" "Can't use 'required' and 'default' together. 'required'"
"really means 'the user must provide this.'", "really means 'the user must provide this.'",
) )
@ -250,7 +246,7 @@ class ListProperty(Property):
if isinstance(item, self.contained): if isinstance(item, self.contained):
valid = item valid = item
elif isinstance(item, Mapping): elif isinstance(item, collections.abc.Mapping):
# attempt a mapping-like usage... # attempt a mapping-like usage...
valid = self.contained(allow_custom=allow_custom, **item) valid = self.contained(allow_custom=allow_custom, **item)
@ -738,7 +734,7 @@ class ObservableProperty(Property):
if dictified == {}: if dictified == {}:
raise ValueError("The observable property must contain a non-empty dictionary") raise ValueError("The observable property must contain a non-empty dictionary")
valid_refs = dict((k, v['type']) for (k, v) in dictified.items()) valid_refs = {k: v['type'] for (k, v) in dictified.items()}
has_custom = False has_custom = False
for key, obj in dictified.items(): for key, obj in dictified.items():
@ -771,8 +767,7 @@ class ExtensionsProperty(DictionaryProperty):
"""Property for representing extensions on Observable objects. """Property for representing extensions on Observable objects.
""" """
def __init__(self, spec_version=DEFAULT_VERSION, enclosing_type=None, required=False): def __init__(self, spec_version=DEFAULT_VERSION, required=False):
self.enclosing_type = enclosing_type
super(ExtensionsProperty, self).__init__(spec_version=spec_version, required=required) super(ExtensionsProperty, self).__init__(spec_version=spec_version, required=required)
def clean(self, value, allow_custom): def clean(self, value, allow_custom):
@ -786,17 +781,21 @@ class ExtensionsProperty(DictionaryProperty):
raise ValueError("The extensions property must contain a dictionary") raise ValueError("The extensions property must contain a dictionary")
has_custom = False has_custom = False
specific_type_map = STIX2_OBJ_MAPS[self.spec_version]['observable-extensions'].get(self.enclosing_type, {})
for key, subvalue in dictified.items(): for key, subvalue in dictified.items():
if key in specific_type_map: cls = class_for_type(key, self.spec_version, "extensions")
cls = specific_type_map[key] if cls:
if type(subvalue) is dict: if isinstance(subvalue, dict):
ext = cls(allow_custom=allow_custom, **subvalue) ext = cls(allow_custom=allow_custom, **subvalue)
elif type(subvalue) is cls: elif isinstance(subvalue, cls):
# If already an instance of an _Extension class, assume it's valid # If already an instance of the registered class, assume
# it's valid
ext = subvalue ext = subvalue
else: else:
raise ValueError("Cannot determine extension type.") raise TypeError(
"Can't create extension '{}' from {}.".format(
key, type(subvalue),
),
)
has_custom = has_custom or ext.has_custom has_custom = has_custom or ext.has_custom
@ -810,12 +809,24 @@ class ExtensionsProperty(DictionaryProperty):
dictified[key] = ext dictified[key] = ext
else: else:
if allow_custom: # If an unregistered "extension-definition--" style extension,
# we don't know what's supposed to be in it, so we can't
# determine whether there's anything custom. So, assume there
# are no customizations. If it's a different type of extension,
# non-registration implies customization (since all spec-defined
# extensions should be pre-registered with the library).
if key.startswith('extension-definition--'):
_validate_id(
key, self.spec_version, 'extension-definition--',
)
elif allow_custom:
has_custom = True has_custom = True
dictified[key] = subvalue
else: else:
raise CustomContentError("Can't parse unknown extension type: {}".format(key)) raise CustomContentError("Can't parse unknown extension type: {}".format(key))
dictified[key] = subvalue
return dictified, has_custom return dictified, has_custom
@ -828,8 +839,9 @@ class STIXObjectProperty(Property):
def clean(self, value, allow_custom): def clean(self, value, allow_custom):
# Any STIX Object (SDO, SRO, or Marking Definition) can be added to # Any STIX Object (SDO, SRO, or Marking Definition) can be added to
# a bundle with no further checks. # a bundle with no further checks.
stix2_classes = {'_DomainObject', '_RelationshipObject', 'MarkingDefinition'}
if any( if any(
x in ('_DomainObject', '_RelationshipObject', 'MarkingDefinition') x in stix2_classes
for x in get_class_hierarchy_names(value) for x in get_class_hierarchy_names(value)
): ):
# A simple "is this a spec version 2.1+ object" test. For now, # A simple "is this a spec version 2.1+ object" test. For now,

View File

@ -1,14 +1,13 @@
import re import re
from . import registry from . import registry, version
from .base import _DomainObject, _Observable from .base import _DomainObject
from .exceptions import DuplicateRegistrationError from .exceptions import DuplicateRegistrationError
from .properties import _validate_type from .properties import _validate_type
from .utils import PREFIX_21_REGEX, get_class_hierarchy_names from .utils import PREFIX_21_REGEX, get_class_hierarchy_names
from .version import DEFAULT_VERSION
def _register_object(new_type, version=DEFAULT_VERSION): def _register_object(new_type, version=version.DEFAULT_VERSION):
"""Register a custom STIX Object type. """Register a custom STIX Object type.
Args: Args:
@ -32,7 +31,7 @@ def _register_object(new_type, version=DEFAULT_VERSION):
properties = new_type._properties properties = new_type._properties
if not version: if not version:
version = DEFAULT_VERSION version = version.DEFAULT_VERSION
if version == "2.1": if version == "2.1":
for prop_name, prop in properties.items(): for prop_name, prop in properties.items():
@ -45,7 +44,7 @@ def _register_object(new_type, version=DEFAULT_VERSION):
OBJ_MAP[new_type._type] = new_type OBJ_MAP[new_type._type] = new_type
def _register_marking(new_marking, version=DEFAULT_VERSION): def _register_marking(new_marking, version=version.DEFAULT_VERSION):
"""Register a custom STIX Marking Definition type. """Register a custom STIX Marking Definition type.
Args: Args:
@ -59,7 +58,7 @@ def _register_marking(new_marking, version=DEFAULT_VERSION):
properties = new_marking._properties properties = new_marking._properties
if not version: if not version:
version = DEFAULT_VERSION version = version.DEFAULT_VERSION
_validate_type(mark_type, version) _validate_type(mark_type, version)
@ -74,7 +73,7 @@ def _register_marking(new_marking, version=DEFAULT_VERSION):
OBJ_MAP_MARKING[mark_type] = new_marking OBJ_MAP_MARKING[mark_type] = new_marking
def _register_observable(new_observable, version=DEFAULT_VERSION): def _register_observable(new_observable, version=version.DEFAULT_VERSION):
"""Register a custom STIX Cyber Observable type. """Register a custom STIX Cyber Observable type.
Args: Args:
@ -86,7 +85,7 @@ def _register_observable(new_observable, version=DEFAULT_VERSION):
properties = new_observable._properties properties = new_observable._properties
if not version: if not version:
version = DEFAULT_VERSION version = version.DEFAULT_VERSION
if version == "2.0": if version == "2.0":
# If using STIX2.0, check properties ending in "_ref/s" are ObjectReferenceProperties # If using STIX2.0, check properties ending in "_ref/s" are ObjectReferenceProperties
@ -133,27 +132,25 @@ def _register_observable(new_observable, version=DEFAULT_VERSION):
OBJ_MAP_OBSERVABLE[new_observable._type] = new_observable OBJ_MAP_OBSERVABLE[new_observable._type] = new_observable
def _register_observable_extension( def _get_extension_class(extension_uuid, version):
observable, new_extension, version=DEFAULT_VERSION, """Retrieve a registered class Extension"""
return registry.STIX2_OBJ_MAPS[version]['extensions'].get(extension_uuid)
def _register_extension(
new_extension, version=version.DEFAULT_VERSION,
): ):
"""Register a custom extension to a STIX Cyber Observable type. """Register a custom extension to any STIX Object type.
Args: Args:
observable: An observable class or instance new_extension (class): A class to register in the Extensions map.
new_extension (class): A class to register in the Observables
Extensions map.
version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). version (str): Which STIX2 version to use. (e.g. "2.0", "2.1").
Defaults to the latest supported version. Defaults to the latest supported version.
""" """
obs_class = observable if isinstance(observable, type) else \
type(observable)
ext_type = new_extension._type ext_type = new_extension._type
properties = new_extension._properties properties = new_extension._properties
if not issubclass(obs_class, _Observable):
raise ValueError("'observable' must be a valid Observable class!")
_validate_type(ext_type, version) _validate_type(ext_type, version)
if not new_extension._properties: if not new_extension._properties:
@ -163,37 +160,18 @@ def _register_observable_extension(
) )
if version == "2.1": if version == "2.1":
if not ext_type.endswith('-ext'): if not (ext_type.endswith('-ext') or ext_type.startswith('extension-definition--')):
raise ValueError( raise ValueError(
"Invalid extension type name '%s': must end with '-ext'." % "Invalid extension type name '%s': must end with '-ext' or start with 'extension-definition--<UUID>'." %
ext_type, ext_type,
) )
for prop_name, prop_value in properties.items(): for prop_name in properties.keys():
if not re.match(PREFIX_21_REGEX, prop_name): if not re.match(PREFIX_21_REGEX, prop_name):
raise ValueError("Property name '%s' must begin with an alpha character." % prop_name) raise ValueError("Property name '%s' must begin with an alpha character." % prop_name)
try: EXT_MAP = registry.STIX2_OBJ_MAPS[version]['extensions']
observable_type = observable._type
except AttributeError:
raise ValueError(
"Unknown observable type. Custom observables must be "
"created with the @CustomObservable decorator.",
)
OBJ_MAP_OBSERVABLE = registry.STIX2_OBJ_MAPS[version]['observables'] if ext_type in EXT_MAP:
EXT_MAP = registry.STIX2_OBJ_MAPS[version]['observable-extensions'] raise DuplicateRegistrationError("Extension", ext_type)
EXT_MAP[ext_type] = new_extension
try:
if ext_type in EXT_MAP[observable_type].keys():
raise DuplicateRegistrationError("Observable Extension", ext_type)
EXT_MAP[observable_type][ext_type] = new_extension
except KeyError:
if observable_type not in OBJ_MAP_OBSERVABLE:
raise ValueError(
"Unknown observable type '%s'. Custom observables "
"must be created with the @CustomObservable decorator."
% observable_type,
)
else:
EXT_MAP[observable_type] = {ext_type: new_extension}

View File

@ -37,7 +37,7 @@ def _collect_stix2_mappings():
STIX2_OBJ_MAPS[ver] = {} STIX2_OBJ_MAPS[ver] = {}
STIX2_OBJ_MAPS[ver]['objects'] = mod.OBJ_MAP STIX2_OBJ_MAPS[ver]['objects'] = mod.OBJ_MAP
STIX2_OBJ_MAPS[ver]['observables'] = mod.OBJ_MAP_OBSERVABLE STIX2_OBJ_MAPS[ver]['observables'] = mod.OBJ_MAP_OBSERVABLE
STIX2_OBJ_MAPS[ver]['observable-extensions'] = mod.EXT_MAP STIX2_OBJ_MAPS[ver]['extensions'] = mod.EXT_MAP
elif re.match(r'^stix2\.v2[0-9]\.common$', name) and is_pkg is False: elif re.match(r'^stix2\.v2[0-9]\.common$', name) and is_pkg is False:
ver = _stix_vid_to_version(stix_vid) ver = _stix_vid_to_version(stix_vid)
mod = importlib.import_module(name, str(top_level_module.__name__)) mod = importlib.import_module(name, str(top_level_module.__name__))
@ -49,7 +49,8 @@ def class_for_type(stix_type, stix_version, category=None):
Get the registered class which implements a particular STIX type for a Get the registered class which implements a particular STIX type for a
particular STIX version. particular STIX version.
:param stix_type: A STIX type as a string :param stix_type: A STIX type as a string, or for extension-definition
style extensions, the STIX ID of the definition.
:param stix_version: A STIX version as a string, e.g. "2.1" :param stix_version: A STIX version as a string, e.g. "2.1"
:param category: An optional "category" value, which is just used directly :param category: An optional "category" value, which is just used directly
as a second key after the STIX version, and depends on how the types as a second key after the STIX version, and depends on how the types
@ -69,12 +70,11 @@ def class_for_type(stix_type, stix_version, category=None):
if class_map: if class_map:
cls = class_map.get(stix_type) cls = class_map.get(stix_type)
else: else:
cls = cat_map["objects"].get(stix_type) \ cls = (
or cat_map["observables"].get(stix_type) \ cat_map["objects"].get(stix_type) or
or cat_map["markings"].get(stix_type) cat_map["observables"].get(stix_type) or
cat_map["markings"].get(stix_type) or
# Left "observable-extensions" out; it has a different cat_map["extensions"].get(stix_type)
# substructure. A version->category->type lookup would result )
# in another map, not a class. So it doesn't fit the pattern.
return cls return cls

View File

@ -1,6 +1,5 @@
"""STIX2 core serialization methods.""" """STIX2 core serialization methods."""
import copy
import datetime as dt import datetime as dt
import io import io
@ -24,7 +23,7 @@ class STIXJSONEncoder(json.JSONEncoder):
if isinstance(obj, (dt.date, dt.datetime)): if isinstance(obj, (dt.date, dt.datetime)):
return format_datetime(obj) return format_datetime(obj)
elif isinstance(obj, stix2.base._STIXBase): elif isinstance(obj, stix2.base._STIXBase):
tmp_obj = dict(copy.deepcopy(obj)) tmp_obj = dict(obj)
for prop_name in obj._defaulted_optional_properties: for prop_name in obj._defaulted_optional_properties:
del tmp_obj[prop_name] del tmp_obj[prop_name]
return tmp_obj return tmp_obj
@ -177,7 +176,7 @@ def find_property_index(obj, search_key, search_value):
if isinstance(obj, stix2.base._STIXBase): if isinstance(obj, stix2.base._STIXBase):
if search_key in obj and obj[search_key] == search_value: if search_key in obj and obj[search_key] == search_value:
idx = _find(obj.object_properties(), search_key) idx = _find(list(obj), search_key)
else: else:
idx = _find_property_in_seq(obj.values(), search_key, search_value) idx = _find_property_in_seq(obj.values(), search_key, search_value)
elif isinstance(obj, dict): elif isinstance(obj, dict):

View File

@ -37,7 +37,7 @@ def test_attack_pattern_example():
description="...", description="...",
) )
assert str(ap) == EXPECTED assert ap.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -111,6 +111,6 @@ def test_less_precise_timestamps():
description="...", description="...",
) )
assert str(ap) == EXPECTED assert ap.serialize(pretty=True) == EXPECTED
# TODO: Add other examples # TODO: Add other examples

View File

@ -120,7 +120,6 @@ def test_create_bundle_fp_serialize_pretty(indicator, malware, relationship):
bundle.fp_serialize(buffer, pretty=True) bundle.fp_serialize(buffer, pretty=True)
assert str(bundle) == EXPECTED_BUNDLE
assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
assert buffer.getvalue() == EXPECTED_BUNDLE assert buffer.getvalue() == EXPECTED_BUNDLE
@ -138,7 +137,7 @@ def test_create_bundle_fp_serialize_nonpretty(indicator, malware, relationship):
def test_create_bundle1(indicator, malware, relationship): def test_create_bundle1(indicator, malware, relationship):
bundle = stix2.v20.Bundle(objects=[indicator, malware, relationship]) bundle = stix2.v20.Bundle(objects=[indicator, malware, relationship])
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
@ -151,31 +150,31 @@ def test_create_bundle2(indicator, malware, relationship):
def test_create_bundle_with_positional_args(indicator, malware, relationship): def test_create_bundle_with_positional_args(indicator, malware, relationship):
bundle = stix2.v20.Bundle(indicator, malware, relationship) bundle = stix2.v20.Bundle(indicator, malware, relationship)
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_with_positional_listarg(indicator, malware, relationship): def test_create_bundle_with_positional_listarg(indicator, malware, relationship):
bundle = stix2.v20.Bundle([indicator, malware, relationship]) bundle = stix2.v20.Bundle([indicator, malware, relationship])
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_with_listarg_and_positional_arg(indicator, malware, relationship): def test_create_bundle_with_listarg_and_positional_arg(indicator, malware, relationship):
bundle = stix2.v20.Bundle([indicator, malware], relationship) bundle = stix2.v20.Bundle([indicator, malware], relationship)
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_with_listarg_and_kwarg(indicator, malware, relationship): def test_create_bundle_with_listarg_and_kwarg(indicator, malware, relationship):
bundle = stix2.v20.Bundle([indicator, malware], objects=[relationship]) bundle = stix2.v20.Bundle([indicator, malware], objects=[relationship])
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_with_arg_listarg_and_kwarg(indicator, malware, relationship): def test_create_bundle_with_arg_listarg_and_kwarg(indicator, malware, relationship):
bundle = stix2.v20.Bundle([indicator], malware, objects=[relationship]) bundle = stix2.v20.Bundle([indicator], malware, objects=[relationship])
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_invalid(indicator, malware, relationship): def test_create_bundle_invalid(indicator, malware, relationship):

View File

@ -21,7 +21,7 @@ EXPECTED = """{
def test_campaign_example(): def test_campaign_example():
campaign = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS) campaign = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
assert str(campaign) == EXPECTED assert campaign.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -28,7 +28,7 @@ def test_course_of_action_example():
description="This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...", description="This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
) )
assert str(coa) == EXPECTED assert coa.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -480,8 +480,18 @@ class NewObservable():
def test_custom_observable_object_1(): def test_custom_observable_object_1():
no = NewObservable(property1='something') no = NewObservable(
property1='something',
extensions={
'archive-ext': stix2.v20.observables.ArchiveExt(
contains_refs=['file--e277603e-1060-5ad4-9937-c26c97f1ca68'],
version='2.0',
comment='for real',
),
},
)
assert no.property1 == 'something' assert no.property1 == 'something'
assert no.extensions['archive-ext'].comment == 'for real'
def test_custom_observable_object_2(): def test_custom_observable_object_2():
@ -740,7 +750,7 @@ def test_observed_data_with_custom_observable_object():
@stix2.v20.CustomExtension( @stix2.v20.CustomExtension(
stix2.v20.DomainName, 'x-new-ext', [ 'x-new-ext', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),
('property2', stix2.properties.IntegerProperty()), ('property2', stix2.properties.IntegerProperty()),
], ],
@ -785,7 +795,7 @@ def test_custom_extension_wrong_observable_type():
}, },
) )
assert 'Cannot determine extension type' in excinfo.value.reason assert "Can't create extension 'ntfs-ext' from" in excinfo.value.reason
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -802,64 +812,22 @@ def test_custom_extension_wrong_observable_type():
) )
def test_custom_extension_with_list_and_dict_properties_observable_type(data): def test_custom_extension_with_list_and_dict_properties_observable_type(data):
@stix2.v20.CustomExtension( @stix2.v20.CustomExtension(
stix2.v20.UserAccount, 'some-extension', [ 'some-extension', [
('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)), ('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)),
], ],
) )
class SomeCustomExtension: class SomeCustomExtension:
pass pass
example = SomeCustomExtension(keys=[{'test123': 123, 'test345': 'aaaa'}]) example = SomeCustomExtension(keys=[{'test123': 123, 'test345': 'aaaa'}])
assert data == str(example) assert data == example.serialize(pretty=True)
def test_custom_extension_invalid_observable():
# These extensions are being applied to improperly-created Observables.
# The Observable classes should have been created with the CustomObservable decorator.
class Foo(object):
pass
with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension(
Foo, 'x-new-ext', [
('property1', stix2.properties.StringProperty(required=True)),
],
)
class FooExtension():
pass # pragma: no cover
assert str(excinfo.value) == "'observable' must be a valid Observable class!"
class Bar(stix2.v20.observables._Observable):
pass
with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension(
Bar, 'x-new-ext', [
('property1', stix2.properties.StringProperty(required=True)),
],
)
class BarExtension():
pass
assert "Unknown observable type" in str(excinfo.value)
assert "Custom observables must be created with the @CustomObservable decorator." in str(excinfo.value)
class Baz(stix2.v20.observables._Observable):
_type = 'Baz'
with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension(
Baz, 'x-new-ext', [
('property1', stix2.properties.StringProperty(required=True)),
],
)
class BazExtension():
pass
assert "Unknown observable type" in str(excinfo.value)
assert "Custom observables must be created with the @CustomObservable decorator." in str(excinfo.value)
def test_custom_extension_invalid_type_name(): def test_custom_extension_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension( @stix2.v20.CustomExtension(
stix2.v20.File, 'x', { 'x', {
'property1': stix2.properties.StringProperty(required=True), 'property1': stix2.properties.StringProperty(required=True),
}, },
) )
class FooExtension(): class FooExtension():
@ -868,8 +836,8 @@ def test_custom_extension_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension( @stix2.v20.CustomExtension(
stix2.File, 'x_new_ext', { 'x_new_ext', {
'property1': stix2.properties.StringProperty(required=True), 'property1': stix2.properties.StringProperty(required=True),
}, },
) )
class BlaExtension(): class BlaExtension():
@ -879,29 +847,29 @@ def test_custom_extension_invalid_type_name():
def test_custom_extension_no_properties(): def test_custom_extension_no_properties():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@stix2.v20.CustomExtension(stix2.v20.DomainName, 'x-new-ext2', None) @stix2.v20.CustomExtension('x-new-ext2', None)
class BarExtension(): class BarExtension():
pass pass
def test_custom_extension_empty_properties(): def test_custom_extension_empty_properties():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@stix2.v20.CustomExtension(stix2.v20.DomainName, 'x-new-ext2', []) @stix2.v20.CustomExtension('x-new-ext2', [])
class BarExtension(): class BarExtension():
pass pass
def test_custom_extension_dict_properties(): def test_custom_extension_dict_properties():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@stix2.v20.CustomExtension(stix2.v20.DomainName, 'x-new-ext2', {}) @stix2.v20.CustomExtension('x-new-ext2', {})
class BarExtension(): class BarExtension():
pass pass
def test_custom_extension_no_init_1(): def test_custom_extension_no_init_1():
@stix2.v20.CustomExtension( @stix2.v20.CustomExtension(
stix2.v20.DomainName, 'x-new-extension', [ 'x-new-extension', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),
], ],
) )
class NewExt(): class NewExt():
@ -913,8 +881,8 @@ def test_custom_extension_no_init_1():
def test_custom_extension_no_init_2(): def test_custom_extension_no_init_2():
@stix2.v20.CustomExtension( @stix2.v20.CustomExtension(
stix2.v20.DomainName, 'x-new-ext2', [ 'x-new-ext2', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),
], ],
) )
class NewExt2(object): class NewExt2(object):
@ -1059,7 +1027,7 @@ def test_register_custom_object():
def test_extension_property_location(): def test_extension_property_location():
assert 'extensions' in stix2.v20.OBJ_MAP_OBSERVABLE['x-new-observable']._properties assert 'extensions' in stix2.v20.OBJ_MAP_OBSERVABLE['x-new-observable']._properties
assert 'extensions' not in stix2.v20.EXT_MAP['domain-name']['x-new-ext']._properties assert 'extensions' not in stix2.v20.EXT_MAP['x-new-ext']._properties
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -1095,7 +1063,7 @@ def test_custom_object_nested_dictionary(data):
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}}, dictionary={'key': {'key_b': 'value', 'key_a': 'value'}},
) )
assert data == str(example) assert data == example.serialize(pretty=True)
@stix2.v20.CustomObject( @stix2.v20.CustomObject(
@ -1177,8 +1145,8 @@ def test_register_marking_with_version():
def test_register_observable_extension_with_version(): def test_register_observable_extension_with_version():
@stix2.v20.CustomExtension( @stix2.v20.CustomExtension(
stix2.v20.UserAccount, 'some-extension-2', [ 'some-extension-2', [
('keys', stix2.properties.StringProperty(required=True)), ('keys', stix2.properties.StringProperty(required=True)),
], ],
) )
class SomeCustomExtension2: class SomeCustomExtension2:
@ -1186,15 +1154,15 @@ def test_register_observable_extension_with_version():
example = SomeCustomExtension2(keys='test123') example = SomeCustomExtension2(keys='test123')
assert example._type in stix2.registry.STIX2_OBJ_MAPS['2.0']['observable-extensions']['user-account'] assert example._type in stix2.registry.STIX2_OBJ_MAPS['2.0']['extensions']
def test_register_duplicate_observable_extension(): def test_register_duplicate_observable_extension():
with pytest.raises(DuplicateRegistrationError) as excinfo: with pytest.raises(DuplicateRegistrationError) as excinfo:
@stix2.v20.CustomExtension( @stix2.v20.CustomExtension(
stix2.v20.UserAccount, 'some-extension-2', [ 'some-extension-2', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),
('property2', stix2.properties.IntegerProperty()), ('property2', stix2.properties.IntegerProperty()),
], ],
) )
class NewExtension2(): class NewExtension2():

View File

@ -26,7 +26,7 @@ def test_external_reference_veris():
url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json", url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json",
) )
assert str(ref) == VERIS assert ref.serialize(pretty=True) == VERIS
CAPEC = """{ CAPEC = """{
@ -41,7 +41,7 @@ def test_external_reference_capec():
external_id="CAPEC-550", external_id="CAPEC-550",
) )
assert str(ref) == CAPEC assert ref.serialize(pretty=True) == CAPEC
assert re.match("ExternalReference\\(source_name=u?'capec', external_id=u?'CAPEC-550'\\)", repr(ref)) assert re.match("ExternalReference\\(source_name=u?'capec', external_id=u?'CAPEC-550'\\)", repr(ref))
@ -59,7 +59,7 @@ def test_external_reference_capec_url():
url="http://capec.mitre.org/data/definitions/550.html", url="http://capec.mitre.org/data/definitions/550.html",
) )
assert str(ref) == CAPEC_URL assert ref.serialize(pretty=True) == CAPEC_URL
THREAT_REPORT = """{ THREAT_REPORT = """{
@ -76,7 +76,7 @@ def test_external_reference_threat_report():
url="http://www.example.com/threat-report.pdf", url="http://www.example.com/threat-report.pdf",
) )
assert str(ref) == THREAT_REPORT assert ref.serialize(pretty=True) == THREAT_REPORT
BUGZILLA = """{ BUGZILLA = """{
@ -93,7 +93,7 @@ def test_external_reference_bugzilla():
url="https://www.example.com/bugs/1370", url="https://www.example.com/bugs/1370",
) )
assert str(ref) == BUGZILLA assert ref.serialize(pretty=True) == BUGZILLA
OFFLINE = """{ OFFLINE = """{
@ -108,7 +108,7 @@ def test_external_reference_offline():
description="Threat report", description="Threat report",
) )
assert str(ref) == OFFLINE assert ref.serialize(pretty=True) == OFFLINE
assert re.match("ExternalReference\\(source_name=u?'ACME Threat Intel', description=u?'Threat report'\\)", repr(ref)) assert re.match("ExternalReference\\(source_name=u?'ACME Threat Intel', description=u?'Threat report'\\)", repr(ref))
# Yikes! This works # Yikes! This works
assert eval("stix2." + repr(ref)) == ref assert eval("stix2." + repr(ref)) == ref

View File

@ -26,7 +26,7 @@ def test_identity_example():
identity_class="individual", identity_class="individual",
) )
assert str(identity) == EXPECTED assert identity.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -74,6 +74,6 @@ def test_identity_with_custom():
) )
assert identity.x_foo == "bar" assert identity.x_foo == "bar"
assert "x_foo" in identity.object_properties() assert "x_foo" in identity
# TODO: Add other examples # TODO: Add other examples

View File

@ -28,6 +28,7 @@ EXPECTED_INDICATOR_REPR = "Indicator(" + " ".join(
modified='2017-01-01T00:00:01.000Z', modified='2017-01-01T00:00:01.000Z',
pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
valid_from='1970-01-01T00:00:01Z', valid_from='1970-01-01T00:00:01Z',
revoked=False,
labels=['malicious-activity'] labels=['malicious-activity']
""".split(), """.split(),
) + ")" ) + ")"
@ -48,7 +49,7 @@ def test_indicator_with_all_required_properties():
) )
assert ind.revoked is False assert ind.revoked is False
assert str(ind) == EXPECTED_INDICATOR assert ind.serialize(pretty=True) == EXPECTED_INDICATOR
rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(ind)) rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(ind))
assert rep == EXPECTED_INDICATOR_REPR assert rep == EXPECTED_INDICATOR_REPR

View File

@ -38,7 +38,7 @@ def test_intrusion_set_example():
goals=["acquisition-theft", "harassment", "damage"], goals=["acquisition-theft", "harassment", "damage"],
) )
assert str(intrusion_set) == EXPECTED assert intrusion_set.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -16,7 +16,7 @@ def test_lockheed_martin_cyber_kill_chain():
phase_name="reconnaissance", phase_name="reconnaissance",
) )
assert str(recon) == LMCO_RECON assert recon.serialize(pretty=True) == LMCO_RECON
FOO_PRE_ATTACK = """{ FOO_PRE_ATTACK = """{
@ -31,7 +31,7 @@ def test_kill_chain_example():
phase_name="pre-attack", phase_name="pre-attack",
) )
assert str(preattack) == FOO_PRE_ATTACK assert preattack.serialize(pretty=True) == FOO_PRE_ATTACK
def test_kill_chain_required_properties(): def test_kill_chain_required_properties():

View File

@ -33,7 +33,7 @@ def test_malware_with_all_required_properties():
name="Cryptolocker", name="Cryptolocker",
) )
assert str(mal) == EXPECTED_MALWARE assert mal.serialize(pretty=True) == EXPECTED_MALWARE
def test_malware_with_empty_optional_field(): def test_malware_with_empty_optional_field():
@ -49,7 +49,7 @@ def test_malware_with_empty_optional_field():
external_references=[], external_references=[],
) )
assert str(mal) == EXPECTED_MALWARE assert mal.serialize(pretty=True) == EXPECTED_MALWARE
def test_malware_autogenerated_properties(malware): def test_malware_autogenerated_properties(malware):

View File

@ -21,7 +21,7 @@ EXPECTED_TLP_MARKING_DEFINITION = """{
EXPECTED_STATEMENT_MARKING_DEFINITION = """{ EXPECTED_STATEMENT_MARKING_DEFINITION = """{
"type": "marking-definition", "type": "marking-definition",
"id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", "id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
"created": "2017-01-20T00:00:00Z", "created": "2017-01-20T00:00:00.000Z",
"definition_type": "statement", "definition_type": "statement",
"definition": { "definition": {
"statement": "Copyright 2016, Example Corp" "statement": "Copyright 2016, Example Corp"
@ -71,7 +71,7 @@ EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS = """{
def test_marking_def_example_with_tlp(): def test_marking_def_example_with_tlp():
assert str(TLP_WHITE) == EXPECTED_TLP_MARKING_DEFINITION assert TLP_WHITE.serialize(pretty=True) == EXPECTED_TLP_MARKING_DEFINITION
def test_marking_def_example_with_statement_positional_argument(): def test_marking_def_example_with_statement_positional_argument():
@ -82,7 +82,7 @@ def test_marking_def_example_with_statement_positional_argument():
definition=stix2.v20.StatementMarking(statement="Copyright 2016, Example Corp"), definition=stix2.v20.StatementMarking(statement="Copyright 2016, Example Corp"),
) )
assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION assert marking_definition.serialize(pretty=True) == EXPECTED_STATEMENT_MARKING_DEFINITION
def test_marking_def_example_with_kwargs_statement(): def test_marking_def_example_with_kwargs_statement():
@ -94,7 +94,7 @@ def test_marking_def_example_with_kwargs_statement():
definition=stix2.v20.StatementMarking(**kwargs), definition=stix2.v20.StatementMarking(**kwargs),
) )
assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION assert marking_definition.serialize(pretty=True) == EXPECTED_STATEMENT_MARKING_DEFINITION
def test_marking_def_invalid_type(): def test_marking_def_invalid_type():
@ -118,7 +118,7 @@ def test_campaign_with_markings_example():
description="Campaign by Green Group against a series of targets in the financial services sector.", description="Campaign by Green Group against a series of targets in the financial services sector.",
object_marking_refs=TLP_WHITE, object_marking_refs=TLP_WHITE,
) )
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING assert campaign.serialize(pretty=True) == EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING
def test_granular_example(): def test_granular_example():
@ -127,7 +127,7 @@ def test_granular_example():
selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"], selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"],
) )
assert str(granular_marking) == EXPECTED_GRANULAR_MARKING assert granular_marking.serialize(pretty=True) == EXPECTED_GRANULAR_MARKING
def test_granular_example_with_bad_selector(): def test_granular_example_with_bad_selector():
@ -159,7 +159,7 @@ def test_campaign_with_granular_markings_example():
), ),
], ],
) )
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS assert campaign.serialize(pretty=True) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -47,7 +47,7 @@ def test_observed_data_example():
}, },
) )
assert str(observed_data) == EXPECTED assert observed_data.serialize(pretty=True) == EXPECTED
EXPECTED_WITH_REF = """{ EXPECTED_WITH_REF = """{
@ -97,7 +97,7 @@ def test_observed_data_example_with_refs():
}, },
) )
assert str(observed_data) == EXPECTED_WITH_REF assert observed_data.serialize(pretty=True) == EXPECTED_WITH_REF
def test_observed_data_example_with_bad_refs(): def test_observed_data_example_with_bad_refs():
@ -1117,6 +1117,7 @@ def test_process_example_empty_error():
assert excinfo.value.cls == stix2.v20.Process assert excinfo.value.cls == stix2.v20.Process
properties_of_process = list(stix2.v20.Process._properties.keys()) properties_of_process = list(stix2.v20.Process._properties.keys())
properties_of_process.remove("type") properties_of_process.remove("type")
properties_of_process.remove("extensions")
assert excinfo.value.properties == sorted(properties_of_process) assert excinfo.value.properties == sorted(properties_of_process)
msg = "At least one of the ({1}) properties for {0} must be populated." msg = "At least one of the ({1}) properties for {0} must be populated."
msg = msg.format( msg = msg.format(

View File

@ -452,7 +452,7 @@ def test_embedded_property_dict_custom():
def test_extension_property_valid(): def test_extension_property_valid():
ext_prop = ExtensionsProperty(spec_version="2.0", enclosing_type='file') ext_prop = ExtensionsProperty(spec_version="2.0")
result = ext_prop.clean( result = ext_prop.clean(
{ {
'windows-pebinary-ext': { 'windows-pebinary-ext': {
@ -481,13 +481,13 @@ def test_extension_property_valid():
def test_extension_property_invalid1(): def test_extension_property_invalid1():
ext_prop = ExtensionsProperty(spec_version="2.0", enclosing_type='file') ext_prop = ExtensionsProperty(spec_version="2.0")
with pytest.raises(ValueError): with pytest.raises(ValueError):
ext_prop.clean(1, False) ext_prop.clean(1, False)
def test_extension_property_invalid2(): def test_extension_property_invalid2():
ext_prop = ExtensionsProperty(spec_version="2.0", enclosing_type='file') ext_prop = ExtensionsProperty(spec_version="2.0")
with pytest.raises(CustomContentError): with pytest.raises(CustomContentError):
ext_prop.clean( ext_prop.clean(
{ {
@ -509,7 +509,7 @@ def test_extension_property_invalid2():
def test_extension_property_invalid3(): def test_extension_property_invalid3():
ext_prop = ExtensionsProperty(spec_version="2.0", enclosing_type='file') ext_prop = ExtensionsProperty(spec_version="2.0")
with pytest.raises(ExtraPropertiesError): with pytest.raises(ExtraPropertiesError):
ext_prop.clean( ext_prop.clean(
{ {
@ -537,20 +537,6 @@ def test_extension_property_invalid3():
assert result[1] assert result[1]
def test_extension_property_invalid_type():
ext_prop = ExtensionsProperty(spec_version="2.0", enclosing_type='indicator')
with pytest.raises(CustomContentError) as excinfo:
ext_prop.clean(
{
'windows-pebinary-ext': {
'pe_type': 'exe',
},
},
False,
)
assert "Can't parse unknown extension" in str(excinfo.value)
def test_extension_at_least_one_property_constraint(): def test_extension_at_least_one_property_constraint():
with pytest.raises(AtLeastOnePropertyError): with pytest.raises(AtLeastOnePropertyError):
stix2.v20.TCPExt() stix2.v20.TCPExt()

View File

@ -32,7 +32,7 @@ def test_relationship_all_required_properties():
source_ref=INDICATOR_ID, source_ref=INDICATOR_ID,
target_ref=MALWARE_ID, target_ref=MALWARE_ID,
) )
assert str(rel) == EXPECTED_RELATIONSHIP assert rel.serialize(pretty=True) == EXPECTED_RELATIONSHIP
def test_relationship_autogenerated_properties(relationship): def test_relationship_autogenerated_properties(relationship):

View File

@ -48,7 +48,7 @@ def test_report_example():
], ],
) )
assert str(report) == EXPECTED assert report.serialize(pretty=True) == EXPECTED
def test_report_example_objects_in_object_refs(): def test_report_example_objects_in_object_refs():
@ -68,7 +68,7 @@ def test_report_example_objects_in_object_refs():
], ],
) )
assert str(report) == EXPECTED assert report.serialize(pretty=True) == EXPECTED
def test_report_example_objects_in_object_refs_with_bad_id(): def test_report_example_objects_in_object_refs_with_bad_id():

View File

@ -33,7 +33,7 @@ BAD_SIGHTING = """{
def test_sighting_all_required_properties(): def test_sighting_all_required_properties():
now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc)
s = stix2.v20.Sighting( sighting = stix2.v20.Sighting(
type='sighting', type='sighting',
id=SIGHTING_ID, id=SIGHTING_ID,
created=now, created=now,
@ -41,7 +41,7 @@ def test_sighting_all_required_properties():
sighting_of_ref=INDICATOR_ID, sighting_of_ref=INDICATOR_ID,
where_sighted_refs=[IDENTITY_ID], where_sighted_refs=[IDENTITY_ID],
) )
assert str(s) == EXPECTED_SIGHTING assert sighting.serialize(pretty=True) == EXPECTED_SIGHTING
def test_sighting_bad_where_sighted_refs(): def test_sighting_bad_where_sighted_refs():

View File

@ -32,7 +32,7 @@ def test_threat_actor_example():
name="Evil Org", name="Evil Org",
) )
assert str(threat_actor) == EXPECTED assert threat_actor.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -43,7 +43,7 @@ def test_tool_example():
name="VNC", name="VNC",
) )
assert str(tool) == EXPECTED assert tool.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -36,7 +36,7 @@ def test_vulnerability_example():
], ],
) )
assert str(vulnerability) == EXPECTED assert vulnerability.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -9,6 +9,7 @@ CAMPAIGN_ID = "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f"
COURSE_OF_ACTION_ID = "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f" COURSE_OF_ACTION_ID = "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f"
GROUPING_ID = "grouping--753abcde-3141-5926-ace5-0a810b1ff996" GROUPING_ID = "grouping--753abcde-3141-5926-ace5-0a810b1ff996"
IDENTITY_ID = "identity--311b2d2d-f010-4473-83ec-1edf84858f4c" IDENTITY_ID = "identity--311b2d2d-f010-4473-83ec-1edf84858f4c"
INCIDENT_ID = "incident--40fc3b35-0dc4-4afd-9927-288d44bfce20"
INDICATOR_ID = "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7" INDICATOR_ID = "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7"
INFRASTRUCTURE_ID = "infrastructure--3000ae1b-784c-f03d-8abc-0a625b2ff018" INFRASTRUCTURE_ID = "infrastructure--3000ae1b-784c-f03d-8abc-0a625b2ff018"
INTRUSION_SET_ID = "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29" INTRUSION_SET_ID = "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29"
@ -26,6 +27,12 @@ TOOL_ID = "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f"
SIGHTING_ID = "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb" SIGHTING_ID = "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb"
VULNERABILITY_ID = "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061" VULNERABILITY_ID = "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061"
EXTENSION_DEFINITION_IDS = [
"extension-definition--1f611280-fbe1-48e8-92ab-ff47ce02d5b7", # new-sdo
"extension-definition--368f4787-5b43-467c-9693-0c9de4289c4b", # property-extension
"extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8", # top-level-property-extension
"extension-definition--150c1738-28c9-44d0-802d-70523218240b", # new-sdo, new-sco, property-extension
]
MARKING_IDS = [ MARKING_IDS = [
"marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
"marking-definition--443eb5c3-a76c-4a0a-8caa-e93998e7bc09", "marking-definition--443eb5c3-a76c-4a0a-8caa-e93998e7bc09",

View File

@ -38,7 +38,7 @@ def test_attack_pattern_example():
description="...", description="...",
) )
assert str(ap) == EXPECTED assert ap.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -114,7 +114,7 @@ def test_less_precise_timestamps():
description="...", description="...",
) )
assert str(ap) == EXPECTED assert ap.serialize(pretty=True) == EXPECTED
# TODO: Add other examples # TODO: Add other examples

View File

@ -130,7 +130,6 @@ def test_create_bundle_fp_serialize_pretty(indicator, malware, relationship):
bundle.fp_serialize(buffer, pretty=True) bundle.fp_serialize(buffer, pretty=True)
assert str(bundle) == EXPECTED_BUNDLE
assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
assert buffer.getvalue() == EXPECTED_BUNDLE assert buffer.getvalue() == EXPECTED_BUNDLE
@ -148,7 +147,7 @@ def test_create_bundle_fp_serialize_nonpretty(indicator, malware, relationship):
def test_create_bundle1(indicator, malware, relationship): def test_create_bundle1(indicator, malware, relationship):
bundle = stix2.v21.Bundle(objects=[indicator, malware, relationship]) bundle = stix2.v21.Bundle(objects=[indicator, malware, relationship])
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
@ -161,31 +160,31 @@ def test_create_bundle2(indicator, malware, relationship):
def test_create_bundle_with_positional_args(indicator, malware, relationship): def test_create_bundle_with_positional_args(indicator, malware, relationship):
bundle = stix2.v21.Bundle(indicator, malware, relationship) bundle = stix2.v21.Bundle(indicator, malware, relationship)
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_with_positional_listarg(indicator, malware, relationship): def test_create_bundle_with_positional_listarg(indicator, malware, relationship):
bundle = stix2.v21.Bundle([indicator, malware, relationship]) bundle = stix2.v21.Bundle([indicator, malware, relationship])
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_with_listarg_and_positional_arg(indicator, malware, relationship): def test_create_bundle_with_listarg_and_positional_arg(indicator, malware, relationship):
bundle = stix2.v21.Bundle([indicator, malware], relationship) bundle = stix2.v21.Bundle([indicator, malware], relationship)
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_with_listarg_and_kwarg(indicator, malware, relationship): def test_create_bundle_with_listarg_and_kwarg(indicator, malware, relationship):
bundle = stix2.v21.Bundle([indicator, malware], objects=[relationship]) bundle = stix2.v21.Bundle([indicator, malware], objects=[relationship])
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_with_arg_listarg_and_kwarg(indicator, malware, relationship): def test_create_bundle_with_arg_listarg_and_kwarg(indicator, malware, relationship):
bundle = stix2.v21.Bundle([indicator], malware, objects=[relationship]) bundle = stix2.v21.Bundle([indicator], malware, objects=[relationship])
assert str(bundle) == EXPECTED_BUNDLE assert bundle.serialize(pretty=True) == EXPECTED_BUNDLE
def test_create_bundle_invalid(indicator, malware, relationship): def test_create_bundle_invalid(indicator, malware, relationship):

View File

@ -24,7 +24,7 @@ def test_campaign_example():
**CAMPAIGN_MORE_KWARGS **CAMPAIGN_MORE_KWARGS
) )
assert str(campaign) == EXPECTED assert campaign.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -42,7 +42,7 @@ COA_WITH_REF_DICT = json.loads(COA_WITH_REF_JSON)
) )
def test_course_of_action_example(sdo_json, sdo_dict): def test_course_of_action_example(sdo_json, sdo_dict):
coa = stix2.v21.CourseOfAction(**sdo_dict) coa = stix2.v21.CourseOfAction(**sdo_dict)
assert str(coa) == sdo_json assert coa.serialize(pretty=True) == sdo_json
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -1,3 +1,4 @@
import contextlib
import uuid import uuid
import pytest import pytest
@ -8,7 +9,9 @@ import stix2.registration
import stix2.registry import stix2.registry
import stix2.v21 import stix2.v21
from ...exceptions import DuplicateRegistrationError, InvalidValueError from ...exceptions import (
DuplicateRegistrationError, InvalidValueError, MissingPropertiesError,
)
from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID
# Custom Properties in SDOs # Custom Properties in SDOs
@ -939,7 +942,7 @@ def test_custom_observable_object_no_id_contrib_props():
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.DomainName, 'x-new-ext', [ 'x-new-ext', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),
('property2', stix2.properties.IntegerProperty()), ('property2', stix2.properties.IntegerProperty()),
], ],
@ -984,7 +987,7 @@ def test_custom_extension_wrong_observable_type():
}, },
) )
assert 'Cannot determine extension type' in excinfo.value.reason assert "Can't create extension 'ntfs-ext'" in excinfo.value.reason
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -1001,64 +1004,22 @@ def test_custom_extension_wrong_observable_type():
) )
def test_custom_extension_with_list_and_dict_properties_observable_type(data): def test_custom_extension_with_list_and_dict_properties_observable_type(data):
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.UserAccount, 'x-some-extension-ext', [ 'x-some-extension-ext', [
('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)), ('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)),
], ],
) )
class SomeCustomExtension: class SomeCustomExtension:
pass pass
example = SomeCustomExtension(keys=[{'test123': 123, 'test345': 'aaaa'}]) example = SomeCustomExtension(keys=[{'test123': 123, 'test345': 'aaaa'}])
assert data == str(example) assert data == example.serialize(pretty=True)
def test_custom_extension_invalid_observable():
# These extensions are being applied to improperly-created Observables.
# The Observable classes should have been created with the CustomObservable decorator.
class Foo(object):
pass
with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension(
Foo, 'x-new-ext', [
('property1', stix2.properties.StringProperty(required=True)),
],
)
class FooExtension():
pass # pragma: no cover
assert str(excinfo.value) == "'observable' must be a valid Observable class!"
class Bar(stix2.v21.observables._Observable):
pass
with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension(
Bar, 'x-new-ext', [
('property1', stix2.properties.StringProperty(required=True)),
],
)
class BarExtension():
pass
assert "Unknown observable type" in str(excinfo.value)
assert "Custom observables must be created with the @CustomObservable decorator." in str(excinfo.value)
class Baz(stix2.v21.observables._Observable):
_type = 'Baz'
with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension(
Baz, 'x-new-ext', [
('property1', stix2.properties.StringProperty(required=True)),
],
)
class BazExtension():
pass
assert "Unknown observable type" in str(excinfo.value)
assert "Custom observables must be created with the @CustomObservable decorator." in str(excinfo.value)
def test_custom_extension_invalid_type_name(): def test_custom_extension_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.File, 'x', { 'x', {
'property1': stix2.properties.StringProperty(required=True), 'property1': stix2.properties.StringProperty(required=True),
}, },
) )
class FooExtension(): class FooExtension():
@ -1067,8 +1028,8 @@ def test_custom_extension_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.File, 'x_new_ext', { 'x_new_ext', {
'property1': stix2.properties.StringProperty(required=True), 'property1': stix2.properties.StringProperty(required=True),
}, },
) )
class BlaExtension(): class BlaExtension():
@ -1077,8 +1038,8 @@ def test_custom_extension_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.File, '7x-new-ext', { '7x-new-ext', {
'property1': stix2.properties.StringProperty(required=True), 'property1': stix2.properties.StringProperty(required=True),
}, },
) )
class Bla2Extension(): class Bla2Extension():
@ -1088,29 +1049,29 @@ def test_custom_extension_invalid_type_name():
def test_custom_extension_no_properties(): def test_custom_extension_no_properties():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@stix2.v21.CustomExtension(stix2.v21.DomainName, 'x-new2-ext', None) @stix2.v21.CustomExtension('x-new2-ext', None)
class BarExtension(): class BarExtension():
pass pass
def test_custom_extension_empty_properties(): def test_custom_extension_empty_properties():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@stix2.v21.CustomExtension(stix2.v21.DomainName, 'x-new2-ext', []) @stix2.v21.CustomExtension('x-new2-ext', [])
class BarExtension(): class BarExtension():
pass pass
def test_custom_extension_dict_properties(): def test_custom_extension_dict_properties():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@stix2.v21.CustomExtension(stix2.v21.DomainName, 'x-new2-ext', {}) @stix2.v21.CustomExtension('x-new2-ext', {})
class BarExtension(): class BarExtension():
pass pass
def test_custom_extension_no_init_1(): def test_custom_extension_no_init_1():
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.DomainName, 'x-new-extension-ext', [ 'x-new-extension-ext', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),
], ],
) )
class NewExt(): class NewExt():
@ -1122,8 +1083,8 @@ def test_custom_extension_no_init_1():
def test_custom_extension_no_init_2(): def test_custom_extension_no_init_2():
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.DomainName, 'x-new2-ext', [ 'x-new2-ext', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),
], ],
) )
class NewExt2(object): class NewExt2(object):
@ -1136,8 +1097,8 @@ def test_custom_extension_no_init_2():
def test_invalid_custom_property_in_extension(): def test_invalid_custom_property_in_extension():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.DomainName, 'x-new3-ext', [ 'x-new3-ext', [
('6property1', stix2.properties.StringProperty(required=True)), ('6property1', stix2.properties.StringProperty(required=True)),
], ],
) )
class NewExt(): class NewExt():
@ -1270,6 +1231,41 @@ def test_parse_observable_with_unregistered_custom_extension(data):
assert not isinstance(parsed_ob['extensions']['x-foobar-ext'], stix2.base._STIXBase) assert not isinstance(parsed_ob['extensions']['x-foobar-ext'], stix2.base._STIXBase)
def test_unregistered_new_style_extension():
f_dict = {
"type": "file",
"name": "foo.txt",
"extensions": {
"extension-definition--31adb724-a9a4-44b6-8ec2-fd4b181c9507": {
"extension-type": "property-extension",
"a": 1,
"b": True,
},
},
}
f = stix2.parse(f_dict, allow_custom=False)
assert f.extensions[
"extension-definition--31adb724-a9a4-44b6-8ec2-fd4b181c9507"
]["a"] == 1
assert f.extensions[
"extension-definition--31adb724-a9a4-44b6-8ec2-fd4b181c9507"
]["b"]
assert not f.has_custom
f = stix2.parse(f_dict, allow_custom=True)
assert f.extensions[
"extension-definition--31adb724-a9a4-44b6-8ec2-fd4b181c9507"
]["a"] == 1
assert f.extensions[
"extension-definition--31adb724-a9a4-44b6-8ec2-fd4b181c9507"
]["b"]
assert not f.has_custom
def test_register_custom_object(): def test_register_custom_object():
# Not the way to register custom object. # Not the way to register custom object.
class CustomObject2(object): class CustomObject2(object):
@ -1282,7 +1278,7 @@ def test_register_custom_object():
def test_extension_property_location(): def test_extension_property_location():
assert 'extensions' in stix2.v21.OBJ_MAP_OBSERVABLE['x-new-observable']._properties assert 'extensions' in stix2.v21.OBJ_MAP_OBSERVABLE['x-new-observable']._properties
assert 'extensions' not in stix2.v21.EXT_MAP['domain-name']['x-new-ext']._properties assert 'extensions' not in stix2.v21.EXT_MAP['x-new-ext']._properties
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -1319,7 +1315,7 @@ def test_custom_object_nested_dictionary(data):
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}}, dictionary={'key': {'key_b': 'value', 'key_a': 'value'}},
) )
assert data == str(example) assert data == example.serialize(pretty=True)
@stix2.v21.CustomObject( @stix2.v21.CustomObject(
@ -1387,9 +1383,9 @@ def test_register_duplicate_observable():
def test_register_observable_custom_extension(): def test_register_observable_custom_extension():
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.DomainName, 'x-new-2-ext', [ 'x-new-2-ext', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),
('property2', stix2.properties.IntegerProperty()), ('property2', stix2.properties.IntegerProperty()),
], ],
) )
class NewExtension2(): class NewExtension2():
@ -1398,15 +1394,15 @@ def test_register_observable_custom_extension():
example = NewExtension2(property1="Hi there") example = NewExtension2(property1="Hi there")
assert 'domain-name' in stix2.registry.STIX2_OBJ_MAPS['2.1']['observables'] assert 'domain-name' in stix2.registry.STIX2_OBJ_MAPS['2.1']['observables']
assert example._type in stix2.registry.STIX2_OBJ_MAPS['2.1']['observable-extensions']['domain-name'] assert example._type in stix2.registry.STIX2_OBJ_MAPS['2.1']['extensions']
def test_register_duplicate_observable_extension(): def test_register_duplicate_observable_extension():
with pytest.raises(DuplicateRegistrationError) as excinfo: with pytest.raises(DuplicateRegistrationError) as excinfo:
@stix2.v21.CustomExtension( @stix2.v21.CustomExtension(
stix2.v21.DomainName, 'x-new-2-ext', [ 'x-new-2-ext', [
('property1', stix2.properties.StringProperty(required=True)), ('property1', stix2.properties.StringProperty(required=True)),
('property2', stix2.properties.IntegerProperty()), ('property2', stix2.properties.IntegerProperty()),
], ],
) )
class NewExtension2(): class NewExtension2():
@ -1414,6 +1410,476 @@ def test_register_duplicate_observable_extension():
assert "cannot be registered again" in str(excinfo.value) assert "cannot be registered again" in str(excinfo.value)
def test_unregistered_top_level_extension_passes_with_allow_custom_false():
indicator = stix2.v21.Indicator(
id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c',
created='2014-02-20T09:16:08.989000Z',
modified='2014-02-20T09:16:08.989000Z',
name='File hash for Poison Ivy variant',
description='This file hash indicates that a sample of Poison Ivy is present.',
labels=[
'malicious-activity',
],
rank=5,
toxicity=8,
pattern='[file:hashes.\'SHA-256\' = \'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c\']',
pattern_type='stix',
valid_from='2014-02-20T09:00:00.000000Z',
extensions={
'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e': {
'extension_type': 'toplevel-property-extension',
},
},
allow_custom=False,
)
assert indicator.rank == 5
assert indicator.toxicity == 8
assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['extension_type'] == 'toplevel-property-extension'
assert isinstance(indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e'], dict)
def test_unregistered_embedded_extension_passes_with_allow_custom_false():
indicator = stix2.v21.Indicator(
id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c',
created='2014-02-20T09:16:08.989000Z',
modified='2014-02-20T09:16:08.989000Z',
name='File hash for Poison Ivy variant',
description='This file hash indicates that a sample of Poison Ivy is present.',
labels=[
'malicious-activity',
],
pattern='[file:hashes.\'SHA-256\' = \'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c\']',
pattern_type='stix',
valid_from='2014-02-20T09:00:00.000000Z',
extensions={
'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e': {
'extension_type': 'property-extension',
'rank': 5,
'toxicity': 8,
},
},
allow_custom=False,
)
assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['rank'] == 5
assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['toxicity'] == 8
assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['extension_type'] == 'property-extension'
assert isinstance(indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e'], dict)
def test_registered_top_level_extension_passes_with_allow_custom_false():
@stix2.v21.CustomExtension(
'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e', [
('rank', stix2.properties.IntegerProperty(required=True)),
('toxicity', stix2.properties.IntegerProperty(required=True)),
],
)
class ExtensionFoo1:
extension_type = 'toplevel-property-extension'
indicator = stix2.v21.Indicator(
id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c',
created='2014-02-20T09:16:08.989000Z',
modified='2014-02-20T09:16:08.989000Z',
name='File hash for Poison Ivy variant',
description='This file hash indicates that a sample of Poison Ivy is present.',
labels=[
'malicious-activity',
],
rank=5,
toxicity=8,
pattern='[file:hashes.\'SHA-256\' = \'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c\']',
pattern_type='stix',
valid_from='2014-02-20T09:00:00.000000Z',
extensions={
'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e': {
'extension_type': 'toplevel-property-extension',
},
},
allow_custom=False,
)
assert indicator.rank == 5
assert indicator.toxicity == 8
assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['extension_type'] == 'toplevel-property-extension'
assert isinstance(indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e'], ExtensionFoo1)
def test_registered_embedded_extension_passes_with_allow_custom_false():
@stix2.v21.CustomExtension(
'extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e', [
('rank', stix2.properties.IntegerProperty(required=True)),
('toxicity', stix2.properties.IntegerProperty(required=True)),
],
)
class ExtensionFoo1:
extension_type = "property-extension"
indicator = stix2.v21.Indicator(
id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c',
created='2014-02-20T09:16:08.989000Z',
modified='2014-02-20T09:16:08.989000Z',
name='File hash for Poison Ivy variant',
description='This file hash indicates that a sample of Poison Ivy is present.',
labels=[
'malicious-activity',
],
pattern='[file:hashes.\'SHA-256\' = \'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c\']',
pattern_type='stix',
valid_from='2014-02-20T09:00:00.000000Z',
extensions={
'extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e': {
'extension_type': 'property-extension',
'rank': 5,
'toxicity': 8,
},
},
allow_custom=False,
)
assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e']['rank'] == 5
assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e']['toxicity'] == 8
assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e']['extension_type'] == 'property-extension'
assert isinstance(indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e'], ExtensionFoo1)
def test_registered_new_extension_sdo_allow_custom_false():
@stix2.v21.CustomObject(
'my-favorite-sdo', [
('name', stix2.properties.StringProperty(required=True)),
('some_property_name1', stix2.properties.StringProperty(required=True)),
('some_property_name2', stix2.properties.StringProperty()),
], 'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999',
)
class MyFavSDO:
pass
my_favorite_sdo = {
'type': 'my-favorite-sdo',
'spec_version': '2.1',
'id': 'my-favorite-sdo--c5ba9dba-5ad9-4bbe-9825-df4cb8675774',
'created': '2014-02-20T09:16:08.989000Z',
'modified': '2014-02-20T09:16:08.989000Z',
'name': 'This is the name of my favorite',
'some_property_name1': 'value1',
'some_property_name2': 'value2',
# 'extensions': {
# 'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999': ExtensionDefinitiond83fce45ef584c6ca3f41fbc32e98c6e()
# }
}
sdo_object = stix2.parse(my_favorite_sdo)
assert isinstance(sdo_object, MyFavSDO)
assert isinstance(
sdo_object.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999'],
stix2.v21.EXT_MAP['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999'],
)
sdo_serialized = sdo_object.serialize()
assert '"extensions": {"extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999": {"extension_type": "new-sdo"}}' in sdo_serialized
def test_registered_new_extension_sro_allow_custom_false():
@stix2.v21.CustomObject(
'my-favorite-sro', [
('name', stix2.properties.StringProperty(required=True)),
('some_property_name1', stix2.properties.StringProperty(required=True)),
('some_property_name2', stix2.properties.StringProperty()),
], 'extension-definition--e96690a5-dc13-4f27-99dd-0f2188ad74ce', False,
)
class MyFavSRO:
pass
my_favorite_sro = {
'type': 'my-favorite-sro',
'spec_version': '2.1',
'id': 'my-favorite-sro--c5ba9dba-5ad9-4bbe-9825-df4cb8675774',
'created': '2014-02-20T09:16:08.989000Z',
'modified': '2014-02-20T09:16:08.989000Z',
'name': 'This is the name of my favorite',
'some_property_name1': 'value1',
'some_property_name2': 'value2',
# 'extensions': {
# 'extension-definition--e96690a5-dc13-4f27-99dd-0f2188ad74ce': ExtensionDefinitiond83fce45ef584c6ca3f41fbc32e98c6e()
# }
}
sro_object = stix2.parse(my_favorite_sro)
assert isinstance(sro_object, MyFavSRO)
assert isinstance(
sro_object.extensions['extension-definition--e96690a5-dc13-4f27-99dd-0f2188ad74ce'],
stix2.v21.EXT_MAP['extension-definition--e96690a5-dc13-4f27-99dd-0f2188ad74ce'],
)
sdo_serialized = sro_object.serialize()
assert '"extensions": {"extension-definition--e96690a5-dc13-4f27-99dd-0f2188ad74ce": {"extension_type": "new-sro"}}' in sdo_serialized
def test_registered_new_extension_sco_allow_custom_false():
@stix2.v21.CustomObservable(
'my-favorite-sco', [
('name', stix2.properties.StringProperty(required=True)),
('some_network_protocol_field', stix2.properties.StringProperty(required=True)),
], ['name', 'some_network_protocol_field'], 'extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff',
)
class MyFavSCO:
pass
my_favorite_sco = {
'type': 'my-favorite-sco',
'spec_version': '2.1',
'id': 'my-favorite-sco--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874',
'name': 'This is the name of my favorite SCO',
'some_network_protocol_field': 'value',
# 'extensions': {
# 'extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff': {
# 'is_extension_so': true
# }
# }
}
sco_object = stix2.parse(my_favorite_sco)
assert isinstance(sco_object, MyFavSCO)
assert isinstance(
sco_object.extensions['extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff'],
stix2.v21.EXT_MAP['extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff'],
)
sco_serialized = sco_object.serialize()
assert '"extensions": {"extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff": {"extension_type": "new-sco"}}' in sco_serialized
def test_registered_new_extension_marking_allow_custom_false():
@stix2.v21.CustomMarking(
'my-favorite-marking', [
('some_marking_field', stix2.properties.StringProperty(required=True)),
], 'extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff',
)
class MyFavMarking:
pass
my_favorite_marking = {
'type': 'marking-definition',
'spec_version': '2.1',
'id': 'marking-definition--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874',
'name': 'This is the name of my favorite Marking',
'extensions': {
'extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff': {
'extension_type': 'property-extension',
'some_marking_field': 'value',
},
},
}
marking_object = stix2.parse(my_favorite_marking)
assert isinstance(marking_object, stix2.v21.MarkingDefinition)
assert isinstance(
marking_object.extensions['extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff'],
stix2.v21.EXT_MAP['extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff'],
)
marking_serialized = marking_object.serialize(sort_keys=True)
assert '"extensions": {"extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff": ' \
'{"extension_type": "property-extension", "some_marking_field": "value"}}' in marking_serialized
@contextlib.contextmanager
def _register_extension(ext, props):
ext_def_id = "extension-definition--" + str(uuid.uuid4())
stix2.v21.CustomExtension(
ext_def_id,
props,
)(ext)
try:
yield ext_def_id
finally:
# "unregister" the extension
del stix2.registry.STIX2_OBJ_MAPS["2.1"]["extensions"][ext_def_id]
def test_nested_ext_prop_meta():
class TestExt:
extension_type = "property-extension"
props = {
"intprop": stix2.properties.IntegerProperty(required=True),
"strprop": stix2.properties.StringProperty(
required=False, default=lambda: "foo",
),
}
with _register_extension(TestExt, props) as ext_def_id:
obj = stix2.v21.Identity(
name="test",
extensions={
ext_def_id: {
"extension_type": "property-extension",
"intprop": "1",
"strprop": 2,
},
},
)
assert obj.extensions[ext_def_id].extension_type == "property-extension"
assert obj.extensions[ext_def_id].intprop == 1
assert obj.extensions[ext_def_id].strprop == "2"
obj = stix2.v21.Identity(
name="test",
extensions={
ext_def_id: {
"extension_type": "property-extension",
"intprop": "1",
},
},
)
# Ensure default kicked in
assert obj.extensions[ext_def_id].strprop == "foo"
with pytest.raises(InvalidValueError):
stix2.v21.Identity(
name="test",
extensions={
ext_def_id: {
"extension_type": "property-extension",
# wrong value type
"intprop": "foo",
},
},
)
with pytest.raises(InvalidValueError):
stix2.v21.Identity(
name="test",
extensions={
ext_def_id: {
"extension_type": "property-extension",
# missing required property
"strprop": "foo",
},
},
)
with pytest.raises(InvalidValueError):
stix2.v21.Identity(
name="test",
extensions={
ext_def_id: {
"extension_type": "property-extension",
"intprop": 1,
# Use of undefined property
"foo": False,
},
},
)
with pytest.raises(InvalidValueError):
stix2.v21.Identity(
name="test",
extensions={
ext_def_id: {
# extension_type doesn't match with registration
"extension_type": "new-sdo",
"intprop": 1,
"strprop": "foo",
},
},
)
def test_toplevel_ext_prop_meta():
class TestExt:
extension_type = "toplevel-property-extension"
props = {
"intprop": stix2.properties.IntegerProperty(required=True),
"strprop": stix2.properties.StringProperty(
required=False, default=lambda: "foo",
),
}
with _register_extension(TestExt, props) as ext_def_id:
obj = stix2.v21.Identity(
name="test",
intprop="1",
strprop=2,
extensions={
ext_def_id: {
"extension_type": "toplevel-property-extension",
},
},
)
assert obj.extensions[ext_def_id].extension_type == "toplevel-property-extension"
assert obj.intprop == 1
assert obj.strprop == "2"
obj = stix2.v21.Identity(
name="test",
intprop=1,
extensions={
ext_def_id: {
"extension_type": "toplevel-property-extension",
},
},
)
# Ensure default kicked in
assert obj.strprop == "foo"
with pytest.raises(InvalidValueError):
stix2.v21.Identity(
name="test",
intprop="foo", # wrong value type
extensions={
ext_def_id: {
"extension_type": "toplevel-property-extension",
},
},
)
with pytest.raises(InvalidValueError):
stix2.v21.Identity(
name="test",
intprop=1,
extensions={
ext_def_id: {
"extension_type": "toplevel-property-extension",
# Use of undefined property
"foo": False,
},
},
)
with pytest.raises(InvalidValueError):
stix2.v21.Identity(
name="test",
intprop=1,
extensions={
ext_def_id: {
"extension_type": "toplevel-property-extension",
# Use of a defined property, but intended for the
# top level. This should still error out.
"strprop": 1,
},
},
)
with pytest.raises(MissingPropertiesError):
stix2.v21.Identity(
name="test",
strprop="foo", # missing required property
extensions={
ext_def_id: {
"extension_type": "toplevel-property-extension",
},
},
)
def test_allow_custom_propagation(): def test_allow_custom_propagation():
obj_dict = { obj_dict = {
"type": "bundle", "type": "bundle",

View File

@ -43,11 +43,7 @@ def test_no_contrib_props_defined():
_properties = OrderedDict(( _properties = OrderedDict((
('type', TypeProperty(_type, spec_version='2.1')), ('type', TypeProperty(_type, spec_version='2.1')),
('id', IDProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')),
( ('extensions', ExtensionsProperty(spec_version='2.1')),
'extensions', ExtensionsProperty(
spec_version='2.1', enclosing_type=_type,
),
),
)) ))
_id_contributing_properties = [] _id_contributing_properties = []
@ -64,11 +60,7 @@ def test_json_compatible_prop_values():
_properties = OrderedDict(( _properties = OrderedDict((
('type', TypeProperty(_type, spec_version='2.1')), ('type', TypeProperty(_type, spec_version='2.1')),
('id', IDProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')),
( ('extensions', ExtensionsProperty(spec_version='2.1')),
'extensions', ExtensionsProperty(
spec_version='2.1', enclosing_type=_type,
),
),
('string', StringProperty()), ('string', StringProperty()),
('int', IntegerProperty()), ('int', IntegerProperty()),
('float', FloatProperty()), ('float', FloatProperty()),
@ -104,11 +96,7 @@ def test_json_incompatible_timestamp_value():
_properties = OrderedDict(( _properties = OrderedDict((
('type', TypeProperty(_type, spec_version='2.1')), ('type', TypeProperty(_type, spec_version='2.1')),
('id', IDProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')),
( ('extensions', ExtensionsProperty(spec_version='2.1')),
'extensions', ExtensionsProperty(
spec_version='2.1', enclosing_type=_type,
),
),
('timestamp', TimestampProperty()), ('timestamp', TimestampProperty()),
)) ))
_id_contributing_properties = ['timestamp'] _id_contributing_properties = ['timestamp']
@ -140,11 +128,7 @@ def test_embedded_object():
_properties = OrderedDict(( _properties = OrderedDict((
('type', TypeProperty(_type, spec_version='2.1')), ('type', TypeProperty(_type, spec_version='2.1')),
('id', IDProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')),
( ('extensions', ExtensionsProperty(spec_version='2.1')),
'extensions', ExtensionsProperty(
spec_version='2.1', enclosing_type=_type,
),
),
('sub_obj', EmbeddedObjectProperty(type=SubObj)), ('sub_obj', EmbeddedObjectProperty(type=SubObj)),
)) ))
_id_contributing_properties = ['sub_obj'] _id_contributing_properties = ['sub_obj']
@ -171,11 +155,7 @@ def test_empty_hash():
_properties = OrderedDict(( _properties = OrderedDict((
('type', TypeProperty(_type, spec_version='2.1')), ('type', TypeProperty(_type, spec_version='2.1')),
('id', IDProperty(_type, spec_version='2.1')), ('id', IDProperty(_type, spec_version='2.1')),
( ('extensions', ExtensionsProperty(spec_version='2.1')),
'extensions', ExtensionsProperty(
spec_version='2.1', enclosing_type=_type,
),
),
('hashes', HashesProperty(HASHING_ALGORITHM)), ('hashes', HashesProperty(HASHING_ALGORITHM)),
)) ))
_id_contributing_properties = ['hashes'] _id_contributing_properties = ['hashes']

View File

@ -0,0 +1,107 @@
import datetime as dt
import pytest
import pytz
import stix2
from .constants import EXTENSION_DEFINITION_IDS
EXPECTED = f"""{{
"type": "extension-definition",
"spec_version": "2.1",
"id": "{EXTENSION_DEFINITION_IDS[0]}",
"created_by_ref": "identity--11b76a96-5d2b-45e0-8a5a-f6994f370731",
"created": "2014-02-20T09:16:08.000Z",
"modified": "2014-02-20T09:16:08.000Z",
"name": "New SDO 1",
"description": "This schema creates a new object type called my-favorite-sdo-1",
"schema": "https://www.example.com/schema-my-favorite-sdo-1/v1/",
"version": "1.2.1",
"extension_types": [
"new-sdo"
]
}}"""
def test_extension_definition_example():
extension_definition = stix2.v21.ExtensionDefinition(
id=EXTENSION_DEFINITION_IDS[0],
created_by_ref="identity--11b76a96-5d2b-45e0-8a5a-f6994f370731",
created="2014-02-20T09:16:08.000Z",
modified="2014-02-20T09:16:08.000Z",
name="New SDO 1",
description="This schema creates a new object type called my-favorite-sdo-1",
schema="https://www.example.com/schema-my-favorite-sdo-1/v1/",
version="1.2.1",
extension_types=["new-sdo"],
)
assert extension_definition.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize(
"data", [
EXPECTED,
{
"id": f"{EXTENSION_DEFINITION_IDS[0]}",
"type": "extension-definition",
"spec_version": "2.1",
"created_by_ref": "identity--11b76a96-5d2b-45e0-8a5a-f6994f370731",
"created": "2014-02-20T09:16:08.000Z",
"modified": "2014-02-20T09:16:08.000Z",
"name": "New SDO 1",
"description": "This schema creates a new object type called my-favorite-sdo-1",
"schema": "https://www.example.com/schema-my-favorite-sdo-1/v1/",
"version": "1.2.1",
"extension_types": ["new-sdo"],
},
],
)
def test_parse_extension_definition(data):
extension_definition = stix2.parse(data, version="2.1")
assert extension_definition.type == 'extension-definition'
assert extension_definition.spec_version == '2.1'
assert extension_definition.id == EXTENSION_DEFINITION_IDS[0]
assert extension_definition.created == dt.datetime(2014, 2, 20, 9, 16, 8, tzinfo=pytz.utc)
assert extension_definition.modified == dt.datetime(2014, 2, 20, 9, 16, 8, tzinfo=pytz.utc)
assert extension_definition.name == 'New SDO 1'
assert extension_definition.description == 'This schema creates a new object type called my-favorite-sdo-1'
assert extension_definition.schema == 'https://www.example.com/schema-my-favorite-sdo-1/v1/'
assert extension_definition.version == '1.2.1'
assert extension_definition.extension_types == ['new-sdo']
def test_parse_no_type():
with pytest.raises(stix2.exceptions.ParseError):
stix2.parse(
"""{
"id": "{EXTENSION_DEFINITION_IDS[0]}",
"spec_version": "2.1",
"name": "New SDO 1",
"description": "This schema creates a new object type called my-favorite-sdo-1",
"created": "2014-02-20T09:16:08.989000Z",
"modified": "2014-02-20T09:16:08.989000Z",
"created_by_ref": "identity--11b76a96-5d2b-45e0-8a5a-f6994f370731",
"schema": "https://www.example.com/schema-my-favorite-sdo-1/v1/",
"version": "1.2.1",
"extension_types": [ "new-sdo" ]
}""", version="2.1",
)
def test_extension_definition_with_custom():
extension_definition = stix2.v21.ExtensionDefinition(
created_by_ref="identity--11b76a96-5d2b-45e0-8a5a-f6994f370731",
created="2014-02-20T09:16:08.000Z",
modified="2014-02-20T09:16:08.000Z",
name="New SDO 1",
description="This schema creates a new object type called my-favorite-sdo-1",
schema="https://www.example.com/schema-my-favorite-sdo-1/v1/",
version="1.2.1",
extension_types=["new-sdo"],
custom_properties={'x_foo': 'bar'},
)
assert extension_definition.x_foo == "bar"

View File

@ -26,7 +26,7 @@ def test_external_reference_veris():
url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json", url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json",
) )
assert str(ref) == VERIS assert ref.serialize(pretty=True) == VERIS
CAPEC = """{ CAPEC = """{
@ -41,7 +41,7 @@ def test_external_reference_capec():
external_id="CAPEC-550", external_id="CAPEC-550",
) )
assert str(ref) == CAPEC assert ref.serialize(pretty=True) == CAPEC
assert re.match("ExternalReference\\(source_name=u?'capec', external_id=u?'CAPEC-550'\\)", repr(ref)) assert re.match("ExternalReference\\(source_name=u?'capec', external_id=u?'CAPEC-550'\\)", repr(ref))
@ -59,7 +59,7 @@ def test_external_reference_capec_url():
url="http://capec.mitre.org/data/definitions/550.html", url="http://capec.mitre.org/data/definitions/550.html",
) )
assert str(ref) == CAPEC_URL assert ref.serialize(pretty=True) == CAPEC_URL
THREAT_REPORT = """{ THREAT_REPORT = """{
@ -76,7 +76,7 @@ def test_external_reference_threat_report():
url="http://www.example.com/threat-report.pdf", url="http://www.example.com/threat-report.pdf",
) )
assert str(ref) == THREAT_REPORT assert ref.serialize(pretty=True) == THREAT_REPORT
BUGZILLA = """{ BUGZILLA = """{
@ -93,7 +93,7 @@ def test_external_reference_bugzilla():
url="https://www.example.com/bugs/1370", url="https://www.example.com/bugs/1370",
) )
assert str(ref) == BUGZILLA assert ref.serialize(pretty=True) == BUGZILLA
OFFLINE = """{ OFFLINE = """{
@ -108,7 +108,7 @@ def test_external_reference_offline():
description="Threat report", description="Threat report",
) )
assert str(ref) == OFFLINE assert ref.serialize(pretty=True) == OFFLINE
assert re.match("ExternalReference\\(source_name=u?'ACME Threat Intel', description=u?'Threat report'\\)", repr(ref)) assert re.match("ExternalReference\\(source_name=u?'ACME Threat Intel', description=u?'Threat report'\\)", repr(ref))
# Yikes! This works # Yikes! This works
assert eval("stix2." + repr(ref)) == ref assert eval("stix2." + repr(ref)) == ref

View File

@ -38,7 +38,7 @@ def test_grouping_with_all_required_properties():
], ],
) )
assert str(grp) == EXPECTED_GROUPING assert grp.serialize(pretty=True) == EXPECTED_GROUPING
def test_grouping_autogenerated_properties(grouping): def test_grouping_autogenerated_properties(grouping):

View File

@ -27,7 +27,7 @@ def test_identity_example():
identity_class="individual", identity_class="individual",
) )
assert str(identity) == EXPECTED assert identity.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -77,6 +77,5 @@ def test_identity_with_custom():
) )
assert identity.x_foo == "bar" assert identity.x_foo == "bar"
assert "x_foo" in identity.object_properties()
# TODO: Add other examples # TODO: Add other examples

View File

@ -0,0 +1,80 @@
import datetime as dt
import pytest
import pytz
import stix2
from .constants import INCIDENT_ID
EXPECTED = """{
"type": "incident",
"spec_version": "2.1",
"id": "incident--40fc3b35-0dc4-4afd-9927-288d44bfce20",
"created": "2015-12-21T19:59:11.000Z",
"modified": "2015-12-21T19:59:11.000Z",
"name": "Breach of Cyber Tech Dynamics",
"description": "Intrusion into enterprise network"
}"""
def test_incident_example():
incident = stix2.v21.Incident(
id=INCIDENT_ID,
created="2015-12-21T19:59:11.000Z",
modified="2015-12-21T19:59:11.000Z",
name="Breach of Cyber Tech Dynamics",
description="Intrusion into enterprise network",
)
assert incident.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize(
"data", [
EXPECTED,
{
"created": "2015-12-21T19:59:11.000Z",
"id": INCIDENT_ID,
"description": "Intrusion into enterprise network",
"modified": "2015-12-21T19:59:11.000Z",
"name": "Breach of Cyber Tech Dynamics",
"spec_version": "2.1",
"type": "incident",
},
],
)
def test_parse_incident(data):
incident = stix2.parse(data, version="2.1")
assert incident.type == 'incident'
assert incident.spec_version == '2.1'
assert incident.id == INCIDENT_ID
assert incident.created == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc)
assert incident.modified == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc)
assert incident.name == 'Breach of Cyber Tech Dynamics'
assert incident.description == 'Intrusion into enterprise network'
def test_parse_no_type():
with pytest.raises(stix2.exceptions.ParseError):
stix2.parse(
"""
{
"id": "incident--40fc3b35-0dc4-4afd-9927-288d44bfce20",
"created": "2015-12-21T19:59:11.000Z",
"modified": "2015-12-21T19:59:11.000Z",
"name": "Breach of Cyber Tech Dynamics",
"description": "Intrusion into enterprise network"
}""", version="2.1",
)
def test_incident_with_custom():
incident = stix2.v21.Incident(
name="Breach of Cyber Tech Dynamics",
description="Intrusion into enterprise network",
custom_properties={'x_foo': 'bar'},
)
assert incident.x_foo == "bar"

View File

@ -30,7 +30,8 @@ EXPECTED_INDICATOR_REPR = "Indicator(" + " ".join(
pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
pattern_type='stix', pattern_type='stix',
pattern_version='2.1', pattern_version='2.1',
valid_from='1970-01-01T00:00:01Z' valid_from='1970-01-01T00:00:01Z',
revoked=False
""".split(), """.split(),
) + ")" ) + ")"
@ -50,7 +51,7 @@ def test_indicator_with_all_required_properties():
) )
assert ind.revoked is False assert ind.revoked is False
assert str(ind) == EXPECTED_INDICATOR assert ind.serialize(pretty=True) == EXPECTED_INDICATOR
rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(ind)) rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(ind))
assert rep == EXPECTED_INDICATOR_REPR assert rep == EXPECTED_INDICATOR_REPR

View File

@ -28,7 +28,7 @@ def test_infrastructure_with_all_required_properties():
name="Poison Ivy C2", name="Poison Ivy C2",
) )
assert str(infra) == EXPECTED_INFRASTRUCTURE assert infra.serialize(pretty=True) == EXPECTED_INFRASTRUCTURE
def test_infrastructure_autogenerated_properties(infrastructure): def test_infrastructure_autogenerated_properties(infrastructure):

View File

@ -39,7 +39,7 @@ def test_intrusion_set_example():
goals=["acquisition-theft", "harassment", "damage"], goals=["acquisition-theft", "harassment", "damage"],
) )
assert str(intrusion_set) == EXPECTED assert intrusion_set.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -16,7 +16,7 @@ def test_lockheed_martin_cyber_kill_chain():
phase_name="reconnaissance", phase_name="reconnaissance",
) )
assert str(recon) == LMCO_RECON assert recon.serialize(pretty=True) == LMCO_RECON
FOO_PRE_ATTACK = """{ FOO_PRE_ATTACK = """{
@ -31,7 +31,7 @@ def test_kill_chain_example():
phase_name="pre-attack", phase_name="pre-attack",
) )
assert str(preattack) == FOO_PRE_ATTACK assert preattack.serialize(pretty=True) == FOO_PRE_ATTACK
def test_kill_chain_required_properties(): def test_kill_chain_required_properties():

View File

@ -27,7 +27,8 @@ EXPECTED_LOCATION_1_REPR = "Location(" + " ".join(
created='2016-04-06T20:03:00.000Z', created='2016-04-06T20:03:00.000Z',
modified='2016-04-06T20:03:00.000Z', modified='2016-04-06T20:03:00.000Z',
latitude=48.8566, latitude=48.8566,
longitude=2.3522""".split(), longitude=2.3522,
revoked=False""".split(),
) + ")" ) + ")"
EXPECTED_LOCATION_2 = """{ EXPECTED_LOCATION_2 = """{
@ -47,14 +48,15 @@ EXPECTED_LOCATION_2_REPR = "Location(" + " ".join(
id='location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64', id='location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64',
created='2016-04-06T20:03:00.000Z', created='2016-04-06T20:03:00.000Z',
modified='2016-04-06T20:03:00.000Z', modified='2016-04-06T20:03:00.000Z',
region='northern-america'""".split(), region='northern-america',
revoked=False""".split(),
) + ")" ) + ")"
def test_location_with_some_required_properties(): def test_location_with_some_required_properties():
now = dt.datetime(2016, 4, 6, 20, 3, 0, tzinfo=pytz.utc) now = dt.datetime(2016, 4, 6, 20, 3, 0, tzinfo=pytz.utc)
loc = stix2.v21.Location( location = stix2.v21.Location(
id=LOCATION_ID, id=LOCATION_ID,
created=now, created=now,
modified=now, modified=now,
@ -62,8 +64,8 @@ def test_location_with_some_required_properties():
longitude=2.3522, longitude=2.3522,
) )
assert str(loc) == EXPECTED_LOCATION_1 assert location.serialize(pretty=True) == EXPECTED_LOCATION_1
rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(loc)) rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(location))
assert rep == EXPECTED_LOCATION_1_REPR assert rep == EXPECTED_LOCATION_1_REPR

View File

@ -23,7 +23,7 @@ EXPECTED_MALWARE = """{
def test_malware_with_all_required_properties(): def test_malware_with_all_required_properties():
now = dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc) now = dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc)
mal = stix2.v21.Malware( malware = stix2.v21.Malware(
type="malware", type="malware",
id=MALWARE_ID, id=MALWARE_ID,
created=now, created=now,
@ -32,7 +32,7 @@ def test_malware_with_all_required_properties():
is_family=False, is_family=False,
) )
assert str(mal) == EXPECTED_MALWARE assert malware.serialize(pretty=True) == EXPECTED_MALWARE
def test_malware_autogenerated_properties(malware): def test_malware_autogenerated_properties(malware):

View File

@ -48,9 +48,9 @@ MALWARE_ANALYSIS_DICT = json.loads(MALWARE_ANALYSIS_JSON)
def test_malware_analysis_example(): def test_malware_analysis_example():
ma = stix2.v21.MalwareAnalysis(**MALWARE_ANALYSIS_DICT) malware_analysis = stix2.v21.MalwareAnalysis(**MALWARE_ANALYSIS_DICT)
assert str(ma) == MALWARE_ANALYSIS_JSON assert malware_analysis.serialize(pretty=True) == MALWARE_ANALYSIS_JSON
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -1,7 +1,7 @@
import pytest import pytest
from stix2 import exceptions from stix2 import exceptions, parse
from stix2.v21 import ( from stix2.v21 import (
TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, MarkingDefinition, TLPMarking, TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, MarkingDefinition, TLPMarking,
) )
@ -143,3 +143,29 @@ def test_unknown_tlp_marking():
definition_type='tlp', definition_type='tlp',
definition=TLPMarking(tlp='gray'), definition=TLPMarking(tlp='gray'),
) )
def test_marking_definition_missing_definition():
my_favorite_marking = {
'type': 'marking-definition',
'spec_version': '2.1',
'id': 'marking-definition--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874',
'name': 'This is the name of my favorite Marking',
'definition_type': 'foobar',
}
with pytest.raises(exceptions.PropertyPresenceError):
parse(my_favorite_marking)
def test_marking_definition_missing_definition_type():
my_favorite_marking = {
'type': 'marking-definition',
'spec_version': '2.1',
'id': 'marking-definition--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874',
'name': 'This is the name of my favorite Marking',
'definition': {
'some_type': 'foobar',
},
}
with pytest.raises(exceptions.InvalidValueError):
parse(my_favorite_marking)

View File

@ -99,7 +99,7 @@ EXPECTED_CAMPAIGN_WITH_GRANULAR_LANG_MARKINGS = u"""{
def test_marking_def_example_with_tlp(): def test_marking_def_example_with_tlp():
assert str(TLP_WHITE) == EXPECTED_TLP_MARKING_DEFINITION assert TLP_WHITE.serialize(pretty=True) == EXPECTED_TLP_MARKING_DEFINITION
def test_marking_def_example_with_statement_positional_argument(): def test_marking_def_example_with_statement_positional_argument():
@ -110,7 +110,7 @@ def test_marking_def_example_with_statement_positional_argument():
definition=stix2.StatementMarking(statement="Copyright 2016, Example Corp"), definition=stix2.StatementMarking(statement="Copyright 2016, Example Corp"),
) )
assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION assert marking_definition.serialize(pretty=True) == EXPECTED_STATEMENT_MARKING_DEFINITION
def test_marking_def_example_with_kwargs_statement(): def test_marking_def_example_with_kwargs_statement():
@ -122,7 +122,7 @@ def test_marking_def_example_with_kwargs_statement():
definition=stix2.StatementMarking(**kwargs), definition=stix2.StatementMarking(**kwargs),
) )
assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION assert marking_definition.serialize(pretty=True) == EXPECTED_STATEMENT_MARKING_DEFINITION
def test_marking_def_invalid_type(): def test_marking_def_invalid_type():
@ -145,7 +145,7 @@ def test_campaign_with_markings_example():
description="Campaign by Green Group against a series of targets in the financial services sector.", description="Campaign by Green Group against a series of targets in the financial services sector.",
object_marking_refs=TLP_WHITE, object_marking_refs=TLP_WHITE,
) )
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING assert campaign.serialize(pretty=True) == EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING
def test_granular_example(): def test_granular_example():
@ -154,7 +154,7 @@ def test_granular_example():
selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"], selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"],
) )
assert str(granular_marking) == EXPECTED_GRANULAR_MARKING assert granular_marking.serialize(pretty=True) == EXPECTED_GRANULAR_MARKING
def test_granular_example_with_bad_selector(): def test_granular_example_with_bad_selector():
@ -185,7 +185,7 @@ def test_campaign_with_granular_markings_example():
), ),
], ],
) )
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_REF_MARKINGS assert campaign.serialize(pretty=True) == EXPECTED_CAMPAIGN_WITH_GRANULAR_REF_MARKINGS
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -48,6 +48,7 @@ EXPECTED_OPINION_REPR = "Note(" + " ".join((
content='%s', content='%s',
authors=['John Doe'], authors=['John Doe'],
object_refs=['campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f'], object_refs=['campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f'],
revoked=False,
external_references=[ExternalReference(source_name='job-tracker', external_id='job-id-1234')] external_references=[ExternalReference(source_name='job-tracker', external_id='job-id-1234')]
""" % CONTENT """ % CONTENT
).split()) + ")" ).split()) + ")"
@ -73,7 +74,7 @@ def test_note_with_required_properties():
], ],
) )
assert str(note) == EXPECTED_NOTE assert note.serialize(pretty=True) == EXPECTED_NOTE
rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(note)) rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(note))
assert rep == EXPECTED_OPINION_REPR assert rep == EXPECTED_OPINION_REPR

View File

@ -155,7 +155,7 @@ def test_observed_data_example_with_object_refs():
], ],
) )
assert str(observed_data) == EXPECTED_OBJECT_REFS assert observed_data.serialize(pretty=True) == EXPECTED_OBJECT_REFS
def test_observed_data_object_constraint(): def test_observed_data_object_constraint():
@ -1218,8 +1218,8 @@ def test_process_example_empty_error():
stix2.v21.Process() stix2.v21.Process()
assert excinfo.value.cls == stix2.v21.Process assert excinfo.value.cls == stix2.v21.Process
properties_of_process = list(stix2.v21.Process._properties.keys()) properties_of_process = stix2.v21.Process._properties.keys()
properties_of_process = [prop for prop in properties_of_process if prop not in ["type", "id", "defanged", "spec_version"]] properties_of_process -= {"type", "id", "defanged", "spec_version", "extensions"}
assert excinfo.value.properties == sorted(properties_of_process) assert excinfo.value.properties == sorted(properties_of_process)
msg = "At least one of the ({1}) properties for {0} must be populated." msg = "At least one of the ({1}) properties for {0} must be populated."
msg = msg.format( msg = msg.format(

View File

@ -38,7 +38,8 @@ EXPECTED_OPINION_REPR = "Opinion(" + " ".join((
modified='2016-05-12T08:17:27.000Z', modified='2016-05-12T08:17:27.000Z',
explanation="%s", explanation="%s",
opinion='strongly-disagree', opinion='strongly-disagree',
object_refs=['relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471'] object_refs=['relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471'],
revoked=False
""" % EXPLANATION """ % EXPLANATION
).split()) + ")" ).split()) + ")"
@ -56,7 +57,7 @@ def test_opinion_with_required_properties():
explanation=EXPLANATION, explanation=EXPLANATION,
) )
assert str(opi) == EXPECTED_OPINION assert opi.serialize(pretty=True) == EXPECTED_OPINION
rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(opi)) rep = re.sub(r"(\[|=| )u('|\"|\\\'|\\\")", r"\g<1>\g<2>", repr(opi))
assert rep == EXPECTED_OPINION_REPR assert rep == EXPECTED_OPINION_REPR

View File

@ -486,7 +486,7 @@ def test_embedded_property_dict_custom():
def test_extension_property_valid(): def test_extension_property_valid():
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='file') ext_prop = ExtensionsProperty(spec_version='2.1')
result = ext_prop.clean( result = ext_prop.clean(
{ {
'windows-pebinary-ext': { 'windows-pebinary-ext': {
@ -515,13 +515,13 @@ def test_extension_property_valid():
def test_extension_property_invalid1(): def test_extension_property_invalid1():
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='file') ext_prop = ExtensionsProperty(spec_version='2.1')
with pytest.raises(ValueError): with pytest.raises(ValueError):
ext_prop.clean(1, False) ext_prop.clean(1, False)
def test_extension_property_invalid2(): def test_extension_property_invalid2():
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='file') ext_prop = ExtensionsProperty(spec_version='2.1')
with pytest.raises(CustomContentError): with pytest.raises(CustomContentError):
ext_prop.clean( ext_prop.clean(
{ {
@ -543,7 +543,7 @@ def test_extension_property_invalid2():
def test_extension_property_invalid3(): def test_extension_property_invalid3():
ext_prop = ExtensionsProperty(spec_version="2.1", enclosing_type='file') ext_prop = ExtensionsProperty(spec_version="2.1")
with pytest.raises(ExtraPropertiesError): with pytest.raises(ExtraPropertiesError):
ext_prop.clean( ext_prop.clean(
{ {
@ -571,20 +571,6 @@ def test_extension_property_invalid3():
assert result[1] assert result[1]
def test_extension_property_invalid_type():
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='indicator')
with pytest.raises(CustomContentError) as excinfo:
ext_prop.clean(
{
'windows-pebinary-ext': {
'pe_type': 'exe',
},
},
False,
)
assert "Can't parse unknown extension" in str(excinfo.value)
def test_extension_at_least_one_property_constraint(): def test_extension_at_least_one_property_constraint():
with pytest.raises(AtLeastOnePropertyError): with pytest.raises(AtLeastOnePropertyError):
stix2.v21.TCPExt() stix2.v21.TCPExt()

View File

@ -33,7 +33,7 @@ def test_relationship_all_required_properties():
source_ref=INDICATOR_ID, source_ref=INDICATOR_ID,
target_ref=MALWARE_ID, target_ref=MALWARE_ID,
) )
assert str(rel) == EXPECTED_RELATIONSHIP assert rel.serialize(pretty=True) == EXPECTED_RELATIONSHIP
def test_relationship_autogenerated_properties(relationship): def test_relationship_autogenerated_properties(relationship):

View File

@ -49,7 +49,7 @@ def test_report_example():
], ],
) )
assert str(report) == EXPECTED assert report.serialize(pretty=True) == EXPECTED
def test_report_example_objects_in_object_refs(): def test_report_example_objects_in_object_refs():
@ -69,7 +69,7 @@ def test_report_example_objects_in_object_refs():
], ],
) )
assert str(report) == EXPECTED assert report.serialize(pretty=True) == EXPECTED
def test_report_example_objects_in_object_refs_with_bad_id(): def test_report_example_objects_in_object_refs_with_bad_id():

View File

@ -38,7 +38,7 @@ BAD_SIGHTING = """{
def test_sighting_all_required_properties(): def test_sighting_all_required_properties():
now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc)
s = stix2.v21.Sighting( sighting = stix2.v21.Sighting(
type='sighting', type='sighting',
id=SIGHTING_ID, id=SIGHTING_ID,
created=now, created=now,
@ -46,7 +46,7 @@ def test_sighting_all_required_properties():
sighting_of_ref=INDICATOR_ID, sighting_of_ref=INDICATOR_ID,
where_sighted_refs=[IDENTITY_ID, LOCATION_ID], where_sighted_refs=[IDENTITY_ID, LOCATION_ID],
) )
assert str(s) == EXPECTED_SIGHTING assert sighting.serialize(pretty=True) == EXPECTED_SIGHTING
def test_sighting_bad_where_sighted_refs(): def test_sighting_bad_where_sighted_refs():

View File

@ -34,7 +34,7 @@ def test_threat_actor_example():
threat_actor_types=["crime-syndicate"], threat_actor_types=["crime-syndicate"],
) )
assert str(threat_actor) == EXPECTED assert threat_actor.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -45,7 +45,7 @@ def test_tool_example():
tool_types=["remote-access"], tool_types=["remote-access"],
) )
assert str(tool) == EXPECTED assert tool.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -37,7 +37,7 @@ def test_vulnerability_example():
], ],
) )
assert str(vulnerability) == EXPECTED assert vulnerability.serialize(pretty=True) == EXPECTED
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -82,26 +82,18 @@ OBJ_MAP_OBSERVABLE = {
} }
EXT_MAP = { EXT_MAP = {
'file': { 'archive-ext': ArchiveExt,
'archive-ext': ArchiveExt, 'ntfs-ext': NTFSExt,
'ntfs-ext': NTFSExt, 'pdf-ext': PDFExt,
'pdf-ext': PDFExt, 'raster-image-ext': RasterImageExt,
'raster-image-ext': RasterImageExt, 'windows-pebinary-ext': WindowsPEBinaryExt,
'windows-pebinary-ext': WindowsPEBinaryExt, 'http-request-ext': HTTPRequestExt,
}, 'icmp-ext': ICMPExt,
'network-traffic': { 'socket-ext': SocketExt,
'http-request-ext': HTTPRequestExt, 'tcp-ext': TCPExt,
'icmp-ext': ICMPExt, 'windows-process-ext': WindowsProcessExt,
'socket-ext': SocketExt, 'windows-service-ext': WindowsServiceExt,
'tcp-ext': TCPExt, 'unix-account-ext': UNIXAccountExt,
},
'process': {
'windows-process-ext': WindowsProcessExt,
'windows-service-ext': WindowsServiceExt,
},
'user-account': {
'unix-account-ext': UNIXAccountExt,
},
} }

View File

@ -20,7 +20,7 @@ class Bundle(_STIXBase20):
# Not technically correct: STIX 2.0 spec doesn't say spec_version must # Not technically correct: STIX 2.0 spec doesn't say spec_version must
# have this value, but it's all we support for now. # have this value, but it's all we support for now.
('spec_version', StringProperty(fixed='2.0')), ('spec_version', StringProperty(fixed='2.0')),
('objects', ListProperty(STIXObjectProperty(spec_version="2.0"))), ('objects', ListProperty(STIXObjectProperty(spec_version='2.0'))),
]) ])
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View File

@ -75,7 +75,6 @@ class TLPMarking(_STIXBase20):
`the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709287>`__. `the STIX 2.0 specification <http://docs.oasis-open.org/cti/stix/v2.0/cs01/part1-stix-core/stix-v2.0-cs01-part1-stix-core.html#_Toc496709287>`__.
""" """
# TODO: don't allow the creation of any other TLPMarkings than the ones below
_type = 'tlp' _type = 'tlp'
_properties = OrderedDict([ _properties = OrderedDict([
('tlp', StringProperty(required=True)), ('tlp', StringProperty(required=True)),
@ -131,7 +130,7 @@ class MarkingDefinition(_STIXBase20, _MarkingsMixin):
]) ])
def __init__(self, **kwargs): def __init__(self, **kwargs):
if set(('definition_type', 'definition')).issubset(kwargs.keys()): if {'definition_type', 'definition'}.issubset(kwargs.keys()):
# Create correct marking type object # Create correct marking type object
try: try:
marking_type = OBJ_MAP_MARKING[kwargs['definition_type']] marking_type = OBJ_MAP_MARKING[kwargs['definition_type']]

View File

@ -31,8 +31,8 @@ class Artifact(_Observable):
('mime_type', StringProperty()), ('mime_type', StringProperty()),
('payload_bin', BinaryProperty()), ('payload_bin', BinaryProperty()),
('url', StringProperty()), ('url', StringProperty()),
('hashes', HashesProperty(HASHING_ALGORITHM, spec_version="2.0")), ('hashes', HashesProperty(HASHING_ALGORITHM, spec_version='2.0')),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -52,7 +52,7 @@ class AutonomousSystem(_Observable):
('number', IntegerProperty(required=True)), ('number', IntegerProperty(required=True)),
('name', StringProperty()), ('name', StringProperty()),
('rir', StringProperty()), ('rir', StringProperty()),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -71,7 +71,7 @@ class Directory(_Observable):
('modified', TimestampProperty()), ('modified', TimestampProperty()),
('accessed', TimestampProperty()), ('accessed', TimestampProperty()),
('contains_refs', ListProperty(ObjectReferenceProperty(valid_types=['file', 'directory']))), ('contains_refs', ListProperty(ObjectReferenceProperty(valid_types=['file', 'directory']))),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -85,7 +85,7 @@ class DomainName(_Observable):
('type', TypeProperty(_type, spec_version='2.0')), ('type', TypeProperty(_type, spec_version='2.0')),
('value', StringProperty(required=True)), ('value', StringProperty(required=True)),
('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types=['ipv4-addr', 'ipv6-addr', 'domain-name']))), ('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types=['ipv4-addr', 'ipv6-addr', 'domain-name']))),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -100,7 +100,7 @@ class EmailAddress(_Observable):
('value', StringProperty(required=True)), ('value', StringProperty(required=True)),
('display_name', StringProperty()), ('display_name', StringProperty()),
('belongs_to_ref', ObjectReferenceProperty(valid_types='user-account')), ('belongs_to_ref', ObjectReferenceProperty(valid_types='user-account')),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -139,11 +139,11 @@ class EmailMessage(_Observable):
('bcc_refs', ListProperty(ObjectReferenceProperty(valid_types='email-addr'))), ('bcc_refs', ListProperty(ObjectReferenceProperty(valid_types='email-addr'))),
('subject', StringProperty()), ('subject', StringProperty()),
('received_lines', ListProperty(StringProperty)), ('received_lines', ListProperty(StringProperty)),
('additional_header_fields', DictionaryProperty(spec_version="2.0")), ('additional_header_fields', DictionaryProperty(spec_version='2.0')),
('body', StringProperty()), ('body', StringProperty()),
('body_multipart', ListProperty(EmbeddedObjectProperty(type=EmailMIMEComponent))), ('body_multipart', ListProperty(EmbeddedObjectProperty(type=EmailMIMEComponent))),
('raw_email_ref', ObjectReferenceProperty(valid_types='artifact')), ('raw_email_ref', ObjectReferenceProperty(valid_types='artifact')),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -200,7 +200,7 @@ class PDFExt(_Extension):
_properties = OrderedDict([ _properties = OrderedDict([
('version', StringProperty()), ('version', StringProperty()),
('is_optimized', BooleanProperty()), ('is_optimized', BooleanProperty()),
('document_info_dict', DictionaryProperty(spec_version="2.0")), ('document_info_dict', DictionaryProperty(spec_version='2.0')),
('pdfid0', StringProperty()), ('pdfid0', StringProperty()),
('pdfid1', StringProperty()), ('pdfid1', StringProperty()),
]) ])
@ -217,7 +217,7 @@ class RasterImageExt(_Extension):
('image_width', IntegerProperty()), ('image_width', IntegerProperty()),
('bits_per_pixel', IntegerProperty()), ('bits_per_pixel', IntegerProperty()),
('image_compression_algorithm', StringProperty()), ('image_compression_algorithm', StringProperty()),
('exif_tags', DictionaryProperty(spec_version="2.0")), ('exif_tags', DictionaryProperty(spec_version='2.0')),
]) ])
@ -324,7 +324,7 @@ class File(_Observable):
('decryption_key', StringProperty()), ('decryption_key', StringProperty()),
('contains_refs', ListProperty(ObjectReferenceProperty)), ('contains_refs', ListProperty(ObjectReferenceProperty)),
('content_ref', ObjectReferenceProperty(valid_types='artifact')), ('content_ref', ObjectReferenceProperty(valid_types='artifact')),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -344,7 +344,7 @@ class IPv4Address(_Observable):
('value', StringProperty(required=True)), ('value', StringProperty(required=True)),
('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))), ('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))),
('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))), ('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -359,7 +359,7 @@ class IPv6Address(_Observable):
('value', StringProperty(required=True)), ('value', StringProperty(required=True)),
('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))), ('resolves_to_refs', ListProperty(ObjectReferenceProperty(valid_types='mac-addr'))),
('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))), ('belongs_to_refs', ListProperty(ObjectReferenceProperty(valid_types='autonomous-system'))),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -372,7 +372,7 @@ class MACAddress(_Observable):
_properties = OrderedDict([ _properties = OrderedDict([
('type', TypeProperty(_type, spec_version='2.0')), ('type', TypeProperty(_type, spec_version='2.0')),
('value', StringProperty(required=True)), ('value', StringProperty(required=True)),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -385,7 +385,7 @@ class Mutex(_Observable):
_properties = OrderedDict([ _properties = OrderedDict([
('type', TypeProperty(_type, spec_version='2.0')), ('type', TypeProperty(_type, spec_version='2.0')),
('name', StringProperty(required=True)), ('name', StringProperty(required=True)),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -399,7 +399,7 @@ class HTTPRequestExt(_Extension):
('request_method', StringProperty(required=True)), ('request_method', StringProperty(required=True)),
('request_value', StringProperty(required=True)), ('request_value', StringProperty(required=True)),
('request_version', StringProperty()), ('request_version', StringProperty()),
('request_header', DictionaryProperty(spec_version="2.0")), ('request_header', DictionaryProperty(spec_version='2.0')),
('message_body_length', IntegerProperty()), ('message_body_length', IntegerProperty()),
('message_body_data_ref', ObjectReferenceProperty(valid_types='artifact')), ('message_body_data_ref', ObjectReferenceProperty(valid_types='artifact')),
]) ])
@ -452,7 +452,7 @@ class SocketExt(_Extension):
], ],
), ),
), ),
('options', DictionaryProperty(spec_version="2.0")), ('options', DictionaryProperty(spec_version='2.0')),
( (
'socket_type', EnumProperty( 'socket_type', EnumProperty(
allowed=[ allowed=[
@ -501,12 +501,12 @@ class NetworkTraffic(_Observable):
('dst_byte_count', IntegerProperty()), ('dst_byte_count', IntegerProperty()),
('src_packets', IntegerProperty()), ('src_packets', IntegerProperty()),
('dst_packets', IntegerProperty()), ('dst_packets', IntegerProperty()),
('ipfix', DictionaryProperty(spec_version="2.0")), ('ipfix', DictionaryProperty(spec_version='2.0')),
('src_payload_ref', ObjectReferenceProperty(valid_types='artifact')), ('src_payload_ref', ObjectReferenceProperty(valid_types='artifact')),
('dst_payload_ref', ObjectReferenceProperty(valid_types='artifact')), ('dst_payload_ref', ObjectReferenceProperty(valid_types='artifact')),
('encapsulates_refs', ListProperty(ObjectReferenceProperty(valid_types='network-traffic'))), ('encapsulates_refs', ListProperty(ObjectReferenceProperty(valid_types='network-traffic'))),
('encapsulates_by_ref', ObjectReferenceProperty(valid_types='network-traffic')), ('encapsulates_by_ref', ObjectReferenceProperty(valid_types='network-traffic')),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -526,7 +526,7 @@ class WindowsProcessExt(_Extension):
('priority', StringProperty()), ('priority', StringProperty()),
('owner_sid', StringProperty()), ('owner_sid', StringProperty()),
('window_title', StringProperty()), ('window_title', StringProperty()),
('startup_info', DictionaryProperty(spec_version="2.0")), ('startup_info', DictionaryProperty(spec_version='2.0')),
]) ])
@ -595,13 +595,13 @@ class Process(_Observable):
('cwd', StringProperty()), ('cwd', StringProperty()),
('arguments', ListProperty(StringProperty)), ('arguments', ListProperty(StringProperty)),
('command_line', StringProperty()), ('command_line', StringProperty()),
('environment_variables', DictionaryProperty(spec_version="2.0")), ('environment_variables', DictionaryProperty(spec_version='2.0')),
('opened_connection_refs', ListProperty(ObjectReferenceProperty(valid_types='network-traffic'))), ('opened_connection_refs', ListProperty(ObjectReferenceProperty(valid_types='network-traffic'))),
('creator_user_ref', ObjectReferenceProperty(valid_types='user-account')), ('creator_user_ref', ObjectReferenceProperty(valid_types='user-account')),
('binary_ref', ObjectReferenceProperty(valid_types='file')), ('binary_ref', ObjectReferenceProperty(valid_types='file')),
('parent_ref', ObjectReferenceProperty(valid_types='process')), ('parent_ref', ObjectReferenceProperty(valid_types='process')),
('child_refs', ListProperty(ObjectReferenceProperty('process'))), ('child_refs', ListProperty(ObjectReferenceProperty('process'))),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -632,7 +632,7 @@ class Software(_Observable):
('languages', ListProperty(StringProperty)), ('languages', ListProperty(StringProperty)),
('vendor', StringProperty()), ('vendor', StringProperty()),
('version', StringProperty()), ('version', StringProperty()),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -645,7 +645,7 @@ class URL(_Observable):
_properties = OrderedDict([ _properties = OrderedDict([
('type', TypeProperty(_type, spec_version='2.0')), ('type', TypeProperty(_type, spec_version='2.0')),
('value', StringProperty(required=True)), ('value', StringProperty(required=True)),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -684,7 +684,7 @@ class UserAccount(_Observable):
('password_last_changed', TimestampProperty()), ('password_last_changed', TimestampProperty()),
('account_first_login', TimestampProperty()), ('account_first_login', TimestampProperty()),
('account_last_login', TimestampProperty()), ('account_last_login', TimestampProperty()),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -733,7 +733,7 @@ class WindowsRegistryKey(_Observable):
('modified', TimestampProperty()), ('modified', TimestampProperty()),
('creator_user_ref', ObjectReferenceProperty(valid_types='user-account')), ('creator_user_ref', ObjectReferenceProperty(valid_types='user-account')),
('number_of_subkeys', IntegerProperty()), ('number_of_subkeys', IntegerProperty()),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -784,7 +784,7 @@ class X509Certificate(_Observable):
('subject_public_key_modulus', StringProperty()), ('subject_public_key_modulus', StringProperty()),
('subject_public_key_exponent', IntegerProperty()), ('subject_public_key_exponent', IntegerProperty()),
('x509_v3_extensions', EmbeddedObjectProperty(type=X509V3ExtensionsType)), ('x509_v3_extensions', EmbeddedObjectProperty(type=X509V3ExtensionsType)),
('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.0')),
]) ])
@ -807,16 +807,16 @@ def CustomObservable(type='x-custom-observable', properties=None):
itertools.chain.from_iterable([ itertools.chain.from_iterable([
[('type', TypeProperty(type, spec_version='2.0'))], [('type', TypeProperty(type, spec_version='2.0'))],
properties, properties,
[('extensions', ExtensionsProperty(spec_version="2.0", enclosing_type=type))], [('extensions', ExtensionsProperty(spec_version='2.0'))],
]), ]),
) )
return _custom_observable_builder(cls, type, _properties, '2.0', _Observable) return _custom_observable_builder(cls, type, _properties, '2.0', _Observable)
return wrapper return wrapper
def CustomExtension(observable=None, type='x-custom-observable-ext', properties=None): def CustomExtension(type='x-custom-observable-ext', properties=None):
"""Decorator for custom extensions to STIX Cyber Observables. """Decorator for custom extensions to STIX Cyber Observables.
""" """
def wrapper(cls): def wrapper(cls):
return _custom_extension_builder(cls, observable, type, properties, '2.0', _Extension) return _custom_extension_builder(cls, type, properties, '2.0', _Extension)
return wrapper return wrapper

View File

@ -216,7 +216,7 @@ class ObservedData(_DomainObject):
('first_observed', TimestampProperty(required=True)), ('first_observed', TimestampProperty(required=True)),
('last_observed', TimestampProperty(required=True)), ('last_observed', TimestampProperty(required=True)),
('number_observed', IntegerProperty(min=1, max=999999999, required=True)), ('number_observed', IntegerProperty(min=1, max=999999999, required=True)),
('objects', ObservableProperty(spec_version="2.0", required=True)), ('objects', ObservableProperty(spec_version='2.0', required=True)),
('revoked', BooleanProperty(default=lambda: False)), ('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)), ('labels', ListProperty(StringProperty)),
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),

View File

@ -19,24 +19,23 @@ from .base import (
) )
from .bundle import Bundle from .bundle import Bundle
from .common import ( from .common import (
TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference, TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomExtension, CustomMarking,
GranularMarking, KillChainPhase, LanguageContent, MarkingDefinition, ExtensionDefinition, ExternalReference, GranularMarking, KillChainPhase,
StatementMarking, TLPMarking, LanguageContent, MarkingDefinition, StatementMarking, TLPMarking,
) )
from .observables import ( from .observables import (
URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem, URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem,
CustomExtension, CustomObservable, Directory, DomainName, EmailAddress, CustomObservable, Directory, DomainName, EmailAddress, EmailMessage,
EmailMessage, EmailMIMEComponent, File, HTTPRequestExt, ICMPExt, EmailMIMEComponent, File, HTTPRequestExt, ICMPExt, IPv4Address,
IPv4Address, IPv6Address, MACAddress, Mutex, NetworkTraffic, NTFSExt, IPv6Address, MACAddress, Mutex, NetworkTraffic, NTFSExt, PDFExt, Process,
PDFExt, Process, RasterImageExt, SocketExt, Software, TCPExt, RasterImageExt, SocketExt, Software, TCPExt, UNIXAccountExt, UserAccount,
UNIXAccountExt, UserAccount, WindowsPEBinaryExt, WindowsPEBinaryExt, WindowsPEOptionalHeaderType, WindowsPESection,
WindowsPEOptionalHeaderType, WindowsPESection, WindowsProcessExt, WindowsProcessExt, WindowsRegistryKey, WindowsRegistryValueType,
WindowsRegistryKey, WindowsRegistryValueType, WindowsServiceExt, WindowsServiceExt, X509Certificate, X509V3ExtensionsType,
X509Certificate, X509V3ExtensionsType,
) )
from .sdo import ( from .sdo import (
AttackPattern, Campaign, CourseOfAction, CustomObject, Grouping, Identity, AttackPattern, Campaign, CourseOfAction, CustomObject, Grouping, Identity,
Indicator, Infrastructure, IntrusionSet, Location, Malware, Incident, Indicator, Infrastructure, IntrusionSet, Location, Malware,
MalwareAnalysis, Note, ObservedData, Opinion, Report, ThreatActor, Tool, MalwareAnalysis, Note, ObservedData, Opinion, Report, ThreatActor, Tool,
Vulnerability, Vulnerability,
) )
@ -49,6 +48,7 @@ OBJ_MAP = {
'course-of-action': CourseOfAction, 'course-of-action': CourseOfAction,
'grouping': Grouping, 'grouping': Grouping,
'identity': Identity, 'identity': Identity,
'incident': Incident,
'indicator': Indicator, 'indicator': Indicator,
'infrastructure': Infrastructure, 'infrastructure': Infrastructure,
'intrusion-set': IntrusionSet, 'intrusion-set': IntrusionSet,
@ -65,6 +65,7 @@ OBJ_MAP = {
'threat-actor': ThreatActor, 'threat-actor': ThreatActor,
'tool': Tool, 'tool': Tool,
'sighting': Sighting, 'sighting': Sighting,
'extension-definition': ExtensionDefinition,
'vulnerability': Vulnerability, 'vulnerability': Vulnerability,
} }
@ -90,38 +91,29 @@ OBJ_MAP_OBSERVABLE = {
} }
EXT_MAP = { EXT_MAP = {
'file': { 'archive-ext': ArchiveExt,
'archive-ext': ArchiveExt, 'ntfs-ext': NTFSExt,
'ntfs-ext': NTFSExt, 'pdf-ext': PDFExt,
'pdf-ext': PDFExt, 'raster-image-ext': RasterImageExt,
'raster-image-ext': RasterImageExt, 'windows-pebinary-ext': WindowsPEBinaryExt,
'windows-pebinary-ext': WindowsPEBinaryExt, 'http-request-ext': HTTPRequestExt,
}, 'icmp-ext': ICMPExt,
'network-traffic': { 'socket-ext': SocketExt,
'http-request-ext': HTTPRequestExt, 'tcp-ext': TCPExt,
'icmp-ext': ICMPExt, 'windows-process-ext': WindowsProcessExt,
'socket-ext': SocketExt, 'windows-service-ext': WindowsServiceExt,
'tcp-ext': TCPExt, 'unix-account-ext': UNIXAccountExt,
},
'process': {
'windows-process-ext': WindowsProcessExt,
'windows-service-ext': WindowsServiceExt,
},
'user-account': {
'unix-account-ext': UNIXAccountExt,
},
} }
# Ensure star-imports from this module get the right symbols. "base" is a # Ensure star-imports from this module get the right symbols. "base" is a
# known problem, since there are multiple modules with that name and one can # known problem, since there are multiple modules with that name and one can
# accidentally overwrite another. # accidentally overwrite another.
__all__ = """ __all__ = """
Bundle, Bundle,
TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference, TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExtensionDefinition,
GranularMarking, KillChainPhase, LanguageContent, MarkingDefinition, ExternalReference, GranularMarking, KillChainPhase, LanguageContent,
StatementMarking, TLPMarking, MarkingDefinition, StatementMarking, TLPMarking,
URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem, URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem,
CustomExtension, CustomObservable, Directory, DomainName, EmailAddress, CustomExtension, CustomObservable, Directory, DomainName, EmailAddress,
@ -134,7 +126,7 @@ __all__ = """
X509Certificate, X509V3ExtensionsType, X509Certificate, X509V3ExtensionsType,
AttackPattern, Campaign, CourseOfAction, CustomObject, Grouping, Identity, AttackPattern, Campaign, CourseOfAction, CustomObject, Grouping, Identity,
Indicator, Infrastructure, IntrusionSet, Location, Malware, Incident, Indicator, Infrastructure, IntrusionSet, Location, Malware,
MalwareAnalysis, Note, ObservedData, Opinion, Report, ThreatActor, Tool, MalwareAnalysis, Note, ObservedData, Opinion, Report, ThreatActor, Tool,
Vulnerability, Vulnerability,

View File

@ -10,11 +10,24 @@ class _STIXBase21(_STIXBase):
class _Observable(_Observable, _STIXBase21): class _Observable(_Observable, _STIXBase21):
pass
def __init__(self, **kwargs):
super(_Observable, self).__init__(**kwargs)
if 'id' not in kwargs:
# Specific to 2.1+ observables: generate a deterministic ID
id_ = self._generate_id()
# Spec says fall back to UUIDv4 if no contributing properties were
# given. That's what already happened (the following is actually
# overwriting the default uuidv4), so nothing to do here.
if id_ is not None:
# Can't assign to self (we're immutable), so slip the ID in
# more sneakily.
self._inner["id"] = id_
class _Extension(_Extension, _STIXBase21): class _Extension(_Extension, _STIXBase21):
pass extension_type = None
class _DomainObject(_DomainObject, _STIXBase21): class _DomainObject(_DomainObject, _STIXBase21):

View File

@ -10,7 +10,7 @@ from .base import _STIXBase21
class Bundle(_STIXBase21): class Bundle(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_nuwp4rox8c7r>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_gms872kuzdmg>`__.
""" """
_type = 'bundle' _type = 'bundle'
@ -37,7 +37,7 @@ class Bundle(_STIXBase21):
def get_obj(self, obj_uuid): def get_obj(self, obj_uuid):
if "objects" in self._inner: if "objects" in self._inner:
found_objs = [elem for elem in self.objects if elem['id'] == obj_uuid] found_objs = [elem for elem in self.objects if elem['id'] == obj_uuid]
if found_objs == []: if not found_objs:
raise KeyError("'%s' does not match the id property of any of the bundle's objects" % obj_uuid) raise KeyError("'%s' does not match the id property of any of the bundle's objects" % obj_uuid)
return found_objs return found_objs
else: else:

View File

@ -2,23 +2,25 @@
from collections import OrderedDict from collections import OrderedDict
from ..custom import _custom_marking_builder from . import _Extension
from ..exceptions import InvalidValueError from ..custom import _custom_extension_builder, _custom_marking_builder
from ..exceptions import InvalidValueError, PropertyPresenceError
from ..markings import _MarkingsMixin from ..markings import _MarkingsMixin
from ..markings.utils import check_tlp_marking from ..markings.utils import check_tlp_marking
from ..properties import ( from ..properties import (
BooleanProperty, DictionaryProperty, HashesProperty, IDProperty, BooleanProperty, DictionaryProperty, EnumProperty, ExtensionsProperty,
IntegerProperty, ListProperty, Property, ReferenceProperty, HashesProperty, IDProperty, IntegerProperty, ListProperty, Property,
SelectorProperty, StringProperty, TimestampProperty, TypeProperty, ReferenceProperty, SelectorProperty, StringProperty, TimestampProperty,
TypeProperty,
) )
from ..utils import NOW, _get_dict from ..utils import NOW, _get_dict
from .base import _STIXBase21 from .base import _STIXBase21
from .vocab import HASHING_ALGORITHM from .vocab import EXTENSION_TYPE, HASHING_ALGORITHM
class ExternalReference(_STIXBase21): class ExternalReference(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_bajcvqteiard>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_72bcfr3t79jx>`__.
""" """
_properties = OrderedDict([ _properties = OrderedDict([
@ -52,7 +54,7 @@ class ExternalReference(_STIXBase21):
class KillChainPhase(_STIXBase21): class KillChainPhase(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_i4tjv75ce50h>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_i4tjv75ce50h>`__.
""" """
_properties = OrderedDict([ _properties = OrderedDict([
@ -63,7 +65,7 @@ class KillChainPhase(_STIXBase21):
class GranularMarking(_STIXBase21): class GranularMarking(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_robezi5egfdr>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_robezi5egfdr>`__.
""" """
_properties = OrderedDict([ _properties = OrderedDict([
@ -79,7 +81,7 @@ class GranularMarking(_STIXBase21):
class LanguageContent(_STIXBase21): class LanguageContent(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_nfwr8z9ax2bi>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_z9r1cwtu8jja>`__.
""" """
_type = 'language-content' _type = 'language-content'
@ -91,9 +93,9 @@ class LanguageContent(_STIXBase21):
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
('object_ref', ReferenceProperty(valid_types=["SCO", "SDO", "SRO"], spec_version='2.1', required=True)), ('object_ref', ReferenceProperty(valid_types=["SCO", "SDO", "SRO"], spec_version='2.1', required=True)),
# TODO: 'object_modified' it MUST be an exact match for the modified time of the STIX Object (SRO or SDO) being referenced. # TODO: 'object_modified' MUST be an exact match for the modified time of the STIX Object being referenced
('object_modified', TimestampProperty(precision='millisecond')), ('object_modified', TimestampProperty(precision='millisecond')),
# TODO: 'contents' https://docs.google.com/document/d/1ShNq4c3e1CkfANmD9O--mdZ5H0O_GLnjN28a_yrEaco/edit#heading=h.cfz5hcantmvx # TODO: Implement 'contents' property requirements as defined in STIX 2.1 CS02
('contents', DictionaryProperty(spec_version='2.1', required=True)), ('contents', DictionaryProperty(spec_version='2.1', required=True)),
('revoked', BooleanProperty(default=lambda: False)), ('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)), ('labels', ListProperty(StringProperty)),
@ -101,12 +103,55 @@ class LanguageContent(_STIXBase21):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
class ExtensionDefinition(_STIXBase21):
"""For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_32j232tfvtly>`__.
"""
_type = 'extension-definition'
_properties = OrderedDict([
('type', TypeProperty(_type, spec_version='2.1')),
('spec_version', StringProperty(fixed='2.1')),
('id', IDProperty(_type, spec_version='2.1')),
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1', required=True)),
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
('name', StringProperty(required=True)),
('description', StringProperty()),
('schema', StringProperty(required=True)),
('version', StringProperty(required=True)),
(
'extension_types', ListProperty(
EnumProperty(
allowed=EXTENSION_TYPE,
), required=True,
),
),
('extension_properties', ListProperty(StringProperty)),
('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)),
('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)),
])
def CustomExtension(type='x-custom-ext', properties=None):
"""Custom STIX Object Extension decorator.
"""
def wrapper(cls):
return _custom_extension_builder(cls, type, properties, '2.1', _Extension)
return wrapper
class TLPMarking(_STIXBase21): class TLPMarking(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_yd3ar14ekwrs>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_yd3ar14ekwrs>`__.
""" """
_type = 'tlp' _type = 'tlp'
@ -117,7 +162,7 @@ class TLPMarking(_STIXBase21):
class StatementMarking(_STIXBase21): class StatementMarking(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_3ru8r05saera>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_3ru8r05saera>`__.
""" """
_type = 'statement' _type = 'statement'
@ -147,26 +192,27 @@ class MarkingProperty(Property):
class MarkingDefinition(_STIXBase21, _MarkingsMixin): class MarkingDefinition(_STIXBase21, _MarkingsMixin):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_hr5vgqxjk7ns>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_k5fndj2c7c1k>`__.
""" """
_type = 'marking-definition' _type = 'marking-definition'
_properties = OrderedDict([ _properties = OrderedDict([
('type', TypeProperty(_type, spec_version='2.1')), ('type', TypeProperty(_type, spec_version='2.1')),
('spec_version', StringProperty(fixed='2.1')), ('spec_version', StringProperty(fixed='2.1')),
('id', IDProperty(_type)), ('id', IDProperty(_type, spec_version='2.1')),
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
('definition_type', StringProperty(required=True)), ('definition_type', StringProperty()),
('name', StringProperty()), ('name', StringProperty()),
('definition', MarkingProperty(required=True)), ('definition', MarkingProperty()),
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def __init__(self, **kwargs): def __init__(self, **kwargs):
if set(('definition_type', 'definition')).issubset(kwargs.keys()): if {'definition_type', 'definition'}.issubset(kwargs.keys()):
# Create correct marking type object # Create correct marking type object
try: try:
marking_type = OBJ_MAP_MARKING[kwargs['definition_type']] marking_type = OBJ_MAP_MARKING[kwargs['definition_type']]
@ -181,6 +227,18 @@ class MarkingDefinition(_STIXBase21, _MarkingsMixin):
def _check_object_constraints(self): def _check_object_constraints(self):
super(MarkingDefinition, self)._check_object_constraints() super(MarkingDefinition, self)._check_object_constraints()
definition = self.get("definition")
definition_type = self.get("definition_type")
extensions = self.get("extensions")
if not (definition_type and definition) and not extensions:
raise PropertyPresenceError(
"MarkingDefinition objects must have the properties "
"'definition_type' and 'definition' if 'extensions' is not present",
MarkingDefinition,
)
check_tlp_marking(self, '2.1') check_tlp_marking(self, '2.1')
def serialize(self, pretty=False, include_optional_defaults=False, **kwargs): def serialize(self, pretty=False, include_optional_defaults=False, **kwargs):
@ -194,7 +252,7 @@ OBJ_MAP_MARKING = {
} }
def CustomMarking(type='x-custom-marking', properties=None): def CustomMarking(type='x-custom-marking', properties=None, extension_name=None):
"""Custom STIX Marking decorator. """Custom STIX Marking decorator.
Example: Example:
@ -209,6 +267,16 @@ def CustomMarking(type='x-custom-marking', properties=None):
""" """
def wrapper(cls): def wrapper(cls):
if extension_name:
@CustomExtension(type=extension_name, properties=properties)
class NameExtension:
extension_type = 'property-extension'
extension = extension_name.split('--')[1]
extension = extension.replace('-', '')
NameExtension.__name__ = 'ExtensionDefinition' + extension
cls.with_extension = extension_name
return _custom_marking_builder(cls, type, MarkingDefinition._properties, '2.1', _STIXBase21)
return _custom_marking_builder(cls, type, properties, '2.1', _STIXBase21) return _custom_marking_builder(cls, type, properties, '2.1', _STIXBase21)
return wrapper return wrapper

View File

@ -8,7 +8,7 @@ _Observable and do not have a ``_type`` attribute.
from collections import OrderedDict from collections import OrderedDict
import itertools import itertools
from ..custom import _custom_extension_builder, _custom_observable_builder from ..custom import _custom_observable_builder
from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError
from ..properties import ( from ..properties import (
BinaryProperty, BooleanProperty, DictionaryProperty, BinaryProperty, BooleanProperty, DictionaryProperty,
@ -18,7 +18,7 @@ from ..properties import (
TypeProperty, TypeProperty,
) )
from .base import _Extension, _Observable, _STIXBase21 from .base import _Extension, _Observable, _STIXBase21
from .common import GranularMarking from .common import CustomExtension, GranularMarking
from .vocab import ( from .vocab import (
ACCOUNT_TYPE, ENCRYPTION_ALGORITHM, HASHING_ALGORITHM, ACCOUNT_TYPE, ENCRYPTION_ALGORITHM, HASHING_ALGORITHM,
NETWORK_SOCKET_ADDRESS_FAMILY, NETWORK_SOCKET_TYPE, NETWORK_SOCKET_ADDRESS_FAMILY, NETWORK_SOCKET_TYPE,
@ -29,7 +29,7 @@ from .vocab import (
class Artifact(_Observable): class Artifact(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_rqwyxo6gp7cv>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_4jegwl6ojbes>`__.
""" """
_type = 'artifact' _type = 'artifact'
@ -46,7 +46,7 @@ class Artifact(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["hashes", "payload_bin"] _id_contributing_properties = ["hashes", "payload_bin"]
@ -58,7 +58,7 @@ class Artifact(_Observable):
class AutonomousSystem(_Observable): class AutonomousSystem(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_bxebwa6l91fb>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_27gux0aol9e3>`__.
""" """
_type = 'autonomous-system' _type = 'autonomous-system'
@ -72,14 +72,14 @@ class AutonomousSystem(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["number"] _id_contributing_properties = ["number"]
class Directory(_Observable): class Directory(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_vhpkn06q7fvl>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_lyvpga5hlw52>`__.
""" """
_type = 'directory' _type = 'directory'
@ -97,14 +97,14 @@ class Directory(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["path"] _id_contributing_properties = ["path"]
class DomainName(_Observable): class DomainName(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_i2zf5h7vnrd9>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_prhhksbxbg87>`__.
""" """
_type = 'domain-name' _type = 'domain-name'
@ -117,14 +117,14 @@ class DomainName(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["value"] _id_contributing_properties = ["value"]
class EmailAddress(_Observable): class EmailAddress(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_am7srelb9c14>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_wmenahkvqmgj>`__.
""" """
_type = 'email-addr' _type = 'email-addr'
@ -138,19 +138,19 @@ class EmailAddress(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["value"] _id_contributing_properties = ["value"]
class EmailMIMEComponent(_STIXBase21): class EmailMIMEComponent(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_kzv52qqc0xw1>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_qpo5x7d8mefq>`__.
""" """
_properties = OrderedDict([ _properties = OrderedDict([
('body', StringProperty()), ('body', StringProperty()),
('body_raw_ref', ReferenceProperty(valid_types=['artifact', 'file'], spec_version="2.1")), ('body_raw_ref', ReferenceProperty(valid_types=['artifact', 'file'], spec_version='2.1')),
('content_type', StringProperty()), ('content_type', StringProperty()),
('content_disposition', StringProperty()), ('content_disposition', StringProperty()),
]) ])
@ -162,7 +162,7 @@ class EmailMIMEComponent(_STIXBase21):
class EmailMessage(_Observable): class EmailMessage(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_loz634bn09om>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_grboc7sq5514>`__.
""" """
_type = 'email-message' _type = 'email-message'
@ -188,7 +188,7 @@ class EmailMessage(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["from_ref", "subject", "body"] _id_contributing_properties = ["from_ref", "subject", "body"]
@ -202,19 +202,19 @@ class EmailMessage(_Observable):
class ArchiveExt(_Extension): class ArchiveExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_mm25z9wuw4tr>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_xi3g7dwaigs6>`__.
""" """
_type = 'archive-ext' _type = 'archive-ext'
_properties = OrderedDict([ _properties = OrderedDict([
('contains_refs', ListProperty(ReferenceProperty(valid_types=['file', 'directory'], spec_version="2.1"), required=True)), ('contains_refs', ListProperty(ReferenceProperty(valid_types=['file', 'directory'], spec_version='2.1'), required=True)),
('comment', StringProperty()), ('comment', StringProperty()),
]) ])
class AlternateDataStream(_STIXBase21): class AlternateDataStream(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_nbqgazg6fsma>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_8i2ts0xicqea>`__.
""" """
_properties = OrderedDict([ _properties = OrderedDict([
@ -226,7 +226,7 @@ class AlternateDataStream(_STIXBase21):
class NTFSExt(_Extension): class NTFSExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_tb77nk1g3y6f>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_o6cweepfrsci>`__.
""" """
_type = 'ntfs-ext' _type = 'ntfs-ext'
@ -238,7 +238,7 @@ class NTFSExt(_Extension):
class PDFExt(_Extension): class PDFExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_30hzxqrmkg8w>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_8xmpb2ghp9km>`__.
""" """
_type = 'pdf-ext' _type = 'pdf-ext'
@ -253,7 +253,7 @@ class PDFExt(_Extension):
class RasterImageExt(_Extension): class RasterImageExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_20mnz0u5ppxr>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_u5z7i2ox8w4x>`__.
""" """
_type = 'raster-image-ext' _type = 'raster-image-ext'
@ -267,7 +267,7 @@ class RasterImageExt(_Extension):
class WindowsPEOptionalHeaderType(_STIXBase21): class WindowsPEOptionalHeaderType(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_wyp5qdc2wugy>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_29l09w731pzc>`__.
""" """
_properties = OrderedDict([ _properties = OrderedDict([
@ -311,7 +311,7 @@ class WindowsPEOptionalHeaderType(_STIXBase21):
class WindowsPESection(_STIXBase21): class WindowsPESection(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_wiqw87xsov3t>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_ioapwyd8oimw>`__.
""" """
_properties = OrderedDict([ _properties = OrderedDict([
@ -324,7 +324,7 @@ class WindowsPESection(_STIXBase21):
class WindowsPEBinaryExt(_Extension): class WindowsPEBinaryExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_5f9bgdmj91h5>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_gg5zibddf9bs>`__.
""" """
_type = 'windows-pebinary-ext' _type = 'windows-pebinary-ext'
@ -346,7 +346,7 @@ class WindowsPEBinaryExt(_Extension):
class File(_Observable): class File(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_vq03pryd7u32>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_99bl2dibcztv>`__.
""" """
_type = 'file' _type = 'file'
@ -369,7 +369,7 @@ class File(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["hashes", "name", "parent_directory_ref", "extensions"] _id_contributing_properties = ["hashes", "name", "parent_directory_ref", "extensions"]
@ -380,7 +380,7 @@ class File(_Observable):
class IPv4Address(_Observable): class IPv4Address(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ta83c412bfsc>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_ki1ufj1ku8s0>`__.
""" """
_type = 'ipv4-addr' _type = 'ipv4-addr'
@ -394,14 +394,14 @@ class IPv4Address(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["value"] _id_contributing_properties = ["value"]
class IPv6Address(_Observable): class IPv6Address(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_f76hsv2pvwwq>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_oeggeryskriq>`__.
""" """
_type = 'ipv6-addr' _type = 'ipv6-addr'
@ -415,14 +415,14 @@ class IPv6Address(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["value"] _id_contributing_properties = ["value"]
class MACAddress(_Observable): class MACAddress(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_6lhrrdef8852>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_f92nr9plf58y>`__.
""" """
_type = 'mac-addr' _type = 'mac-addr'
@ -434,14 +434,14 @@ class MACAddress(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["value"] _id_contributing_properties = ["value"]
class Mutex(_Observable): class Mutex(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_u65ia5eoc7cv>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_84hwlkdmev1w>`__.
""" """
_type = 'mutex' _type = 'mutex'
@ -453,14 +453,14 @@ class Mutex(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["name"] _id_contributing_properties = ["name"]
class HTTPRequestExt(_Extension): class HTTPRequestExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_60k6dn28qicj>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_b0e376hgtml8>`__.
""" """
_type = 'http-request-ext' _type = 'http-request-ext'
@ -470,14 +470,13 @@ class HTTPRequestExt(_Extension):
('request_version', StringProperty()), ('request_version', StringProperty()),
('request_header', DictionaryProperty(spec_version='2.1')), ('request_header', DictionaryProperty(spec_version='2.1')),
('message_body_length', IntegerProperty()), ('message_body_length', IntegerProperty()),
('message_body_data_ref', ReferenceProperty(valid_types='artifact', spec_version="2.1")), ('message_body_data_ref', ReferenceProperty(valid_types='artifact', spec_version='2.1')),
]) ])
class ICMPExt(_Extension): class ICMPExt(_Extension):
# TODO: Add link
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_3g6wds21zwzl>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_ozypx0lmkebv>`__.
""" """
_type = 'icmp-ext' _type = 'icmp-ext'
@ -489,7 +488,7 @@ class ICMPExt(_Extension):
class SocketExt(_Extension): class SocketExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_f54f1hripxsg>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_8jamupj9ubdv>`__.
""" """
_type = 'socket-ext' _type = 'socket-ext'
@ -519,7 +518,7 @@ class SocketExt(_Extension):
class TCPExt(_Extension): class TCPExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_2z78x4m8ewcw>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_k2njqio7f142>`__.
""" """
_type = 'tcp-ext' _type = 'tcp-ext'
@ -531,7 +530,7 @@ class TCPExt(_Extension):
class NetworkTraffic(_Observable): class NetworkTraffic(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_e5nyr5squmsd>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_rgnc3w40xy>`__.
""" """
_type = 'network-traffic' _type = 'network-traffic'
@ -559,7 +558,7 @@ class NetworkTraffic(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["start", "end", "src_ref", "dst_ref", "src_port", "dst_port", "protocols", "extensions"] _id_contributing_properties = ["start", "end", "src_ref", "dst_ref", "src_port", "dst_port", "protocols", "extensions"]
@ -586,7 +585,7 @@ class NetworkTraffic(_Observable):
class WindowsProcessExt(_Extension): class WindowsProcessExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_4wfs4ve800kf>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_oyegq07gjf5t>`__.
""" """
_type = 'windows-process-ext' _type = 'windows-process-ext'
@ -603,7 +602,7 @@ class WindowsProcessExt(_Extension):
class WindowsServiceExt(_Extension): class WindowsServiceExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_s2rmoe7djlt>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_lbcvc2ahx1s0>`__.
""" """
_type = 'windows-service-ext' _type = 'windows-service-ext'
@ -613,7 +612,7 @@ class WindowsServiceExt(_Extension):
('display_name', StringProperty()), ('display_name', StringProperty()),
('group_name', StringProperty()), ('group_name', StringProperty()),
('start_type', EnumProperty(WINDOWS_SERVICE_START_TYPE)), ('start_type', EnumProperty(WINDOWS_SERVICE_START_TYPE)),
('service_dll_refs', ListProperty(ReferenceProperty(valid_types='file', spec_version="2.1"))), ('service_dll_refs', ListProperty(ReferenceProperty(valid_types='file', spec_version='2.1'))),
('service_type', EnumProperty(WINDOWS_SERVICE_TYPE)), ('service_type', EnumProperty(WINDOWS_SERVICE_TYPE)),
('service_status', EnumProperty(WINDOWS_SERVICE_STATUS)), ('service_status', EnumProperty(WINDOWS_SERVICE_STATUS)),
]) ])
@ -621,7 +620,7 @@ class WindowsServiceExt(_Extension):
class Process(_Observable): class Process(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ur7snm473t1d>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_hpppnm86a1jm>`__.
""" """
_type = 'process' _type = 'process'
@ -644,7 +643,7 @@ class Process(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = [] _id_contributing_properties = []
@ -665,7 +664,7 @@ class Process(_Observable):
class Software(_Observable): class Software(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_jru33yeokrmh>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_7rkyhtkdthok>`__.
""" """
_type = 'software' _type = 'software'
@ -682,14 +681,14 @@ class Software(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["name", "cpe", "swid", "vendor", "version"] _id_contributing_properties = ["name", "cpe", "swid", "vendor", "version"]
class URL(_Observable): class URL(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_6bsklda6vc0c>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_ah3hict2dez0>`__.
""" """
_type = 'url' _type = 'url'
@ -701,14 +700,14 @@ class URL(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["value"] _id_contributing_properties = ["value"]
class UNIXAccountExt(_Extension): class UNIXAccountExt(_Extension):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_z25gmwyz67kl>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_hodiamlggpw5>`__.
""" """
_type = 'unix-account-ext' _type = 'unix-account-ext'
@ -722,7 +721,7 @@ class UNIXAccountExt(_Extension):
class UserAccount(_Observable): class UserAccount(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_hah33g4ntxnx>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_azo70vgj1vm2>`__.
""" """
_type = 'user-account' _type = 'user-account'
@ -747,14 +746,14 @@ class UserAccount(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["account_type", "user_id", "account_login"] _id_contributing_properties = ["account_type", "user_id", "account_login"]
class WindowsRegistryValueType(_STIXBase21): class WindowsRegistryValueType(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_6jiqabgqp2hp>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_u7n4ndghs3qq>`__.
""" """
_type = 'windows-registry-value-type' _type = 'windows-registry-value-type'
@ -767,7 +766,7 @@ class WindowsRegistryValueType(_STIXBase21):
class WindowsRegistryKey(_Observable): class WindowsRegistryKey(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_bdim4of4dl37>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_luvw8wjlfo3y>`__.
""" """
_type = 'windows-registry-key' _type = 'windows-registry-key'
@ -784,14 +783,14 @@ class WindowsRegistryKey(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["key", "values"] _id_contributing_properties = ["key", "values"]
class X509V3ExtensionsType(_STIXBase21): class X509V3ExtensionsType(_STIXBase21):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_c1kt4dheb6vz>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_oudvonxzdlku>`__.
""" """
_type = 'x509-v3-extensions-type' _type = 'x509-v3-extensions-type'
@ -817,7 +816,7 @@ class X509V3ExtensionsType(_STIXBase21):
class X509Certificate(_Observable): class X509Certificate(_Observable):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_g3kniyun8ykv>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_8abcy1o5x9w1>`__.
""" """
_type = 'x509-certificate' _type = 'x509-certificate'
@ -841,7 +840,7 @@ class X509Certificate(_Observable):
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('defanged', BooleanProperty(default=lambda: False)), ('defanged', BooleanProperty(default=lambda: False)),
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)), ('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
_id_contributing_properties = ["hashes", "serial_number"] _id_contributing_properties = ["hashes", "serial_number"]
@ -858,7 +857,7 @@ class X509Certificate(_Observable):
self._check_at_least_one_property(att_list) self._check_at_least_one_property(att_list)
def CustomObservable(type='x-custom-observable', properties=None, id_contrib_props=None): def CustomObservable(type='x-custom-observable', properties=None, id_contrib_props=None, extension_name=None):
"""Custom STIX Cyber Observable Object type decorator. """Custom STIX Cyber Observable Object type decorator.
Example: Example:
@ -874,24 +873,29 @@ def CustomObservable(type='x-custom-observable', properties=None, id_contrib_pro
""" """
def wrapper(cls): def wrapper(cls):
_properties = list( _properties = list(
itertools.chain.from_iterable([ itertools.chain(
[('type', TypeProperty(type, spec_version='2.1'))], [
[('spec_version', StringProperty(fixed='2.1'))], ('type', TypeProperty(type, spec_version='2.1')),
[('id', IDProperty(type, spec_version='2.1'))], ('spec_version', StringProperty(fixed='2.1')),
('id', IDProperty(type, spec_version='2.1')),
],
properties, properties,
[('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1')))], [
[('granular_markings', ListProperty(GranularMarking))], ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
[('defanged', BooleanProperty(default=lambda: False))], ('granular_markings', ListProperty(GranularMarking)),
[('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=type))], ('defanged', BooleanProperty(default=lambda: False)),
]), ('extensions', ExtensionsProperty(spec_version='2.1')),
],
),
) )
if extension_name:
@CustomExtension(type=extension_name, properties={})
class NameExtension:
extension_type = 'new-sco'
extension = extension_name.split('--')[1]
extension = extension.replace('-', '')
NameExtension.__name__ = 'ExtensionDefinition' + extension
cls.with_extension = extension_name
return _custom_observable_builder(cls, type, _properties, '2.1', _Observable, id_contrib_props) return _custom_observable_builder(cls, type, _properties, '2.1', _Observable, id_contrib_props)
return wrapper return wrapper
def CustomExtension(observable=None, type='x-custom-observable-ext', properties=None):
"""Decorator for custom extensions to STIX Cyber Observables.
"""
def wrapper(cls):
return _custom_extension_builder(cls, observable, type, properties, '2.1', _Extension)
return wrapper

View File

@ -1,7 +1,6 @@
"""STIX 2.1 Domain Objects.""" """STIX 2.1 Domain Objects."""
from collections import OrderedDict from collections import OrderedDict
import itertools
from urllib.parse import quote_plus from urllib.parse import quote_plus
import warnings import warnings
@ -12,13 +11,16 @@ from ..exceptions import (
InvalidValueError, PropertyPresenceError, STIXDeprecationWarning, InvalidValueError, PropertyPresenceError, STIXDeprecationWarning,
) )
from ..properties import ( from ..properties import (
BooleanProperty, EnumProperty, FloatProperty, IDProperty, IntegerProperty, BooleanProperty, EnumProperty, ExtensionsProperty, FloatProperty,
ListProperty, ObservableProperty, OpenVocabProperty, PatternProperty, IDProperty, IntegerProperty, ListProperty, ObservableProperty,
ReferenceProperty, StringProperty, TimestampProperty, TypeProperty, OpenVocabProperty, PatternProperty, ReferenceProperty, StringProperty,
TimestampProperty, TypeProperty,
) )
from ..utils import NOW from ..utils import NOW
from .base import _DomainObject from .base import _DomainObject
from .common import ExternalReference, GranularMarking, KillChainPhase from .common import (
CustomExtension, ExternalReference, GranularMarking, KillChainPhase,
)
from .vocab import ( from .vocab import (
ATTACK_MOTIVATION, ATTACK_RESOURCE_LEVEL, GROUPING_CONTEXT, IDENTITY_CLASS, ATTACK_MOTIVATION, ATTACK_RESOURCE_LEVEL, GROUPING_CONTEXT, IDENTITY_CLASS,
IMPLEMENTATION_LANGUAGE, INDICATOR_TYPE, INDUSTRY_SECTOR, IMPLEMENTATION_LANGUAGE, INDICATOR_TYPE, INDUSTRY_SECTOR,
@ -31,7 +33,7 @@ from .vocab import (
class AttackPattern(_DomainObject): class AttackPattern(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_4ohsa4pay4h4>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_axjijf603msy>`__.
""" """
_type = 'attack-pattern' _type = 'attack-pattern'
@ -53,12 +55,13 @@ class AttackPattern(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
class Campaign(_DomainObject): class Campaign(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_vvysvm8mt434>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_pcpvfz4ik6d6>`__.
""" """
_type = 'campaign' _type = 'campaign'
@ -82,6 +85,7 @@ class Campaign(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -97,7 +101,7 @@ class Campaign(_DomainObject):
class CourseOfAction(_DomainObject): class CourseOfAction(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_d5yf99f0a230>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_a925mpw39txn>`__.
""" """
_type = 'course-of-action' _type = 'course-of-action'
@ -117,12 +121,13 @@ class CourseOfAction(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
class Grouping(_DomainObject): class Grouping(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_9e3uldaqqha2>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_t56pn7elv6u7>`__.
""" """
_type = 'grouping' _type = 'grouping'
@ -144,12 +149,13 @@ class Grouping(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
class Identity(_DomainObject): class Identity(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ru8fmldl2p6w>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_wh296fiwpklp>`__.
""" """
_type = 'identity' _type = 'identity'
@ -173,12 +179,40 @@ class Identity(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
])
class Incident(_DomainObject):
"""For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_sczfhw64pjxt>`__.
"""
_type = 'incident'
_properties = OrderedDict([
('type', TypeProperty(_type, spec_version='2.1')),
('spec_version', StringProperty(fixed='2.1')),
('id', IDProperty(_type, spec_version='2.1')),
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
('name', StringProperty(required=True)),
('description', StringProperty()),
('kill_chain_phases', ListProperty(KillChainPhase)),
('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()),
('lang', StringProperty()),
('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
class Indicator(_DomainObject): class Indicator(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_wfiae74706sw>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_muftrcpnf89v>`__.
""" """
_type = 'indicator' _type = 'indicator'
@ -205,6 +239,7 @@ class Indicator(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -237,7 +272,7 @@ class Indicator(_DomainObject):
class Infrastructure(_DomainObject): class Infrastructure(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_l2alfbbcmfep>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_jo3k1o6lr9>`__.
""" """
_type = 'infrastructure' _type = 'infrastructure'
@ -262,6 +297,7 @@ class Infrastructure(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -277,7 +313,7 @@ class Infrastructure(_DomainObject):
class IntrusionSet(_DomainObject): class IntrusionSet(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ticprjb32bc4>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_jo3k1o6lr9>`__.
""" """
_type = 'intrusion-set' _type = 'intrusion-set'
@ -304,6 +340,7 @@ class IntrusionSet(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -319,7 +356,7 @@ class IntrusionSet(_DomainObject):
class Location(_DomainObject): class Location(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_sqez6sri9vtz>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_th8nitr8jb4k>`__.
""" """
_type = 'location' _type = 'location'
@ -348,6 +385,7 @@ class Location(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -426,7 +464,7 @@ class Location(_DomainObject):
class Malware(_DomainObject): class Malware(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_gc4ooz6oaz7y>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_s5l7katgbp09>`__.
""" """
_type = 'malware' _type = 'malware'
@ -457,6 +495,7 @@ class Malware(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -478,7 +517,7 @@ class Malware(_DomainObject):
class MalwareAnalysis(_DomainObject): class MalwareAnalysis(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_dw67pa20zss5>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_6hdrixb3ua4j>`__.
""" """
_type = 'malware-analysis' _type = 'malware-analysis'
@ -512,6 +551,7 @@ class MalwareAnalysis(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -522,7 +562,7 @@ class MalwareAnalysis(_DomainObject):
class Note(_DomainObject): class Note(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_hr77jvcbs9jk>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_gudodcg1sbb9>`__.
""" """
_type = 'note' _type = 'note'
@ -544,12 +584,13 @@ class Note(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
class ObservedData(_DomainObject): class ObservedData(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_h1590esrzg5f>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_p49j1fwoxldc>`__.
""" """
_type = 'observed-data' _type = 'observed-data'
@ -564,7 +605,7 @@ class ObservedData(_DomainObject):
('last_observed', TimestampProperty(required=True)), ('last_observed', TimestampProperty(required=True)),
('number_observed', IntegerProperty(min=1, max=999999999, required=True)), ('number_observed', IntegerProperty(min=1, max=999999999, required=True)),
('objects', ObservableProperty(spec_version='2.1')), ('objects', ObservableProperty(spec_version='2.1')),
('object_refs', ListProperty(ReferenceProperty(valid_types=["SCO", "SRO"], spec_version="2.1"))), ('object_refs', ListProperty(ReferenceProperty(valid_types=["SCO", "SRO"], spec_version='2.1'))),
('revoked', BooleanProperty(default=lambda: False)), ('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)), ('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()), ('confidence', IntegerProperty()),
@ -572,6 +613,7 @@ class ObservedData(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -602,7 +644,7 @@ class ObservedData(_DomainObject):
class Opinion(_DomainObject): class Opinion(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_sr2hswmu5t1>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_ht1vtzfbtzda>`__.
""" """
_type = 'opinion' _type = 'opinion'
@ -624,12 +666,13 @@ class Opinion(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
class Report(_DomainObject): class Report(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_ha4fpad0r9pf>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_n8bjzg1ysgdq>`__.
""" """
_type = 'report' _type = 'report'
@ -652,12 +695,13 @@ class Report(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
class ThreatActor(_DomainObject): class ThreatActor(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_2wowmlcbkqst>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_k017w16zutw>`__.
""" """
_type = 'threat-actor' _type = 'threat-actor'
@ -688,6 +732,7 @@ class ThreatActor(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def _check_object_constraints(self): def _check_object_constraints(self):
@ -703,7 +748,7 @@ class ThreatActor(_DomainObject):
class Tool(_DomainObject): class Tool(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_m21z3a1f3lou>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_z4voa9ndw8v>`__.
""" """
_type = 'tool' _type = 'tool'
@ -727,12 +772,13 @@ class Tool(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
class Vulnerability(_DomainObject): class Vulnerability(_DomainObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_d9f0iay06wtx>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_q5ytzmajn6re>`__.
""" """
_type = 'vulnerability' _type = 'vulnerability'
@ -752,10 +798,11 @@ class Vulnerability(_DomainObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
def CustomObject(type='x-custom-type', properties=None): def CustomObject(type='x-custom-type', properties=None, extension_name=None, is_sdo=True):
"""Custom STIX Object type decorator. """Custom STIX Object type decorator.
Example: Example:
@ -785,29 +832,42 @@ def CustomObject(type='x-custom-type', properties=None):
""" """
def wrapper(cls): def wrapper(cls):
_properties = list( extension_properties = [x for x in properties if not x[0].startswith('x_')]
itertools.chain.from_iterable([ _properties = (
[ [
('type', TypeProperty(type, spec_version='2.1')), ('type', TypeProperty(type, spec_version='2.1')),
('spec_version', StringProperty(fixed='2.1')), ('spec_version', StringProperty(fixed='2.1')),
('id', IDProperty(type, spec_version='2.1')), ('id', IDProperty(type, spec_version='2.1')),
('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')), ('created_by_ref', ReferenceProperty(valid_types='identity', spec_version='2.1')),
('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')), ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond', precision_constraint='min')),
], ]
[x for x in properties if not x[0].startswith('x_')], + extension_properties
[ + [
('revoked', BooleanProperty(default=lambda: False)), ('revoked', BooleanProperty(default=lambda: False)),
('labels', ListProperty(StringProperty)), ('labels', ListProperty(StringProperty)),
('confidence', IntegerProperty()), ('confidence', IntegerProperty()),
('lang', StringProperty()), ('lang', StringProperty()),
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
], ('extensions', ExtensionsProperty(spec_version='2.1')),
sorted([x for x in properties if x[0].startswith('x_')], key=lambda x: x[0]), ]
]), + sorted((x for x in properties if x[0].startswith('x_')), key=lambda x: x[0])
) )
if extension_name:
@CustomExtension(type=extension_name, properties={})
class NameExtension:
if is_sdo:
extension_type = 'new-sdo'
else:
extension_type = 'new-sro'
extension = extension_name.split('--')[1]
extension = extension.replace('-', '')
NameExtension.__name__ = 'ExtensionDefinition' + extension
cls.with_extension = extension_name
return _custom_object_builder(cls, type, _properties, '2.1', _DomainObject) return _custom_object_builder(cls, type, _properties, '2.1', _DomainObject)
return wrapper return wrapper

View File

@ -3,8 +3,9 @@
from collections import OrderedDict from collections import OrderedDict
from ..properties import ( from ..properties import (
BooleanProperty, IDProperty, IntegerProperty, ListProperty, BooleanProperty, ExtensionsProperty, IDProperty, IntegerProperty,
ReferenceProperty, StringProperty, TimestampProperty, TypeProperty, ListProperty, ReferenceProperty, StringProperty, TimestampProperty,
TypeProperty,
) )
from ..utils import NOW from ..utils import NOW
from .base import _RelationshipObject from .base import _RelationshipObject
@ -13,7 +14,7 @@ from .common import ExternalReference, GranularMarking
class Relationship(_RelationshipObject): class Relationship(_RelationshipObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_al0fb8fcd9e7>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_e2e1szrqfoan>`__.
""" """
_invalid_source_target_types = ['bundle', 'language-content', 'marking-definition', 'relationship', 'sighting'] _invalid_source_target_types = ['bundle', 'language-content', 'marking-definition', 'relationship', 'sighting']
@ -39,6 +40,7 @@ class Relationship(_RelationshipObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
# Explicitly define the first three kwargs to make readable Relationship declarations. # Explicitly define the first three kwargs to make readable Relationship declarations.
@ -69,7 +71,7 @@ class Relationship(_RelationshipObject):
class Sighting(_RelationshipObject): class Sighting(_RelationshipObject):
"""For more detailed information on this object's properties, see """For more detailed information on this object's properties, see
`the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_7p0n81ikux8f>`__. `the STIX 2.1 specification <https://docs.oasis-open.org/cti/stix/v2.1/cs02/stix-v2.1-cs02.html#_a795guqsap3r>`__.
""" """
_type = 'sighting' _type = 'sighting'
@ -95,6 +97,7 @@ class Sighting(_RelationshipObject):
('external_references', ListProperty(ExternalReference)), ('external_references', ListProperty(ExternalReference)),
('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))), ('object_marking_refs', ListProperty(ReferenceProperty(valid_types='marking-definition', spec_version='2.1'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
('extensions', ExtensionsProperty(spec_version='2.1')),
]) ])
# Explicitly define the first kwargs to make readable Sighting declarations. # Explicitly define the first kwargs to make readable Sighting declarations.

View File

@ -87,6 +87,22 @@ ENCRYPTION_ALGORITHM = [
] ]
EXTENSION_TYPE_NEW_SDO = "new-sdo"
EXTENSION_TYPE_NEW_SCO = "new-sco"
EXTENSION_TYPE_NEW_SRO = "new-sro"
EXTENSION_TYPE_PROPERTY_EXTENSION = "property-extension"
EXTENSION_TYPE_TOPLEVEL_PROPERTY_EXTENSION = "toplevel-property-extension"
EXTENSION_TYPE = [
EXTENSION_TYPE_NEW_SDO,
EXTENSION_TYPE_NEW_SCO,
EXTENSION_TYPE_NEW_SRO,
EXTENSION_TYPE_PROPERTY_EXTENSION,
EXTENSION_TYPE_TOPLEVEL_PROPERTY_EXTENSION,
]
GROUPING_CONTEXT_SUSPICIOUS_ACTIVITY = "suspicious-activity" GROUPING_CONTEXT_SUSPICIOUS_ACTIVITY = "suspicious-activity"
GROUPING_CONTEXT_MALWARE_ANALYSIS = "malware-analysis" GROUPING_CONTEXT_MALWARE_ANALYSIS = "malware-analysis"
GROUPING_CONTEXT_UNSPECIFIED = "unspecified" GROUPING_CONTEXT_UNSPECIFIED = "unspecified"