#!/usr/bin/python

from spyse import spyse
import argparse
import json
import sys

def banner():
	print("""
	  ██████  ██▓███ ▓██   ██▓  ██████ ▓█████ 
	▒██    ▒ ▓██░  ██▒▒██  ██▒▒██    ▒ ▓█   ▀ 
	░ ▓██▄   ▓██░ ██▓▒ ▒██ ██░░ ▓██▄   ▒███   
	  ▒   ██▒▒██▄█▓▒ ▒ ░ ▐██▓░  ▒   ██▒▒▓█  ▄ 
	▒██████▒▒▒██▒ ░  ░ ░ ██▒▓░▒██████▒▒░▒████▒
	▒ ▒▓▒ ▒ ░▒▓▒░ ░  ░  ██▒▒▒ ▒ ▒▓▒ ▒ ░░░ ▒░ ░
	░ ░▒  ░ ░░▒ ░     ▓██ ░▒░ ░ ░▒  ░ ░ ░ ░  ░
	░  ░  ░  ░░       ▒ ▒ ░░  ░  ░  ░     ░   
	      ░           ░ ░           ░     ░  ░
	                  ░ ░           by @zer0pwn          
	""")

parser = argparse.ArgumentParser(
	description="Client for Spyse.com",
	epilog="Usage: spyse -target hackerone.com --subdomains")
parser.add_argument('-target', help="target")
parser.add_argument('-param', help="parameter to use (ip, domain, cidr, url, hash)")
parser.add_argument('-page', help="page")
parser.add_argument('-apikey', help="set the api key")
parser.add_argument('--raw', help="show raw json", action="store_true")
parser.add_argument('--dns-ptr', help="show dns ptr records", action="store_true")
parser.add_argument('--dns-soa', help="show dns soa records", action="store_true")
parser.add_argument('--dns-mx', help="show dns mx records", action="store_true")
parser.add_argument('--dns-aaaa', help="show dns aaaa records", action="store_true")
parser.add_argument('--dns-ns', help="show dns ns records", action="store_true")
parser.add_argument('--dns-a', help="show dns a records", action="store_true")
parser.add_argument('--dns-txt', help="show dns txt records", action="store_true")
parser.add_argument('--dns-all', help="show all dns records", action="store_true")
parser.add_argument('--domains-with-same-ns', help="show domains with same ns", action="store_true")
parser.add_argument('--domains-using-as-mx', help="show domains using as mx", action="store_true")
parser.add_argument('--domains-on-ip', help="show domains on ip", action="store_true")
parser.add_argument('--domains-with-same-mx', help="show domains with same mx", action="store_true")
parser.add_argument('--domains-using-as-ns', help="show domains using as ns", action="store_true")
parser.add_argument('--download-dns-aaaa', help="download dns aaaa records", action="store_true")
parser.add_argument('--download-dns-soa', help="download dns soa records", action="store_true")
parser.add_argument('--download-dns-ns', help="download dns ns records", action="store_true")
parser.add_argument('--download-dns-ptr', help="download dns ptr records", action="store_true")
parser.add_argument('--download-dns-mx', help="download dns mx records", action="store_true")
parser.add_argument('--download-dns-a', help="download dns a records", action="store_true")
parser.add_argument('--download-dns-txt', help="download dns txt records", action="store_true")
parser.add_argument('--download-dns-all', help="download all dns records", action="store_true")
parser.add_argument('--ip-port-lookup', help="show ip port lookup", action="store_true")
parser.add_argument('--ip-port-lookup-aggregate', help="show ip port lookup aggregate", action="store_true")
parser.add_argument('--ssl-certificates', help="show ssl certificates associated with a target", action="store_true")
parser.add_argument('--subdomains', help="show subdomains", action="store_true")
args = parser.parse_args()

if not args.raw:
	banner()

if(args.apikey):
	s = spyse(args.apikey)
else:
	s = spyse()

def get_dns_ptr(target, param, page, raw=False):
	if(raw == True):
		return json.dumps(s.dns_ptr(target, param=param, page=page))
	else:
		data = s.dns_ptr(target, param=param, page=page)
		retval = ""

		for record in data['records']:
			retval += "PTR RECORD @ {} FROM HOSTNAME {}\n".format(
				record['ip']['ip'],
				record['hostname']
			)
		return retval
	return False

def get_dns_soa(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.dns_soa(target, param=param, page=page))
	else:
		data = s.dns_soa(target, param=param, page=page)
		retval = ""
		for record in data['records']:
			retval += "SOA RECORD @ {} FROM {} WITH SERIAL {}\n".format(
				record['domain']['domain'],
				record['domain']['ip']['ip'],
				record['serial']
			)
		return retval
	return False

def get_dns_mx(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.dns_mx(target, param=param, page=page))
	else:
		data = s.dns_mx(target, param=param, page=page)
		retval = ""
		for record in data['records']:
			retval += "MX RECORD @ {} FROM IP {}\n".format(
				record['mx_domain']['domain'],
				record['mx_domain']['ip']['ip']
			)
		return retval
	return False

def get_dns_aaaa(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.dns_aaaa(target, param=param, page=page))
	else:
		data = s.dns_aaaa(target, param=param, page=page)
		retval = ""
		for record in data['records']:
			retval += "AAAA RECORD @ {} FROM IP {}\n".format(
				record['domain']['domain'],
				record['ipv6']
			)
		return retval
	return False

def get_dns_ns(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.dns_ns(target, param=param, page=page))
	else:
		data = s.dns_ns(target, param=param, page=page)
		retval = ""
		for record in data['records']:
			retval += "NS RECORD @ {} FROM {}\n".format(
				record['ns_domain']['domain'],
				record['ns_domain']['ip']['ip']
			)
		return retval
	return False

def get_dns_a(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.dns_a(target, param=param, page=page))
		sys.exit()
	else:
		data = s.dns_a(target, param=param, page=page)
		retval = ""
		for record in data['records']:
			retval += "A RECORD @ {} FROM {}\n".format(
				record['domain']['domain'],
				record['ip']['ip']
			)
		return retval
	return False

def get_dns_txt(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.dns_txt(target, param=param, page=page))
	else:
		data = s.dns_txt(target, param=param, page=page)
		retval = "TXT RECORDS FROM {}\n".format(target)
		for record in data['records']:
			retval += '> {}\n'.format(record['data'])
		return retval
	return False

# spyse needs to fix this endpoint
def get_domains_with_same_ns(target, param, page, raw=False):
	return s.domains_with_same_ns(target, param, page)


def get_domains_using_as_mx(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.domains_using_as_mx(target, param=param, page=page))
	else:
		data = s.domains_using_as_mx(target, param=param, page=page)
		retval = ""
		for record in data['records']:
			retval += "{} USING SAME MX AS {} ON IP {}\n".format(
				record['domain'],
				args.target,
				record['ip']['ip']
			)
		return retval
	return False

def get_domains_on_ip(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.domains_on_ip(target, param=param, page=page))
	else:
		retval = ""
		data = s.domains_on_ip(target, param=param, page=page)
		for record in data['records']:
			retval += "{}\n".format(record['domain'])
		return retval
	return False

# spyse needs to fix this endpoint
def get_domains_with_same_mx(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.domains_with_same_mx(target, param=param, page=page))
	else:
		return s.domains_with_same_mx(target, param=param, page=page)
	return False

def get_domains_using_as_ns(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.domains_using_as_ns(target, param, page))
	else:
		retval = ""
		data = s.domains_using_as_ns(target, param, page)
		for record in data['records']:
			retval += "DOMAIN {} FROM IP {}\n".format(
				record['domain'],
				record['ip']['ip']
			)
		return retval
	return False

def get_download_dns_aaaa(target, param, page):
	return s.download_dns_aaaa(target, param, page)

def get_download_dns_soa(target, param, page):
	return s.download_dns_soa(target, param, page)

def get_download_dns_ns(target, param, page):
	return s.download_dns_ns(target, param, page)

def get_download_dns_ptr(target, param, page):
	return s.download_dns_ptr(target, param, page)

def get_download_dns_mx(target, param, page):
	return s.download_dns_mx(target, param, page)

def get_download_dns_a(target, param, page):
	return s.download_dns_a(target, param, page)

def get_download_dns_txt(target, param, page):
	return s.download_dns_txt(target, param, page)

def get_ssl_certificates(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.ssl_certificates(target, param, page))
	else:
		try:
			certs = s.ssl_certificates(target, param, page)
			retval = ""
			for cert in certs:
				retval += '---------------------------------------------------\n'
				domains = cert['domains']
				ips	= cert['ips']
				for domain in domains:
					retval += '[+] SSL cert assigned to domain {}\n'.format(domain['domain'])
				retval += '[*] Valid from: {}\n'.format(cert['valid_from'])
				retval += '[*] Valid to: {}\n'.format(cert['valid_to'])
				retval += '[*] Hash: {}\n\n'.format(cert['hash'])
				for ip in ips:
					retval += '-> Associated with IP {}\n'.format(ip['ip'])
				retval += '---------------------------------------------------\n\n'
			return retval
		except:
			return certs
		return False

def get_subdomains_aggregate(target, param, page, raw=False):
	if args.raw:
		return json.dumps(s.subdomains_aggregate(target, param=param, page=page))
	else:
		retval = ""
		data = s.subdomains_aggregate(target, param=param, page=page)['cidr']
		keys = data.keys()

		for key in keys:
			domains = data[key]['results']
			for d in domains:
				domain = d['data']['domains']
				if len(domain) > 1:
					for i in domain:
						retval += "{}\n".format(i)
				else:
					retval += "{}\n".format(domain[0])
		return retval
	return False

def get_dns_all(target, param, page, raw=False):
	if args.raw:
		data = {}
		data["PTR_RECORDS"] = json.loads(get_dns_ptr(target, param=param, page=page, raw=True))
		data["SOA_RECORDS"] = json.loads(get_dns_soa(target, param=param, page=page, raw=True))
		data["MX_RECORDS"] = json.loads(get_dns_mx(target, param=param, page=page, raw=True))
		data["AAAA_RECORDS"] = json.loads(get_dns_aaaa(target, param=param, page=page, raw=True))
		data["A_RECORDS"] = json.loads(get_dns_a(target, param=param, page=page, raw=True))
		data["NS_RECORDS"] = json.loads(get_dns_ns(target, param=param, page=page, raw=True))
		data["TXT_RECORDS"] = json.loads(get_dns_txt(target, param=param, page=page, raw=True))
		return json.dumps(data)
	else:
		data = ""
		data += get_dns_ptr(target, param=param, page=page)
		data += get_dns_soa(target, param=param, page=page)
		data += get_dns_mx(target, param=param, page=page)
		data += get_dns_aaaa(target, param=param, page=page)
		data += get_dns_a(target, param=param, page=page)
		data += get_dns_ns(target, param=param, page=page)
		data += get_dns_txt(target, param=param, page=page)
	return data

def get_download_dns_all(target, param, page):
	data = ""
	data += get_download_dns_aaaa(target, param, page) + "\n"
	data += get_download_dns_soa(target, param, page) + "\n"
	data += get_download_dns_ptr(target, param, page) + "\n"
	data += get_download_dns_mx(target, param, page) + "\n"
	data += get_download_dns_a(target, param, page) + "\n"
	data += get_download_dns_txt(target, param, page) + "\n"
	return data

def get_ip_port_lookup(target, param, page):
	if args.raw:
		return json.dumps(s.ip_port_lookup(target, param=param, page=page))
	else:
		data = s.ip_port_lookup(target, param=param, page=page)
		retval = ""
		for record in data:
			ip = record['ip']['ip']
			ports = []
			for i in record['iplList']:
				ports.append(i['port'])
				retval += "ip: '{}' port: '{}'\n".format(ip, i['port'])
		return retval
	return False

def get_ip_port_lookup_aggregate(target, param, page):
	if args.raw:
		return json.dumps(s.ip_port_lookup_aggregate(target, param=param, page=page))
	else:
		data = s.ip_port_lookup_aggregate(target, param=param, page=page)
		retval = ""
		if 'cidr' in data['blocks']:
			cidr = data['blocks']['cidr']['results']
			for i in cidr:
				retval += "Found {} open port(s) regarding {}\n".format(i['count'], i['q'])
		if 'as' in data['blocks']:
			aas = data['blocks']['as']['results']
			for i in aas:
				retval += "Found {} open port(s) regarding {}\n".format(i['count'], i['q'])
		if 'service' in data['blocks']:
			service = data['blocks']['service']['results']
			for i in service:
				retval += "Found {} open port(s) regarding {}\n".format(i['count'], i['q'])
		if 'protocol' in data['blocks']:
			protocol = data['blocks']['protocol']['results']
			for i in protocol:
				retval += "Found {} open port(s) regarding {}\n".format(i['count'], i['q'])
		if 'ports' in data['blocks']:
			ports = data['blocks']['port']['results']
			for i in ports:
				retval += "Found {} open port(s) regarding {}\n".format(i['count'], i['q'])
		return retval
	return False



if args.target:
	if args.page:
		page = args.page
	else:
		page = 1

	target = args.target

	if args.param:
		param = args.param
	else:
		param = "domain"

	if args.dns_ptr:
		print(get_dns_ptr(args.target, param, page, raw=args.raw))

	if args.dns_soa:
		print(get_dns_soa(args.target, param, page, raw=args.raw))

	if args.dns_mx:
		print(get_dns_mx(args.target, param, page, raw=args.raw))

	if args.dns_aaaa:
		print(get_dns_aaaa(args.target, param, page, raw=args.raw))

	if args.dns_ns:
		print(get_dns_ns(args.target, param, page, raw=args.raw))

	if args.dns_a:
		print(get_dns_a(args.target, param, page, raw=args.raw))

	if args.dns_txt:
		print(get_dns_txt(args.target, param, page, raw=args.raw))

	if args.domains_with_same_ns:
		print(get_domains_with_same_ns(args.target, param, page, raw=args.raw))

	if args.domains_using_as_mx:
		print(get_domains_using_as_mx(args.target, param, page, raw=args.raw))

	if args.domains_on_ip:
		# detect whether input is cidr or ip or q
		if "/" in args.target:
			param = "cidr"
		elif ":" in args.target:
			param = "q"
		else:
			param = "ip"
		print(get_domains_on_ip(args.target, param, page, raw=args.raw))

	if args.subdomains:
		print(get_subdomains_aggregate(args.target, param, page, raw=args.raw))

	if args.dns_all:
		print(get_dns_all(args.target, param, page))

	if args.domains_using_as_ns:
		print(get_domains_using_as_ns(args.target, param, page))

	if args.download_dns_aaaa:
		print(get_download_dns_aaaa(args.target, param, page))

	if args.download_dns_soa:
		print(get_download_dns_soa(args.target, param, page))

	if args.download_dns_ns:
		print(get_download_dns_ns(args.target, param, page))

	if args.download_dns_ptr:
		print(get_download_dns_ptr(args.target, param, page))

	if args.download_dns_mx:
		print(get_download_dns_mx(args.target, param, page))

	if args.download_dns_a:
		print(get_download_dns_a(args.target, param, page))
	
	if args.download_dns_txt:
		print(get_download_dns_txt(args.target, param, page))

	if args.download_dns_all:
		print(get_download_dns_all(args.target, param, page))

	if args.ssl_certificates:
		# detect whether input is cidr or ip or q
		if "/" in args.target:
			param = "cidr"
		elif ":" in args.target:
			param = "q"
		print(get_ssl_certificates(args.target, param, page))

	if args.ip_port_lookup:
		# detect whether input is cidr or ip or q
		if "/" in args.target:
			param = "cidr"
		elif ":" in args.target:
			param = "q"
		else:
			param = "ip"
		print(get_ip_port_lookup(args.target, param, page))

	if args.ip_port_lookup_aggregate:
		# detect whether input is cidr or ip or q
		if "/" in args.target:
			param = "cidr"
		elif ":" in args.target:
			param = "q"
		else:
			param = "ip"
		print(get_ip_port_lookup_aggregate(args.target, param, page))
