# encoding: utf-8
from burp import IBurpExtender
from burp import IHttpListener
from burp import ITab
from burp import IContextMenuFactory
from burp import IParameter
from StringIO import StringIO
from zipfile import ZipFile
from shutil import rmtree, make_archive, copytree, copy
from java.awt import GridLayout, Component, Color
from java.util import ArrayList
from javax.swing import JSplitPane, JTabbedPane, JButton, JPanel, JLabel, JTextArea, JList, BoxLayout, DefaultListModel, JScrollPane, JMenuItem, JTextField, JCheckBox
from jarray import array
from javax.swing.text import DefaultHighlighter
from time import sleep
import base64
import os
import threading

EXTENDER_FLAG = "zipFileRaiderFl4g"
ZIP_NAME = "myZip"
SCAN_ZIP_NAME = "myScanZip"
TEMP_PATH = "zipFileRaider" + os.sep + "tmp"
SCAN_TEMP_PATH = "zipFileRaider" + os.sep + "scan_tmp"
RUNNING_SCAN_PATH = "zipFileRaider" + os.sep + "running_scan_tmp"
INSETION_POINT_SYMBOL = u"§inserti0nP0int§"
PAYLOAD_PARAM_NAME = "extenderPayl0ad%d"
PAYLOAD_FILENAME = "extenderPayl0ad_filename"

class BurpExtender(IBurpExtender, IHttpListener, ITab, IContextMenuFactory):

    #
    # implement IBurpExtender
    #

    def	registerExtenderCallbacks(self, callbacks):
        self.isLock = False
        self.magicParam = None
        self.scanMagicParam = None
        self.scanMessageInfo = None
        self.repeaterMessageInfo = None
        self.currentScanItem = None
        self.scanInsertionPoint = {}

        # obtain an extension helpers object
        self._helpers = callbacks.getHelpers()
        self._callbacks = callbacks
        # set our extension name
        callbacks.setExtensionName("ZIP File Raider")
        # register ourselves as an HTTP listener
        callbacks.registerHttpListener(self)
        # register context menu
        callbacks.registerContextMenuFactory(self)

        self.initGUI()
        callbacks.addSuiteTab(self)
        print "[+]Init burp extender"

    ## implement IContextMenuFactory
    def createMenuItems(self, invocation):
        #get only  selected message
        self.messageInfo = invocation.getSelectedMessages()[0]
        menuItemList = ArrayList()
        menuItemList.add(JMenuItem("Send request to ZIP File Raider extender Repeater", actionPerformed = self.contextRepeaterClick))
        menuItemList.add(JMenuItem("Send request to ZIP File Raider extender Scanner", actionPerformed = self.contextScannerClick))
        return menuItemList

    def contextRepeaterClick(self, event):
        self.sendRequestToExtender("Repeater")

    def contextScannerClick(self, event):
        self.sendRequestToExtender("Scanner")

    def sendRequestToExtender(self, tab):
        #get filename
        zipfilename = "Archive(default_name).zip"
        filenameParam = self._helpers.getRequestParameter(self.messageInfo.getRequest(), "filename")
        if filenameParam == None:
            print "This request is not contain upload file"
            return
        if filenameParam.getType() == IParameter.PARAM_MULTIPART_ATTR:
            zipfilename = filenameParam.getValue()

        #get magicparam
        requestString = self._helpers.bytesToString(self.messageInfo.getRequest())
        magicParamStart, magicParamEnd = None, None

        initialIndex = filenameParam.getValueStart() - 12
        for i in range(initialIndex, 0 , -1):
            if requestString[i] == '"' :
                if magicParamEnd == None:
                    magicParamEnd = i
                elif requestString[i-6:i] == " name=":
                    magicParamStart = i + 1
                    break

        if magicParamStart == None:
            print "[-]Cannot detect file parameter name"
            return
        else:
            magicparam = requestString[magicParamStart:magicParamEnd]

        dataParameter = self._helpers.getRequestParameter(self.messageInfo.getRequest(), magicparam)
        #Check is zip upload or not
        if not dataParameter is None:
            value = dataParameter.getValue()
            if tab == "Repeater":
                self.repeaterMessageInfo = self.messageInfo
                self.extractZipFile(value, TEMP_PATH)
                self.showListFileDir(TEMP_PATH)
                self.repeaterZipFilename = zipfilename
                self.magicParam = magicparam
            else:
                self.removeDirectory(RUNNING_SCAN_PATH)
                self.scanTemplateFileName = []
                self.insertionPointCount = 0
                self.scanMessageInfo = self.messageInfo
                self.extractZipFile(value, SCAN_TEMP_PATH)
                self.showScanListFileDir(SCAN_TEMP_PATH)
                self.scanZipFilename = zipfilename
                self.scanMagicParam = magicparam
        else:
            print "no data param"

    ## implement IHttpListener
    def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
        # only process requests
        if not messageIsRequest:
            return

        extenderFlag = self._helpers.getRequestParameter(messageInfo.getRequest(), EXTENDER_FLAG)

        if not extenderFlag is None:

            while self.isLock:
                sleep(0.5)
                # print "sleep"
                pass 
            self.isLock = True

            payloads = []

            for i in range(0, self.insertionPointCount):
                paramData = self._helpers.getRequestParameter(messageInfo.getRequest(), PAYLOAD_PARAM_NAME % i)
                try:
                    payloads.append(paramData.getValue())
                except Exception as e :
                    payloads.append("")

            payloadsIndex = 0

            for template in self.scanTemplateFileName:
                newFileContent = ""

                fileContentString = self._helpers.bytesToString(self.runningScanTemplate[template])
                contentStrings = fileContentString.split(INSETION_POINT_SYMBOL)
                for i, s in enumerate(contentStrings):
                    newFileContent += s
                    if i == len(contentStrings) - 1:
                        break
                    else:
                        newFileContent += payloads[payloadsIndex]
                        payloadsIndex += 1

                newFileContent = self._helpers.stringToBytes(newFileContent)
                try:
                    self.writeFile(RUNNING_SCAN_PATH + os.sep + template, newFileContent)
                except Exception as e :
                    print "Error1 %s" % e

            # ZipAndGo
            try:
                self.compressToZip(SCAN_ZIP_NAME, RUNNING_SCAN_PATH + os.sep + SCAN_TEMP_PATH)
                zipContent = self.readFile(SCAN_ZIP_NAME + ".zip")
                newRequest = self._helpers.updateParameter(messageInfo.getRequest(), self._helpers.buildParameter(self.scanMagicParam, zipContent, IParameter.PARAM_BODY))

                # add filename
                if self.isScanZipFilename:
                    filenamePayload = self._helpers.getRequestParameter(messageInfo.getRequest(), PAYLOAD_FILENAME).getValue()
                    newRequest = self.addMultipartFilenameParam(filenamePayload ,newRequest, self.scanMagicParam)
                    newRequest = self._helpers.removeParameter(newRequest, self._helpers.buildParameter(PAYLOAD_FILENAME, "none", IParameter.PARAM_BODY))
                else:
                    newRequest = self.addMultipartFilenameParam(self.scanZipFilename ,newRequest, self.scanMagicParam)
                
                #remove unnecessary param
                for i in range(0, self.insertionPointCount):
                    newRequest = self._helpers.removeParameter(newRequest, self._helpers.buildParameter(PAYLOAD_PARAM_NAME%i, "none", IParameter.PARAM_BODY))
                newRequest = self._helpers.removeParameter(newRequest, self._helpers.buildParameter(EXTENDER_FLAG, "none", IParameter.PARAM_BODY))
                
                # set to newRequest
                messageInfo.setRequest(newRequest)
            except Exception as e :
                print "Error2 %s" % e

            # print "[+]request sent"
            self.isLock = False
            return

        else:
            # not from our extender
            return

    def extractZipFile(self, data, des_path):
        b = base64.b64encode(data)
        zipfile = ZipFile(StringIO(base64.b64decode(b)))
        # remove tmp folder
        self.removeDirectory(des_path)
        zipfile.extractall(des_path)
        print "[*]extract done"

    def compressToZip(self, zipnName, zipDirPath):
        make_archive(zipnName, "zip", zipDirPath)
        return

    def removeDirectory(self, rm_path):
        if not os.path.exists(rm_path):
            return
        try:
            rmtree(rm_path)
        except Exception as e :
            print "[-]Error while remove %s folder %s" % (rm_path, e)

    def showListFileDir(self, mypath):
        self.filename = []
        self.fileDirList = []
        self.absFilePath = {}
        for root, dirs, files in os.walk(mypath):
            path = root.split(os.sep)
            fname = os.path.basename(root)
            dirPath = (len(path) - 3) * "---" + fname
            self.fileDirList.append(dirPath)
            self.filename.append(fname)
            for file in files:
                filePath = (len(path)-2) * "---" + file
                self.fileDirList.append(filePath)
                self.filename.append(file)
                self.absFilePath[filePath] = root + os.sep + file
        self.fileDirList.remove(TEMP_PATH.split(os.sep)[1])
        self.filename.remove(TEMP_PATH.split(os.sep)[1])
        self.dirList.setListData(self.fileDirList)

    def showScanListFileDir(self, mypath):
        self.scanFilename = []
        self.scanFileDirList = []
        self.scanAbsFilePath = {}
        for root, dirs, files in os.walk(mypath):
            path = root.split(os.sep)
            fname = os.path.basename(root)
            dirPath = (len(path) - 3) * "---" + fname
            self.scanFileDirList.append(dirPath)
            self.scanFilename.append(fname)
            for file in files:
                filePath = (len(path)-2) * "---" + file
                self.scanFileDirList.append(filePath)
                self.scanFilename.append(file)
                self.scanAbsFilePath[filePath] = root + os.sep + file
        self.scanFileDirList.remove(SCAN_TEMP_PATH.split(os.sep)[1])
        self.scanFilename.remove(SCAN_TEMP_PATH.split(os.sep)[1])
        self.scanDirList.setListData(self.scanFileDirList)

    def listSelect(self, event):
        index = self.dirList.selectedIndex
        key = self.fileDirList[index]
        self.lblFilename.text = self.filename[index]
        if key in self.absFilePath:
            self.editField.setMessage(self.readFile(self.absFilePath[key]), False)
        else:
            #dir
            self.editField.setMessage("/*Directory*/", False)

    def scanListSelect(self, event):
        index = self.scanDirList.selectedIndex
        key = self.scanFileDirList[index]
        self.scanLblFilename.text = self.scanFilename[index]
        if key in self.scanAbsFilePath:
            #file
            if self.scanAbsFilePath[key] in self.scanTemplateFileName:
                content = self.readFile(self.scanAbsFilePath[key])
                for idx, el in enumerate(self.scanInsertionPoint[self.scanAbsFilePath[key]]):
                    # print el
                    content = self.setInsertionMark(content, el[0] + idx*2, el[1] + idx*2)
                self.scanEditField.setMessage(content, False)
            else:
                self.scanEditField.setMessage(self.readFile(self.scanAbsFilePath[key]), False)
        else:
            #dir
            self.scanEditField.setMessage("/*Directory*/", False)

    def readFile(self, path):
        file = open(path, "rb")
        fileContent = file.read()
        file.close()
        return fileContent

    def writeFile(self, path, content):
        file = open(path, "wb")
        file.write(content)
        file.close()

    def updateContentLength(self, request):
        request = self._helpers.addParameter(request, self._helpers.buildParameter("dump", "none", IParameter.PARAM_BODY))
        request = self._helpers.removeParameter(request, self._helpers.buildParameter("dump", "none", IParameter.PARAM_BODY))
        return request

    def addMultipartFilenameParam(self, zipfilename, request, magicparam):
        dataParameter = self._helpers.getRequestParameter(request, magicparam)
        getFilenameOffset = dataParameter.getNameEnd() + 1

        filename = '; filename="%s"' % zipfilename
        try:
            requestString = self._helpers.bytesToString(request)
            requestString = requestString[:getFilenameOffset] + filename + requestString[getFilenameOffset:]
            request = self._helpers.stringToBytes(requestString)
            request = self.updateContentLength(request)
            return request
        except Exception as e :
            print(e)
            return

    def makeRequest(self, zipContent):
        print "[+]thread is running (making request)"
        request = self.repeaterMessageInfo.getRequest()
        request = self._helpers.updateParameter(request, self._helpers.buildParameter(self.magicParam, zipContent, IParameter.PARAM_BODY))
        
        # add filename
        request = self.addMultipartFilenameParam(self.repeaterZipFilename ,request, self.magicParam)

        # sending request
        result = self._callbacks.makeHttpRequest(self.repeaterMessageInfo.getHttpService(), request)
        self.requestPanel.setMessage(result.getRequest(), True)
        try:
            self.responsePanel.setMessage(result.getResponse(), False)
        except Exception as e :
            self.responsePanel.setMessage("An error occured", False)
        print "[+]done"

    def btnGoClick(self, event):
        if self.repeaterMessageInfo == None:
            return
        self.saveEditFile()
        self.compressToZip(ZIP_NAME, TEMP_PATH)
        zipContent = self.readFile(ZIP_NAME + ".zip")

        t1 = threading.Thread(target=self.makeRequest, args=[zipContent])
        t1.start()
        # print "[+]thread start"

    def saveEditFile(self):
        if self.repeaterMessageInfo == None:
            return
        index = self.dirList.selectedIndex
        key = self.fileDirList[index]

        if key in self.absFilePath:
            #file
            content = self.editField.getMessage()
            self.writeFile(self.absFilePath[key], content)

    def btnSaveClick(self, event):
        self.saveEditFile()

    def btnClearClick(self, event):
        self.dirList.setListData([])
        self.editField.setMessage("", False)
        self.lblFilename.text = "File name"
        self.requestPanel.setMessage("", True)
        self.responsePanel.setMessage("", False)
        self.repeaterMessageInfo = None
        self.removeDirectory(TEMP_PATH)

    def btnResetRepeaterClick(self, event):
        print "btnClick"
        if self.repeaterMessageInfo == None:
            print "return"
            return
        dataParameter = self._helpers.getRequestParameter(self.repeaterMessageInfo.getRequest(), self.magicParam)
        value = dataParameter.getValue()
        # print value
        self.extractZipFile(value, TEMP_PATH)
        # self.sendRequestToExtender("Repeater")
        self.listSelect(event)

    def scanBtnClearClick(self, event):
        self.scanTemplateFileName = []
        self.scanInsertionPoint = {}
        self.insertionPointCount = 0
        self.scanDirList.setListData([])
        self.scanEditField.setMessage("", False)
        self.scanLblFilename.text = "File name"
        self.scanMessageInfo = None
        self.removeDirectory(SCAN_TEMP_PATH)
        self.removeDirectory(RUNNING_SCAN_PATH)

    def scanBtnClearInsClick(self, event):
        self.scanTemplateFileName = []
        self.scanInsertionPoint = {}
        self.insertionPointCount = 0
        self.removeDirectory(RUNNING_SCAN_PATH)
        self.scanListSelect(event)

    def addInsertionPoint(self, insStart, insEnd):
        index = self.scanDirList.selectedIndex
        key = self.scanFileDirList[index]

        if key in self.scanAbsFilePath:
            #file
            if not self.scanAbsFilePath[key] in self.scanTemplateFileName:
                self.scanTemplateFileName.append(self.scanAbsFilePath[key])
                self.scanInsertionPoint[self.scanAbsFilePath[key]] = [[insStart, insEnd]]
            else:
                offset = len(self.scanInsertionPoint[self.scanAbsFilePath[key]]) * 2
                self.scanInsertionPoint[self.scanAbsFilePath[key]].append([insStart - offset, insEnd - offset])

    def btnSetInsertionPointClick(self, event):
        if self.scanMessageInfo == None:
            return
        # show in UI
        insertionPointChar = u"§"

        selectedText = self.scanEditField.getSelectedData()
        if selectedText == None:
            print "[-]No selected area"
            return
        start = self.scanEditField.getSelectionBounds()[0]
        end = start + len(selectedText)

        requestString = self.scanEditField.getMessage()

        newRequestString = self.setInsertionMark(requestString, start, end)

        self.scanEditField.setMessage(newRequestString, False)

        #save insertion point
        self.addInsertionPoint(start, end)
        self.insertionPointCount += 1

    def setInsertionMark(self, requestString, start, end):
        insertionPointChar = u"§"
        selectedText = requestString[start:end]
        newRequestString = self._helpers.bytesToString(requestString[:start]) + insertionPointChar + self._helpers.bytesToString(selectedText) + insertionPointChar + self._helpers.bytesToString(requestString[end:])
        newRequestString = self._helpers.stringToBytes(newRequestString)
        return newRequestString

    def prepareScanRequest(self, request):
        for i in range(0, self.insertionPointCount):
            param = self._helpers.buildParameter(PAYLOAD_PARAM_NAME % i, self.runningScanDefaultPayload[i], IParameter.PARAM_BODY)
            request = self._helpers.addParameter(request, param)
        # add flag
        param = self._helpers.buildParameter(EXTENDER_FLAG, "1", IParameter.PARAM_BODY)
        request = self._helpers.addParameter(request, param)
        # add filename scan
        if self.checkboxScanFilename.isSelected():
            self.isScanZipFilename = True
            param = self._helpers.buildParameter(PAYLOAD_FILENAME, self.scanZipFilename, IParameter.PARAM_BODY)
            request = self._helpers.addParameter(request, param)
        else:
            self.isScanZipFilename = False
        return request

    def prepareScanInsertionOffset(self, request, paramName):
        param = self._helpers.getRequestParameter(request, paramName)
        startOffset = param.getValueStart()
        endOffset = param.getValueEnd()
        return array([startOffset, endOffset], 'i')

    def btnScanClick(self, event):
        if self.scanMessageInfo == None:
            return
        self.runningScanTemplate = {}
        self.runningScanDefaultPayload = []
        self.removeDirectory(RUNNING_SCAN_PATH)

        os.makedirs(RUNNING_SCAN_PATH)
        copytree(SCAN_TEMP_PATH, RUNNING_SCAN_PATH + os.sep + SCAN_TEMP_PATH)

        # self.insertionPointCount = 3
        insertionPointNo = 0

        # read template
        for template in self.scanTemplateFileName:
            t = self._helpers.bytesToString(self.readFile(template))
            temp = ""
            insertionPointNoOfFile = 0
            # point to begin of file
            insPoint = []
            for el in self.scanInsertionPoint[template]:
                insPoint.append(el[0])
                insPoint.append(el[1])
            insPoint.sort()
            currentPoint = 0
            for i in xrange(0, len(insPoint) - 1, 2):
                # print p
                temp += t[currentPoint:insPoint[i]] + INSETION_POINT_SYMBOL
                currentPoint = insPoint[i + 1]
                self.runningScanDefaultPayload.append(t[insPoint[i]:insPoint[i + 1]])
                insertionPointNo += 1
            temp += t[currentPoint:]
            temp = self._helpers.stringToBytes(temp)

            self.runningScanTemplate[template] = temp

        if insertionPointNo != self.insertionPointCount:
            print "[-]Error while parsing template"
            return

        #send to scanner
        httpService = self.scanMessageInfo.getHttpService()
        # request = self.scanMessageInfo.getRequest()
        request = self.prepareScanRequest(self.scanMessageInfo.getRequest())
        isHttps = True if httpService.getProtocol() == 'https' else False
        insertionOffset = []

        for i in range(0, self.insertionPointCount):
            insertionOffset.append(self.prepareScanInsertionOffset(request,PAYLOAD_PARAM_NAME % i))
        if self.isScanZipFilename:
            insertionOffset.append(self.prepareScanInsertionOffset(request,PAYLOAD_FILENAME))
        self.currentScanItem = self._callbacks.doActiveScan(httpService.getHost(), httpService.getPort(), isHttps, request, insertionOffset)
        print "[*]Scanner is running"
        self._callbacks.issueAlert("Send to Active Scanner")
        t = threading.Thread(target=self.checkScannerStatus)
        t.start()
        
    def checkScannerStatus(self):
        self.disableScanUi()
        while True:
            if self.currentScanItem == None:
                self.scannerStatusLabel.text = "<html><i style='color:grey'> Canceled</i></html>"
                self.enableScanUi()
                return
            else:
                status = self.currentScanItem.getStatus()
                if status == "finished":
                    self.scannerStatusLabel.text = "<html><i style='color:green'> Complete</i></html>"
                    self.enableScanUi()
                    self._callbacks.issueAlert("Scan Complete")
                    return
                self.scannerStatusLabel.text = "<html><i style='color:orange'> %s</i></html>" % (status)
            #schedule run every 1 sec
            sleep(1)

    def cancelScan(self, event):
        self.currentScanItem.cancel()
        self.currentScanItem = None
        self.enableScanUi()

    def disableScanUi(self):
        self.scanBtnCancel.setEnabled(True)
        self.scanBtnGo.setEnabled(False)
        self.scanBtnSave.setEnabled(False)
        self.scanBtnClearInsertionPoint.setEnabled(False)
        self.scanBtnClear.setEnabled(False)
        self.scanDirList.setEnabled(False)
    
    def enableScanUi(self):
        self.scanBtnCancel.setEnabled(False)
        self.scanBtnGo.setEnabled(True)
        self.scanBtnSave.setEnabled(True)
        self.scanBtnClearInsertionPoint.setEnabled(True)
        self.scanBtnClear.setEnabled(True)
        self.scanEditField.setMessage("", False)
        self.scanDirList.setEnabled(True)

    #init extender GUI
    def initGUI(self):
        #
        # Manual tab
        #
        tabPane = JTabbedPane(JTabbedPane.TOP)
        reqRestabPane = JTabbedPane(JTabbedPane.TOP)
        splitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT)
        tabPane.addTab("Repeater", splitPane)
        splitPane2 = JSplitPane(JSplitPane.HORIZONTAL_SPLIT)
        splitPane.setLeftComponent(splitPane2)

        panel1 = JPanel()
        panel2 = JPanel()

        splitPane2.setLeftComponent(panel1)
        splitPane2.setRightComponent(panel2)
        splitPane.setRightComponent(reqRestabPane)

        panel1.setLayout(BoxLayout(panel1,BoxLayout.Y_AXIS))
        panel2.setLayout(BoxLayout(panel2,BoxLayout.Y_AXIS))

        self.requestPanel = self._callbacks.createMessageEditor(None, False)
        self.responsePanel = self._callbacks.createMessageEditor(None, False)

        label1 = JLabel("files and folders")
        self.lblFilename = JLabel("File name")
        label3 = JLabel("Response")
        self.editField = self._callbacks.createMessageEditor(None, True)
        self.dirList = JList([], valueChanged = self.listSelect)

        listFileDirPane = JScrollPane(self.dirList)

        ## Set left align
        listFileDirPane.setAlignmentX(Component.LEFT_ALIGNMENT)

        btnPanel = JPanel()
        btnGo = JButton("Compress & Go", actionPerformed = self.btnGoClick)
        btnSave = JButton("Save", actionPerformed = self.btnSaveClick)
        btnClear = JButton("Clear", actionPerformed = self.btnClearClick)
        btnReset = JButton("Reset", actionPerformed = self.btnResetRepeaterClick)
        btnPanel.add(btnGo)
        btnPanel.add(btnSave)
        btnPanel.add(btnReset)
        btnPanel.add(btnClear)
        btnPanel.setLayout(BoxLayout(btnPanel,BoxLayout.X_AXIS))

        panel1.add(label1)
        panel1.add(listFileDirPane)

        panel2.add(self.lblFilename)
        panel2.add(self.editField.getComponent())
        panel2.add(btnPanel)

        reqRestabPane.addTab("Response",self.responsePanel.getComponent())
        reqRestabPane.addTab("Request",self.requestPanel.getComponent())

        splitPane.setResizeWeight(0.6)

        #
        # Scanner tab
        #
        scanSplitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT)
        tabPane.addTab("Scanner", scanSplitPane)
        scanSplitPane2 = JSplitPane(JSplitPane.HORIZONTAL_SPLIT)
        scanSplitPane.setLeftComponent(scanSplitPane2)

        scanPanel1 = JPanel()
        scanPanel2 = JPanel()
        scanPanel3 = JPanel()
        scanSplitPane2.setLeftComponent(scanPanel1)
        scanSplitPane2.setRightComponent(scanPanel2)
        scanSplitPane.setRightComponent(scanPanel3)

        scanPanel1.setLayout(BoxLayout(scanPanel1,BoxLayout.Y_AXIS))
        scanPanel2.setLayout(BoxLayout(scanPanel2,BoxLayout.Y_AXIS))
        scanPanel3.setLayout(BoxLayout(scanPanel3,BoxLayout.Y_AXIS))

        scanLabel1 = JLabel("files and folders")
        self.scanLblFilename = JLabel("File name")
        scanLabel3 = JLabel("<html><h3>Config scanner</h3></html>")
        scanLabel4 = JLabel("<html><h3>Scanner status</h3></html>")
        scanLabel5 = JLabel("""<html>
                                <div>
                                    <h3>Notice</h3>
                                    <ul>
                                        <li>Possible to run only a scan at time</li>
                                        <li>Work with .zip file only</li>
                                        <li>Cannot continue after exit Burp</li>
                                    </ul>
                                </div>
                            </html>""")
        self.scannerStatusLabel = JLabel("<html><i style='color:grey'> Not Running</i></html>")
        self.checkboxScanFilename = JCheckBox("Also scan zip filename (this may be upload several files to server)")
        self.scanEditField = self._callbacks.createMessageEditor(None, False)
        self.scanDirList = JList([], valueChanged = self.scanListSelect)

        scanListFileDirPane = JScrollPane(self.scanDirList)

        ## Set left align
        scanListFileDirPane.setAlignmentX(Component.LEFT_ALIGNMENT)

        scanBtnPanel = JPanel()
        self.scanBtnGo = JButton("Set insertion point", actionPerformed = self.btnSetInsertionPointClick)
        self.scanBtnSave = JButton("Send to scanner", actionPerformed = self.btnScanClick)
        self.scanBtnClearInsertionPoint = JButton("Clear insertion points", actionPerformed = self.scanBtnClearInsClick)
        self.scanBtnClear = JButton("Clear", actionPerformed = self.scanBtnClearClick)
        self.scanBtnCancel = JButton("Cancel", actionPerformed = self.cancelScan)
        scanBtnPanel.add(self.scanBtnGo)
        scanBtnPanel.add(self.scanBtnSave)
        scanBtnPanel.add(self.scanBtnClearInsertionPoint)
        scanBtnPanel.add(self.scanBtnClear)
        scanBtnPanel.setLayout(BoxLayout(scanBtnPanel,BoxLayout.X_AXIS))

        scanPanel1.add(scanLabel1)
        scanPanel1.add(scanListFileDirPane)

        scanPanel2.add(self.scanLblFilename)
        scanPanel2.add(self.scanEditField.getComponent())
        scanPanel2.add(scanBtnPanel)
        
        scanPanel3.add(scanLabel3)
        scanPanel3.add(self.checkboxScanFilename)
        scanPanel3.add(scanLabel4)
        scanPanel3.add(self.scannerStatusLabel)
        scanPanel3.add(self.scanBtnCancel)
        self.scanBtnCancel.setEnabled(False)
        scanPanel3.add(scanLabel5)

        scanSplitPane.setResizeWeight(0.6)

        self.tab = tabPane

    # implement ITab
    def getTabCaption(self):
        return "ZIP File Raider"

    def getUiComponent(self):
        return self.tab