This repository has been archived by the owner on Jun 21, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquiver.py
193 lines (167 loc) · 6.75 KB
/
quiver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import requests
import argparse
import sys
from texttable import Texttable
__author__ = '@2xxeformyshirt'
__version__ = '1.0.0'
parser = argparse.ArgumentParser()
parser.add_argument('-t',dest='target',type=str,required=True,help='target domain')
parser.add_argument('-a',dest='apikey',type=str,required=False,help='Hunter.io API key')
parser.add_argument('-l',dest='apilist',type=str,required=False,help='file of API keys')
parser.add_argument('-o',dest='outputfile',type=str,required=True,help='Output file location')
parser.add_argument('-f','--free',dest='freetier',action='store_true',required=False,help='Enable free tier limit restrictions')
parser.add_argument('-p','--print',dest='printtable',action='store_true',required=False,help='print a text table of the results')
args = vars(parser.parse_args())
if len(sys.argv) == 1:
print '[-] Missing arguments...quitting!'
sys.exit()
BANNER=''' /\___/\
| | Quiver
\ /
|___| @2xxeformyshirt
'''
class Prey():
def __init__(self,fn,ln,em):
self.fn = fn
self.ln = ln
self.em = em
class HunterKey():
def __init__(self,key,stamina):
self.key = key
self.stamina = stamina
class HunterManager():
def __init__(self,args):
'''exit if api key and API file are both supplied or neither are supplied
check stamina (number of requests left) of each key'''
self.kt = 0
self.apilist = []
if args['apikey'] is None and args['apilist'] is None:
print '[-] Missing API input...quitting!'
sys.exit()
elif args['apikey'] is not None and args['apilist'] is not None:
print '[-] Too many API inputs...quitting!'
sys.exit()
elif args['apikey'] is not None:
self.kt = self.checkkeystatus(args['apikey'])
if self.kt <= 0:
print '[-] Key has no stamina...quitting!'
sys.exit()
self.apikey = HunterKey(args['apikey'],self.kt)
self.apilist.append(self.apikey)
elif args['apilist'] is not None:
with open(args['apilist'],'r') as f:
for key in f.readlines():
kr = self.checkkeystatus(key.strip())
if kr > 0:
self.apilist.append(HunterKey(key.strip(),kr))
else:
print '[-] Key %s exhausted' % key.strip()
if len(self.apilist) == 0:
print '[-] Not API keys found in file'
sys.exit()
for k in self.apilist:
self.kt = self.kt + k.stamina
if self.kt <= 0:
print '[-] Keys have no stamina...quitting!'
sys.exit()
self.apikey = self.apilist[0]
self.multikey = True
self.target = args['target']
self.outputfile = args['outputfile']
self.freetier = args['freetier']
self.people = []
self.apilistall = self.apilist
def checkkeystatus(self,key):
'''check the number of requests a key can make before being exhausted'''
url = 'https://api.hunter.io/v2/account?api_key=%s' % key
r = requests.get(url)
if str(r.status_code)[:1] != '2':
print '[-] Error calling Hunter.io API...quitting!'
sys.exit()
return (r.json()['data']['calls']['available'] - r.json()['data']['calls']['used'])
def rotatekey(self):
if len(self.apilist) == 0:
print '[-] All keys exhausted...quitting!'
sys.exit()
else:
self.apilist.pop(0)
self.apikey = self.apilist[0]
def apirequest(self,offset):
'''request maximum number of usernames for a single request (100)'''
if self.apikey.stamina == 0:
print '[-] Key %s exhausted' % self.apikey.key
if self.multikey:
self.rotatekey()
url = 'https://api.hunter.io/v2/domain-search?domain=%s&api_key=%s&limit=100&offset=%s' % (self.target,self.apikey.key,str(offset))
r = requests.get(url)
if str(r.status_code)[:1] != '2':
print '[-] Error calling Hunter.io API...quitting!'
sys.exit()
'''reduce stamina by 1 (note: responses with status=400 do not decrement stamina)'''
self.apikey.stamina = self.apikey.stamina - 1
return r.json()
def appendperson(self,of,rjson):
'''extracts firstname, lastname, and email from json and adds to list'''
for prey in rjson['data']['emails']:
p = Prey(prey['first_name'],prey['last_name'],prey['value'])
line = '%s,%s,%s\n' % (p.fn,p.ln,p.em)
of.write(line)
self.people.append(p)
def main(args):
print BANNER
hunter = HunterManager(args)
print '[+] Hunting for users associated with %s' % hunter.target
'''determine if number of results is within free tier limit
quit if not within free tier limit and switch set'''
rjson = hunter.apirequest(0)
maxemails = rjson['meta']['results']
numreq = maxemails/100
if maxemails % 100 != 0:
numreq = numreq + 1
if hunter.freetier:
if numreq > 100:
print '[-] Number of requests exceeds free tier limit...quitting!'
sys.exit()
'''quit if there isnt enough key stamina to fulfill all requests'''
if hunter.kt < numreq:
print '[-] Not enough stamina to fulfill requests'
sys.exit()
'''start writing ouput'''
of = open(hunter.outputfile,'w+')
of.write('First,Last,Email\n')
'''add emails from original request to list'''
hunter.appendperson(of,rjson)
'''request remaining people'''
i = 1
while i < numreq:
rjson = hunter.apirequest(i*100)
hunter.appendperson(of,rjson)
i = i + 1
print '[+] Results written to %s\n' % hunter.outputfile
'''print table of people'''
if args['printtable']:
table1 = Texttable()
table1.set_deco(Texttable.HEADER)
table1.set_cols_align(['l', 'l', 'l'])
table1.add_row(['First Name','Last Name','Email'])
for person in hunter.people:
table1.add_row([person.fn,person.ln,person.em])
print '[+] Printing results:'
print table1.draw()+'\n'
'''write out status of each key'''
table2 = Texttable()
table2.set_deco(Texttable.HEADER)
table2.set_cols_align(['l', 'l'])
table2.add_row(['Key','Stamina'])
for k in hunter.apilistall:
ks = hunter.checkkeystatus(k.key)
table2.add_row([k.key,ks])
print '[+] Retrieving new staminas:'
print table2.draw()+'\n'
of.close()
if __name__ == '__main__':
try:
main(args)
except KeyboardInterrupt:
print '[-] User interrupt...quitting!'
sys.exit()