#!/usr/bin/env python3
|
|
|
|
class Colours:
|
|
HEADER = '\033[95m'
|
|
OKBLUE = '\033[94m'
|
|
OKGREEN = '\033[92m'
|
|
WARNING = '\033[93m'
|
|
FAIL = '\033[91m'
|
|
ENDC = '\033[0m'
|
|
BOLD = '\033[1m'
|
|
UNDERLINE = '\033[4m'
|
|
|
|
try:
|
|
import os
|
|
import re
|
|
import sys
|
|
import getopt
|
|
import requests
|
|
from clint.textui import progress
|
|
from bs4 import BeautifulSoup
|
|
except Exception as err:
|
|
print(Colours.FAIL + "Error: {}".format(err) + Colours.ENDC)
|
|
|
|
def Usage():
|
|
use_msg = '''
|
|
---------- Usage ----------
|
|
leak-lookup [options] [search term]
|
|
---------------------------
|
|
Options:
|
|
-h: Prints this help message
|
|
-p: Searches haveibeenpwned.com
|
|
-d: Searches for leaked database
|
|
---------------------------
|
|
'''
|
|
print(use_msg)
|
|
|
|
def DownloadDatabase(url, name):
|
|
try:
|
|
r = requests.get(url, stream=True)
|
|
with open(name, 'wb') as f:
|
|
total_length = int(r.headers.get('content-length'))
|
|
for chunk in progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1):
|
|
if chunk:
|
|
f.write(chunk)
|
|
f.flush()
|
|
except (KeyboardInterrupt, SystemExit, EOFError):
|
|
print(Colours.FAIL + "An error occurred, cleaning up" + Colours.ENDC)
|
|
os.remove(name)
|
|
|
|
def DatabaseQuery(database):
|
|
r = requests.get("https://www.databases.today/search-nojs.php?for=" + database)
|
|
if r.reason != "OK":
|
|
print(Colours.FAIL + "Error code: {}".format(r.status_code) + Colours.ENDC)
|
|
sys.exit(1)
|
|
soup = BeautifulSoup(r.text, "html.parser")
|
|
dbs = soup.find(id="myTable").find_all("tr")
|
|
entries = []
|
|
for table in dbs:
|
|
entry = table.find_all("td")
|
|
if len(entry) != 0:
|
|
entries.append([entry[0].text, entry[4].a.get("href")])
|
|
print("Which file would you like to download?")
|
|
for index, dllink in enumerate(entries):
|
|
print("{}) {}".format(index + 1, dllink[0]))
|
|
print("a) All")
|
|
print("q) Quit")
|
|
download_choice = input(">> ")
|
|
if download_choice == "q":
|
|
sys.exit(0)
|
|
elif download_choice == "a":
|
|
for x in dllink:
|
|
DownloadDatabase(x[1], x[0])
|
|
else:
|
|
try:
|
|
download_choice = int(download_choice) - 1
|
|
DownloadDatabase(dllink[1], dllink[0].split(" (")[0])
|
|
except:
|
|
print(Colours.FAIL + "Error: Invalid selection" + Colours.ENDC)
|
|
sys.exit(1)
|
|
|
|
|
|
def QueryHaveIBeenPwned(email):
|
|
r = requests.post("https://haveibeenpwned.com/", data={"Account": email})
|
|
if r.reason != "OK":
|
|
print(Colours.FAIL + "Error code: {}".format(r.status_code) + Colours.ENDC)
|
|
sys.exit(1)
|
|
soup = BeautifulSoup(r.text, "html.parser")
|
|
pwnCount = re.match("Pwned on \d+", soup.find(id="pwnCount").text)
|
|
if pwnCount == None:
|
|
print(Colours.OKGREEN + "{} has no public leaks".format(email) + Colours.ENDC)
|
|
return
|
|
print(Colours.FAIL + "{} has {} public leaks avalible".format(email, pwnCount.group().split(" ")[-1]) + Colours.ENDC)
|
|
leaks = []
|
|
for leak in soup.find_all(class_="pwnedWebsite"):
|
|
leak_name = None
|
|
leak_status = None
|
|
compromised_data = None
|
|
leak_name_html = leak.find(class_="pwnedCompanyTitle")
|
|
if leak_name_html:
|
|
if "(" in leak_name_html.text:
|
|
leak_name = leak_name_html.text.split(" (")[0]
|
|
leak_status = leak_name_html.text.split(" (")[1][:-2]
|
|
else:
|
|
leak_name = leak_name_html.text[:-1]
|
|
leak_status = None
|
|
compromised_data_html = leak.find(class_="dataClasses")
|
|
if compromised_data_html:
|
|
compromised_data = compromised_data_html.text
|
|
if leak_name:
|
|
leaks.append([leak_name, leak_status, compromised_data])
|
|
print("\nDownload databases:")
|
|
for index, leak in enumerate(leaks):
|
|
if leak[1] == None:
|
|
print("{}) {}: {}".format(index + 1, leak[0], leak[2]))
|
|
else:
|
|
print("{}) {} ({}): {}".format(index + 1, leak[0], leak[1], leak[2]))
|
|
print("a) Download all")
|
|
print("q) Quit")
|
|
download_choice = input(">> ")
|
|
if download_choice == "q":
|
|
sys.exit(0)
|
|
elif download_choice == "a":
|
|
for leak in leaks:
|
|
DatabaseQuery(leak[0])
|
|
try:
|
|
download_choice = int(download_choice) - 1
|
|
DatabaseQuery(leaks[download_choice][0])
|
|
except:
|
|
print(Colours.FAIL + "Error: Invalid selection" + Colours.ENDC)
|
|
sys.exit(1)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv[1:]) == 0:
|
|
Usage()
|
|
sys.exit(1)
|
|
try:
|
|
options, remainder = getopt.getopt(sys.argv[1:],'hpd',['h', 'p','d',])
|
|
except getopt.GetoptError as err:
|
|
print(Colours.FAIL + "Error: {}".format(err) + Colours.ENDC)
|
|
sys.exit(1)
|
|
|
|
for opt, arg in options:
|
|
if opt == "-h":
|
|
Usage()
|
|
sys.exit(0)
|
|
elif opt == "-p":
|
|
if len(remainder) == 0:
|
|
Usage()
|
|
sys.exit(1)
|
|
QueryHaveIBeenPwned(" ".join(remainder))
|
|
elif opt == "-d":
|
|
if len(remainder) == 0:
|
|
Usage()
|
|
sys.exit(1)
|
|
DatabaseQuery(" ".join(remainder))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except (KeyboardInterrupt, SystemExit, EOFError):
|
|
sys.exit(0)
|