You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
5.3 KiB

  1. #!/usr/bin/env python3
  2. class Colours:
  3. HEADER = '\033[95m'
  4. OKBLUE = '\033[94m'
  5. OKGREEN = '\033[92m'
  6. WARNING = '\033[93m'
  7. FAIL = '\033[91m'
  8. ENDC = '\033[0m'
  9. BOLD = '\033[1m'
  10. UNDERLINE = '\033[4m'
  11. try:
  12. import os
  13. import re
  14. import sys
  15. import getopt
  16. import requests
  17. from clint.textui import progress
  18. from bs4 import BeautifulSoup
  19. except Exception as err:
  20. print(Colours.FAIL + "Error: {}".format(err) + Colours.ENDC)
  21. def Usage():
  22. use_msg = '''
  23. ---------- Usage ----------
  24. leak-lookup [options] [search term]
  25. ---------------------------
  26. Options:
  27. -h: Prints this help message
  28. -p: Searches haveibeenpwned.com
  29. -d: Searches for leaked database
  30. ---------------------------
  31. '''
  32. print(use_msg)
  33. def DownloadDatabase(url, name):
  34. try:
  35. r = requests.get(url, stream=True)
  36. with open(name, 'wb') as f:
  37. total_length = int(r.headers.get('content-length'))
  38. for chunk in progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1):
  39. if chunk:
  40. f.write(chunk)
  41. f.flush()
  42. except (KeyboardInterrupt, SystemExit, EOFError):
  43. print(Colours.FAIL + "An error occurred, cleaning up" + Colours.ENDC)
  44. os.remove(name)
  45. def DatabaseQuery(database):
  46. r = requests.get("https://www.databases.today/search-nojs.php?for=" + database)
  47. if r.reason != "OK":
  48. print(Colours.FAIL + "Error code: {}".format(r.status_code) + Colours.ENDC)
  49. sys.exit(1)
  50. soup = BeautifulSoup(r.text, "html.parser")
  51. dbs = soup.find(id="myTable").find_all("tr")
  52. entries = []
  53. for table in dbs:
  54. entry = table.find_all("td")
  55. if len(entry) != 0:
  56. entries.append([entry[0].text, entry[4].a.get("href")])
  57. print("Which file would you like to download?")
  58. for index, dllink in enumerate(entries):
  59. print("{}) {}".format(index + 1, dllink[0]))
  60. print("a) All")
  61. print("q) Quit")
  62. download_choice = input(">> ")
  63. if download_choice == "q":
  64. sys.exit(0)
  65. elif download_choice == "a":
  66. for x in dllink:
  67. DownloadDatabase(x[1], x[0])
  68. else:
  69. try:
  70. download_choice = int(download_choice) - 1
  71. DownloadDatabase(dllink[1], dllink[0].split(" (")[0])
  72. except:
  73. print(Colours.FAIL + "Error: Invalid selection" + Colours.ENDC)
  74. sys.exit(1)
  75. def QueryHaveIBeenPwned(email):
  76. r = requests.post("https://haveibeenpwned.com/", data={"Account": email})
  77. if r.reason != "OK":
  78. print(Colours.FAIL + "Error code: {}".format(r.status_code) + Colours.ENDC)
  79. sys.exit(1)
  80. soup = BeautifulSoup(r.text, "html.parser")
  81. pwnCount = re.match("Pwned on \d+", soup.find(id="pwnCount").text)
  82. if pwnCount == None:
  83. print(Colours.OKGREEN + "{} has no public leaks".format(email) + Colours.ENDC)
  84. return
  85. print(Colours.FAIL + "{} has {} public leaks avalible".format(email, pwnCount.group().split(" ")[-1]) + Colours.ENDC)
  86. leaks = []
  87. for leak in soup.find_all(class_="pwnedWebsite"):
  88. leak_name = None
  89. leak_status = None
  90. compromised_data = None
  91. leak_name_html = leak.find(class_="pwnedCompanyTitle")
  92. if leak_name_html:
  93. if "(" in leak_name_html.text:
  94. leak_name = leak_name_html.text.split(" (")[0]
  95. leak_status = leak_name_html.text.split(" (")[1][:-2]
  96. else:
  97. leak_name = leak_name_html.text[:-1]
  98. leak_status = None
  99. compromised_data_html = leak.find(class_="dataClasses")
  100. if compromised_data_html:
  101. compromised_data = compromised_data_html.text
  102. if leak_name:
  103. leaks.append([leak_name, leak_status, compromised_data])
  104. print("\nDownload databases:")
  105. for index, leak in enumerate(leaks):
  106. if leak[1] == None:
  107. print("{}) {}: {}".format(index + 1, leak[0], leak[2]))
  108. else:
  109. print("{}) {} ({}): {}".format(index + 1, leak[0], leak[1], leak[2]))
  110. print("a) Download all")
  111. print("q) Quit")
  112. download_choice = input(">> ")
  113. if download_choice == "q":
  114. sys.exit(0)
  115. elif download_choice == "a":
  116. for leak in leaks:
  117. DatabaseQuery(leak[0])
  118. try:
  119. download_choice = int(download_choice) - 1
  120. DatabaseQuery(leaks[download_choice][0])
  121. except:
  122. print(Colours.FAIL + "Error: Invalid selection" + Colours.ENDC)
  123. sys.exit(1)
  124. def main():
  125. if len(sys.argv[1:]) == 0:
  126. Usage()
  127. sys.exit(1)
  128. try:
  129. options, remainder = getopt.getopt(sys.argv[1:],'hpd',['h', 'p','d',])
  130. except getopt.GetoptError as err:
  131. print(Colours.FAIL + "Error: {}".format(err) + Colours.ENDC)
  132. sys.exit(1)
  133. for opt, arg in options:
  134. if opt == "-h":
  135. Usage()
  136. sys.exit(0)
  137. elif opt == "-p":
  138. if len(remainder) == 0:
  139. Usage()
  140. sys.exit(1)
  141. QueryHaveIBeenPwned(" ".join(remainder))
  142. elif opt == "-d":
  143. if len(remainder) == 0:
  144. Usage()
  145. sys.exit(1)
  146. DatabaseQuery(" ".join(remainder))
  147. if __name__ == "__main__":
  148. try:
  149. main()
  150. except (KeyboardInterrupt, SystemExit, EOFError):
  151. sys.exit(0)