├── .gitignore ├── .travis.yml ├── AUTHORS.rst ├── CHANGES.rst ├── LICENSE.rst ├── MANIFEST.in ├── README.md ├── pypwned └── __init__.py ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | MANIFEST 22 | 23 | # Installer logs 24 | pip-log.txt 25 | 26 | # Unit test / coverage reports 27 | .coverage 28 | .tox 29 | nosetests.xml 30 | 31 | # Translations 32 | *.mo 33 | 34 | # Mr Developer 35 | .mr.developer.cfg 36 | .project 37 | .pydevproject 38 | 39 | # IntelliJ 40 | .idea/ 41 | *.iml 42 | 43 | # OSX 44 | .DS_Store 45 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | script: nosetests 3 | deploy: 4 | provider: pypi 5 | user: icanhasfay 6 | password: 7 | secure: EMyK2IGeHFptopbjH+L1iIfXdFLzT7TuB23p46YLKE4zX2Z9yNcNcXmq/3kjiKs6B7vul+5KaDyO3qEOOj0DedXyyPK0AAddBy8MSYfKw7dJEFKbpdJfGFuFgFzHQvjCSqOnEcQs6HsLoxRA1zLxqado6zBIkKT42X8tM20GzIg= 8 | on: 9 | repo: icanhasfay/PyPwned 10 | tags: true 11 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | - Eric Fay @icanhasfay -------------------------------------------------------------------------------- /CHANGES.rst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanhasfay/PyPwned/f10202e96b3a7d4d3128812039db30f16227d2c1/CHANGES.rst -------------------------------------------------------------------------------- /LICENSE.rst: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Eric Fay @icanhasfay 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md CHANGES.rst AUTHORS.rst LICENSE.rst 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PyPwned 2 | ====== 3 | [![Build Status](https://travis-ci.org/icanhasfay/PyPwned.svg)](https://travis-ci.org/icanhasfay/PyPwned) 4 | 5 | A Python client for the HaveIBeenPwned REST API. https://haveibeenpwned.com/ 6 | 7 | Installation 8 | ----- 9 | ```pip install pypwned``` 10 | 11 | Requires 12 | ----- 13 | * requests 14 | * pyOpenSSL 15 | * ndg-httpsclient 16 | * pyasn1 17 | 18 | Usage 19 | ----- 20 | > Note: The below examples assume you have loaded the envrionment variable HIBP_API_KEY with your appropriate Have I Been Pwned API key. 21 | More details here, https://haveibeenpwned.com/API/Key. 22 | 23 | ### Breaches 24 | 25 | 26 | #### Getting all breaches for an account 27 | 28 | ##### Get all breaches for an account across all domains. 29 | 30 | ``` 31 | import pypwned, os 32 | your_hibp_key = os.environ.get("HIBP_API_KEY") 33 | pwny = pypwned.pwned(your_hibp_key) 34 | pwny.getAllBreachesForAccount(email="foo@bar.com") 35 | ``` 36 | 37 | ##### Get all breaches for an account across a specific domain. 38 | 39 | ``` 40 | import pypwned, os 41 | your_hibp_key = os.environ.get("HIBP_API_KEY") 42 | pwny = pypwned.pwned(your_hibp_key) 43 | pwny.getAllBreachesForAccount(email="foo@bar.com",domain="adobe.com") 44 | ``` 45 | 46 | 47 | #### Getting all breached sites in the system 48 | 49 | ##### Return the details of each breach in the system. 50 | 51 | ``` 52 | import pypwned, os 53 | your_hibp_key = os.environ.get("HIBP_API_KEY") 54 | pwny = pypwned.pwned(your_hibp_key) 55 | pwny.getAllBreaches() 56 | ``` 57 | 58 | ##### Return the details of each breach associated with a specific domain. 59 | 60 | ``` 61 | import pypwned, os 62 | your_hibp_key = os.environ.get("HIBP_API_KEY") 63 | pwny = pypwned.pwned(your_hibp_key) 64 | pwny.getAllBreaches(domain="adobe.com") 65 | ``` 66 | 67 | #### Getting a single breached site 68 | 69 | Return the details of a single breach, by breach name. 70 | 71 | ``` 72 | import pypwned, os 73 | your_hibp_key = os.environ.get("HIBP_API_KEY") 74 | pwny = pypwned.pwned(your_hibp_key) 75 | pwny.getSingleBreachedSite(name="adobe") 76 | ``` 77 | 78 | #### Getting all data classes in the system 79 | 80 | Return the different types of data classes that are associated with a record in a breach. E.G, Email addresses and passwords 81 | 82 | ``` 83 | import pypwned, os 84 | your_hibp_key = os.environ.get("HIBP_API_KEY") 85 | pwny = pypwned.pwned(your_hibp_key) 86 | pwny.getAllDataClasses() 87 | ``` 88 | 89 | ### Pastes 90 | 91 | 92 | #### Getting all pastes for an account 93 | 94 | Return any pastes that contain the given email address 95 | 96 | ``` 97 | import pypwned, os 98 | your_hibp_key = os.environ.get("HIBP_API_KEY") 99 | pwny = pypwned.pwned(your_hibp_key) 100 | pwny.getAllPastesForAccount(account="foo@bar.com") 101 | ``` 102 | 103 | -------------------------------------------------------------------------------- /pypwned/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Eric Fay' 2 | __version__ = "1.0.0" 3 | 4 | 5 | import requests 6 | import json 7 | import re 8 | 9 | baseAPIURL = "https://haveibeenpwned.com/api/v3/" 10 | 11 | fourHundredString = "400 - Bad request - the account does not comply with an acceptable format (i.e. it's an empty string)" 12 | fourOThreeString = "403 - Forbidden - no user agent has been specified in the request" 13 | fourOFourString = "404 - Not found - the account could not be found and has therefore not been pwned" 14 | fourTwentyNineString = "Rate limit exceeded, refer to acceptable use of the API: https://haveibeenpwned.com/API/v2#AcceptableUse" 15 | fiveHundredString = "A server error occurred on haveibeenpwned.com. Please try again later." 16 | emailFormatString = "The provided string is not an email address" 17 | 18 | class pwned: 19 | 20 | def __init__(self,key): 21 | self.API_KEY = key 22 | self.headers = {'hibp-api-key': self.API_KEY} 23 | 24 | def getAllBreachesForAccount(self, email, domain=""): 25 | # Pattern is a derivation of RFC-5322 26 | # Grabbed from http://emailregex.com/ 27 | pattern = re.compile(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)") 28 | if not pattern.match(email): 29 | return emailFormatString 30 | urlEndpoint = "breachedaccount/" 31 | if domain == "": 32 | urlToFetch = baseAPIURL+urlEndpoint+email 33 | r = requests.get(urlToFetch, verify=True, headers=self.headers) 34 | if r.status_code == 400: 35 | return fourHundredString 36 | elif r.status_code == 403: 37 | return fourOThreeString 38 | elif r.status_code == 404: 39 | return fourOFourString 40 | elif r.status_code == 429: 41 | return fourTwentyNineString 42 | elif r.status_code >= 500: 43 | return fiveHundredString 44 | else: 45 | return r.json() 46 | else: 47 | domainParams = "?domain="+domain 48 | urlToFetch = baseAPIURL+urlEndpoint+email+domainParams 49 | r = requests.get(urlToFetch, verify=True, headers=self.headers) 50 | if r.status_code == 400: 51 | return fourHundredString 52 | elif r.status_code == 403: 53 | return fourOThreeString 54 | elif r.status_code == 404: 55 | return fourOFourString 56 | elif r.status_code == 429: 57 | return fourTwentyNineString 58 | elif r.status_code >= 500: 59 | return fiveHundredString 60 | else: 61 | return r.json() 62 | 63 | 64 | def getAllBreaches(self, domain=""): 65 | urlEndpoint = "breaches/" 66 | if domain == "": 67 | urlToFetch = baseAPIURL+urlEndpoint 68 | r = requests.get(urlToFetch, verify=True, headers=self.headers) 69 | return r.json() 70 | else: 71 | domainParams = "?domain="+domain 72 | urlToFetch = baseAPIURL+urlEndpoint+domainParams 73 | r = requests.get(urlToFetch, verify=True, headers=self.headers) 74 | if r.status_code == 400: 75 | return fourHundredString 76 | elif r.status_code == 403: 77 | return fourOThreeString 78 | elif r.status_code == 404: 79 | return fourOFourString 80 | elif r.status_code == 429: 81 | return fourTwentyNineString 82 | elif r.status_code >= 500: 83 | return fiveHundredString 84 | else: 85 | return r.json() 86 | 87 | 88 | def getSingleBreachedSite(self, name): 89 | urlEndpoint = "breach/" 90 | urlToFetch = baseAPIURL+urlEndpoint+name 91 | r = requests.get(urlToFetch, verify=True, headers=self.headers) 92 | if r.status_code == 400: 93 | return fourHundredString 94 | elif r.status_code == 403: 95 | return fourOThreeString 96 | elif r.status_code == 404: 97 | return fourOFourString 98 | elif r.status_code == 429: 99 | return fourTwentyNineString 100 | elif r.status_code >= 500: 101 | return fiveHundredString 102 | else: 103 | return r.json() 104 | 105 | 106 | def getAllDataClasses(self): 107 | urlEndpoint = "dataclasses/" 108 | urlToFetch = baseAPIURL+urlEndpoint 109 | r = requests.get(urlToFetch, verify=True, headers=self.headers) 110 | if r.status_code == 400: 111 | return fourHundredString 112 | elif r.status_code == 403: 113 | return fourOThreeString 114 | elif r.status_code == 404: 115 | return fourOFourString 116 | elif r.status_code == 429: 117 | return fourTwentyNineString 118 | elif r.status_code >= 500: 119 | return fiveHundredString 120 | else: 121 | return r.json() 122 | 123 | 124 | def getAllPastesForAccount(self, account): 125 | urlEndpoint = "pasteaccount/" 126 | urlToFetch = baseAPIURL+urlEndpoint+account 127 | r = requests.get(urlToFetch, verify=True, headers=self.headers) 128 | if r.status_code == 400: 129 | return fourHundredString 130 | elif r.status_code == 403: 131 | return fourOThreeString 132 | elif r.status_code == 404: 133 | return fourOFourString 134 | elif r.status_code == 429: 135 | return fourTwentyNineString 136 | elif r.status_code >= 500: 137 | return fiveHundredString 138 | else: 139 | return r.json() 140 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | pyOpenSSL 3 | ndg-httpsclient 4 | pyasn1 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name="pypwned", 5 | packages=["pypwned"], 6 | package_dir={"pypwned": "pypwned"}, 7 | version="1.0.0", 8 | description="A Python client for the HaveIBeenPwned REST API", 9 | long_description=open("README.md").read() + "\n\n" + open("CHANGES.rst").read(), 10 | author="Eric Fay", 11 | author_email="icanhasfay@gmail.com", 12 | url="https://github.com/icanhasfay/PyPwned", 13 | license="MIT", 14 | install_requires=["requests"], 15 | long_description_content_type="text/markdown", 16 | classifiers=( 17 | "Intended Audience :: Developers", 18 | "Intended Audience :: End Users/Desktop", 19 | "Intended Audience :: Financial and Insurance Industry", 20 | "Intended Audience :: Healthcare Industry", 21 | "Intended Audience :: Information Technology", 22 | "Intended Audience :: System Administrators", 23 | "Natural Language :: English", 24 | "License :: OSI Approved :: MIT License", 25 | "Operating System :: OS Independent", 26 | "Programming Language :: Python", 27 | "Programming Language :: Python :: 2", 28 | "Topic :: Security", 29 | ) 30 | ) 31 | --------------------------------------------------------------------------------