Skip to content

Commit

Permalink
Merge pull request #35 from passivetotal/context-headers
Browse files Browse the repository at this point in the history
Send new request headers for metrics and troubleshooting.
  • Loading branch information
aeetos authored Jul 15, 2021
2 parents 9cb234c + cad4374 commit 384f0c7
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 11 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## v2.5.2

#### Enhancements

- Send new request headers for metrics and troubleshooting with the `set_context`
method on the `analyzer` module and within the core API request libs.
- Abstract package version into a distinct file to consolidate updates and ensure
consistency across docs and pypi. Add `get_version` method to `analyzer` module
for easy access to the current version number.


#### Bug Fixes




## v2.5.1

#### Enhancements
Expand Down
15 changes: 7 additions & 8 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import sys
import os
import re

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
Expand Down Expand Up @@ -55,14 +56,12 @@
copyright = u'2021, RiskIQ'
author = u'RiskIQ'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2.5'
# The full version, including alpha/beta/rc tags.
release = '2.5.1'
# pylint: disable=locally-disabled, invalid-name
with open('../passivetotal/_version.py', 'r') as fd:
v_match = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE)
release = v_match.group(1)
version = '.'.join(release.split('.')[0:-1])
# pylint: enable=locally-disabled, invalid-name

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
1 change: 1 addition & 0 deletions passivetotal/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VERSION="2.5.2"
20 changes: 20 additions & 0 deletions passivetotal/analyzer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from collections import namedtuple
from datetime import datetime, timezone, timedelta
from passivetotal import *
from passivetotal._version import VERSION
from passivetotal.api import Context
from passivetotal.analyzer._common import AnalyzerError, AnalyzerAPIError, is_ip

DEFAULT_DAYS_BACK = 90
Expand Down Expand Up @@ -56,6 +58,7 @@ def init(**kwargs):
else:
api_clients[name] = c.from_config()
api_clients[name].exception_class = AnalyzerAPIError
api_clients[name].set_context('python','passivetotal',VERSION,'analyzer')
config['is_ready'] = True

def get_api(name):
Expand Down Expand Up @@ -91,6 +94,23 @@ def get_object(input, type=None):
raise AnalyzerError('type must be IPAddress or Hostname')
return objs[type](input)

def get_version():
"""Get the current version of this package."""
return VERSION

def set_context(provider, variant, version, feature=''):
"""Define the application context for an implementation using the analyzer module.
Sets a header to be sent in API requests that is used for metrics and troubleshooting.
:param provider: The company, partner, provider or other top-level application context.
:param variant: The specific app, libary subcomponent, or feature category.
:param version: Version of the app, feature or code setting the context.
:param feature: Optional sub-feature, dashboard or script name.
"""
for client in api_clients.values():
client.set_context(provider, variant, version, feature)

def set_date_range(days_back=DEFAULT_DAYS_BACK, start=None, start_date=None, end=None, end_date=None):
"""Set a range of dates for all date-bounded API queries.
Expand Down
48 changes: 46 additions & 2 deletions passivetotal/api.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
"""PassiveTotal API Interface."""

__author__ = 'Brandon Dixon (PassiveTotal)'
__version__ = '1.0.0'

import json
import logging
import requests
import sys
from urllib.parse import quote as urlquote
from passivetotal.config import Config
from passivetotal._version import VERSION

__author__ = 'Brandon Dixon (PassiveTotal)'
__version__ = VERSION



class Client(object):
Expand Down Expand Up @@ -58,6 +62,7 @@ def __init__(self, username, api_key, server=DEFAULT_SERVER,
if '127.0.0.1' in server:
self.verify = False
self.exception_class = exception_class
self.set_context('python','passivetotal',VERSION)

@classmethod
def from_config(cls):
Expand All @@ -78,6 +83,18 @@ def set_debug(self, status):
self.logger.setLevel('DEBUG')
else:
self.logger.setLevel('INFO')

def set_context(self, provider, variant, version, feature=''):
"""Set the context for this request.
:param provider: The company, partner, provider or other top-level application context.
:param variant: The specific app, libary subcomponent, or feature category.
:param version: Version of the app, feature or code setting the context.
:param feature: Optional sub-feature, dashboard or script name.
"""
context = Context(provider, variant, version, feature)
self.context = context
self.headers.update(context.get_header())

def _endpoint(self, endpoint, action, *url_args):
"""Return the URL for the action.
Expand Down Expand Up @@ -181,3 +198,30 @@ def _send_data(self, method, endpoint, action,
kwargs['proxies'] = self.proxies
response = requests.request(method, api_url, **kwargs)
return self._json(response)



class Context:

"""Integration context for a set of API requests."""

HEADER_NAME = 'X-RISKIQ-CONTEXT'

def __init__(self, provider, variant, version, feature = ''):
"""Build a new context header.
:param provider: The company, partner, provider or other top-level application context.
:param variant: The specific app, libary subcomponent, or feature category.
:param version: Version of the app, feature or code setting the context.
:param feature: Optional sub-feature, dashboard or script name.
"""
self._fields = (provider, variant, version, feature)

def get_header_name(self):
return self.HEADER_NAME

def get_header_value(self):
return '/'.join(map(lambda f: urlquote(f, safe=''), self._fields))

def get_header(self):
return { self.get_header_name() : self.get_header_value() }
9 changes: 8 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
#!/usr/bin/env python
import os
import re
from setuptools import setup, find_packages


def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()

# pylint: disable=locally-disabled, invalid-name
with open('passivetotal/_version.py', 'r') as fd:
v_match = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE)
__version__ = v_match.group(1) if v_match else 'no version'
# pylint: enable=locally-disabled, invalid-name

setup(
name='passivetotal',
version='2.5.1',
version=__version__,
description='Library for the RiskIQ PassiveTotal and Illuminate API',
url="https://github.com/passivetotal/python_api",
author="RiskIQ",
Expand Down

0 comments on commit 384f0c7

Please sign in to comment.