Hello community,

here is the log from the commit of package python-shodan for openSUSE:Factory 
checked in at 2018-09-04 22:54:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-shodan (Old)
 and      /work/SRC/openSUSE:Factory/.python-shodan.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-shodan"

Tue Sep  4 22:54:19 2018 rev:4 rq:628028 version:1.9.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-shodan/python-shodan.changes      
2018-06-29 22:27:15.966444336 +0200
+++ /work/SRC/openSUSE:Factory/.python-shodan.new/python-shodan.changes 
2018-09-04 22:55:03.352772436 +0200
@@ -1,0 +2,8 @@
+Wed Aug  1 08:24:12 UTC 2018 - [email protected]
+
+- update to version 1.9.0:
+ * New optional parameter proxies for all interfaces to specify a proxy array 
for the requests library (#72)
+- update to version 1.8.1:
+ * Fixed bug that prevented shodan scan submit from finishing (#70)
+
+-------------------------------------------------------------------

Old:
----
  shodan-1.8.0.tar.gz

New:
----
  shodan-1.9.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-shodan.spec ++++++
--- /var/tmp/diff_new_pack.erBpgU/_old  2018-09-04 22:55:03.696773612 +0200
+++ /var/tmp/diff_new_pack.erBpgU/_new  2018-09-04 22:55:03.700773626 +0200
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %{!?license: %global license %doc}
 Name:           python-shodan
-Version:        1.8.0
+Version:        1.9.0
 Release:        0
 Summary:        Python library and command-line utility for Shodan
 License:        MIT
@@ -38,7 +38,6 @@
 Requires:       python-requests >= 2.2.1
 Recommends:     python-curses
 Suggests:       %{name}-doc
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildArch:      noarch
 
 %python_subpackages

++++++ shodan-1.8.0.tar.gz -> shodan-1.9.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/LICENSE new/shodan-1.9.0/LICENSE
--- old/shodan-1.8.0/LICENSE    2014-10-05 01:45:40.000000000 +0200
+++ new/shodan-1.9.0/LICENSE    2018-05-31 23:52:28.000000000 +0200
@@ -1,4 +1,4 @@
-Copyright (c) 2014 John Matherly <[email protected]>
+Copyright (c) 2014- John Matherly <[email protected]>
 
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/PKG-INFO new/shodan-1.9.0/PKG-INFO
--- old/shodan-1.8.0/PKG-INFO   2018-05-29 12:28:02.000000000 +0200
+++ new/shodan-1.9.0/PKG-INFO   2018-08-01 08:26:35.000000000 +0200
@@ -1,16 +1,92 @@
 Metadata-Version: 1.1
 Name: shodan
-Version: 1.8.0
+Version: 1.9.0
 Summary: Python library and command-line utility for Shodan 
(https://developer.shodan.io)
 Home-page: http://github.com/achillean/shodan-python/tree/master
 Author: John Matherly
 Author-email: [email protected]
 License: UNKNOWN
-Description: UNKNOWN
+Description: shodan: The official Python library for accessing Shodan
+        ========================================================
+        
+        .. image:: https://img.shields.io/pypi/v/shodan.svg
+            :target: https://pypi.org/project/shodan/
+        
+        .. image:: 
https://img.shields.io/github/contributors/achillean/shodan-python.svg
+            :target: 
https://github.com/achillean/shodan-python/graphs/contributors
+        
+        Shodan is a search engine for Internet-connected devices. Google lets 
you search for websites,
+        Shodan lets you search for devices. This library provides developers 
easy access to all of the
+        data stored in Shodan in order to automate tasks and integrate into 
existing tools.
+        
+        Features
+        --------
+        
+        - Search Shodan
+        - `Fast/ bulk IP lookups 
<https://help.shodan.io/developer-fundamentals/looking-up-ip-info>`_
+        - Streaming API support for real-time consumption of Shodan firehose
+        - `Network alerts (aka private firehose) 
<https://help.shodan.io/guides/how-to-monitor-network>`_
+        - Exploit search API fully implemented
+        - Bulk data downloads
+        
+        
+        Quick Start
+        -----------
+        
+        .. code-block:: python
+        
+            from shodan import Shodan
+        
+            api = Shodan('MY API KEY')
+        
+            # Lookup an IP
+            ipinfo = api.host('8.8.8.8')
+            print(ipinfo)
+        
+            # Search for websites that have been "hacked"
+            for banner in api.search_cursor('http.title:"hacked by"'):
+                print(banner)
+        
+            # Get the total number of industrial control systems services on 
the Internet
+            ics_services = api.count('tag:ics')
+            print('Industrial Control Systems: 
{}'.format(ics_services['total']))
+        
+        Grab your API key from https://account.shodan.io
+        
+        Installation
+        ------------
+        
+        To install the Shodan library, simply:
+        
+        .. code-block:: bash
+        
+            $ pip install shodan
+        
+        Or if you don't have pip installed (which you should seriously 
install):
+        
+        .. code-block:: bash
+        
+            $ easy_install shodan
+        
+        
+        Documentation
+        -------------
+        
+        Documentation is available at https://shodan.readthedocs.org/ and 
https://help.shodan.io
+        
 Keywords: security,network
 Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: MIT License
+Classifier: Natural Language :: English
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/README.rst new/shodan-1.9.0/README.rst
--- old/shodan-1.8.0/README.rst 2018-03-16 22:35:35.000000000 +0100
+++ new/shodan-1.9.0/README.rst 2018-06-01 04:35:05.000000000 +0200
@@ -1,6 +1,12 @@
 shodan: The official Python library for accessing Shodan
 ========================================================
 
+.. image:: https://img.shields.io/pypi/v/shodan.svg
+    :target: https://pypi.org/project/shodan/
+
+.. image:: 
https://img.shields.io/github/contributors/achillean/shodan-python.svg
+    :target: https://github.com/achillean/shodan-python/graphs/contributors
+
 Shodan is a search engine for Internet-connected devices. Google lets you 
search for websites,
 Shodan lets you search for devices. This library provides developers easy 
access to all of the
 data stored in Shodan in order to automate tasks and integrate into existing 
tools.
@@ -9,10 +15,35 @@
 --------
 
 - Search Shodan
-- Fast IP lookups
+- `Fast/ bulk IP lookups 
<https://help.shodan.io/developer-fundamentals/looking-up-ip-info>`_
 - Streaming API support for real-time consumption of Shodan firehose
+- `Network alerts (aka private firehose) 
<https://help.shodan.io/guides/how-to-monitor-network>`_
 - Exploit search API fully implemented
+- Bulk data downloads
+
+
+Quick Start
+-----------
+
+.. code-block:: python
+
+    from shodan import Shodan
+
+    api = Shodan('MY API KEY')
+
+    # Lookup an IP
+    ipinfo = api.host('8.8.8.8')
+    print(ipinfo)
+
+    # Search for websites that have been "hacked"
+    for banner in api.search_cursor('http.title:"hacked by"'):
+        print(banner)
+
+    # Get the total number of industrial control systems services on the 
Internet
+    ics_services = api.count('tag:ics')
+    print('Industrial Control Systems: {}'.format(ics_services['total']))
 
+Grab your API key from https://account.shodan.io
 
 Installation
 ------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/setup.py new/shodan-1.9.0/setup.py
--- old/shodan-1.8.0/setup.py   2018-05-29 12:26:18.000000000 +0200
+++ new/shodan-1.9.0/setup.py   2018-08-01 08:08:43.000000000 +0200
@@ -2,24 +2,36 @@
 
 from setuptools import setup
 
-dependencies = open('requirements.txt', 'r').read().split('\n')
+DEPENDENCIES = open('requirements.txt', 'r').read().split('\n')
+README = open('README.rst', 'r').read()
 
 setup(
     name = 'shodan',
-    version = '1.8.0',
+    version = '1.9.0',
     description = 'Python library and command-line utility for Shodan 
(https://developer.shodan.io)',
+    long_description = README,
+    long_description_content_type = 'text/x-rst',
     author = 'John Matherly',
     author_email = '[email protected]',
     url = 'http://github.com/achillean/shodan-python/tree/master',
     packages = ['shodan', 'shodan.cli', 'shodan.cli.converter'],
     entry_points = {'console_scripts': ['shodan = shodan.__main__:main']},
-    install_requires = dependencies,
+    install_requires = DEPENDENCIES,
     keywords = ['security', 'network'],
     classifiers = [
+        'Development Status :: 5 - Production/Stable',
         'Intended Audience :: Developers',
         'License :: OSI Approved :: MIT License',
+        'Natural Language :: English',
         'Operating System :: OS Independent',
         'Programming Language :: Python',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.6',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: 3.5',
+        'Programming Language :: Python :: 3.6',
         'Topic :: Software Development :: Libraries :: Python Modules',
     ],
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/shodan/__main__.py 
new/shodan-1.9.0/shodan/__main__.py
--- old/shodan-1.8.0/shodan/__main__.py 2018-05-29 12:11:21.000000000 +0200
+++ new/shodan-1.9.0/shodan/__main__.py 2018-08-01 08:07:51.000000000 +0200
@@ -522,7 +522,7 @@
             for banner in host['data']:
                 if banner['port'] in ports:
                     ports.remove(banner['port'])
-            
+
             # Add the placeholder banners
             for port in ports:
                 banner = {
@@ -898,7 +898,7 @@
                         versions = [version for version in 
sorted(banner['ssl']['versions']) if not version.startswith('-')]
                         if len(versions) > 0:
                             click.echo('    |-- SSL Versions: {}'.format(', 
'.join(versions)))
-                    if 'dhparams' in banner['ssl']:
+                    if 'dhparams' in banner['ssl'] and 
banner['ssl']['dhparams']:
                         click.echo('    |-- Diffie-Hellman Parameters:')
                         click.echo('        {:15s}{}\n        
{:15s}{}'.format('Bits:', banner['ssl']['dhparams']['bits'], 'Generator:', 
banner['ssl']['dhparams']['generator']))
                         if 'fingerprint' in banner['ssl']['dhparams']:
@@ -1013,7 +1013,7 @@
         results = api.search(query, limit=limit)
     except shodan.APIError as e:
         raise click.ClickException(e.value)
-    
+
     # Error out if no results were found
     if results['total'] == 0:
         raise click.ClickException('No search results found')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/shodan/client.py 
new/shodan-1.9.0/shodan/client.py
--- old/shodan-1.8.0/shodan/client.py   2017-12-05 06:44:11.000000000 +0100
+++ new/shodan-1.9.0/shodan/client.py   2018-08-01 08:07:51.000000000 +0200
@@ -43,7 +43,7 @@
     :ivar exploits: An instance of `shodan.Shodan.Exploits` that provides 
access to the Exploits REST API.
     :ivar stream: An instance of `shodan.Shodan.Stream` that provides access 
to the Streaming API.
     """
-    
+
     class Data:
 
         def __init__(self, parent):
@@ -62,7 +62,7 @@
             :returns: A list of objects where each object contains a 'name', 
'size', 'timestamp' and 'url'
             """
             return self.parent._request('/shodan/data/{}'.format(dataset), {})
-    
+
     class Tools:
 
         def __init__(self, parent):
@@ -74,16 +74,16 @@
             :returns: str -- your IP address
             """
             return self.parent._request('/tools/myip', {})
-    
+
     class Exploits:
 
         def __init__(self, parent):
             self.parent = parent
-            
+
         def search(self, query, page=1, facets=None):
             """Search the entire Shodan Exploits archive using the same query 
syntax
             as the website.
-            
+
             :param query: The exploit search query; same syntax as website.
             :type query: str
             :param facets: A list of strings or tuples to get summary 
information on.
@@ -100,17 +100,17 @@
                 query_args['facets'] = create_facet_string(facets)
 
             return self.parent._request('/api/search', query_args, 
service='exploits')
-            
+
         def count(self, query, facets=None):
             """Search the entire Shodan Exploits archive but only return the 
total # of results,
             not the actual exploits.
-            
+
             :param query: The exploit search query; same syntax as website.
             :type query: str
             :param facets: A list of strings or tuples to get summary 
information on.
             :type facets: str
             :returns: dict -- a dictionary containing the results of the 
search.
-            
+
             """
             query_args = {
                 'query': query,
@@ -119,7 +119,7 @@
                 query_args['facets'] = create_facet_string(facets)
 
             return self.parent._request('/api/count', query_args, 
service='exploits')
-    
+
     class Labs:
 
         def __init__(self, parent):
@@ -127,19 +127,21 @@
 
         def honeyscore(self, ip):
             """Calculate the probability of an IP being an ICS honeypot.
-            
+
             :param ip: IP address of the device
             :type ip: str
 
             :returns: int -- honeyscore ranging from 0.0 to 1.0
             """
             return self.parent._request('/labs/honeyscore/{}'.format(ip), {})
-    
-    def __init__(self, key):
+
+    def __init__(self, key, proxies=None):
         """Initializes the API object.
-        
+
         :param key: The Shodan API key.
         :type key: str
+        :param proxies: A proxies array for the requests library, e.g. 
{'https': 'your proxy'}
+        :type key: dict
         """
         self.api_key = key
         self.base_url = 'https://api.shodan.io'
@@ -148,23 +150,25 @@
         self.exploits = self.Exploits(self)
         self.labs = self.Labs(self)
         self.tools = self.Tools(self)
-        self.stream = Stream(key)
+        self.stream = Stream(key, proxies=proxies)
         self._session = requests.Session()
-            
+        if proxies:
+            self._session.proxies.update(proxies)
+
     def _request(self, function, params, service='shodan', method='get'):
         """General-purpose function to create web requests to SHODAN.
-        
+
         Arguments:
             function  -- name of the function you want to execute
             params    -- dictionary of parameters for the function
-        
+
         Returns
             A dictionary containing the function's results.
-        
+
         """
         # Add the API key parameter automatically
         params['key'] = self.api_key
-        
+
         # Determine the base_url based on which service we're interacting with
         base_url = {
             'shodan': self.base_url,
@@ -187,22 +191,22 @@
                 error = data.json()['error']
             except Exception as e:
                 error = 'Invalid API key'
-            
+
             raise APIError(error)
-        
+
         # Parse the text into JSON
         try:
             data = data.json()
         except:
             raise APIError('Unable to parse JSON response')
-        
+
         # Raise an exception if an error occurred
         if type(data) == dict and 'error' in data:
             raise APIError(data['error'])
-        
+
         # Return the data
         return data
-    
+
     def count(self, query, facets=None):
         """Returns the total number of search results for the query.
 
@@ -210,7 +214,7 @@
         :type query: str
         :param facets: (optional) A list of properties to get summary 
information on
         :type facets: str
-        
+
         :returns: A dictionary with 1 main property: total. If facets have 
been provided then another property called "facets" will be available at the 
top-level of the dictionary. Visit the website for more detailed information.
         """
         query_args = {
@@ -219,7 +223,7 @@
         if facets:
             query_args['facets'] = create_facet_string(facets)
         return self._request('/shodan/host/count', query_args)
-    
+
     def host(self, ips, history=False, minify=False):
         """Get all available information on an IP.
 
@@ -232,14 +236,14 @@
         """
         if isinstance(ips, basestring):
             ips = [ips]
-        
+
         params = {}
         if history:
             params['history'] = history
         if minify:
             params['minify'] = minify
         return self._request('/shodan/host/%s' % ','.join(ips), params)
-    
+
     def info(self):
         """Returns information about the current API key, such as a list of 
add-ons
         and other features that are enabled for the current user's API plan.
@@ -281,7 +285,7 @@
         """
         if isinstance(ips, basestring):
             ips = [ips]
-        
+
         if isinstance(ips, dict):
             networks = json.dumps(ips)
         else:
@@ -320,7 +324,7 @@
         :returns: A dictionary with general information about the scan, 
including its status in getting processed.
         """
         return self._request('/shodan/scan/%s' % scan_id, {})
-    
+
     def search(self, query, page=1, limit=None, offset=None, facets=None, 
minify=True):
         """Search the SHODAN database.
 
@@ -336,8 +340,8 @@
         :type facets: str
         :param minify: (optional) Whether to minify the banner and only return 
the important data
         :type minify: bool
-        
-        :returns: A dictionary with 2 main items: matches and total. If facets 
have been provided then another property called "facets" will be available at 
the top-level of the dictionary. Visit the website for more detailed 
information.        
+
+        :returns: A dictionary with 2 main items: matches and total. If facets 
have been provided then another property called "facets" will be available at 
the top-level of the dictionary. Visit the website for more detailed 
information.
         """
         args = {
             'query': query,
@@ -352,9 +356,9 @@
 
         if facets:
             args['facets'] = create_facet_string(facets)
-        
+
         return self._request('/shodan/host/search', args)
-    
+
     def search_cursor(self, query, minify=True, retries=5):
         """Search the SHODAN database.
 
@@ -369,7 +373,7 @@
         :type minify: bool
         :param retries: (optional) How often to retry the search in case it 
times out
         :type minify: int
-        
+
         :returns: A search cursor that can be used as an iterator/ generator.
         """
         args = {
@@ -396,13 +400,13 @@
 
                 tries += 1
                 time.sleep(1.0) # wait 1 second if the search errored out for 
some reason
-    
+
     def search_tokens(self, query):
         """Returns information about the search query itself (filters used 
etc.)
 
         :param query: Search query; identical syntax to the website
         :type query: str
-        
+
         :returns: A dictionary with 4 main properties: filters, errors, 
attributes and string.
         """
         query_args = {
@@ -481,7 +485,8 @@
             'expires': expires,
         }
 
-        response = api_request(self.api_key, '/shodan/alert', data=data, 
params={}, method='post')
+        response = api_request(self.api_key, '/shodan/alert', data=data, 
params={}, method='post',
+                               proxies=self._session.proxies)
 
         return response
 
@@ -494,7 +499,8 @@
 
         response = api_request(self.api_key, func, params={
             'include_expired': include_expired,
-            })
+            },
+            proxies=self._session.proxies)
 
         return response
 
@@ -502,7 +508,8 @@
         """Delete the alert with the given ID."""
         func = '/shodan/alert/%s' % aid
 
-        response = api_request(self.api_key, func, params={}, method='delete')
+        response = api_request(self.api_key, func, params={}, method='delete',
+                               proxies=self._session.proxies)
 
         return response
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/shodan/helpers.py 
new/shodan-1.9.0/shodan/helpers.py
--- old/shodan-1.8.0/shodan/helpers.py  2017-06-17 00:16:47.000000000 +0200
+++ new/shodan-1.9.0/shodan/helpers.py  2018-08-01 08:07:51.000000000 +0200
@@ -23,17 +23,19 @@
         facet_str += ','
     return facet_str[:-1]
 
-    
-def api_request(key, function, params=None, data=None, 
base_url='https://api.shodan.io', method='get', retries=1):
+
+def api_request(key, function, params=None, data=None, 
base_url='https://api.shodan.io',
+                method='get', retries=1, proxies=None):
     """General-purpose function to create web requests to SHODAN.
-    
+
     Arguments:
         function  -- name of the function you want to execute
         params    -- dictionary of parameters for the function
-    
+        proxies   -- a proxies array for the requests library
+
     Returns
         A dictionary containing the function's results.
-    
+
     """
     # Add the API key parameter automatically
     params['key'] = key
@@ -44,11 +46,13 @@
     while tries <= retries:
         try:
             if method.lower() == 'post':
-                data = requests.post(base_url + function, json.dumps(data), 
params=params, headers={'content-type': 'application/json'})
+                data = requests.post(base_url + function, json.dumps(data), 
params=params,
+                                     headers={'content-type': 
'application/json'},
+                                     proxies=proxies)
             elif method.lower() == 'delete':
-                data = requests.delete(base_url + function, params=params)
+                data = requests.delete(base_url + function, params=params, 
proxies=proxies)
             else:
-                data = requests.get(base_url + function, params=params)
+                data = requests.get(base_url + function, params=params, 
proxies=proxies)
 
             # Exit out of the loop
             break
@@ -66,17 +70,17 @@
         except:
             pass
         raise APIError('Invalid API key')
-    
+
     # Parse the text into JSON
     try:
         data = data.json()
     except:
         raise APIError('Unable to parse JSON response')
-    
+
     # Raise an exception if an error occurred
     if type(data) == dict and data.get('error', None):
         raise APIError(data['error'])
-    
+
     # Return the data
     return data
 
@@ -93,10 +97,10 @@
             from ujson import loads
         except:
             pass
-    
+
     if isinstance(files, basestring):
         files = [files]
-    
+
     for filename in files:
         # Create a file handle depending on the filetype
         if filename.endswith('.gz'):
@@ -157,7 +161,7 @@
         return '1 byte'
     if bytes < 1024:
         return '%.*f %s' % (precision, bytes, "bytes")
-    
+
     suffixes = ['KB', 'MB', 'GB', 'TB', 'PB']
     multiple = 1024.0    #.0 force float on python 2
     for suffix in suffixes:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/shodan/stream.py 
new/shodan-1.9.0/shodan/stream.py
--- old/shodan-1.8.0/shodan/stream.py   2017-12-03 23:57:41.000000000 +0100
+++ new/shodan-1.9.0/shodan/stream.py   2018-08-01 08:07:51.000000000 +0200
@@ -9,18 +9,31 @@
 
     base_url = 'https://stream.shodan.io'
 
-    def __init__(self, api_key):
+    def __init__(self, api_key, proxies=None):
         self.api_key = api_key
+        self.proxies = proxies
 
     def _create_stream(self, name, timeout=None):
+        params = {
+            'key': self.api_key,
+        }
+        stream_url = self.base_url + name
+
         # The user doesn't want to use a timeout
         # If the timeout is specified as 0 then we also don't want to have a 
timeout
         if ( timeout and timeout <= 0 ) or ( timeout == 0 ):
             timeout = None
-        
+
+        # If the user requested a timeout then we need to disable heartbeat 
messages
+        # which are intended to keep stream connections alive even if there 
isn't any data
+        # flowing through.
+        if timeout:
+            params['heartbeat'] = False
+
         try:
             while True:
-                req = requests.get(self.base_url + name, params={'key': 
self.api_key}, stream=True, timeout=timeout)
+                req = requests.get(stream_url, params=params, stream=True, 
timeout=timeout,
+                                   proxies=self.proxies)
 
                 # Status code 524 is special to Cloudflare
                 # It means that no data was sent from the streaming servers 
which caused Cloudflare
@@ -46,7 +59,7 @@
             req.encoding = 'utf-8'
         return req
 
-    def _iter_stream(self, stream, raw, timeout=None):
+    def _iter_stream(self, stream, raw):
         for line in stream.iter_lines(decode_unicode=True):
             # The Streaming API sends out heartbeat messages that are newlines
             # We want to ignore those messages since they don't contain any 
data
@@ -55,16 +68,6 @@
                     yield line
                 else:
                     yield json.loads(line)
-            else:
-                # If the user specified a timeout then we want to keep track 
of how long we've
-                # been getting heartbeat messages and exit the loop if it's 
been too long since
-                # we've seen any activity.
-                if timeout:
-                    # TODO: This is a placeholder for now but since the 
Streaming API added heartbeats it broke
-                    # the ability to use inactivity timeouts (the connection 
timeout still works). The timeout is
-                    # mostly needed when doing on-demand scans and wanting to 
temporarily consume data from a
-                    # network alert.
-                    pass
 
     def alert(self, aid=None, timeout=None, raw=False):
         if aid:
@@ -120,4 +123,4 @@
         stream = self._create_stream('/shodan/ports/%s' % ','.join([str(port) 
for port in ports]), timeout=timeout)
         for line in self._iter_stream(stream, raw):
             yield line
-            
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/shodan/threatnet.py 
new/shodan-1.9.0/shodan/threatnet.py
--- old/shodan-1.8.0/shodan/threatnet.py        2017-05-17 19:09:05.000000000 
+0200
+++ new/shodan-1.9.0/shodan/threatnet.py        2018-08-01 08:07:51.000000000 
+0200
@@ -11,17 +11,19 @@
     :type key: str
     :ivar stream: An instance of `shodan.Threatnet.Stream` that provides 
access to the Streaming API.
     """
-    
+
     class Stream:
 
         base_url = 'https://stream.shodan.io'
 
-        def __init__(self, parent):
+        def __init__(self, parent, proxies=None):
             self.parent = parent
+            self.proxies = proxies
 
         def _create_stream(self, name):
             try:
-                req = requests.get(self.base_url + name, params={'key': 
self.parent.api_key}, stream=True)
+                req = requests.get(self.base_url + name, params={'key': 
self.parent.api_key},
+                                   stream=True, proxies=self.proxies)
             except:
                 raise APIError('Unable to contact the Shodan Streaming API')
 
@@ -53,10 +55,10 @@
                 if line:
                     banner = json.loads(line)
                     yield banner
-    
+
     def __init__(self, key):
         """Initializes the API object.
-        
+
         :param key: The Shodan API key.
         :type key: str
         """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/shodan-1.8.0/shodan.egg-info/PKG-INFO 
new/shodan-1.9.0/shodan.egg-info/PKG-INFO
--- old/shodan-1.8.0/shodan.egg-info/PKG-INFO   2018-05-29 12:28:02.000000000 
+0200
+++ new/shodan-1.9.0/shodan.egg-info/PKG-INFO   2018-08-01 08:26:34.000000000 
+0200
@@ -1,16 +1,92 @@
 Metadata-Version: 1.1
 Name: shodan
-Version: 1.8.0
+Version: 1.9.0
 Summary: Python library and command-line utility for Shodan 
(https://developer.shodan.io)
 Home-page: http://github.com/achillean/shodan-python/tree/master
 Author: John Matherly
 Author-email: [email protected]
 License: UNKNOWN
-Description: UNKNOWN
+Description: shodan: The official Python library for accessing Shodan
+        ========================================================
+        
+        .. image:: https://img.shields.io/pypi/v/shodan.svg
+            :target: https://pypi.org/project/shodan/
+        
+        .. image:: 
https://img.shields.io/github/contributors/achillean/shodan-python.svg
+            :target: 
https://github.com/achillean/shodan-python/graphs/contributors
+        
+        Shodan is a search engine for Internet-connected devices. Google lets 
you search for websites,
+        Shodan lets you search for devices. This library provides developers 
easy access to all of the
+        data stored in Shodan in order to automate tasks and integrate into 
existing tools.
+        
+        Features
+        --------
+        
+        - Search Shodan
+        - `Fast/ bulk IP lookups 
<https://help.shodan.io/developer-fundamentals/looking-up-ip-info>`_
+        - Streaming API support for real-time consumption of Shodan firehose
+        - `Network alerts (aka private firehose) 
<https://help.shodan.io/guides/how-to-monitor-network>`_
+        - Exploit search API fully implemented
+        - Bulk data downloads
+        
+        
+        Quick Start
+        -----------
+        
+        .. code-block:: python
+        
+            from shodan import Shodan
+        
+            api = Shodan('MY API KEY')
+        
+            # Lookup an IP
+            ipinfo = api.host('8.8.8.8')
+            print(ipinfo)
+        
+            # Search for websites that have been "hacked"
+            for banner in api.search_cursor('http.title:"hacked by"'):
+                print(banner)
+        
+            # Get the total number of industrial control systems services on 
the Internet
+            ics_services = api.count('tag:ics')
+            print('Industrial Control Systems: 
{}'.format(ics_services['total']))
+        
+        Grab your API key from https://account.shodan.io
+        
+        Installation
+        ------------
+        
+        To install the Shodan library, simply:
+        
+        .. code-block:: bash
+        
+            $ pip install shodan
+        
+        Or if you don't have pip installed (which you should seriously 
install):
+        
+        .. code-block:: bash
+        
+            $ easy_install shodan
+        
+        
+        Documentation
+        -------------
+        
+        Documentation is available at https://shodan.readthedocs.org/ and 
https://help.shodan.io
+        
 Keywords: security,network
 Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: MIT License
+Classifier: Natural Language :: English
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
 Classifier: Topic :: Software Development :: Libraries :: Python Modules


Reply via email to