Hello community,
here is the log from the commit of package python-pyhibp for openSUSE:Factory checked in at 2019-07-02 10:39:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pyhibp (Old)
and /work/SRC/openSUSE:Factory/.python-pyhibp.new.4615 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyhibp"
Tue Jul 2 10:39:46 2019 rev:2 rq:712996 version:3.1.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pyhibp/python-pyhibp.changes 2019-02-01 11:45:44.184534553 +0100
+++ /work/SRC/openSUSE:Factory/.python-pyhibp.new.4615/python-pyhibp.changes 2019-07-02 10:39:47.186708781 +0200
@@ -1,0 +2,24 @@
+Mon Jul 1 12:34:45 UTC 2019 - Martin Hauke
+
+- Update to version 3.1.0
+ * New function: pwnedpasswords.suffix_search(hash_prefix=prefix)
+ was created in order to have a dedicated function return the
+ suffix list.
+ * Function modification notice: pwnedpasswords.is_password_breached
+ will be modified in an upcoming release to remove the ability
+ to search for suffixes; use suffix_search(hash_prefix=prefix)
+ instead. The parameter first_5_hash_chars will be removed as a
+ consequence.
+ * Upcoming return type change for empty sets: For the functions
+ get_account_breaches, get_all_breaches, get_single_breach, and
+ get_pastes--all contained in the pyhibp module--when no items
+ would be returned from the HIBP backend, the returned item will
+ be an empty object matching the standard return type for the
+ function, and not a Boolean False.
+ This will occur when v4.0.0 is released. Return types will be:
+ - get_account_breaches -> [] / list
+ - get_all_breaches -> [] / list
+ - get_single_breach -> {} / dict
+ - get_pastes -> [] / list
+
+-------------------------------------------------------------------
Old:
----
pyhibp-3.0.0.tar.gz
New:
----
pyhibp-3.1.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pyhibp.spec ++++++
--- /var/tmp/diff_new_pack.YoruMU/_old 2019-07-02 10:39:47.642709476 +0200
+++ /var/tmp/diff_new_pack.YoruMU/_new 2019-07-02 10:39:47.646709481 +0200
@@ -1,5 +1,5 @@
#
-# spec file for package python-pyHIBP
+# spec file for package python-pyhibp
#
# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
#
@@ -12,12 +12,13 @@
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
+#
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-pyhibp
-Version: 3.0.0
+Version: 3.1.0
Release: 0
Summary: An interface to Troy Hunt's 'Have I Been Pwned' public API
License: AGPL-3.0-or-later
@@ -50,7 +51,7 @@
### Tests need network access to https://haveibeenpwned.com
#%%check
-#%%python_expand PYTHONPATH=%%{buildroot}%%{$python_sitelib} py.test-%%{$python_version}
+#%%pytest
%files %{python_files}
%license LICENSE
++++++ pyhibp-3.0.0.tar.gz -> pyhibp-3.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/CHANGELOG.md new/pyhibp-3.1.0/CHANGELOG.md
--- old/pyhibp-3.0.0/CHANGELOG.md 2018-11-10 01:39:46.000000000 +0100
+++ new/pyhibp-3.1.0/CHANGELOG.md 2019-06-30 10:46:01.000000000 +0200
@@ -1,11 +1,34 @@
pyHIBP Changelog
================
-v3.0.0 (UNRELEASED)
+v3.1.0 (In progress...)
+-----------------------
+- **New function**: ``pwnedpasswords.suffix_search(hash_prefix=prefix)`` was created in order to have a dedicated function
+ return the suffix list.
+- **Function modification notice**: ``pwnedpasswords.is_password_breached`` will be modified in an upcoming release to
+ remove the ability to search for suffixes; use ``suffix_search(hash_prefix=prefix)`` instead. The parameter
+ ``first_5_hash_chars`` will be removed as a consequence.
+- **Upcoming return type change for empty sets**: For the functions ``get_account_breaches``, ``get_all_breaches``,
+ ``get_single_breach``, and ``get_pastes``--all contained in the ``pyhibp`` module--when no items would be returned
+ from the HIBP backend, the returned item will be an empty object matching the standard return type for the function,
+ and not a Boolean ``False``. This will occur when ``v4.0.0`` is released. Return types will be:
+ - ``get_account_breaches`` -> ``[] / list``
+ - ``get_all_breaches`` -> ``[] / list``
+ - ``get_single_breach`` -> ``{} / dict``
+ - ``get_pastes`` -> ``[] / list``
+- As a reminder, Python 2.7 support will be dropped from support in the near future. This will occur at the same time
+ as the removal of the range search functionality available via ``pwnedpasswords.is_password_breached(first_5_hash_chars=prefix)``
+ so as to minimize disruption.
+
+v3.0.0 (2018-11-10)
-------------------
-- **Backwards Incompatible Change**: The package name has been changed to fall in-line with the PEP 8 guideline calling for [all lowercase characters in package/module names](https://www.python.org/dev/peps/pep-0008/#package-and-module-names). Existing code will need to change invocations of ``pyHIBP`` to ``pyhibp``.
- - We will, however, still refer to the package/module as _pyHIBP_ when it is used outside of the context of Python code.
-- **Future Python 2 Deprecation**: As per PEP 373, [Python 2.7.x support ends on 2020-01-01](https://www.python.org/dev/peps/pep-0373/#maintenance-releases). That being said, we will be dropping Python 2 as a supported version _prior_ to this date.
-- The `requests` dependency has been bumped to require versions at or above `2.20.0` (due to CVE-2018-18074 affecting the `requests` package for older versions).
+- **Backwards Incompatible Change**: The package name has been changed to fall in-line with the PEP 8 guideline calling
+ for [all lowercase characters in package/module names](https://www.python.org/dev/peps/pep-0008/#package-and-module-names).
+ Existing code will need to change invocations of ``pyHIBP`` to ``pyhibp``.
+ - We will, however, still refer to the package/module as _pyHIBP_ when it is used outside of the context of Python code.
+- **Future Python 2 Deprecation**: As per PEP 373, [Python 2.7.x support ends on 2020-01-01](https://www.python.org/dev/peps/pep-0373/#maintenance-releases).
+ That being said, we will be dropping Python 2 as a supported version _prior_ to this date.
+- The `requests` dependency has been bumped to require versions at or above `2.20.0` (due to CVE-2018-18074 affecting
+ the `requests` package for older versions).
v2.1.1 (2018-09-18)
-------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/PKG-INFO new/pyhibp-3.1.0/PKG-INFO
--- old/pyhibp-3.0.0/PKG-INFO 2018-11-10 02:56:39.000000000 +0100
+++ new/pyhibp-3.1.0/PKG-INFO 2019-06-30 11:17:16.000000000 +0200
@@ -1,102 +1,102 @@
-Metadata-Version: 2.1
-Name: pyhibp
-Version: 3.0.0
-Summary: An interface to Troy Hunt's 'Have I Been Pwned' public API
-Home-page: https://gitlab.com/kitsunix/pyHIBP/pyHIBP
-Author: Kyra F. Kitsune
-License: UNKNOWN
-Description: pyHIBP (pyHave I Been Pwned)
- ============================
- [![image](https://img.shields.io/pypi/v/pyHIBP.svg)](https://pypi.org/project/pyHIBP/)
- [![image](https://img.shields.io/pypi/l/pyHIBP.svg)](https://pypi.org/project/pyHIBP/)
- [![image](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master)
-
-
- A Python interface to Troy Hunt's 'Have I Been Pwned?' (HIBP) public API. A full reference to the API
- specification can be found at the [HIBP API Reference](https://haveibeenpwned.com/API/v2).
-
- This module detects when the rate limit of the API has been hit, and raises a RuntimeError when the limit is exceeded,
- or when another API-defined error condition is encountered based on the submitted data. Calls
- to the module returning Boolean `True` or the object as decoded from the API query (currently, lists), represent
- a detection that a breached account/paste/password was found; Boolean `False` means that the item was not found.
-
- Note that the `pwnedpasswords` API backend does not have a rate limit. If you are intending to bulk-query passwords or
- hashes, you may also consider downloading the raw data files accessible via the [Pwned Passwords](https://haveibeenpwned.com/Passwords) page.
-
- Installing
- ----------
- ```bash
- $ pip install pyhibp
- ```
-
- Example usage
- -------------
- For an interactive example, check out the Jupyter Notebook for [`pyhibp`](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master?filepath...),
- as well as [`pyhibp.pwnedpasswords`](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master?filepath...).
-
- ```python
- import pyhibp
- from pyhibp import pwnedpasswords as pw
-
- # Check a password to see if it has been disclosed in a public breach corpus
- resp = pw.is_password_breached(password="secret")
- if resp:
- print("Password breached!")
- print("This password was used {0} time(s) before.".format(resp))
-
- # Get breaches that affect a given account
- resp = pyhibp.get_account_breaches(account="test@example.com", truncate_response=True)
-
- # Get all breach information
- resp = pyhibp.get_all_breaches()
-
- # Get a single breach
- resp = pyhibp.get_single_breach(breach_name="Adobe")
-
- # Get pastes affecting a given email address
- resp = pyhibp.get_pastes(email_address="test@example.com")
-
- # Get data classes in the HIBP system
- resp = pyhibp.get_data_classes()
- ```
-
- Developing
- ----------
- This project is currently intended to be compatible with Python 2 and Python 3. As such, we use virtual environments via `pipenv`.
- To develop or test, execute the following:
-
- ```bash
- # Install the prerequisite virtual environment provider
- $ pip install pipenv
- # Initialize the pipenv environment and install the module within it
- $ make dev
- # To run PEP8, tests, and check the manifest
- $ make tox
- ```
-
- Other commands can be found in the `Makefile`.
-
- Goals
- -----
- - Synchronize to the latest HIBP API(s), implementing endpoint accessing functions where it makes sense. For instance,
- in the interest of security, the ability to submit a SHA-1 to the Pwned Passwords endpoint is not implemented. See
- "Regarding password checking" below for further details.
- - For breaches and pastes, act as an intermediary; return the JSON as received from the service.
-
- Regarding password checking
- ---------------------------
- - For passwords, the option to supply a plaintext password to check is provided as an implementation convenience.
- - For added security, `pwnedpasswords.is_password_breached()` only transmits the first five characters of the SHA-1
- hash to the Pwned Passwords API endpoint; a secure password will remain secure without disclosing the full hash.
-
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
-Classifier: Intended Audience :: Developers
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.5
-Description-Content-Type: text/markdown
-Provides-Extra: dev
+Metadata-Version: 2.1
+Name: pyhibp
+Version: 3.1.0
+Summary: An interface to Troy Hunt's 'Have I Been Pwned' public API
+Home-page: https://gitlab.com/kitsunix/pyHIBP/pyHIBP
+Author: Kyra F. Kitsune
+License: UNKNOWN
+Description: pyHIBP (pyHave I Been Pwned)
+ ============================
+ [![image](https://img.shields.io/pypi/v/pyHIBP.svg)](https://pypi.org/project/pyHIBP/)
+ [![image](https://img.shields.io/pypi/l/pyHIBP.svg)](https://pypi.org/project/pyHIBP/)
+ [![image](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master)
+
+
+ A Python interface to Troy Hunt's 'Have I Been Pwned?' (HIBP) public API. A full reference to the API
+ specification can be found at the [HIBP API Reference](https://haveibeenpwned.com/API/v2).
+
+ This module detects when the rate limit of the API has been hit, and raises a RuntimeError when the limit
+ is exceeded, or when another API-defined error condition is encountered based on the submitted data. When
+ data is found from a call, the data returned will be in the format as retrieved from the endpoint, documented
+ in the return-type information for the relevant function.
+
+ Note that the `pwnedpasswords` API backend does not have a rate limit. If you are intending to bulk-query passwords or
+ hashes, you should consider downloading the raw data files accessible via the [Pwned Passwords](https://haveibeenpwned.com/Passwords) page.
+
+ Installing
+ ----------
+ ```bash
+ $ pip install pyhibp
+ ```
+
+ Example usage
+ -------------
+ For an interactive example, check out the Jupyter Notebook for [`pyhibp`](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master?filepath...),
+ as well as [`pyhibp.pwnedpasswords`](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master?filepath...).
+
+ ```python
+ import pyhibp
+ from pyhibp import pwnedpasswords as pw
+
+ # Check a password to see if it has been disclosed in a public breach corpus
+ resp = pw.is_password_breached(password="secret")
+ if resp:
+ print("Password breached!")
+ print("This password was used {0} time(s) before.".format(resp))
+
+ # Get breaches that affect a given account
+ resp = pyhibp.get_account_breaches(account="test@example.com", truncate_response=True)
+
+ # Get all breach information
+ resp = pyhibp.get_all_breaches()
+
+ # Get a single breach
+ resp = pyhibp.get_single_breach(breach_name="Adobe")
+
+ # Get pastes affecting a given email address
+ resp = pyhibp.get_pastes(email_address="test@example.com")
+
+ # Get data classes in the HIBP system
+ resp = pyhibp.get_data_classes()
+ ```
+
+ Developing
+ ----------
+ This project is currently intended to be compatible with Python 2 and Python 3. As such, we use virtual environments via `pipenv`.
+ To develop or test, execute the following:
+
+ ```bash
+ # Install the prerequisite virtual environment provider
+ $ pip install pipenv
+ # Initialize the pipenv environment and install the module within it
+ $ make dev
+ # To run PEP8, tests, and check the manifest
+ $ make tox
+ ```
+
+ Other commands can be found in the `Makefile`.
+
+ Goals
+ -----
+ - Synchronize to the latest HIBP API(s), implementing endpoint accessing functions where it makes sense. For instance,
+ in the interest of security, the ability to submit a SHA-1 to the Pwned Passwords endpoint is not implemented. See
+ "Regarding password checking" below for further details.
+ - For breaches and pastes, act as an intermediary; return the JSON as received from the service.
+
+ Regarding password checking
+ ---------------------------
+ - For passwords, the option to supply a plaintext password to check is provided as an implementation convenience.
+ - For added security, `pwnedpasswords.is_password_breached()` only transmits the first five characters of the SHA-1
+ hash to the Pwned Passwords API endpoint; a secure password will remain secure without disclosing the full hash.
+
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Description-Content-Type: text/markdown
+Provides-Extra: dev
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/Pipfile new/pyhibp-3.1.0/Pipfile
--- old/pyhibp-3.0.0/Pipfile 2018-11-10 01:39:46.000000000 +0100
+++ new/pyhibp-3.1.0/Pipfile 2019-06-30 10:46:01.000000000 +0200
@@ -1,18 +1,13 @@
[[source]]
-
verify_ssl = true
url = "https://pypi.python.org/simple"
name = "pypi"
-
[packages]
-
requests = ">=2.20.0"
six = ">=1.11.0"
-
[dev-packages]
-
tox = "*"
pytest = "*"
pytest-cov = "*"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/README.md new/pyhibp-3.1.0/README.md
--- old/pyhibp-3.0.0/README.md 2018-11-10 01:39:46.000000000 +0100
+++ new/pyhibp-3.1.0/README.md 2019-06-30 10:46:01.000000000 +0200
@@ -8,13 +8,13 @@
A Python interface to Troy Hunt's 'Have I Been Pwned?' (HIBP) public API. A full reference to the API
specification can be found at the [HIBP API Reference](https://haveibeenpwned.com/API/v2).
-This module detects when the rate limit of the API has been hit, and raises a RuntimeError when the limit is exceeded,
-or when another API-defined error condition is encountered based on the submitted data. Calls
-to the module returning Boolean `True` or the object as decoded from the API query (currently, lists), represent
-a detection that a breached account/paste/password was found; Boolean `False` means that the item was not found.
+This module detects when the rate limit of the API has been hit, and raises a RuntimeError when the limit
+is exceeded, or when another API-defined error condition is encountered based on the submitted data. When
+data is found from a call, the data returned will be in the format as retrieved from the endpoint, documented
+in the return-type information for the relevant function.
Note that the `pwnedpasswords` API backend does not have a rate limit. If you are intending to bulk-query passwords or
-hashes, you may also consider downloading the raw data files accessible via the [Pwned Passwords](https://haveibeenpwned.com/Passwords) page.
+hashes, you should consider downloading the raw data files accessible via the [Pwned Passwords](https://haveibeenpwned.com/Passwords) page.
Installing
----------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/setup.cfg new/pyhibp-3.1.0/setup.cfg
--- old/pyhibp-3.0.0/setup.cfg 2018-11-10 02:56:39.000000000 +0100
+++ new/pyhibp-3.1.0/setup.cfg 2019-06-30 11:17:16.000000000 +0200
@@ -1,11 +1,11 @@
-[bdist_wheel]
-universal = 1
-
-[flake8]
-exclude = .git
-ignore = E501
-
-[egg_info]
-tag_build =
-tag_date = 0
-
+[bdist_wheel]
+universal = 1
+
+[flake8]
+exclude = .git
+ignore = E501
+
+[egg_info]
+tag_build =
+tag_date = 0
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/src/pyhibp/__init__.py new/pyhibp-3.1.0/src/pyhibp/__init__.py
--- old/pyhibp-3.0.0/src/pyhibp/__init__.py 2018-11-10 02:28:07.000000000 +0100
+++ new/pyhibp-3.1.0/src/pyhibp/__init__.py 2019-06-30 10:46:01.000000000 +0200
@@ -23,6 +23,7 @@
:param response: The response object from a call to `requests`
:return: True if HTTP Status 200, False if 404. Raises RuntimeError on API-defined status codes of
400, 403, 429; NotImplementedError if the API returns an unexpected HTTP status code.
+ :rtype: bool
"""
if response.status_code == 200:
# The request was successful (we found an item)
@@ -52,14 +53,15 @@
Gets breaches for a specified account from the HIBP system, optionally restricting the returned results
to a specified domain.
- :param account: The user's account name (such as an email address or a user-name). Default None.
- :param domain: The domain to check for breaches. Default None.
+ :param account: The user's account name (such as an email address or a user-name). Default None. `str` type.
+ :param domain: The domain to check for breaches. Default None. `str` type.
:param truncate_response: If ``account`` is specified, truncates the response down to the breach names.
- Default False.
- :param include_unverified: If set to True, unverified breaches are included in the result. Default False.
+ Default False. `bool` type.
+ :param include_unverified: If set to True, unverified breaches are included in the result. Default False. `bool` type
:return: A list object containing one or more dict objects, based on the information being requested,
provided there was matching information. Boolean False returned if no information was found according to
the HIBP API.
+ :rtype: list
"""
# Account/Domain don't need to be specified, but they must be text if so.
if account is None or not isinstance(account, six.string_types):
@@ -80,6 +82,7 @@
if _process_response(response=resp):
return resp.json()
else:
+ # TODO: v4.0.0: return []
return False
@@ -87,9 +90,10 @@
"""
Returns a listing of all sites breached in the HIBP database.
- :param domain: Optional, default None. If specified, get all breaches for the domain with the specified name.
+ :param domain: Optional, default None. If specified, get all breaches for the domain with the specified name. `str` type.
:return: A list object containing one or more dict objects if breaches are present. Returns Boolean False
if ``domain`` is specified, but the resultant list would be length zero.
+ :rtype: list
"""
if domain is not None and not isinstance(domain, six.string_types):
raise AttributeError("The domain parameter, if specified, must be a string.")
@@ -101,6 +105,7 @@
if _process_response(response=resp) and len(resp.json()) > 0:
return resp.json()
else:
+ # TODO: v4.0.0: return []
return False
@@ -108,9 +113,10 @@
"""
Returns a single breach's information from the HIBP's database.
- :param breach_name: The breach to retrieve. Required.
+ :param breach_name: The breach to retrieve. Required. `str` type.
:return: A dict object containing the information for the specified breach name, if it exists in the HIBP
database. Boolean False is returned if the specified breach was not found.
+ :rtype: dict
"""
if not isinstance(breach_name, six.string_types):
raise AttributeError("The breach_name must be specified, and be a string.")
@@ -120,6 +126,7 @@
if _process_response(response=resp):
return resp.json()
else:
+ # TODO: v4.0.0: return {}
return False
@@ -127,9 +134,10 @@
"""
Retrieve all pastes for a specified email address.
- :param email_address: The email address to search. Required.
+ :param email_address: The email address to search. Required. `str` type.
:return: A list object containing one or more dict objects corresponding to the pastes the specified email
address was found in. Boolean False returned if no pastes are detected for the given account.
+ :rtype: list
"""
if not isinstance(email_address, six.string_types):
raise AttributeError("The email address supplied must be provided, and be a string.")
@@ -139,6 +147,7 @@
if _process_response(response=resp):
return resp.json()
else:
+ # TODO: v4.0.0: return []
return False
@@ -148,6 +157,7 @@
:return: A list object containing available data classes, corresponding to attributes found in breaches.
A given breach will have one or more of the data classes in the list.
+ :rtype: list
"""
uri = HIBP_API_BASE_URI + HIBP_API_ENDPOINT_DATA_CLASSES
resp = requests.get(url=uri, headers=pyHIBP_HEADERS)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/src/pyhibp/__version__.py new/pyhibp-3.1.0/src/pyhibp/__version__.py
--- old/pyhibp-3.0.0/src/pyhibp/__version__.py 2018-11-10 02:40:10.000000000 +0100
+++ new/pyhibp-3.1.0/src/pyhibp/__version__.py 2019-06-30 11:09:11.000000000 +0200
@@ -4,5 +4,5 @@
# |)\/| |||)|
# | /
-__version__ = '3.0.0'
+__version__ = '3.1.0'
__url__ = 'https://gitlab.com/kitsunix/pyHIBP/pyHIBP'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/src/pyhibp/pwnedpasswords.py new/pyhibp-3.1.0/src/pyhibp/pwnedpasswords.py
--- old/pyhibp-3.0.0/src/pyhibp/pwnedpasswords.py 2018-11-10 01:39:46.000000000 +0100
+++ new/pyhibp-3.1.0/src/pyhibp/pwnedpasswords.py 2019-06-30 10:46:02.000000000 +0200
@@ -1,4 +1,5 @@
import hashlib
+import warnings
import requests
import six
@@ -20,29 +21,26 @@
number of times that hash appears in the data set. In doing so, the API is not provided the information
required to reconstruct the password (e.g., by brute-forcing the hash).
- Either ```password``, `first_5_hash_chars``, or ``sha1_hash`` must be specified. Only one parameter should be provided.
+ Either ```password`` or ``sha1_hash`` must be specified. Only one parameter should be provided.
The precedence of parameters is as follows:
- 1) password - Computes the remaining two parameters.
- 2) sha1_hash - Computes the following parameter, and will determine if a match was found.
- 3) first_5_hash_chars - Returns a list of partial hashes for the calling application to process.
-
- If ``password`` is provided,
- the password will be converted to a SHA-1 hash, then the first five characters checked against the API's returned
- information, much like as if a full `sha1_hash` were supplied.
-
- Suffix example: 0018A45C4D1DEF81644B54AB7F969B88D65:1
-
- :param password: The password to check. Will be converted to a SHA-1 string.
- :param first_5_hash_chars: The first five characters of a SHA-1 hash string.
- :param sha1_hash: A full SHA-1 hash.
- :return: If ``first_5_hash_chars`` is supplied, a [list] of hash suffixes. If ``password`` or ``sha1_hash`` is supplied,
- and the password was found in the corpus, an Integer representing the number of times the password is in
- the data set; if not found, Integer zero (0) is returned.
+ 1) password - Used to compute the SHA-1 hash of the password.
+ 2) sha1_hash - The hash prefix (hash[0:5]) is passed to the HIBP API, and this function will check the returned list of
+ hash suffixes to determine if a breached password was in the HIBP database.
+
+ Note: Suffix searches, that is, to retrieve a list of hash suffixes by supplying a hash prefix, have moved to
+ `suffix_search()` as of this release (v3.1.0). A compatability shim has been left for this release, but will be removed on the
+ next major version release.
+
+ :param password: The password to check. Will be converted to a SHA-1 string. `str` type.
+ :param sha1_hash: A full SHA-1 hash. `str` type.
+ :return: An Integer representing the number of times the password is in the data set; if not found,
+ Integer zero (0) is returned.
+ :rtype: int
"""
# Parameter validation section
if not any([password, first_5_hash_chars, sha1_hash]):
- raise AttributeError("One of password, first_5_hash_chars, or sha1_hash must be provided.")
+ raise AttributeError("One of password, sha1_hash, or first_5_hash_chars must be provided.")
elif password is not None and not isinstance(password, six.string_types):
raise AttributeError("password must be a string type.")
elif sha1_hash is not None and not isinstance(sha1_hash, six.string_types):
@@ -59,27 +57,66 @@
sha1_hash = sha1_hash.upper()
first_5_hash_chars = sha1_hash[0:5]
- uri = PWNED_PASSWORDS_API_BASE_URI + PWNED_PASSWORDS_API_ENDPOINT_RANGE_SEARCH + first_5_hash_chars
+ suffix_list = suffix_search(hash_prefix=first_5_hash_chars)
- resp = requests.get(url=uri, headers=pyhibp.pyHIBP_HEADERS)
-
- # The server response will have a BOM if we don't do this.
- resp.encoding = RESPONSE_ENCODING
-
- if resp.status_code != 200:
- # The HTTP Status should always be 200 for this request
- raise RuntimeError("Response from the endpoint was not HTTP200; this should not happen. Code was: {0}".format(resp.status_code))
- elif not sha1_hash:
+ if not sha1_hash:
+ # TODO: v4.0.0: Remove this codepath (first_5_hash_chars)
+ warnings.warn("""
+ Hash suffix searching is being moved to its own discrete function, `suffix_search()`. Call `suffix_search(hash_prefix=prefix)`
+ instead. Hash prefixes will not return from is_password_breached() in a future release.
+ """)
# Return the list of hash suffixes.
- return resp.text.split()
+ return suffix_list
else:
# Since the full SHA-1 hash was provided, check to see if it was in the resultant hash suffixes returned.
- response_lines = resp.text.split()
-
- for hash_suffix in response_lines:
+ for hash_suffix in suffix_list:
if sha1_hash[5:] in hash_suffix:
# We found the full hash, so return
return int(hash_suffix.split(':')[1])
# If we get here, there was no match to the supplied SHA-1 hash; return zero.
return 0
+
+
+def suffix_search(hash_prefix=None):
+ """
+ Returns a list of SHA-1 hash suffixes, consisting of the SHA-1 hash characters after position five,
+ and the number of times that password hash was found in the HIBP database, colon separated.
+
+ Leveraging the k-Anonymity model, a list of hashes matching a specified SHA-1 prefix are returned.
+ From this list, the calling application may determine if a given password was breached by comparing
+ the remainder of the SHA-1 hash against the returned results. As an example, for the hash prefix of
+ '42042', the hash suffixes would be:
+
+ ```
+ 005F4A4B9265A2BABE10B1A9AB9409EA3F0:1
+ 00D6F0319225107BD5736B72717BD381660:8
+ 01355DCE0B54F0E8DBBBA8F7B9A9872858A:15
+ 0163E1C872A64A62625F5EB2F3807B7F90B:2
+ 020DDE278E6A9C05B356C929F254CE6AED5:1
+ 021EFB4FAE348050D9EDCD10F8B6A87C957:4
+ ...
+ ```
+
+ If the `prefix` and `suffix` form a complete SHA-1 hash for the password being compared, then it
+ indicates the password has been found in the HIBP database.
+
+ :param hash_prefix: The first five characters of a SHA-1 hash. `str` type.
+ :return: A list of hash suffixes.
+ :rtype: list
+ """
+ if not hash_prefix or not isinstance(hash_prefix, six.string_types):
+ raise AttributeError("hash_prefix must be a supplied, and be a string-type.")
+ if hash_prefix and len(hash_prefix) != 5:
+ raise AttributeError("hash_prefix must be of length 5.")
+
+ uri = PWNED_PASSWORDS_API_BASE_URI + PWNED_PASSWORDS_API_ENDPOINT_RANGE_SEARCH + hash_prefix
+
+ resp = requests.get(url=uri, headers=pyhibp.pyHIBP_HEADERS)
+ if resp.status_code != 200:
+ # The HTTP Status should always be 200 for this request
+ raise RuntimeError("Response from the endpoint was not HTTP200; this should not happen. Code was: {0}".format(resp.status_code))
+ # The server response will have a BOM if we don't do this.
+ resp.encoding = RESPONSE_ENCODING
+
+ return resp.text.split()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/src/pyhibp.egg-info/PKG-INFO new/pyhibp-3.1.0/src/pyhibp.egg-info/PKG-INFO
--- old/pyhibp-3.0.0/src/pyhibp.egg-info/PKG-INFO 2018-11-10 02:56:39.000000000 +0100
+++ new/pyhibp-3.1.0/src/pyhibp.egg-info/PKG-INFO 2019-06-30 11:17:15.000000000 +0200
@@ -1,102 +1,102 @@
-Metadata-Version: 2.1
-Name: pyhibp
-Version: 3.0.0
-Summary: An interface to Troy Hunt's 'Have I Been Pwned' public API
-Home-page: https://gitlab.com/kitsunix/pyHIBP/pyHIBP
-Author: Kyra F. Kitsune
-License: UNKNOWN
-Description: pyHIBP (pyHave I Been Pwned)
- ============================
- [![image](https://img.shields.io/pypi/v/pyHIBP.svg)](https://pypi.org/project/pyHIBP/)
- [![image](https://img.shields.io/pypi/l/pyHIBP.svg)](https://pypi.org/project/pyHIBP/)
- [![image](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master)
-
-
- A Python interface to Troy Hunt's 'Have I Been Pwned?' (HIBP) public API. A full reference to the API
- specification can be found at the [HIBP API Reference](https://haveibeenpwned.com/API/v2).
-
- This module detects when the rate limit of the API has been hit, and raises a RuntimeError when the limit is exceeded,
- or when another API-defined error condition is encountered based on the submitted data. Calls
- to the module returning Boolean `True` or the object as decoded from the API query (currently, lists), represent
- a detection that a breached account/paste/password was found; Boolean `False` means that the item was not found.
-
- Note that the `pwnedpasswords` API backend does not have a rate limit. If you are intending to bulk-query passwords or
- hashes, you may also consider downloading the raw data files accessible via the [Pwned Passwords](https://haveibeenpwned.com/Passwords) page.
-
- Installing
- ----------
- ```bash
- $ pip install pyhibp
- ```
-
- Example usage
- -------------
- For an interactive example, check out the Jupyter Notebook for [`pyhibp`](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master?filepath...),
- as well as [`pyhibp.pwnedpasswords`](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master?filepath...).
-
- ```python
- import pyhibp
- from pyhibp import pwnedpasswords as pw
-
- # Check a password to see if it has been disclosed in a public breach corpus
- resp = pw.is_password_breached(password="secret")
- if resp:
- print("Password breached!")
- print("This password was used {0} time(s) before.".format(resp))
-
- # Get breaches that affect a given account
- resp = pyhibp.get_account_breaches(account="test@example.com", truncate_response=True)
-
- # Get all breach information
- resp = pyhibp.get_all_breaches()
-
- # Get a single breach
- resp = pyhibp.get_single_breach(breach_name="Adobe")
-
- # Get pastes affecting a given email address
- resp = pyhibp.get_pastes(email_address="test@example.com")
-
- # Get data classes in the HIBP system
- resp = pyhibp.get_data_classes()
- ```
-
- Developing
- ----------
- This project is currently intended to be compatible with Python 2 and Python 3. As such, we use virtual environments via `pipenv`.
- To develop or test, execute the following:
-
- ```bash
- # Install the prerequisite virtual environment provider
- $ pip install pipenv
- # Initialize the pipenv environment and install the module within it
- $ make dev
- # To run PEP8, tests, and check the manifest
- $ make tox
- ```
-
- Other commands can be found in the `Makefile`.
-
- Goals
- -----
- - Synchronize to the latest HIBP API(s), implementing endpoint accessing functions where it makes sense. For instance,
- in the interest of security, the ability to submit a SHA-1 to the Pwned Passwords endpoint is not implemented. See
- "Regarding password checking" below for further details.
- - For breaches and pastes, act as an intermediary; return the JSON as received from the service.
-
- Regarding password checking
- ---------------------------
- - For passwords, the option to supply a plaintext password to check is provided as an implementation convenience.
- - For added security, `pwnedpasswords.is_password_breached()` only transmits the first five characters of the SHA-1
- hash to the Pwned Passwords API endpoint; a secure password will remain secure without disclosing the full hash.
-
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
-Classifier: Intended Audience :: Developers
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.5
-Description-Content-Type: text/markdown
-Provides-Extra: dev
+Metadata-Version: 2.1
+Name: pyhibp
+Version: 3.1.0
+Summary: An interface to Troy Hunt's 'Have I Been Pwned' public API
+Home-page: https://gitlab.com/kitsunix/pyHIBP/pyHIBP
+Author: Kyra F. Kitsune
+License: UNKNOWN
+Description: pyHIBP (pyHave I Been Pwned)
+ ============================
+ [![image](https://img.shields.io/pypi/v/pyHIBP.svg)](https://pypi.org/project/pyHIBP/)
+ [![image](https://img.shields.io/pypi/l/pyHIBP.svg)](https://pypi.org/project/pyHIBP/)
+ [![image](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master)
+
+
+ A Python interface to Troy Hunt's 'Have I Been Pwned?' (HIBP) public API. A full reference to the API
+ specification can be found at the [HIBP API Reference](https://haveibeenpwned.com/API/v2).
+
+ This module detects when the rate limit of the API has been hit, and raises a RuntimeError when the limit
+ is exceeded, or when another API-defined error condition is encountered based on the submitted data. When
+ data is found from a call, the data returned will be in the format as retrieved from the endpoint, documented
+ in the return-type information for the relevant function.
+
+ Note that the `pwnedpasswords` API backend does not have a rate limit. If you are intending to bulk-query passwords or
+ hashes, you should consider downloading the raw data files accessible via the [Pwned Passwords](https://haveibeenpwned.com/Passwords) page.
+
+ Installing
+ ----------
+ ```bash
+ $ pip install pyhibp
+ ```
+
+ Example usage
+ -------------
+ For an interactive example, check out the Jupyter Notebook for [`pyhibp`](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master?filepath...),
+ as well as [`pyhibp.pwnedpasswords`](https://mybinder.org/v2/gl/kitsunix%2FpyHIBP%2FpyHIBP-binder/master?filepath...).
+
+ ```python
+ import pyhibp
+ from pyhibp import pwnedpasswords as pw
+
+ # Check a password to see if it has been disclosed in a public breach corpus
+ resp = pw.is_password_breached(password="secret")
+ if resp:
+ print("Password breached!")
+ print("This password was used {0} time(s) before.".format(resp))
+
+ # Get breaches that affect a given account
+ resp = pyhibp.get_account_breaches(account="test@example.com", truncate_response=True)
+
+ # Get all breach information
+ resp = pyhibp.get_all_breaches()
+
+ # Get a single breach
+ resp = pyhibp.get_single_breach(breach_name="Adobe")
+
+ # Get pastes affecting a given email address
+ resp = pyhibp.get_pastes(email_address="test@example.com")
+
+ # Get data classes in the HIBP system
+ resp = pyhibp.get_data_classes()
+ ```
+
+ Developing
+ ----------
+ This project is currently intended to be compatible with Python 2 and Python 3. As such, we use virtual environments via `pipenv`.
+ To develop or test, execute the following:
+
+ ```bash
+ # Install the prerequisite virtual environment provider
+ $ pip install pipenv
+ # Initialize the pipenv environment and install the module within it
+ $ make dev
+ # To run PEP8, tests, and check the manifest
+ $ make tox
+ ```
+
+ Other commands can be found in the `Makefile`.
+
+ Goals
+ -----
+ - Synchronize to the latest HIBP API(s), implementing endpoint accessing functions where it makes sense. For instance,
+ in the interest of security, the ability to submit a SHA-1 to the Pwned Passwords endpoint is not implemented. See
+ "Regarding password checking" below for further details.
+ - For breaches and pastes, act as an intermediary; return the JSON as received from the service.
+
+ Regarding password checking
+ ---------------------------
+ - For passwords, the option to supply a plaintext password to check is provided as an implementation convenience.
+ - For added security, `pwnedpasswords.is_password_breached()` only transmits the first five characters of the SHA-1
+ hash to the Pwned Passwords API endpoint; a secure password will remain secure without disclosing the full hash.
+
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Description-Content-Type: text/markdown
+Provides-Extra: dev
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/test/conftest.py new/pyhibp-3.1.0/test/conftest.py
--- old/pyhibp-3.0.0/test/conftest.py 2018-11-10 01:39:46.000000000 +0100
+++ new/pyhibp-3.1.0/test/conftest.py 2019-06-30 10:46:02.000000000 +0200
@@ -1,3 +1,5 @@
+import time
+
import pytest
import pyhibp
@@ -7,3 +9,16 @@
def dev_user_agent(monkeypatch):
ua_string = pyhibp.pyHIBP_USERAGENT
monkeypatch.setattr(pyhibp, 'pyHIBP_USERAGENT', ua_string + " (Testing Suite)")
+
+
+@pytest.fixture(name="sleep")
+def sleep_test(request):
+ """
+ For the endpoints where a rate limit is specified, or we want to be kind to the endpoint and not
+ needlessly execute requests too quickly, this specifies a test module-configurable sleep duration.
+
+ Usage: Specify a module-level variable named `_PYTEST_SLEEP_DURATION`, and the value is an int,
+ specifying the number of seconds to sleep between test invocations.
+ """
+ sleep_duration = getattr(request.module, "_PYTEST_SLEEP_DURATION", 0)
+ time.sleep(sleep_duration)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/test/test_pwnedpasswords.py new/pyhibp-3.1.0/test/test_pwnedpasswords.py
--- old/pyhibp-3.0.0/test/test_pwnedpasswords.py 2018-11-10 01:39:46.000000000 +0100
+++ new/pyhibp-3.1.0/test/test_pwnedpasswords.py 2019-06-30 10:46:02.000000000 +0200
@@ -1,10 +1,11 @@
import hashlib
-import time
import pytest
from pyhibp import pwnedpasswords as pw
+# While the pwnedpasswords endpoint does not have a limit, be kind anyway. 1 second sleep.
+_PYTEST_SLEEP_DURATION = 1
TEST_PASSWORD = "password"
TEST_PASSWORD_SHA1_HASH = hashlib.sha1(TEST_PASSWORD.encode('utf-8')).hexdigest()
@@ -13,18 +14,12 @@
TEST_PASSWORD_LIKELY_NOT_COMPROMISED_HASH = hashlib.sha1(TEST_PASSWORD_LIKELY_NOT_COMPROMISED.encode('utf-8')).hexdigest()
-@pytest.fixture(autouse=True)
-def rate_limit():
- # There's no rate limit on passwords, but be nice anyway.
- time.sleep(1)
-
-
class TestIsPasswordBreached(object):
def test_no_params_provided_raises(self):
# is_password_breached(password=None, first_5_hash_chars=None, sha1_hash=None):
with pytest.raises(AttributeError) as execinfo:
pw.is_password_breached()
- assert "One of password, first_5_hash_chars, or sha1_hash must be provided." in str(execinfo.value)
+ assert "One of password, sha1_hash, or first_5_hash_chars must be provided." in str(execinfo.value)
def test_password_not_string_raises(self):
# is_password_breached(password=123, first_5_hash_chars=None, sha1_hash=None):
@@ -33,12 +28,14 @@
assert "password must be a string type." in str(execinfo.value)
def test_first_5_hash_chars_not_string_raises(self):
+ # TODO: Deprecated: To be removed in next major release in favor of pw.suffix_search()
# is_password_breached(password=None, first_5_hash_chars=123, sha1_hash=None):
with pytest.raises(AttributeError) as execinfo:
pw.is_password_breached(first_5_hash_chars=123)
assert "first_5_hash_chars must be a string type." in str(execinfo.value)
def test_first_5_hash_chars_not_length_five_raises(self):
+ # TODO: Deprecated: To be removed in next major release in favor of pw.suffix_search()
# is_password_breached(password=None, first_5_hash_chars="123456", sha1_hash=None):
with pytest.raises(AttributeError) as execinfo:
pw.is_password_breached(first_5_hash_chars="123456")
@@ -50,7 +47,9 @@
pw.is_password_breached(sha1_hash=123)
assert "sha1_hash must be a string type." in str(execinfo.value)
+ @pytest.mark.usefixtures('sleep')
def test_list_of_partial_hashes_returned_with_5chars(self):
+ # TODO: Deprecated: To be removed in next major release in favor of pw.suffix_search()
# is_password_breached(password=None, first_5_hash_chars=TEST_PASSWORD_SHA1_HASH[0:5], sha1_hash=None):
resp = pw.is_password_breached(first_5_hash_chars=TEST_PASSWORD_SHA1_HASH[0:5])
assert isinstance(resp, list)
@@ -62,11 +61,13 @@
break
assert match_found
+ @pytest.mark.usefixtures('sleep')
def test_provide_password_to_function(self):
resp = pw.is_password_breached(password="password")
assert isinstance(resp, int)
assert resp > 100
+ @pytest.mark.usefixtures('sleep')
def test_ensure_case_sensitivity_of_hash_does_not_matter(self):
resp_one = pw.is_password_breached(sha1_hash=TEST_PASSWORD_SHA1_HASH.lower())
assert isinstance(resp_one, int)
@@ -78,7 +79,44 @@
assert resp_one == resp_two
+ @pytest.mark.usefixtures('sleep')
def test_zero_count_result_for_non_breached_password(self):
resp = pw.is_password_breached(password=TEST_PASSWORD_LIKELY_NOT_COMPROMISED)
assert isinstance(resp, int)
assert resp == 0
+
+
+class TestSuffixSearch(object):
+ def test_no_param_provided_raises(self):
+ # def suffix_search(hash_prefix=None):
+ with pytest.raises(AttributeError) as execinfo:
+ pw.suffix_search()
+ assert "hash_prefix must be a supplied, and be a string-type." in str(execinfo.value)
+
+ def test_hash_prefix_not_string_raises(self):
+ # def suffix_search(hash_prefix=123):
+ with pytest.raises(AttributeError) as execinfo:
+ pw.suffix_search(hash_prefix=123)
+ assert "hash_prefix must be a supplied, and be a string-type." in str(execinfo.value)
+
+ def test_first_5_hash_chars_not_length_five_raises(self):
+ # suffix_search(hash_prefix="123456"):
+ with pytest.raises(AttributeError) as execinfo:
+ pw.suffix_search(hash_prefix="123456")
+ assert "hash_prefix must be of length 5." in str(execinfo.value)
+
+ @pytest.mark.usefixtures('sleep')
+ def test_list_of_hashes_returned(self):
+ """
+ Test all parameters: The response format for all parameters is the same.
+ """
+ resp = pw.suffix_search(hash_prefix=TEST_PASSWORD_SHA1_HASH[0:5])
+
+ assert isinstance(resp, list)
+ assert len(resp) > 100
+ match_found = False
+ for entry in resp:
+ if TEST_PASSWORD_SHA1_HASH[5:] in entry.lower():
+ match_found = True
+ break
+ assert match_found
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/test/test_pyHIBP.py new/pyhibp-3.1.0/test/test_pyHIBP.py
--- old/pyhibp-3.0.0/test/test_pyHIBP.py 2018-11-10 01:39:46.000000000 +0100
+++ new/pyhibp-3.1.0/test/test_pyHIBP.py 2019-06-30 10:46:02.000000000 +0200
@@ -1,4 +1,3 @@
-import time
import uuid
import pytest
@@ -6,6 +5,9 @@
import pyhibp
+# The breach/paste endpoints enforce a 1500 ms rate limit; so sleep 2 seconds.
+_PYTEST_SLEEP_DURATION = 2
+
TEST_ACCOUNT = "test@example.com"
TEST_DOMAIN = "adobe.com"
TEST_DOMAIN_NAME = "Adobe"
@@ -13,13 +15,8 @@
TEST_NONEXISTENT_ACCOUNT_NAME = "353e8061f2befecb6818ba0c034c632fb0bcae1b"
-@pytest.fixture(autouse=True)
-def rate_limit():
- # The HIBP API has a rate-limit of 1500ms. Sleep for 2 seconds between each test.
- time.sleep(2)
-
-
-class TestGetBreaches(object):
+class TestGetAccountBreaches(object):
+ @pytest.mark.usefixtures('sleep')
def test_get_breaches_account(self):
# get_account_breaches(account=TEST_ACCOUNT, domain=None, truncate_response=False, include_unverified=False):
resp = pyhibp.get_account_breaches(account=TEST_ACCOUNT)
@@ -28,6 +25,7 @@
assert len(resp) >= 20
assert isinstance(resp[0], dict)
+ @pytest.mark.usefixtures('sleep')
def test_get_breaches_account_with_domain(self):
# get_account_breaches(account=TEST_ACCOUNT, domain=TEST_DOMAIN, truncate_response=False, include_unverified=False):
resp = pyhibp.get_account_breaches(account=TEST_ACCOUNT, domain=TEST_DOMAIN)
@@ -37,6 +35,7 @@
assert isinstance(resp[0], dict)
assert resp[0]['Name'] == TEST_DOMAIN_NAME
+ @pytest.mark.usefixtures('sleep')
def test_get_breaches_account_with_truncation(self):
# get_account_breaches(account=TEST_ACCOUNT, domain=None, truncate_response=True, include_unverified=False):
resp = pyhibp.get_account_breaches(account=TEST_ACCOUNT, truncate_response=True)
@@ -49,6 +48,7 @@
assert 'Name' in item
assert 'DataClasses' not in item
+ @pytest.mark.usefixtures('sleep')
def test_get_breaches_retrieve_all_breaches_with_unverified(self):
# get_account_breaches(account=TEST_ACCOUNT, domain=None, truncate_response=False, include_unverified=True):
resp = pyhibp.get_account_breaches(account=TEST_ACCOUNT, include_unverified=True)
@@ -62,11 +62,15 @@
break
assert has_unverified
+ @pytest.mark.usefixtures('sleep')
def test_get_breaches_return_false_if_no_accounts(self):
# get_account_breaches(account=TEST_PASSWORD_SHA1_HASH, domain=None, truncate_response=False, include_unverified=False):
resp = pyhibp.get_account_breaches(account=TEST_NONEXISTENT_ACCOUNT_NAME)
assert not resp
assert isinstance(resp, bool)
+ # TODO: v4.0.0:
+ # assert not resp
+ # assert isinstance(resp, list)
def test_get_breaches_raise_if_account_is_not_specified(self):
# get_account_breaches(account=1, domain=None, truncate_response=False, include_unverified=False):
@@ -91,6 +95,7 @@
class TestGetAllBreaches(object):
+ @pytest.mark.usefixtures('sleep')
def test_get_all_breaches(self):
# def get_all_breaches(domain=None):
resp = pyhibp.get_all_breaches()
@@ -98,6 +103,7 @@
assert len(resp) > 50
assert isinstance(resp[0], dict)
+ @pytest.mark.usefixtures('sleep')
def test_get_all_breaches_filter_to_domain(self):
# def get_all_breaches(domain=TEST_DOMAIN):
resp = pyhibp.get_all_breaches(domain=TEST_DOMAIN)
@@ -107,10 +113,14 @@
assert isinstance(resp[0], dict)
assert resp[0]['Name'] == TEST_DOMAIN_NAME
+ @pytest.mark.usefixtures('sleep')
def test_get_all_breaches_false_if_domain_does_not_exist(self):
resp = pyhibp.get_all_breaches(domain=TEST_NONEXISTENT_ACCOUNT_NAME)
assert not resp
assert isinstance(resp, bool)
+ # TODO: v4.0.0:
+ # assert not resp
+ # assert isinstance(resp, list)
def test_get_all_breaches_raise_if_not_string(self):
# def get_all_breaches(domain=1):
@@ -121,17 +131,22 @@
class TestGetSingleBreach(object):
+ @pytest.mark.usefixtures('sleep')
def test_get_single_breach(self):
# get_single_breach(breach_name=TEST_DOMAIN_NAME)
resp = pyhibp.get_single_breach(breach_name=TEST_DOMAIN_NAME)
assert isinstance(resp, dict)
assert resp['Name'] == TEST_DOMAIN_NAME
+ @pytest.mark.usefixtures('sleep')
def test_get_single_breach_when_breach_does_not_exist(self):
# get_single_breach(breach_name="ThisShouldNotExist")
resp = pyhibp.get_single_breach(breach_name="ThisShouldNotExist")
# Boolean False will be returned from the above (as there is no breach named what we gave it).
assert not resp
+ # TODO: v4.0.0:
+ # assert not resp
+ # assert isinstance(resp, dict)
def test_get_single_breach_raise_when_breach_name_not_specified(self):
# get_single_breach()
@@ -149,6 +164,7 @@
class TestGetPastes(object):
+ @pytest.mark.usefixtures('sleep')
def test_get_pastes(self):
# get_pastes(email_address=TEST_ACCOUNT):
resp = pyhibp.get_pastes(email_address=TEST_ACCOUNT)
@@ -162,7 +178,11 @@
resp = pyhibp.get_pastes(email_address=TEST_NONEXISTENT_ACCOUNT_NAME + "@example.invalid")
assert not resp
assert isinstance(resp, bool)
+ # TODO: v4.0.0:
+ # assert not resp
+ # assert isinstance(resp, list)
+ @pytest.mark.usefixtures('sleep')
def test_get_pastes_raise_if_email_not_specified(self):
# get_pastes():
with pytest.raises(AttributeError) as excinfo:
@@ -177,6 +197,7 @@
class TestGetDataClasses(object):
+ @pytest.mark.usefixtures('sleep')
def test_get_data_classes(self):
# get_data_classes():
resp = pyhibp.get_data_classes()
@@ -187,6 +208,7 @@
class TestMiscellaneous(object):
@pytest.mark.xfail(reason="The rate limit exists in the API docs, but responses are cached, and even attempting to manually (via browser) hit the limit isn't happening.")
+ @pytest.mark.usefixtures('sleep')
def test_raise_if_rate_limit_exceeded(self):
""" The API will respond the same to all exceeded rate limits across all endpoints """
# The rate limit exists, however all responses are cached; so we need to generate some random "accounts".
@@ -197,6 +219,7 @@
pyhibp.get_account_breaches(account=item, truncate_response=True)
assert "HTTP 429" in str(excinfo.value)
+ @pytest.mark.usefixtures('sleep')
def test_raise_if_useragent_is_not_set(self, monkeypatch):
# This should never be encountered normally, since we have the module-level variable/constant;
# That said, test it, since we can, and since we might as well cover the line of code.
@@ -206,6 +229,7 @@
pyhibp.get_account_breaches(account="{0}@test-suite.pyhibp.example.com".format(str(uuid.uuid4())))
assert "HTTP 403" in str(excinfo.value)
+ @pytest.mark.usefixtures('sleep')
def test_raise_if_invalid_format_submitted(self):
# For example, if a null (0x00) character is submitted to an endpoint.
with pytest.raises(RuntimeError) as execinfo:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyhibp-3.0.0/tox.ini new/pyhibp-3.1.0/tox.ini
--- old/pyhibp-3.0.0/tox.ini 2018-11-10 01:39:46.000000000 +0100
+++ new/pyhibp-3.1.0/tox.ini 2019-06-30 10:46:02.000000000 +0200
@@ -1,11 +1,12 @@
[tox]
-envlist = py{27,35,36}
+envlist = py{27,35,36,37}
[testenv]
basepython =
py27: python2.7
py35: python3.5
py36: python3.6
+ py37: python3.7
passenv =
TOXENV
PIP_CACHE_DIR