WIP - just at stash point

stix2.0
= 2018-04-11 13:36:52 -04:00
parent e92db2417a
commit 27647091a5
5 changed files with 102 additions and 66 deletions

View File

@ -16,7 +16,7 @@ import uuid
from six import with_metaclass from six import with_metaclass
from stix2.datastore.filters import Filter from stix2.datastore.filters import Filter, FilterSet
from stix2.utils import deduplicate from stix2.utils import deduplicate
@ -220,13 +220,13 @@ class DataSource(with_metaclass(ABCMeta)):
Attributes: Attributes:
id (str): A unique UUIDv4 to identify this DataSource. id (str): A unique UUIDv4 to identify this DataSource.
filters (set): A collection of filters attached to this DataSource. filters (FilterSet): A collection of filters attached to this DataSource.
""" """
def __init__(self): def __init__(self):
super(DataSource, self).__init__() super(DataSource, self).__init__()
self.id = make_id() self.id = make_id()
self.filters = set() self.filters = FilterSet()
@abstractmethod @abstractmethod
def get(self, stix_id): def get(self, stix_id):
@ -420,7 +420,7 @@ class CompositeDataSource(DataSource):
Args: Args:
stix_id (str): the id of the STIX object to retrieve. stix_id (str): the id of the STIX object to retrieve.
_composite_filters (list): a list of filters passed from a _composite_filters (FilterSet): a collection of filters passed from a
CompositeDataSource (i.e. if this CompositeDataSource is attached CompositeDataSource (i.e. if this CompositeDataSource is attached
to another parent CompositeDataSource), not user supplied. to another parent CompositeDataSource), not user supplied.
@ -432,11 +432,12 @@ class CompositeDataSource(DataSource):
raise AttributeError('CompositeDataSource has no data sources') raise AttributeError('CompositeDataSource has no data sources')
all_data = [] all_data = []
all_filters = set() all_filters = FilterSet()
all_filters.update(self.filters)
all_filters.add(self.filters)
if _composite_filters: if _composite_filters:
all_filters.update(_composite_filters) all_filters.add(_composite_filters)
# for every configured Data Source, call its retrieve handler # for every configured Data Source, call its retrieve handler
for ds in self.data_sources: for ds in self.data_sources:
@ -466,7 +467,7 @@ class CompositeDataSource(DataSource):
Args: Args:
stix_id (str): id of the STIX objects to retrieve. stix_id (str): id of the STIX objects to retrieve.
_composite_filters (list): a list of filters passed from a _composite_filters (FilterSet): a collection of filters passed from a
CompositeDataSource (i.e. if this CompositeDataSource is CompositeDataSource (i.e. if this CompositeDataSource is
attached to a parent CompositeDataSource), not user supplied. attached to a parent CompositeDataSource), not user supplied.
@ -478,12 +479,12 @@ class CompositeDataSource(DataSource):
raise AttributeError('CompositeDataSource has no data sources') raise AttributeError('CompositeDataSource has no data sources')
all_data = [] all_data = []
all_filters = set() all_filters = FilterSet()
all_filters.update(self.filters) all_filters.add(self.filters)
if _composite_filters: if _composite_filters:
all_filters.update(_composite_filters) all_filters.add(_composite_filters)
# retrieve STIX objects from all configured data sources # retrieve STIX objects from all configured data sources
for ds in self.data_sources: for ds in self.data_sources:
@ -505,7 +506,7 @@ class CompositeDataSource(DataSource):
Args: Args:
query (list): list of filters to search on. query (list): list of filters to search on.
_composite_filters (list): a list of filters passed from a _composite_filters (FilterSet): a collection of filters passed from a
CompositeDataSource (i.e. if this CompositeDataSource is CompositeDataSource (i.e. if this CompositeDataSource is
attached to a parent CompositeDataSource), not user supplied. attached to a parent CompositeDataSource), not user supplied.
@ -517,17 +518,17 @@ class CompositeDataSource(DataSource):
raise AttributeError('CompositeDataSource has no data sources') raise AttributeError('CompositeDataSource has no data sources')
if not query: if not query:
# don't mess with the query (i.e. convert to a set, as that's done # don't mess with the query (i.e. deduplicate, as that's done
# within the specific DataSources that are called) # within the specific DataSources that are called)
query = [] query = []
all_data = [] all_data = []
all_filters = FilterSet()
all_filters = set() all_filters.add(self.filters)
all_filters.update(self.filters)
if _composite_filters: if _composite_filters:
all_filters.update(_composite_filters) all_filters.add(_composite_filters)
# federate query to all attached data sources, # federate query to all attached data sources,
# pass composite filters to id # pass composite filters to id

View File

@ -8,7 +8,7 @@ import os
from stix2.core import Bundle, parse from stix2.core import Bundle, parse
from stix2.datastore import DataSink, DataSource, DataStoreMixin from stix2.datastore import DataSink, DataSource, DataStoreMixin
from stix2.datastore.filters import Filter, apply_common_filters from stix2.datastore.filters import Filter, FilterSet, apply_common_filters
from stix2.utils import deduplicate, get_class_hierarchy_names from stix2.utils import deduplicate, get_class_hierarchy_names
@ -165,7 +165,7 @@ class FileSystemSource(DataSource):
Args: Args:
stix_id (str): The STIX ID of the STIX object to be retrieved. stix_id (str): The STIX ID of the STIX object to be retrieved.
_composite_filters (set): set of filters passed from the parent _composite_filters (FilterSet): collection of filters passed from the parent
CompositeDataSource, not user supplied CompositeDataSource, not user supplied
version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If
None, use latest version. None, use latest version.
@ -195,7 +195,7 @@ class FileSystemSource(DataSource):
Args: Args:
stix_id (str): The STIX ID of the STIX objects to be retrieved. stix_id (str): The STIX ID of the STIX objects to be retrieved.
_composite_filters (set): set of filters passed from the parent _composite_filters (FilterSet): collection of filters passed from the parent
CompositeDataSource, not user supplied CompositeDataSource, not user supplied
version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If
None, use latest version. None, use latest version.
@ -217,7 +217,7 @@ class FileSystemSource(DataSource):
Args: Args:
query (list): list of filters to search on query (list): list of filters to search on
_composite_filters (set): set of filters passed from the _composite_filters (FilterSet): collection of filters passed from the
CompositeDataSource, not user supplied CompositeDataSource, not user supplied
version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If
None, use latest version. None, use latest version.
@ -231,20 +231,13 @@ class FileSystemSource(DataSource):
all_data = [] all_data = []
if query is None: query = FilterSet(query)
query = set()
else:
if not isinstance(query, list):
# make sure dont make set from a Filter object,
# need to make a set from a list of Filter objects (even if just one Filter)
query = [query]
query = set(query)
# combine all query filters # combine all query filters
if self.filters: if self.filters:
query.update(self.filters) query.add(self.filters)
if _composite_filters: if _composite_filters:
query.update(_composite_filters) query.add(_composite_filters)
# extract any filters that are for "type" or "id" , as we can then do # extract any filters that are for "type" or "id" , as we can then do
# filtering before reading in the STIX objects. A STIX 'type' filter # filtering before reading in the STIX objects. A STIX 'type' filter
@ -343,8 +336,8 @@ class FileSystemSource(DataSource):
search space of a FileSystemStore (or FileSystemSink). search space of a FileSystemStore (or FileSystemSink).
""" """
file_filters = set() file_filters = []
for filter_ in query: for filter_ in query:
if filter_.property == "id" or filter_.property == "type": if filter_.property == "id" or filter_.property == "type":
file_filters.add(filter_) file_filters.append(filter_)
return file_filters return file_filters

View File

@ -17,6 +17,23 @@ except NameError:
pass pass
def deduplicate_filters(filters):
"""utility for deduplicating list of filters, this
is used when 'set()' cannot be used as one of the
filter values is a dict (or non-hashable type)
Args:
filters (list): a list of filters
Returns: list of unique filters
"""
unique_filters = []
for filter_ in filters:
if filter_ not in unique_filters:
unique_filters.append(filter_)
return unique_filters
def _check_filter_components(prop, op, value): def _check_filter_components(prop, op, value):
"""Check that filter meets minimum validity. """Check that filter meets minimum validity.
@ -168,3 +185,39 @@ def _check_filter(filter_, stix_obj):
else: else:
# Check if property matches # Check if property matches
return filter_._check_property(stix_obj[prop]) return filter_._check_property(stix_obj[prop])
class FilterSet(object):
""" """
def __init__(self, filters=None):
""" """
self._filters = []
if filters:
self.add(filters)
def __iter__(self):
""" """
for f in self._filters:
yield f
def add(self, filters):
""" """
if not isinstance(filters, FilterSet) and not isinstance(filters, list):
filters = [filters]
for f in filters:
if f not in self._filters:
self._filters.append(f)
return
def remove(self, filters):
""" """
if not isinstance(filters, FilterSet) and not isinstance(filters, list):
filters = [filters]
for f in filters:
self._filters.remove(f)
return

View File

@ -18,7 +18,7 @@ import os
from stix2.base import _STIXBase from stix2.base import _STIXBase
from stix2.core import Bundle, parse from stix2.core import Bundle, parse
from stix2.datastore import DataSink, DataSource, DataStoreMixin from stix2.datastore import DataSink, DataSource, DataStoreMixin
from stix2.datastore.filters import Filter, apply_common_filters from stix2.datastore.filters import Filter, FilterSet, apply_common_filters
def _add(store, stix_data=None, version=None): def _add(store, stix_data=None, version=None):
@ -197,7 +197,7 @@ class MemorySource(DataSource):
Args: Args:
stix_id (str): The STIX ID of the STIX object to be retrieved. stix_id (str): The STIX ID of the STIX object to be retrieved.
_composite_filters (set): set of filters passed from the parent _composite_filters (FilterSet): collection of filters passed from the parent
CompositeDataSource, not user supplied CompositeDataSource, not user supplied
Returns: Returns:
@ -236,7 +236,7 @@ class MemorySource(DataSource):
Args: Args:
stix_id (str): The STIX ID of the STIX 2 object to retrieve. stix_id (str): The STIX ID of the STIX 2 object to retrieve.
_composite_filters (set): set of filters passed from the parent _composite_filters (FilterSet): collection of filters passed from the parent
CompositeDataSource, not user supplied CompositeDataSource, not user supplied
Returns: Returns:
@ -258,7 +258,7 @@ class MemorySource(DataSource):
Args: Args:
query (list): list of filters to search on query (list): list of filters to search on
_composite_filters (set): set of filters passed from the _composite_filters (FilterSet): collection of filters passed from the
CompositeDataSource, not user supplied CompositeDataSource, not user supplied
Returns: Returns:
@ -269,19 +269,15 @@ class MemorySource(DataSource):
""" """
if query is None: if query is None:
query = set() query = FilterSet()
else: else:
if not isinstance(query, list): query = FilterSet(query)
# make sure don't make set from a Filter object,
# need to make a set from a list of Filter objects (even if just one Filter)
query = [query]
query = set(query)
# combine all query filters # combine all query filters
if self.filters: if self.filters:
query.update(self.filters) query.add(self.filters)
if _composite_filters: if _composite_filters:
query.update(_composite_filters) query.add(_composite_filters)
# Apply STIX common property filters. # Apply STIX common property filters.
all_data = list(apply_common_filters(self._data.values(), query)) all_data = list(apply_common_filters(self._data.values(), query))

View File

@ -6,7 +6,7 @@ from requests.exceptions import HTTPError
from stix2.base import _STIXBase from stix2.base import _STIXBase
from stix2.core import Bundle, parse from stix2.core import Bundle, parse
from stix2.datastore import DataSink, DataSource, DataStoreMixin from stix2.datastore import DataSink, DataSource, DataStoreMixin
from stix2.datastore.filters import Filter, apply_common_filters from stix2.datastore.filters import Filter, FilterSet, apply_common_filters
from stix2.utils import deduplicate from stix2.utils import deduplicate
TAXII_FILTERS = ['added_after', 'id', 'type', 'version'] TAXII_FILTERS = ['added_after', 'id', 'type', 'version']
@ -120,7 +120,7 @@ class TAXIICollectionSource(DataSource):
Args: Args:
stix_id (str): The STIX ID of the STIX object to be retrieved. stix_id (str): The STIX ID of the STIX object to be retrieved.
_composite_filters (set): set of filters passed from the parent _composite_filters (FilterSet): collection of filters passed from the parent
CompositeDataSource, not user supplied CompositeDataSource, not user supplied
version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If
None, use latest version. None, use latest version.
@ -132,11 +132,12 @@ class TAXIICollectionSource(DataSource):
""" """
# combine all query filters # combine all query filters
query = set() query = FilterSet()
if self.filters: if self.filters:
query.update(self.filters) query.add(self.filters)
if _composite_filters: if _composite_filters:
query.update(_composite_filters) query.add(_composite_filters)
# dont extract TAXII filters from query (to send to TAXII endpoint) # dont extract TAXII filters from query (to send to TAXII endpoint)
# as directly retrieveing a STIX object by ID # as directly retrieveing a STIX object by ID
@ -164,7 +165,7 @@ class TAXIICollectionSource(DataSource):
Args: Args:
stix_id (str): The STIX ID of the STIX objects to be retrieved. stix_id (str): The STIX ID of the STIX objects to be retrieved.
_composite_filters (set): set of filters passed from the parent _composite_filters (FilterSet): collection of filters passed from the parent
CompositeDataSource, not user supplied CompositeDataSource, not user supplied
version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If
None, use latest version. None, use latest version.
@ -198,7 +199,7 @@ class TAXIICollectionSource(DataSource):
Args: Args:
query (list): list of filters to search on query (list): list of filters to search on
_composite_filters (set): set of filters passed from the _composite_filters (FilterSet): collection of filters passed from the
CompositeDataSource, not user supplied CompositeDataSource, not user supplied
version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If version (str): Which STIX2 version to use. (e.g. "2.0", "2.1"). If
None, use latest version. None, use latest version.
@ -209,20 +210,13 @@ class TAXIICollectionSource(DataSource):
parsed into python STIX objects and then returned. parsed into python STIX objects and then returned.
""" """
if query is None: query = FilterSet(query)
query = set()
else:
if not isinstance(query, list):
# make sure dont make set from a Filter object,
# need to make a set from a list of Filter objects (even if just one Filter)
query = [query]
query = set(query)
# combine all query filters # combine all query filters
if self.filters: if self.filters:
query.update(self.filters) query.add(self.filters)
if _composite_filters: if _composite_filters:
query.update(_composite_filters) query.add(_composite_filters)
# parse taxii query params (that can be applied remotely) # parse taxii query params (that can be applied remotely)
taxii_filters = self._parse_taxii_filters(query) taxii_filters = self._parse_taxii_filters(query)
@ -268,17 +262,16 @@ class TAXIICollectionSource(DataSource):
Args: Args:
query (set): set of filters to extract which ones are TAXII query (list): list of filters to extract which ones are TAXII
specific. specific.
Returns: Returns: a list of the TAXII filters
taxii_filters (set): set of the TAXII filters
""" """
taxii_filters = set() taxii_filters = []
for filter_ in query: for filter_ in query:
if filter_.property in TAXII_FILTERS: if filter_.property in TAXII_FILTERS:
taxii_filters.add(filter_) taxii_filters.append(filter_)
return taxii_filters return taxii_filters