"""
Plugins
=======
The following methods allow for interaction with the Tenable Security Center
:sc-api:`Plugins <Plugin.htm>` API. These items are typically seen under the
**Plugins** section of Tenable Security Center.
Methods available on ``sc.plugins``:
.. rst-class:: hide-signature
.. autoclass:: PluginAPI
:members:
"""
import json
from tenable.errors import UnexpectedValueError
from .base import SCEndpoint, SCResultsIterator
class PluginResultsIterator(SCResultsIterator):
pass
[docs]
class PluginAPI(SCEndpoint):
def _constructor(self, **kwargs):
"""
Constructs the plugin query.
"""
if 'fields' in kwargs:
kwargs['fields'] = ','.join(
[
self._check('field', f, str)
for f in self._check('fields', kwargs['fields'], list)
]
)
if 'filter' in kwargs:
# break down the filter tuple into the various query parameters
# that the plugin api expects.
self._check('filter', kwargs['filter'], tuple)
if len(kwargs['filter']) != 3:
raise UnexpectedValueError(
'the filter tuple must be name, operator, value.'
)
kwargs['filterField'] = self._check(
'filter:field', kwargs['filter'][0], str
)
kwargs['op'] = self._check(
'filter:operator',
kwargs['filter'][1],
str,
choices=['eq', 'gt', 'gte', 'like', 'lt', 'lte'],
)
kwargs['value'] = self._check('filter:value', kwargs['filter'][2], str)
del kwargs['filter']
if 'filters' in kwargs:
filters = self._check('filters', kwargs.pop('filters', []), list)
kwargs['filters'] = []
for filter in filters:
self._check('filters:filter', filter, tuple)
f = {
'filterField': self._check('filter:name', filter[0], str),
'filterOperator': self._check(
'filter:op',
filter[1],
str,
choices=['eq', 'gt', 'gte', 'like', 'lt', 'lte'],
),
'filterString': self._check('filter:value', filter[2], str),
}
kwargs['filters'].append(f)
kwargs['filters'] = json.dumps(kwargs['filters'])
if 'sort_field' in kwargs:
# convert the snake_cased variant of the parameter to the camelCased
# variant that the API expects to see.
kwargs['sortField'] = self._check('sort_field', kwargs['sort_field'], str)
del kwargs['sort_field']
if 'sort_direction' in kwargs:
# convert the snake_cased variant of the parameter to the camelCased
# variant that the API expects to see.
kwargs['sortDirection'] = self._check(
'sort_direction',
kwargs['sort_direction'],
str,
choices=['ASC', 'DESC'],
case='upper',
)
del kwargs['sort_direction']
if 'since' in kwargs:
# The since parameter should be an integer.
self._check('since', kwargs['since'], int)
if 'type' in kwargs:
# Validate that the plugin type is what's expected.
self._check(
'type',
kwargs['type'],
str,
choices=[
'active',
'all',
'compliance',
'custom',
'lce',
'notPassive',
'passive',
],
default='all',
)
# While the iterator will handle the offset & limits, a raw json result
# may be requested instead.
if 'offset' in kwargs:
kwargs['startOffset'] = self._check('offset', kwargs['offset'], int)
del kwargs['offset']
if 'limit' in kwargs:
kwargs['endOffset'] = self._check(
'limit', kwargs['limit'], int
) + kwargs.get('startOffset', 0)
del kwargs['limit']
# Pages and json_result parameters should be removed from the document
# if they exist.
if 'pages' in kwargs:
del kwargs['pages']
if 'json_result' in kwargs:
del kwargs['json_result']
# Return the modified keyword dict to the caller.
return kwargs
[docs]
def list(self, **kwargs):
"""
Retrieves the list of plugins.
:sc-api:`plugins: list <Plugin.htm#PluginRESTReference-/plugin>`
Args:
fields (list, optional):
A list of attributes to return.
filter (tuple, optional):
A filter tuple for which to filter the plugins. Filter tuples
must be ``('name', 'operator', 'value')`` and follow a similar
yet different format to the analysis filters.
filters (list[tuple], optional):
A list of filter tuples. Filters are treated as a logical ``OR``.
limit (int, optional):
How many records should be returned in each page of data. If
none is specified, the default is 1000 records.
offset (int, optional):
At what offset within the data should we start returning data.
If none is specified, the default is 0.
pages (int, optional):
How many pages of data should we return. If none is specified
then all pages will return.
sort_field (str, optional):
The field to sort the results on.
sort_direction (str, optional):
The direction in which to sort the results. Valid settings are
``asc`` and ``desc``. The default is ``asc``.
type (str, optional):
The type of plugins to return. Available types are ``active``,
``all``, ``compliance``, ``custom``, ``lce``, ``notPassive``, and
``passive``. If nothing is specified, then ``all`` is assumed.
Returns:
PluginResultsIterator: an iterator object handling data pagination.
Examples:
To retrieve all of the plugins, you'll simply need to call the list
method like so:
>>> plugins = sc.plugins.list()
>>> for plugin in plugins:
... pprint(plugin)
If you only want the plugins with java in the name, you'd run a
query similar to this one:
>>> plugins = sc.plugins.list(
... filter=('name', 'like', 'java'))
For just the active plugins, we'd run:
>>> plugins = sc.plugins.list(type='active')
"""
offset = self._check('offset', kwargs.get('offset', 0), int)
limit = self._check('limit', kwargs.get('limit', 1000), int)
pages = self._check('pages', kwargs.get('pages'), int)
json_result = kwargs.get('json_result', False)
query = self._constructor(**kwargs)
if json_result:
return self._api.get('plugin', params=query).json()['response']
return PluginResultsIterator(
self._api,
_resource='plugin',
_offset=offset,
_limit=limit,
_query=query,
_pages_total=pages,
)
[docs]
def details(self, plugin_id, fields=None):
"""
Returns the details for a specific plugin.
:sc-api:`plugins: details <Plugin.htm#PluginRESTReference-/plugin/{id}>`
Args:
plugin_id (int): The identifier for the plugin.
fields (list, optional): A list of attributes to return.
Returns:
dict: The plugin resource record.
Examples:
>>> plugin = sc.plugins.detail(19506)
>>> pprint(plugin)
"""
params = dict()
if fields:
params['fields'] = ','.join([self._check('field', f, str) for f in fields])
return self._api.get(
'plugin/{}'.format(self._check('plugin_id', plugin_id, int)), params=params
).json()['response']
[docs]
def family_list(self, **kwargs):
"""
Returns the list of plugin families.
:sc-api:`plugin-families: list <Plugin-Family.htm#PluginFamilyRESTReference-/pluginFamily>`
Args:
fields (list, optional):
A list of attributes to return.
filter (tuple, optional):
A filter tuple for which to filter the plugins. Filter tuples
must be ``('name', 'operator', 'value')`` and follow a similar
yet different format to the analysis filters.
sort_field (str, optional):
The field to sort the results on.
sort_direction (str, optional):
The direction in which to sort the results. Valid settings are
``asc`` and ``desc``. The default is ``asc``.
type (str, optional):
The type of plugins to return. Available types are ``active``,
``all``, ``compliance``, ``custom``, ``lce``, ``notPassive``, and
``passive``. If nothing is specified, then ``all`` is assumed.
Returns:
:obj:`list`:
List of plugin family records.
Examples:
>>> for fam in sc.plugins.family_list():
... pprint(fam)
"""
query = self._constructor(**kwargs)
return self._api.get('pluginFamily', params=query).json()['response']
[docs]
def family_details(self, plugin_id, fields=None):
"""
Returns the details for the specified plugin family.
:sc-api:`plugin-family: details <Plugin-Family.htm#PluginFamilyRESTReference-/pluginFamily/{id}>`
Args:
plugin_id (int): The plugin family numeric identifier.
fields (list, optional):
A list of attributes to return.
Returns:
:obj:`dict`:
The plugin family resource.
Examples:
>>> family = sc.plugins.family_details(10)
>>> pprint(family)
"""
params = dict()
if fields:
params['fields'] = ','.join([self._check('field', f, str) for f in fields])
return self._api.get(
'pluginFamily/{}'.format(self._check('plugin_id', plugin_id, int)),
params=params,
).json()['response']
[docs]
def family_plugins(self, plugin_id, **kwargs):
"""
Retrieves the plugins for the specified family.
:sc-api:`plugin-family: plugins <Plugin-Family.htm#PluginFamilyRESTReference-/pluginFamily/{id}/plugins::GET>`
Args:
plugin_id (int): The numeric identifier for the plugin family.
fields (list, optional):
A list of attributes to return.
filter (tuple, optional):
A filter tuple for which to filter the plugins. Filter tuples
must be ``('name', 'operator', 'value')`` and follow a similar
yet different format to the analysis filters.
limit (int, optional):
How many records should be returned in each page of data. If
none is specified, the default is 1000 records.
offset (int, optional):
At what offset within the data should we start returning data.
If none is specified, the default is 0.
pages (int, optional):
How many pages of data should we return. If none is specified
then all pages will return.
sort_field (str, optional):
The field to sort the results on.
sort_direction (str, optional):
The direction in which to sort the results. Valid settings are
``asc`` and ``desc``. The default is ``asc``.
type (str, optional):
The type of plugins to return. Available types are ``active``,
``all``, ``compliance``, ``custom``, ``lce``, ``notPassive``, and
``passive``. If nothing is specified, then ``all`` is assumed.
Returns:
PluginResultsIterator: an iterator object handling data pagination.
Examples:
>>> plugins = sc.plugins.family_plugins(10)
>>> for plugin in plugins:
... pprint(plugin)
"""
offset = self._check('offset', kwargs.get('offset', 0), int)
limit = self._check('limit', kwargs.get('limit', 1000), int)
pages = self._check('pages', kwargs.get('pages'), int)
json_result = kwargs.get('json_result', False)
query = self._constructor(**kwargs)
if json_result:
return self._api.get('plugin', params=query).json()['response']
return PluginResultsIterator(
self._api,
_resource='pluginFamily/{}/plugins'.format(
self._check('plugin_id', plugin_id, int)
),
_offset=offset,
_limit=limit,
_query=query,
_pages_total=pages,
)