import socket
import csv as csvmod
import json as jjson
from xml.dom import minidom

from wfuzz.externals.moduleman.plugin import moduleman_plugin
from wfuzz.plugin_api.base import BasePrinter
from wfuzz.fuzzobjects import FuzzResult

@moduleman_plugin
class magictree(BasePrinter):
    name = "magictree"
    author = ("Xavi Mendez (@xmendez)",)
    version = "0.1"
    summary = "Prints results in magictree format"
    category = ["default"]
    priority = 99

    def __init__(self, output):
        BasePrinter.__init__(self, output)
	self.node_mt = None
	self.node_service = None

    def __create_xml_element(self, parent, caption, text):
	# Create a <xxx> element
	doc = minidom.Document()
	el = doc.createElement(caption)
	parent.appendChild(el)

	# Give the <xxx> element some text
	ptext = doc.createTextNode(text)

	el.appendChild(ptext)
	return el

    def header(self, summary):
	doc = minidom.Document()

	#<magictree class="MtBranchObject">
	self.node_mt = doc.createElement("magictree")
	self.node_mt.setAttribute("class", "MtBranchObject")

	#<testdata class="MtBranchObject">
	node_td = doc.createElement("testdata")
	node_td.setAttribute("class", "MtBranchObject")
	self.node_mt.appendChild(node_td)

	#<host>209.85.146.105
	host = summary.seed.history.host
	if host.find(":") > 0:
	    host, port = host.split(":")
	else:
	    port = 80
	    if summary.seed.history.scheme.lower() == "https":
		port = 443

	try:
	    resolving = socket.gethostbyname(host)
	    node_h = self.__create_xml_element(node_td, "host", str(resolving))
	except socket.gaierror:
	    node_h = self.__create_xml_element(node_td, "host", str(host))

	#<ipproto>tcp
	node_ipr = self.__create_xml_element(node_h, "ipproto", "tcp")

	#<port>80<state>open</state><service>http
	node_port = self.__create_xml_element(node_ipr, "port", str(port))
	self.__create_xml_element(node_port, "state", "open")
	if summary.seed.history.scheme.lower() == "https":
	    node_port = self.__create_xml_element(node_port, "tunnel", "ssl")

	self.node_service = self.__create_xml_element(node_port, "service", "http")

    def result(self, fuzz_result):
        if fuzz_result.type == FuzzResult.result:
            node_url = self.__create_xml_element(self.node_service, "url", str(fuzz_result.url))

            if 'Server' in fuzz_result.history.headers.response:
                self.__create_xml_element(node_url, "HTTPServer", fuzz_result.history.headers.response['Server'])

            location = ""
            if 'Location' in fuzz_result.history.headers.response:
                location = fuzz_result.history.headers.response['Location']

            if fuzz_result.code == 301 or fuzz_result.code == 302 and location:
                self.__create_xml_element(node_url, "RedirectLocation", location)

            self.__create_xml_element(node_url, "ResponseCode", str(fuzz_result.code))
            self.__create_xml_element(node_url, "source", "WFuzz")

    def footer(self, summary):
	self.f.write(self.node_mt.toxml())

@moduleman_plugin
class html(BasePrinter):
    name = "html"
    author = ("Carlos del Ojo", "Christian Martorella", "Adapted to newer versions Xavi Mendez (@xmendez)")
    version = "0.1"
    summary = "Prints results in html format"
    category = ["default"]
    priority = 99

    def __init__(self, output):
        BasePrinter.__init__(self, output)

    def header(self, summary):
	url = summary.url

	self.f.write("<html><head></head><body bgcolor=#000000 text=#FFFFFF><h1>Fuzzing %s</h1>\r\n<table border=\"1\">\r\n<tr><td>#request</td><td>Code</td><td>#lines</td><td>#words</td><td>Url</td></tr>\r\n" % (url) )

    def result(self, fuzz_result):
        if fuzz_result.type == FuzzResult.result:
            htmlc="<font>"

            if fuzz_result.code >= 400 and fuzz_result.code < 500:
                htmlc = "<font color=#FF0000>"
            elif fuzz_result.code>=300 and fuzz_result.code < 400:
                htmlc = "<font color=#8888FF>"
            elif fuzz_result.code>=200 and fuzz_result.code < 300:
                htmlc = "<font color=#00aa00>"

            if fuzz_result.history.method.lower() == "post":
                inputs=""
                for n, v in fuzz_result.history.params.post.items():
                    inputs+="<input type=\"hidden\" name=\"%s\" value=\"%s\">" % (n, v)

                self.f.write ("\r\n<tr><td>%05d</td>\r\n<td>%s%d</font></td>\r\n<td>%4dL</td>\r\n<td>%5dW</td>\r\n<td><table><tr><td>%s</td><td><form method=\"post\" action=\"%s\">%s<input type=submit name=b value=\"send POST\"></form></td></tr></table></td>\r\n</tr>\r\n" %(fuzz_result.nres, htmlc, fuzz_result.code, fuzz_result.lines, fuzz_result.words, fuzz_result.description, fuzz_result.url, inputs))
            else:
                self.f.write("\r\n<tr><td>%05d</td><td>%s%d</font></td><td>%4dL</td><td>%5dW</td><td><a href=%s>%s</a></td></tr>\r\n" %(fuzz_result.nres, htmlc, fuzz_result.code, fuzz_result.lines, fuzz_result.words, fuzz_result.url, fuzz_result.url))

    def footer(self, summary):
	self.f.write("</table></body></html><h5>Wfuzz by EdgeSecurity<h5>\r\n")

@moduleman_plugin
class json(BasePrinter):
    name = "json"
    summary = "Results in json format"
    author = ("Federico (@misterade)", "Minor rework by Ilya Glotov (@ilyaglow)")
    version = "0.2"
    category = ["default"]
    priority = 99


    def __init__(self, output):
        BasePrinter.__init__(self, output)
        self.json_res = []

    def header(self, res):
        pass

    def result(self, res):
        if res.type == FuzzResult.result:
            server = ""
            if 'Server' in res.history.headers.response:
                server = res.history.headers.response['Server']
            location = ""
            if 'Location' in res.history.headers.response:
                location = res.history.headers.response['Location']
            elif res.history.url != res.history.redirect_url:
                location = "(*) %s" % res.history.url
            post_data = []
            if res.history.method.lower() == "post":
                for n, v in res.history.params.post.items():
                    post_data.append({"parameter": n, "value": v})

            res_entry = {
                "chars": res.chars,
                "code": res.code,
                "payload": res.description,
                "lines": res.lines,
                "location": location,
                "method": res.history.method,
                "post_data": post_data,
                "server": server,
                "url": res.url,
                "words": res.words
            }
            self.json_res.append(res_entry)

    def footer(self, summary):
        self.f.write(jjson.dumps(self.json_res))



@moduleman_plugin
class raw(BasePrinter):
    name = "raw"
    author = ("Xavi Mendez (@xmendez)",)
    version = "0.1"
    summary = "Raw output format"
    category = ["default"]
    priority = 99

    def __init__(self, output):
        BasePrinter.__init__(self, output)

    def header(self, summary):
	self.f.write("Target: %s\n" % summary.url)

	if summary.total_req > 0:
	    self.f.write("Total requests: %d\n" % summary.total_req)
	else:
            self.f.write("Total requests: <<unknown>>\n")

        if self.verbose:
            self.f.write("==============================================================================================================================================\n")
            self.f.write("ID	C.Time   Response   Lines      Word         Chars                  Server                                             Redirect   Payload    \n")
            self.f.write("==============================================================================================================================================\n")
        else:
            self.f.write("==================================================================\n")
            self.f.write("ID	Response   Lines      Word         Chars          Request    \n")
            self.f.write("==================================================================\n")

    def _print_verbose(self, res):
	self.f.write("%05d:  " % res.nres)
	self.f.write("%.3fs   C=" % res.timer)

	location = ""
	if 'Location' in res.history.headers.response:
	    location = res.history.headers.response['Location']
	elif res.history.url != res.history.redirect_url:
	    location = "(*) %s" % res.history.url

	server = ""
	if 'Server' in res.history.headers.response:
	    server = res.history.headers.response['Server']

	if res.exception:
	    self.f.write("XXX")
	else:
	    self.f.write("%05d:  C=%03d" % (res.nres, res.code))

	self.f.write("   %4d L\t   %5d W\t  %5d Ch  %20.20s  %51.51s   \"%s\"\n" % (res.lines, res.words, res.chars, server[:17], location[:48], res.description))

	for i in res.plugins_res:
		self.f.write("  |_ %s\n" % i.issue)

    def _print(self, res):
	if res.exception:
	    self.f.write("XXX")
	else:
	    self.f.write("%05d:  C=%03d" % (res.nres, res.code))

	self.f.write("   %4d L\t   %5d W\t  %5d Ch\t  \"%s\"\n" % (res.lines, res.words, res.chars, res.description))

	for i in res.plugins_res:
		self.f.write("  |_ %s\n" % i.issue)

    def result(self, res):
        if res.type == FuzzResult.result:
            if self.verbose:
                self._print_verbose(res)
            else:
                self._print(res)

    def footer(self, summary):
	self.f.write("\n")
	self.f.write("Total time: %s\n" % str(summary.totaltime)[:8])

	if summary.backfeed() > 0:
	    self.f.write("Processed Requests: %s (%d + %d)\n" % (str(summary.processed())[:8], (summary.processed() - summary.backfeed()), summary.backfeed()))
	else:
	    self.f.write("Processed Requests: %s\n" % (str(summary.processed())[:8]))
	self.f.write("Filtered Requests: %s\n" % (str(summary.filtered())[:8]))
	self.f.write("Requests/sec.: %s\n" % str(summary.processed()/summary.totaltime if summary.totaltime > 0 else 0)[:8])

@moduleman_plugin
class csv(BasePrinter):
    name = "csv"
    author=("@Yoginski initial version","Adapted by @egilas to work in newer version of wfuzz")
    summary="CSV printer ftw"
    version="1.0"
    category = ["default"]
    priority = 99
    
    def write(self,e):
        self.f.write(e)
        pass
    
    def __init__(self,output):
        BasePrinter.__init__(self, output)
        self.csv_writer = csvmod.writer(self)

    def header(self, summary):
	self._print_csv(["id", "response", "lines", "word", "chars", "request", "success"])

    def result(self, res):
        if res.type == FuzzResult.result:
            line = [ res.nres,
                    res.code,
                    res.lines,
                    res.words,
                    res.chars,
                    res.description,
                    0 if res.exception else 1]
            self._print_csv(line)

    def noresult(self, res):
        pass

    def footer(self, summary):
        pass

    def _print_csv(self, values):
	self.csv_writer.writerow(values)

