Skip to content

JSON representation ('value' property) #210

Open

Description

@marlontaylor

The return type of the 'value' property in the to_dict() varies. ( see AddressObj:AddressObjectType example)

I suggest always returning the array, in these situations.

input.xml

<stix:STIX_Package  xmlns:example_namespace="http://example_namespace"
xmlns:cyboxCommon="http://cybox.mitre.org/common-2" 
xmlns:cybox="http://cybox.mitre.org/cybox-2"
xmlns:cyboxVocabs="http://cybox.mitre.org/default_vocabularies-2"   
xmlns:AddressObj="http://cybox.mitre.org/objects#AddressObject-2"   
xmlns:stixCommon="http://stix.mitre.org/common-1"   
xmlns:stixVocabs="http://stix.mitre.org/default_vocabularies-1" 
xmlns:stix="http://stix.mitre.org/stix-1"   
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
xsi:schemaLocation="    http://cybox.mitre.org/common-2 http://cybox.mitre.org/XMLSchema/common/2.1/cybox_common.xsd    http://cybox.mitre.org/cybox-2 http://cybox.mitre.org/XMLSchema/core/2.1/cybox_core.xsd http://cybox.mitre.org/default_vocabularies-2 http://cybox.mitre.org/XMLSchema/default_vocabularies/2.1/cybox_default_vocabularies.xsd  http://cybox.mitre.org/objects#AddressObject-2 http://cybox.mitre.org/XMLSchema/objects/Address/2.1/Address_Object.xsd  http://stix.mitre.org/common-1 http://stix.mitre.org/XMLSchema/common/1.1.1/stix_common.xsd http://stix.mitre.org/default_vocabularies-1 http://stix.mitre.org/XMLSchema/default_vocabularies/1.1.1/stix_default_vocabularies.xsd   http://stix.mitre.org/stix-1 http://stix.mitre.org/XMLSchema/core/1.1.1/stix_core.xsd" version="1.1.1">

  <stix:Observables cybox_major_version="2" cybox_minor_version="1" cybox_update_version="0">
    <cybox:Observable id="example_namespace:Observable-de76dce6-22a9-4709-9924-9eab9b7f531b">
      <cybox:Title>IPs</cybox:Title>
      <cybox:Object id="example_namespace:Object-140d93f8-7bd9-4b23-b3bf-6cc3be8d7b28">
        <cybox:Properties xsi:type="AddressObj:AddressObjectType" category="ipv4-addr">
          <AddressObj:Address_Value condition="Equals" is_case_sensitive="false" apply_condition="ANY" delimiter="##example_namespace##">1.1.1.1##example_namespace##2.2.2.2##example_namespace##3.3.3.3</AddressObj:Address_Value>
        </cybox:Properties>
      </cybox:Object>
    </cybox:Observable>
    <cybox:Observable id="example_namespace:Observable-8442aae7-0a38-4d6e-ae99-12ed42402a22">
      <cybox:Title>ip</cybox:Title>
      <cybox:Object id="example_namespace:Object-dbf87db5-fad7-4492-bf2e-b0a4b82e1d14">
        <cybox:Properties xsi:type="AddressObj:AddressObjectType" category="ipv4-addr">
          <AddressObj:Address_Value condition="Equals" is_case_sensitive="false" apply_condition="ANY" delimiter="##example_namespace##">0.0.0.0</AddressObj:Address_Value>
        </cybox:Properties>
      </cybox:Object>
    </cybox:Observable>
  </stix:Observables>

</stix:STIX_Package>

script.py

#!/usr/bin/env python
# Copyright (c) 2014, The MITRE Corporation. All rights reserved.
# See LICENSE.txt for complete terms.

'''
File: ex_01.py

Description: Round-trip example. This script takes a STIX instance document from XML to
a binding object, then to a api object and then to a dictionary. That dictionary is then
converted back into an api object, which is then used to generate an XML document.
'''

import io
from pprint import pprint

from stix.core import STIXPackage

def main():
   fn = 'input.xml'
   stix_package = STIXPackage.from_xml(fn)
   stix_dict = stix_package.to_dict() # parse to dictionary
   pprint(stix_dict)

   stix_package_two = STIXPackage.from_dict(stix_dict) # create python-stix object from dictionary
   xml = stix_package_two.to_xml() # generate xml from python-stix object
   print(xml)

if __name__ == '__main__':
   main()

output.json

{
    "observables": {
        "observables": [
            {
                "object": {
                    "id": "example_namespace:Object-140d93f8-7bd9-4b23-b3bf-6cc3be8d7b28",
                    "properties": {
                        "category": "ipv4-addr",
                        "xsi:type": "AddressObjectType",
                        "address_value": {
                            "apply_condition": "ANY",
                            "delimiter": "##example_namespace##",
                            "is_case_sensitive": false,
                            "condition": "Equals",
                            "value": [
                                "1.1.1.1",
                                "2.2.2.2",
                                "3.3.3.3"
                            ]
                        }
                    }
                },
                "id": "example_namespace:Observable-de76dce6-22a9-4709-9924-9eab9b7f531b",
                "title": "IPs"
            },
            {
                "object": {
                    "id": "example_namespace:Object-dbf87db5-fad7-4492-bf2e-b0a4b82e1d14",
                    "properties": {
                        "category": "ipv4-addr",
                        "xsi:type": "AddressObjectType",
                        "address_value": {
                            "delimiter": "##example_namespace##",
                            "is_case_sensitive": false,
                            "condition": "Equals",
                            "value": "0.0.0.0"
                        }
                    }
                },
                "id": "example_namespace:Observable-8442aae7-0a38-4d6e-ae99-12ed42402a22",
                "title": "ip"
            }
        ],
        "major_version": 2,
        "update_version": 0,
        "minor_version": 1
    },
    "version": "1.1.1"
}

Activity

  1. bworrell commented on Oct 10, 2014

    @bworrell
    Contributor

    @marlontaylor,

    The values vary because you aren't always representing a list of values. Sometimes you are passing along a single value. I understand that you are suggesting that we always use lists there, even if that list has a single value, though I'm not sure if there are undesired consequences to changing this.

    We can look into doing this on the JSON/dict side of things, but for API object instances, you can use the values property on object fields to always return a list of values (even if there is only one property value).

    Python 2.7.8 (default, Jul 28 2014, 01:34:03)
    [GCC 4.8.3] on cygwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>>
    >>> from cybox.objects.address_object import Address
    >>> a = Address()
    >>> a.address_value = "10.0.0.0"
    >>> a.address_value.value
    '10.0.0.0'
    >>> a.address_value.values
    ['10.0.0.0']
    
  2. gtback commented on Oct 15, 2014

    @gtback
    Contributor

    I think that always including a list is a bad idea, particularly for CybOX instances, which can never use a list of values. It might be alright to always use them for patterns, but it will still require applications other than python-cybox to do some conditional parsing—python-cybox already takes care of this here.

    On a related note, we probably don't need to include the delimiter in the dictionary, since we are using a native JSON list rather than a delimited string. That does mean we need to add some logic to choose a new delimiter if it was deliberately set to allow representing the literal string "##comma##". Right now it just raises a ValueError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions