Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
78b38a25b9 | ||
|
bfb35b2517 | ||
|
b1fb5f34cc | ||
|
8cfba9eb4d |
2
build.sh
Normal file → Executable file
2
build.sh
Normal file → Executable file
@ -2,4 +2,4 @@
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
pyinstaller --distpath=../dist --workpath=../build ../src/have_I_b33n_pwned.py
|
||||
pyinstaller --distpath=../dist --workpath=../build -y ../src/have_I_b33n_pwned.py
|
||||
|
145
src/have_I_b33n_pwned.py
Normal file → Executable file
145
src/have_I_b33n_pwned.py
Normal file → Executable file
@ -21,82 +21,83 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# updater script for nextcloud
|
||||
#
|
||||
# TODO
|
||||
#TODO
|
||||
# - add feature: keepass integration? isnt there something like this already?
|
||||
# - handle mail API exeption more precisely
|
||||
|
||||
|
||||
from os import name
|
||||
from sys import argv, stdout, exit
|
||||
from re import match
|
||||
from argparse import ArgumentParser
|
||||
from hashlib import sha1
|
||||
from getpass import getpass
|
||||
from requests import get
|
||||
import requests
|
||||
|
||||
|
||||
RED = "\033[1;31m"
|
||||
GREEN = "\033[0;32m"
|
||||
RESET = "\033[0;0m"
|
||||
API = 'https://api.pwnedpasswords.com/range/'
|
||||
API_MAIL = 'https://haveibeenpwned.com/api/v2/breachedaccount/'
|
||||
ROW = '{:<30}{:<10}{:<45}'
|
||||
HIDDEN = False
|
||||
if name == 'nt': # disable colors for windows environment
|
||||
(RED, GREEN, RESET) = ("", "", "")
|
||||
else:
|
||||
(RED, GREEN, RESET) = ("\033[1;31m", "\033[0;32m", "\033[0;0m")
|
||||
|
||||
PASSWORD_API = 'https://api.pwnedpasswords.com/range/'
|
||||
MAIL_API = 'https://haveibeenpwned.com/api/v2/breachedaccount/'
|
||||
ROW = '{:<30}{:<10}{:<45}'
|
||||
HIDDEN = True
|
||||
INFINITE = True
|
||||
|
||||
|
||||
parser = ArgumentParser(
|
||||
description='Check if your email or password appears in a data leak.',
|
||||
epilog='Moritz Münch, moritzmuench@mailbox.org, willipink.eu, GPL3+'
|
||||
)
|
||||
parser.add_argument('-m', '-mail', '--mail',
|
||||
metavar='foo@adress.bar',
|
||||
nargs='+',
|
||||
help='Email address which should be checked against the leak database.'
|
||||
)
|
||||
parser.add_argument('-p', '-password', '--password',
|
||||
metavar='password',
|
||||
nargs='+',
|
||||
help='Password which should be checked against the leak database.'
|
||||
)
|
||||
epilog='Moritz Münch, moritzmuench@mailbox.org, willipink.eu, GPL3+')
|
||||
parser.add_argument('input',
|
||||
nargs='*',
|
||||
metavar='password or mail adress',
|
||||
help='''You can specify passwords and mail adresses seperated by spaces.
|
||||
If the password contains a space you have to enclose it in quotes like ' or
|
||||
"''')
|
||||
parser.add_argument('-s', '-show', '--show',
|
||||
nargs='?',
|
||||
help='Show entered in leak summary')
|
||||
args = parser.parse_args()
|
||||
if args.show:
|
||||
HIDDEN = False
|
||||
|
||||
|
||||
|
||||
def header():
|
||||
print()
|
||||
print(ROW.format('password', 'leaked', 'sha1'))
|
||||
print('-' * 80)
|
||||
|
||||
|
||||
def prompt_password_or_mail():
|
||||
print()
|
||||
while True:
|
||||
choice = input('Do you wannt to check a password [p] or an email adress [e]: ')
|
||||
if choice == 'p':
|
||||
prompt_password()
|
||||
elif choice == 'e':
|
||||
prompt_mail()
|
||||
|
||||
|
||||
def prompt_password():
|
||||
print()
|
||||
password = getpass('Tell me your password: ')
|
||||
def input_prompt():
|
||||
global HIDDEN
|
||||
HIDDEN = True
|
||||
header()
|
||||
query_password(password)
|
||||
if HIDDEN:
|
||||
user_input = getpass('Tell me your password or mail adress: ')
|
||||
else:
|
||||
user_input = input('Tell me your password or mail adress: ')
|
||||
check_mail_or_password(user_input)
|
||||
|
||||
|
||||
def prompt_mail():
|
||||
print()
|
||||
mail = input('Tell me your mail adress: ')
|
||||
global HIDDEN
|
||||
HIDDEN = True
|
||||
header()
|
||||
query_mail(mail)
|
||||
def check_mail_or_password(user_input):
|
||||
valid_mail = match(r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$', user_input)
|
||||
if valid_mail:
|
||||
query_mail(valid_mail.group())
|
||||
else:
|
||||
query_password(user_input)
|
||||
|
||||
|
||||
def no_connection_to(url):
|
||||
''' Warn about no connection to *url* and exit '''
|
||||
stdout.write(RED)
|
||||
print('Could not connect to {}, please check your internet connection'.format(url))
|
||||
stdout.write(RESET)
|
||||
exit(1)
|
||||
|
||||
|
||||
def query_password(password):
|
||||
''' Query the first 5 digits of the sha1 hash of the user input
|
||||
ti the haveibeenpwned.com api. '''
|
||||
password_hash = sha1(password.encode('UTF-8')).hexdigest().upper()
|
||||
request = password_hash[:5]
|
||||
response = get(API + request).text
|
||||
try:
|
||||
response = requests.get(PASSWORD_API + request).text
|
||||
except requests.exceptions.ConnectionError:
|
||||
no_connection_to(PASSWORD_API)
|
||||
hash_searched = 'not yet'
|
||||
for answer in response.splitlines():
|
||||
data = answer.split(':')
|
||||
@ -104,26 +105,23 @@ def query_password(password):
|
||||
if password_hash == combined_hash:
|
||||
hash_searched = int(data[1])
|
||||
break
|
||||
|
||||
if hash_searched == 'not yet':
|
||||
stdout.write(GREEN)
|
||||
else:
|
||||
stdout.write(RED)
|
||||
|
||||
if HIDDEN:
|
||||
password = '*' * len(password)
|
||||
|
||||
print(ROW.format('password', 'leaked', 'sha1'))
|
||||
print('-' * 80)
|
||||
print(ROW.format(password, hash_searched, password_hash))
|
||||
stdout.write(RESET)
|
||||
|
||||
if HIDDEN:
|
||||
prompt_password_or_mail()
|
||||
if INFINITE:
|
||||
input_prompt()
|
||||
|
||||
|
||||
def query_mail(mail):
|
||||
print()
|
||||
try:
|
||||
response = get(API_MAIL + mail).json()
|
||||
response = requests.get(MAIL_API + mail).json()
|
||||
for breach in response:
|
||||
print('Name: {}'.format(breach['Name']))
|
||||
print('Title: {}'.format(breach['Title']))
|
||||
@ -133,28 +131,27 @@ def query_mail(mail):
|
||||
print('Modified date: {}'.format(breach['ModifiedDate']))
|
||||
print('Pwn count: {}'.format(breach['PwnCount']))
|
||||
print('Description: {}'.format(breach['Description']))
|
||||
stdout.write(RED)
|
||||
print('Breached data: {}'.format(', '.join([data for data in breach['DataClasses']])))
|
||||
stdout.write(RESET)
|
||||
print('Verified: {}'.format('yes' if breach['IsVerified'] == 1 else 'No'))
|
||||
print('Fabricated: {}'.format('yes' if breach['IsFabricated'] == 1 else 'No'))
|
||||
print('Sensitive: {}'.format('yes' if breach['IsSensitive'] == 1 else 'No'))
|
||||
print('Retired: {}'.format('yes' if breach['IsRetired'] == 1 else 'No'))
|
||||
print('Spam: {}'.format('yes' if breach['IsSpamList'] == 1 else 'No'))
|
||||
except requests.exceptions.ConnectionError:
|
||||
no_connection_to(MAIL_API)
|
||||
except:
|
||||
print('The mail adress {} was not found in any leak databases so far'.format(mail))
|
||||
|
||||
if HIDDEN:
|
||||
prompt_password_or_mail()
|
||||
stdout.write(GREEN)
|
||||
print('The mail adress {} is not in the leak database.'.format(mail))
|
||||
stdout.write(RESET)
|
||||
query_password(mail)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if args.password:
|
||||
header()
|
||||
for password in args.password:
|
||||
query_password(password)
|
||||
elif args.mail:
|
||||
for mail in args.mail:
|
||||
query_mail(mail)
|
||||
if args.input:
|
||||
for user_input in args.input:
|
||||
check_mail_or_password(user_input)
|
||||
else:
|
||||
prompt_password_or_mail()
|
||||
print()
|
||||
exit(0)
|
||||
INFINITE = True
|
||||
input_prompt()
|
||||
|
Loading…
x
Reference in New Issue
Block a user