update marking API methods to allow/use the 'lang' property

including utility methods that expand collapse markings
master
Emmanuelle Vargas-Gonzalez 2019-04-22 15:25:46 -04:00
parent f8d4669f80
commit 4bbabaecb2
3 changed files with 110 additions and 47 deletions

View File

@ -22,7 +22,7 @@ Note:
from stix2.markings import granular_markings, object_markings
def get_markings(obj, selectors=None, inherited=False, descendants=False):
def get_markings(obj, selectors=None, inherited=False, descendants=False, marking_ref=True, lang=True):
"""
Get all markings associated to the field(s) specified by selectors.
@ -30,10 +30,13 @@ def get_markings(obj, selectors=None, inherited=False, descendants=False):
obj: An SDO or SRO object.
selectors: string or list of selectors strings relative to the SDO or
SRO in which the properties appear.
inherited: If True, include object level markings and granular markings
inherited relative to the properties.
descendants: If True, include granular markings applied to any children
relative to the properties.
inherited (bool): If True, include object level markings and granular
markings inherited relative to the properties.
descendants (bool): If True, include granular markings applied to any
children relative to the properties.
marking_ref (bool): If False, excludes markings that use
``marking_ref`` property.
lang (bool): If False, excludes markings that use ``lang`` property.
Returns:
list: Marking identifiers that matched the selectors expression.
@ -51,6 +54,8 @@ def get_markings(obj, selectors=None, inherited=False, descendants=False):
selectors,
inherited,
descendants,
marking_ref,
lang
)
if inherited:
@ -59,7 +64,7 @@ def get_markings(obj, selectors=None, inherited=False, descendants=False):
return list(set(results))
def set_markings(obj, marking, selectors=None):
def set_markings(obj, marking, selectors=None, marking_ref=True, lang=True):
"""
Remove all markings associated with selectors and appends a new granular
marking. Refer to `clear_markings` and `add_markings` for details.
@ -70,6 +75,10 @@ def set_markings(obj, marking, selectors=None):
properties selected by `selectors`.
selectors: string or list of selectors strings relative to the SDO or
SRO in which the properties appear.
marking_ref (bool): If False, markings that use the ``marking_ref``
property will not be removed.
lang (bool): If False, markings that use the ``lang`` property
will not be removed.
Returns:
A new version of the given SDO or SRO with specified markings removed
@ -83,7 +92,7 @@ def set_markings(obj, marking, selectors=None):
if selectors is None:
return object_markings.set_markings(obj, marking)
else:
return granular_markings.set_markings(obj, marking, selectors)
return granular_markings.set_markings(obj, marking, selectors, marking_ref, lang)
def remove_markings(obj, marking, selectors=None):
@ -144,7 +153,7 @@ def add_markings(obj, marking, selectors=None):
return granular_markings.add_markings(obj, marking, selectors)
def clear_markings(obj, selectors=None):
def clear_markings(obj, selectors=None, marking_ref=True, lang=True):
"""
Remove all markings associated with the selectors.
@ -152,6 +161,10 @@ def clear_markings(obj, selectors=None):
obj: An SDO or SRO object.
selectors: string or list of selectors strings relative to the SDO or
SRO in which the field(s) appear(s).
marking_ref (bool): If False, markings that use the ``marking_ref``
property will not be removed.
lang (bool): If False, markings that use the ``lang`` property
will not be removed.
Raises:
InvalidSelectorError: If `selectors` fail validation.
@ -169,7 +182,7 @@ def clear_markings(obj, selectors=None):
if selectors is None:
return object_markings.clear_markings(obj)
else:
return granular_markings.clear_markings(obj, selectors)
return granular_markings.clear_markings(obj, selectors, marking_ref, lang)
def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=False):
@ -182,10 +195,11 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa
properties selected by `selectors`.
selectors: string or list of selectors strings relative to the SDO or
SRO in which the field(s) appear(s).
inherited: If True, include object level markings and granular markings
inherited to determine if the properties is/are marked.
descendants: If True, include granular markings applied to any children
of the given selector to determine if the properties is/are marked.
inherited (bool): If True, include object level markings and granular
markings inherited to determine if the properties is/are marked.
descendants (bool): If True, include granular markings applied to any
children of the given selector to determine if the properties
is/are marked.
Returns:
bool: True if ``selectors`` is found on internal SDO or SRO collection.
@ -228,7 +242,7 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa
return result
class _MarkingsMixin():
class _MarkingsMixin(object):
pass

View File

@ -2,10 +2,10 @@
from stix2 import exceptions
from stix2.markings import utils
from stix2.utils import new_version
from stix2.utils import new_version, is_marking
def get_markings(obj, selectors, inherited=False, descendants=False):
def get_markings(obj, selectors, inherited=False, descendants=False, marking_ref=True, lang=True):
"""
Get all granular markings associated to with the properties.
@ -13,10 +13,13 @@ def get_markings(obj, selectors, inherited=False, descendants=False):
obj: An SDO or SRO object.
selectors: string or list of selector strings relative to the SDO or
SRO in which the properties appear.
inherited: If True, include markings inherited relative to the
inherited (bool): If True, include markings inherited relative to the
properties.
descendants: If True, include granular markings applied to any children
relative to the properties.
descendants (bool): If True, include granular markings applied to any
children relative to the properties.
marking_ref (bool): If False, excludes markings that use
``marking_ref`` property.
lang (bool): If False, excludes markings that use ``lang`` property.
Raises:
InvalidSelectorError: If `selectors` fail validation.
@ -43,13 +46,18 @@ def get_markings(obj, selectors, inherited=False, descendants=False):
(user_selector.startswith(marking_selector) and inherited), # Catch inherited selectors.
(marking_selector.startswith(user_selector) and descendants),
]): # Catch descendants selectors
refs = marking.get('marking_ref', [])
results.update([refs])
ref = marking.get('marking_ref')
lng = marking.get('lang')
if ref and marking_ref:
results.add(ref)
if lng and lang:
results.add(lng)
return list(results)
def set_markings(obj, marking, selectors):
def set_markings(obj, marking, selectors, marking_ref=True, lang=True):
"""
Remove all granular markings associated with selectors and append a new
granular marking. Refer to `clear_markings` and `add_markings` for details.
@ -60,19 +68,25 @@ def set_markings(obj, marking, selectors):
SRO in which the properties appear.
marking: identifier or list of marking identifiers that apply to the
properties selected by `selectors`.
marking_ref (bool): If False, markings that use the ``marking_ref``
property will not be removed.
lang (bool): If False, markings that use the ``lang`` property
will not be removed.
Returns:
A new version of the given SDO or SRO with specified markings removed
and new ones added.
"""
obj = clear_markings(obj, selectors)
obj = clear_markings(obj, selectors, marking_ref, lang)
return add_markings(obj, marking, selectors)
def remove_markings(obj, marking, selectors):
"""
Remove a granular marking from the granular_markings collection.
Remove a granular marking from the granular_markings collection. The method
makes a best-effort attempt to distinguish between a marking-definition
or language granular marking.
Args:
obj: An SDO or SRO object.
@ -103,7 +117,10 @@ def remove_markings(obj, marking, selectors):
to_remove = []
for m in marking:
to_remove.append({'marking_ref': m, 'selectors': selectors})
if is_marking(m):
to_remove.append({'marking_ref': m, 'selectors': selectors})
else:
to_remove.append({'lang': m, 'selectors': selectors})
remove = utils.build_granular_marking(to_remove).get('granular_markings')
@ -124,7 +141,9 @@ def remove_markings(obj, marking, selectors):
def add_markings(obj, marking, selectors):
"""
Append a granular marking to the granular_markings collection.
Append a granular marking to the granular_markings collection. The method
makes a best-effort attempt to distinguish between a marking-definition
or language granular marking.
Args:
obj: An SDO or SRO object.
@ -146,7 +165,10 @@ def add_markings(obj, marking, selectors):
granular_marking = []
for m in marking:
granular_marking.append({'marking_ref': m, 'selectors': sorted(selectors)})
if is_marking(m):
granular_marking.append({'marking_ref': m, 'selectors': sorted(selectors)})
else:
granular_marking.append({'lang': m, 'selectors': sorted(selectors)})
if obj.get('granular_markings'):
granular_marking.extend(obj.get('granular_markings'))
@ -156,7 +178,7 @@ def add_markings(obj, marking, selectors):
return new_version(obj, granular_markings=granular_marking, allow_custom=True)
def clear_markings(obj, selectors):
def clear_markings(obj, selectors, marking_ref=True, lang=True):
"""
Remove all granular markings associated with the selectors.
@ -164,6 +186,10 @@ def clear_markings(obj, selectors):
obj: An SDO or SRO object.
selectors: string or list of selectors strings relative to the SDO or
SRO in which the properties appear.
marking_ref (bool): If False, markings that use the ``marking_ref``
property will not be removed.
lang (bool): If False, markings that use the ``lang`` property
will not be removed.
Raises:
InvalidSelectorError: If `selectors` fail validation.
@ -184,11 +210,12 @@ def clear_markings(obj, selectors):
granular_markings = utils.expand_markings(granular_markings)
sdo = utils.build_granular_marking(
[{'selectors': selectors, 'marking_ref': 'N/A'}],
)
granular_dict = utils.build_granular_marking([
{'selectors': selectors, 'marking_ref': 'N/A'},
{'selectors': selectors, 'lang': 'N/A'}
])
clear = sdo.get('granular_markings', [])
clear = granular_dict.get('granular_markings', [])
if not any(
clear_selector in sdo_selectors.get('selectors', [])
@ -201,10 +228,13 @@ def clear_markings(obj, selectors):
for granular_marking in granular_markings:
for s in selectors:
if s in granular_marking.get('selectors', []):
marking_refs = granular_marking.get('marking_ref')
ref = granular_marking.get('marking_ref')
lng = granular_marking.get('lang')
if marking_refs:
if ref and marking_ref:
granular_marking['marking_ref'] = ''
if lng and lang:
granular_marking['lang'] = ''
granular_markings = utils.compress_markings(granular_markings)
@ -222,11 +252,12 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa
obj: An SDO or SRO object.
marking: identifier or list of marking identifiers that apply to the
properties selected by `selectors`.
selectors: string or list of selectors strings relative to the SDO or
SRO in which the properties appear.
inherited: If True, return markings inherited from the given selector.
descendants: If True, return granular markings applied to any children
of the given selector.
selectors (bool): string or list of selectors strings relative to the
SDO or SRO in which the properties appear.
inherited (bool): If True, return markings inherited from the given
selector.
descendants (bool): If True, return granular markings applied to any
children of the given selector.
Raises:
InvalidSelectorError: If `selectors` fail validation.
@ -262,9 +293,12 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa
(marking_selector.startswith(user_selector) and descendants),
]): # Catch descendants selectors
marking_ref = granular_marking.get('marking_ref', '')
lang = granular_marking.get('lang', '')
if marking and any(x == marking_ref for x in marking):
markings.update([marking_ref])
if marking and any(x == lang for x in marking):
markings.update([lang])
marked = True

View File

@ -5,6 +5,7 @@ import collections
import six
from stix2 import exceptions
from stix2.utils import is_marking
def _evaluate_expression(obj, selector):
@ -121,10 +122,15 @@ def compress_markings(granular_markings):
if granular_marking.get('marking_ref'):
map_[granular_marking.get('marking_ref')].update(granular_marking.get('selectors'))
if granular_marking.get('lang'):
map_[granular_marking.get('lang')].update(granular_marking.get('selectors'))
compressed = \
[
{'marking_ref': marking_ref, 'selectors': sorted(selectors)}
for marking_ref, selectors in six.iteritems(map_)
{'marking_ref': item, 'selectors': sorted(selectors)}
if is_marking(item) else
{'lang': item, 'selectors': sorted(selectors)}
for item, selectors in six.iteritems(map_)
]
return compressed
@ -174,13 +180,22 @@ def expand_markings(granular_markings):
for marking in granular_markings:
selectors = marking.get('selectors')
marking_ref = marking.get('marking_ref')
lang = marking.get('lang')
expanded.extend(
[
{'marking_ref': marking_ref, 'selectors': [selector]}
for selector in selectors
],
)
if marking_ref:
expanded.extend(
[
{'marking_ref': marking_ref, 'selectors': [selector]}
for selector in selectors
],
)
if lang:
expanded.extend(
[
{'lang': lang, 'selectors': [selector]}
for selector in selectors
],
)
return expanded