"""
# SOAP Attack
#
# FILENAME      : PDFWriter.py
# AUTHORS       : Andres Andreu <andres [at] neurofuzz dot com>
#                 Cosmin Banciu <ccbanciu [at] gmail dot com>
# MODIFIED BY   : Andres Andreu
# DATE          : 10/8/2008
# LAST UPDATE   : 9/12/2010
# ABSTRACT      : A class to handle the logging of results to a PDF file
#
# Copyright (c) 2008 - 2010 neuroFuzz, LLC
#
"""

import cgi
import os

from cStringIO import StringIO
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch
from reportlab.platypus import Paragraph
from reportlab.platypus import SimpleDocTemplate
from reportlab.platypus import Spacer
from reportlab.platypus import Table
from reportlab.platypus import TableStyle
from reportlab.platypus import XPreformatted
from reportlab.platypus.flowables import Image
from reportlab.rl_config import defaultPageSize

from inc import xmlpp

'''
   PDFWriter is a class that controls all logging
   functionality to PDF file output
'''
class PDFWriter(object):
    def __init__(self, path=None):
        object.__init__(self)
        self.docPath = path
        self.docPathName = path + "/WSFuzzer_Results.pdf"
        self.doc = SimpleDocTemplate(self.docPathName)
        self.title = "neuroFuzz WSFuzzer - SOAP Attack results"
        self.pageinfo = "SENSITIVE - generated by neuroFuzz WSFuzzer - http://www.neurofuzz.com"
        self.styles = getSampleStyleSheet()
        self.PAGE_HEIGHT=defaultPageSize[1]
        self.PAGE_WIDTH=defaultPageSize[0]
        self.Story = [Spacer(1,2*inch)]
        self.style = self.styles["Normal"]
        self.GRID_STYLE = TableStyle(
              [('GRID', (0,0), (-1,-1), 0.25, colors.black),
                    ('ALIGN', (1,1), (-1,-1), 'LEFT')]
              )

    # NAME     : doCoverPage
    # PARAMS   : canvas, doc
    # RETURN   : Nothing
    # DESC     : draws out the cover page onto the canvas obj
    def doCoverPage(self, canvas, doc):
        canvas.saveState()
        canvas.setFont('Times-Bold',12)
        canvas.drawCentredString(self.PAGE_WIDTH/2.0,
                self.PAGE_HEIGHT-108, self.title)
        canvas.setFont('Times-Roman',9)
        canvas.drawString(inch, 0.75 * inch,
                "Cover Page / %s" % self.pageinfo)
        canvas.setAuthor('WSFuzzer - neuroFuzz, LLC')
        canvas.setTitle('WSFuzzer SOAP Attack Penetration Test Results')
        canvas.setSubject('WSFuzzer Results')

        canvas.restoreState()
    # EOF: doCoverPage

    # NAME     : doOtherPages
    # PARAMS   : canvas, doc
    # RETURN   : Nothing
    # DESC     : draws out the structure for everything
    #			 other then the cover page
    def doOtherPages(self, canvas, doc):
        canvas.saveState()
        canvas.setFont('Times-Roman', 9)
        canvas.drawString(inch, 0.75 * inch,
                "Page %d %s" % ((self.doc.page-1), self.pageinfo))
        canvas.restoreState()
    # EOF: doOtherPages

    # NAME     : convertToN
    # PARAMS   : str
    # RETURN   : string
    # DESC     : replaces some XML data so that it
    #            can be displayed properly in the PDF
    def convertToN(self, str):
        c = str
        c = c.replace("\" x","\"\nx")
        c = c.replace("\" S","\"\nS")
        c = c.replace("' x","'\nx")
        c = c.replace("' S","'\nS")
        c = c.replace("&quot; S","&quot;\nS")
        c = c.replace("&quot; x", '&quot;\nx')
        c = c.replace("&gt;&lt;","&gt;\n&lt;")

        return c
    # EOF: convertToN


	# NAME	 : writeData
	# PARAMS : method,params,request,attacktype,idsevasion,roundtrip,rawresponse,code,xmlpayload
	# RETURN : Nothing
	# DESC	 : draws out the data to the PDF obj
    def writeData(self, method=None, params=None, request=None, attacktype=None, idsEvasion=None,
                  roundtrip=None, rawresponse=None, code=None, xmlpayload=None):

        file_str_req = StringIO()
        file_str_resp = StringIO()
        colwidths = ( 1*inch, self.PAGE_WIDTH-(2*inch) )
        dataarr = []

        #################################################################
        # Request
        if attacktype:
            dataarr.append(('Type of Attack',attacktype))
        else:
            dataarr.append(('Type of Attack','Unknown Attack Type'))

        if method:
            dataarr.append(('Method',method))
        else:
            dataarr.append(('Method','Unknown Method'))

        if type(params) is str:
            dataarr.append(('Request Params',params))
        elif type(params) is dict:
            forprint = {}
            # loop on dict escaping HTML entities
            for k,v in params.iteritems():
                forprint[k] = v
            dataarr.append(('Request Params',forprint))
        else:
            dataarr.append(('Request Params','Unknown Params'))

        if idsEvasion:
            dataarr.append(('IDS Evasion',idsEvasion))
        else:
            dataarr.append(('IDS Evasion','Not Used'))
        #################################################################
        #################################################################
        # Response
        if code:
            dataarr.append(('Status Code',code))
        else:
            dataarr.append(('Status Code','Unknown Code'))

        if rawresponse:
            if rawresponse[1] == 1:
                for xx in rawresponse[0]:
                    try:
                        dataarr.append(('Response',Paragraph(str(xx), self.style)))
                    except ValueError:
                        pass
            elif type(rawresponse) is str:
                dataarr.append(('Response',Paragraph(str(rawresponse), self.style)))
            else:
                try:
                    dataarr.append(('Response',Paragraph(str(rawresponse[0]), self.style)))
                except ValueError:
                    pass
        else:
            dataarr.append(('Response','No response extracted'))

        if roundtrip:
            dataarr.append(('Round Trip',roundtrip))
        else:
            dataarr.append(('Round Trip','Unknown Roundtrip'))
        #################################################################

        #################################################################
        # Paylaods
        # Request
        c = cgi.escape(xmlpp.get_pprint(request).strip(), 1)
        c = self.convertToN(c)
        file_str_req.write(str(c))

        # Response
        if xmlpayload:
            c = cgi.escape(xmlpp.get_pprint(xmlpayload).strip(), 1)
            c = self.convertToN(c)
            file_str_resp.write(str(c))

        preqheader = Paragraph("Request:", self.style)
        preq = XPreformatted(str(file_str_req.getvalue()), self.style)
        prespheader = Paragraph("Response:", self.style)
        presp = XPreformatted(str(file_str_resp.getvalue()), self.style)

        # create a list (array) of all values to write
        # then cast to tuple of tuples
        # so array/list looks like: [('l', 'xx'), ('ll', 'xxx'), ('lll', 'xxxxx')]
        data = tuple(dataarr)
        t = Table( data, colwidths, rowHeights=None )
        t.setStyle( self.GRID_STYLE )

        self.Story.append( t )
        self.Story.append(Spacer(1,0.2*inch))
        self.Story.append(preqheader)
        self.Story.append(Spacer(1,0.2*inch))
        self.Story.append(preq)
        self.Story.append(Spacer(1,0.2*inch))
        self.Story.append(prespheader)
        self.Story.append(Spacer(1,0.2*inch))
        self.Story.append(presp)
        self.Story.append(Spacer(1,0.2*inch))
    # EOF: writeData

    # NAME     : insertImage
    # PARAMS   : None
    # RETURN   : Nothing
    # DESC     : actually creates the PDF obj after
    #             is written to memory
    def insertImage(self, imagePath, height, width):
        img = Image(imagePath)
        img.drawHeight = height
        img.drawWidth = width
        self.Story.append(img)
    # EOF: insertImage

    # NAME     : createDoc
    # PARAMS   : None
    # RETURN   : Nothing
    # DESC     : actually creates the PDF obj after
    #			 is written to memory
    def createDoc(self):
        self.doc.build(self.Story, onFirstPage=self.doCoverPage,
           onLaterPages=self.doOtherPages)
    # EOF: createDoc

	# NAME	 : encryptPDF
	# PARAMS : None
	# RETURN : Nothing
	# DESC	 : encrypts the PDF that has already been created.
	#		   this is done via an external java prog called PDFBox,
	#		   which ir jar'd up into the file pdfbox.jar
    def encryptPDF(self):
        cmd ='java -classpath wsdlparser/pdfbox.jar:wsdlparser/bcprov-jdk15-138.jar org/pdfbox/Encrypt ' \
        '-U %s -canModify false -canModifyAnnotations false -canPrint true -canAssemble true ' \
        '-canExtractContent true -keyLength 128 ' \
        '%s %s/enc.pdf' % ('password',self.docPathName,self.docPath)
        os.system(cmd)
    # EOF: encryptPDF
