diff --git a/InSpy.py b/InSpy.py
index 2f6dda0..18a9097 100755
--- a/InSpy.py
+++ b/InSpy.py
@@ -1,15 +1,22 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
# Copyright (c) 2018 Jonathan Broche (@LeapSecurity)
import argparse, sys, os
-from lib.http import *
from lib.workbench import *
from lib.soup import *
from lib.export import *
from lib.logger import *
+hunterapi = "" #insert hunterio api key here
-parser = argparse.ArgumentParser(description='InSpy - A LinkedIn enumeration tool by Jonathan Broche (@LeapSecurity)', version="3.0.1")
+if not hunterapi:
+ print("[+] Your hunter api key is Empty")
+ print("[+] Hunter Api Key is required please fill the hunter api key opening the InSpy.py File")
+ sys.exit(404)
+
+Version ="4.0"
+
+parser = argparse.ArgumentParser(description='InSpy - A LinkedIn enumeration tool by Hari Kiran(TheCyberMonster)\n A forked project of InSpy 3.0')
parser.add_argument('company', help="Company name to use for tasks.")
parser.add_argument('--domain', help="Company domain to use for searching.")
parser.add_argument('--email', help="Email format to create email addresses with. [Accepted Formats: first.last@xyz.com, last.first@xyz.com, firstl@xyz.com, lfirst@xyz.com, flast@xyz.com, lastf@xyz.com, first@xyz.com, last@xyz.com]")
@@ -26,16 +33,14 @@
args = parser.parse_args()
start_logger(args.company)
-hunterapi = "" #insert hunterio api key here
email = args.email
domain = args.domain
-
-print "\nInSpy {}".format(parser.version)
+print("\nInSpy {}".format(Version))
try:
- if domain and not email: #search hunterio for email format
+ if domain and not email: #search hunter.io for email format
email = get_email_format(args.domain, hunterapi)
if email and not domain: #search clearbit for domain
domain = get_domain(args.company)
@@ -48,7 +53,7 @@
email = email.replace("{", "").replace("}","")
- print "\nDomain: {}, Email Format: {}\n".format(domain, email)
+ print("Domain: {}, Email Format: {}".format(domain, email))
employees = {}
@@ -58,15 +63,15 @@
if args.company.lower() in title.lower():
if not name in employees:
employees[name] = title
- print "\n{} Employees identified".format(len(employees.keys()))
+ print("{} Employees identified".format(len(employees.keys())))
else:
- print os.path.abspath(args.titles)
- print "No such file or directory: '{}'".format(args.titles)
-
+ print(os.path.abspath(args.titles))
+ print("No such file or directory: '{}'".format(args.titles))
+ emails=[]
if employees:
#output employees
- for name, title in employees.iteritems():
- print "{} {}".format(name, title[:50].replace('&', '&'))
+ for name, title in employees.items():
+ print("{} {}".format(name, title[:50].replace('&', '&')))
#craft emails
emails = create_emails(employees, domain, email)
@@ -74,9 +79,9 @@
if emails:
#output emails
- print "\nEmails crafted\n".format(len(emails.keys()))
+ print("Emails crafted".format(len(emails.keys())))
for name, email in emails.items():
- print email
+ print(email)
#export results
if args.html:
@@ -88,4 +93,4 @@
if args.csv:
output("csv", args.csv, args.company, domain, employees, emails)
except (KeyboardInterrupt, SystemExit):
- print "\nTerminated script.\n"
\ No newline at end of file
+ print("Terminated script.")
diff --git a/README.md b/README.md
index 0d92ae7..c506c8b 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Version 3.0 introduces the automation of domain and email retrieval in addition
## Installation
-----
-Run `pip install -r requirements.txt` within the cloned InSpy directory.
+Run `pip3 install -r requirements.txt` within the cloned InSpy directory.
Obtain an API key from [HunterIO](https://hunter.io/) and insert it into the hunterio variable within InSpy.py (line 29).
diff --git a/lib/__init__.pyc b/lib/__init__.pyc
deleted file mode 100644
index 2b69e10..0000000
Binary files a/lib/__init__.pyc and /dev/null differ
diff --git a/lib/export.py b/lib/export.py
index 3b4093a..22eeae8 100644
--- a/lib/export.py
+++ b/lib/export.py
@@ -1,4 +1,5 @@
-import json, os, xml.dom.minidom, time, csv
+import json, os, time, csv
+import xml.dom.minidom
from xml.etree.ElementTree import Element, SubElement, tostring
def output(format, file, company, domain, employees, emails):
@@ -17,14 +18,14 @@ def ocsv(filename, company, domain, employees, emails):
fieldnames = ["Employee Name", "Title", "Email"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
- for name, title in employees.iteritems():
+ for name, title in employees.items():
writer.writerow({"Employee Name": name, "Title": title.replace('&', '&'), "Email": emails[name]})
#JSON
def ojson(file, company, domain, employees, emails):
employee_json = []
- for name, title in employees.iteritems():
+ for name, title in employees.items():
employee_json.append({"name": name, "title": title.replace('&', '&'), "email": emails[name]})
full_json = {
@@ -49,7 +50,7 @@ def oxml(file, company, domain, employees, emails):
echild = SubElement(top, 'Employees')
- for name, title in employees.iteritems():
+ for name, title in employees.items():
employee = SubElement(echild, "Employee")
#name
@@ -71,7 +72,7 @@ def oxml(file, company, domain, employees, emails):
def ohtml(file, company, domain, employees, emails):
employee_html = []
- for name, title in employees.iteritems():
+ for name, title in employees.items():
employee_html.append("
{name} | {title} | {email} |
".format(name=name, title=title, email=emails[name]))
page = """
@@ -96,4 +97,4 @@ def ohtml(file, company, domain, employees, emails):
""".format(company=company, time=time.strftime("%Y/%m/%d %H:%M:%S"), html=employee_html)
with open(os.path.abspath(file), 'w') as f:
- f.write(page)
\ No newline at end of file
+ f.write(page)
diff --git a/lib/export.pyc b/lib/export.pyc
deleted file mode 100644
index f62f85e..0000000
Binary files a/lib/export.pyc and /dev/null differ
diff --git a/lib/http.py b/lib/http.py
index b949f0a..90869e1 100644
--- a/lib/http.py
+++ b/lib/http.py
@@ -1,15 +1,13 @@
import requests, random
-from logger import *
-#requests.packages.urllib3.disable_warnings()
+import logging
def random_header():
-
agents = ['Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0',
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13+ (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2',
- 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41',
- 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36']
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13+ (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2',
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41',
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36']
return {'User-Agent': random.choice(agents),'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'}
@@ -27,7 +25,7 @@ def http_request(url):
return {"status": r.status_code, "response": ""}
except requests.exceptions.Timeout as e:
- print "Error: Timed out."
+ print("Error: Timed out.")
logging.error(e)
except Exception as e:
- logging.error(e)
\ No newline at end of file
+ logging.error(e)
diff --git a/lib/http.pyc b/lib/http.pyc
deleted file mode 100644
index 9e537f3..0000000
Binary files a/lib/http.pyc and /dev/null differ
diff --git a/lib/logger.py b/lib/logger.py
index aa8714e..20bbfd9 100644
--- a/lib/logger.py
+++ b/lib/logger.py
@@ -1,4 +1,5 @@
-import logging, sys, time
+
+import logging,time
time_format = time.strftime("%Y-%m-%d %H:%M:%S")
diff --git a/lib/logger.pyc b/lib/logger.pyc
deleted file mode 100644
index e0ec5c5..0000000
Binary files a/lib/logger.pyc and /dev/null differ
diff --git a/lib/soup.py b/lib/soup.py
index 1351719..0320336 100644
--- a/lib/soup.py
+++ b/lib/soup.py
@@ -1,4 +1,5 @@
-import BeautifulSoup, json
+
+from bs4 import BeautifulSoup
def soupify(response):
try:
@@ -7,7 +8,7 @@ def soupify(response):
except (AttributeError, TypeError) as e:
pass
except Exception as e:
- print "Error: {}".format(e)
+ print("Error: {}".format(e))
def get_employees(soup):
try:
@@ -21,5 +22,5 @@ def get_employees(soup):
except (AttributeError, TypeError) as e:
pass
except Exception as e:
- print "Error: {}".format(e)
+ print("Error: {}".format(e))
diff --git a/lib/soup.pyc b/lib/soup.pyc
deleted file mode 100644
index 305db4d..0000000
Binary files a/lib/soup.pyc and /dev/null differ
diff --git a/lib/workbench.py b/lib/workbench.py
index 850c017..8f7d363 100644
--- a/lib/workbench.py
+++ b/lib/workbench.py
@@ -1,35 +1,34 @@
-import re, json, HTMLParser, unicodedata
-from http import *
-from logger import *
+from html.parser import HTMLParser
+import logging
+from lib.http import http_request
-def get_domain(company): #Clearbit API - clearbit.com
+def get_domain(company): #Clearbit API - clearbit.com
clearbit_request = "https://autocomplete.clearbit.com/v1/companies/suggest?query={}".format(company)
clearbit_results = []
domain = ""
r = http_request(clearbit_request)
-
if len(r["response"]) >=1:
- for element in r["response"]:
- if company.lower() == element['name'].lower():
- clearbit_results.append({"name" : element['name'], "domain":element['domain']})
+ if len(r["response"]) >= 1:
+ for element in r["response"]:
+ clearbit_results.append({"name": element['name'], "domain": element['domain']})
- if len(clearbit_results) == 1: #return domain if one result
+ if len(clearbit_results) == 1: #return domain if one result
domain = clearbit_results[0]["domain"]
- elif len(clearbit_results) > 1: #prompt user if multiple domains identified
- print "Multiple domains identified for company. Which one is the target?"
+ elif len(clearbit_results) > 1: #prompt user if multiple domains identified
+ print("Multiple domains identified for company. Which one is the target?")
for index, result in enumerate(clearbit_results):
- print "{}) Name: {}, Domain: {}".format(index, result["name"], result["domain"])
- choice = input()
+ print("{}) Name: {}, Domain: {}".format(index, result["name"], result["domain"]))
+ choice = int(input("Select using S.No \n (Ex: select-> 1 )\n select-> "))
domain = clearbit_results[choice]["domain"]
if domain:
return domain
else:
logging.error("Clearbit API - HTTP {} Error".format(r["status"]))
- print "InSpy could not identify the domain name. Use --domain."
+ print("InSpy could not identify the domain name. Use --domain.")
def get_email_format(domain, apikey): #HunterIO API - hunter.io
@@ -39,7 +38,7 @@ def get_email_format(domain, apikey): #HunterIO API - hunter.io
r = http_request(hunter_request)
if r["status"] == 200:
- for k,v in r["response"].iteritems():
+ for k,v in r["response"].items():
if k == 'data':
if v['pattern']:
emailformat = v['pattern']
@@ -50,7 +49,7 @@ def get_email_format(domain, apikey): #HunterIO API - hunter.io
if emailformat:
return emailformat
else:
- print "InSpy could not identify the email format. Use --email."
+ print("InSpy could not identify the email format. Use --email.")
def search_linkedin(company, file):
titles = []
@@ -74,6 +73,7 @@ def search_linkedin(company, file):
#craft emails
+
def create_emails(employees, domain, eformat):
hparser=HTMLParser.HTMLParser()
emails = {}
@@ -113,4 +113,4 @@ def format_email(eformat, first, last):
}
return formats[eformat]
except Exception as e:
- print e
\ No newline at end of file
+ print(e)
diff --git a/lib/workbench.pyc b/lib/workbench.pyc
deleted file mode 100644
index c8fb15d..0000000
Binary files a/lib/workbench.pyc and /dev/null differ
diff --git a/requirements.txt b/requirements.txt
index dbd1295..1190bd8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,2 @@
-requests==2.20.1
-BeautifulSoup==3.2.1
+requests
+beautifulsoup4