Exemple #1
0
 def _initSplittedLayout(self):
     """Init Splitted layout. It's more convenient for intercept."""
     self._vpaned = RememberingVPaned(self.w3af, 'trap_view')
     self._vpaned.show()
     self.pack_start(self._vpaned, True, True)
     self._vpaned.add(self.request)
     self._vpaned.add(self.response)
Exemple #2
0
 def _initSplittedLayout(self):
     """Init Splitted layout. It's more convenient for intercept."""
     self._vpaned = RememberingVPaned(self.w3af, "trap_view")
     self._vpaned.show()
     self.pack_start(self._vpaned, True, True)
     self._vpaned.add(self.request)
     self._vpaned.add(self.response)
Exemple #3
0
    def _initReqResViewer(self, mainvbox):
        """Create the req/res viewer."""
        self._req_res_viewer = ReqResViewer(self.w3af,
                                            editableRequest=False,
                                            editableResponse=False)
        self._req_res_viewer.set_sensitive(False)
        # Create the req/res selector (when a search with more
        # than one result is done, this window appears)
        self._sw = gtk.ScrolledWindow()
        self._sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self._lstore = gtk.ListStore(gobject.TYPE_UINT, gobject.TYPE_BOOLEAN,
                                     gobject.TYPE_STRING, gobject.TYPE_STRING,
                                     gobject.TYPE_STRING, gobject.TYPE_UINT,
                                     gobject.TYPE_STRING, gobject.TYPE_UINT,
                                     gobject.TYPE_STRING, gobject.TYPE_FLOAT)
        # Create tree view
        self._lstoreTreeview = gtk.TreeView(self._lstore)
        self._lstoreTreeview.set_rules_hint(True)
        self._lstoreTreeview.set_search_column(0)
        self.__add_columns(self._lstoreTreeview)
        self._lstoreTreeview.show()
        self._lstoreTreeview.connect('cursor-changed',
                                     self._view_in_req_res_viewer)
        # Popup menu
        self._rightButtonMenu = None
        self._lstoreTreeview.connect('button-press-event', self._popupMenu)
        #
        #
        # Selection
        #
        treeselection = self._lstoreTreeview.get_selection()
        treeselection.set_mode(gtk.SELECTION_MULTIPLE)

        self._sw.add(self._lstoreTreeview)
        #self._sw.set_sensitive(False)
        self._sw.show_all()
        # I want all sections to be resizable
        self._vpan = RememberingVPaned(self.w3af, "pane-swandrRV", 100)
        self._vpan.pack1(self._sw)
        self._vpan.pack2(self._req_res_viewer)
        self._vpan.show()
        mainvbox.pack_start(self._vpan)
Exemple #4
0
    def _initReqResViewer(self, mainvbox):
        """Create the req/res viewer."""
        self._req_res_viewer = ReqResViewer(self.w3af, editableRequest=False,
                                            editableResponse=False)
        self._req_res_viewer.set_sensitive(False)
        # Create the req/res selector (when a search with more
        # than one result is done, this window appears)
        self._sw = gtk.ScrolledWindow()
        self._sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self._lstore = gtk.ListStore(gobject.TYPE_UINT, gobject.TYPE_BOOLEAN,
                                     gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING,
                                     gobject.TYPE_UINT, gobject.TYPE_STRING,
                                     gobject.TYPE_UINT, gobject.TYPE_STRING, gobject.TYPE_FLOAT)
        # Create tree view
        self._lstoreTreeview = gtk.TreeView(self._lstore)
        self._lstoreTreeview.set_rules_hint(True)
        self._lstoreTreeview.set_search_column(0)
        self.__add_columns(self._lstoreTreeview)
        self._lstoreTreeview.show()
        self._lstoreTreeview.connect(
            'cursor-changed', self._view_in_req_res_viewer)
        # Popup menu
        self._rightButtonMenu = None
        self._lstoreTreeview.connect('button-press-event', self._popupMenu)
        #
        #
        # Selection
        #
        treeselection = self._lstoreTreeview.get_selection()
        treeselection.set_mode(gtk.SELECTION_MULTIPLE)

        self._sw.add(self._lstoreTreeview)
        #self._sw.set_sensitive(False)
        self._sw.show_all()
        # I want all sections to be resizable
        self._vpan = RememberingVPaned(self.w3af, "pane-swandrRV", 100)
        self._vpan.pack1(self._sw)
        self._vpan.pack2(self._req_res_viewer)
        self._vpan.show()
        mainvbox.pack_start(self._vpan)
Exemple #5
0
class reqResViewer(gtk.VBox):
    """
    A widget with the request and the response inside.

    :author: Andres Riancho ([email protected])
    :author: Facundo Batista ( [email protected] )

    """

    def __init__(
        self,
        w3af,
        enableWidget=None,
        withManual=True,
        withFuzzy=True,
        withCompare=True,
        withAudit=True,
        editableRequest=False,
        editableResponse=False,
        widgname="default",
        layout="Tabbed",
    ):

        super(reqResViewer, self).__init__()
        self.w3af = w3af
        # Request
        self.request = requestPart(self, w3af, enableWidget, editableRequest, widgname=widgname)
        self.request.show()
        # Response
        self.response = responsePart(self, w3af, editableResponse, widgname=widgname)
        self.response.show()
        self.layout = layout
        if layout == "Tabbed":
            self._initTabbedLayout()
        else:
            self._initSplittedLayout()
        # Init req toolbox
        self._initToolBox(withManual, withFuzzy, withCompare, withAudit)
        self.show()

    def _initTabbedLayout(self):
        """Init Tabbed layout. It's more convenient for quick view."""
        nb = gtk.Notebook()
        nb.show()
        self.nb = nb
        self.pack_start(nb, True, True)
        nb.append_page(self.request, gtk.Label(_("Request")))
        nb.append_page(self.response, gtk.Label(_("Response")))
        # Info
        self.info = HttpEditor(self.w3af)
        self.info.set_editable(False)
        # self.info.show()
        nb.append_page(self.info, gtk.Label(_("Info")))

    def _initSplittedLayout(self):
        """Init Splitted layout. It's more convenient for intercept."""
        self._vpaned = RememberingVPaned(self.w3af, "trap_view")
        self._vpaned.show()
        self.pack_start(self._vpaned, True, True)
        self._vpaned.add(self.request)
        self._vpaned.add(self.response)

    def focus_response(self):
        if self.layout == "Tabbed":
            self.nb.set_current_page(1)

    def focus_request(self):
        if self.layout == "Tabbed":
            self.nb.set_current_page(0)

    def _initToolBox(self, withManual, withFuzzy, withCompare, withAudit):
        # Buttons

        # This import needs to be here in order to avoid an import loop
        from w3af.core.ui.gui.tools.fuzzy_requests import FuzzyRequests
        from w3af.core.ui.gui.tools.manual_requests import ManualRequests

        hbox = gtk.HBox()
        if withManual or withFuzzy or withCompare:

            if withManual:
                b = SemiStockButton("", gtk.STOCK_INDEX, _("Send Request to Manual Editor"))
                b.connect("clicked", self._send_request, ManualRequests)
                self.request.childButtons.append(b)
                b.show()
                hbox.pack_start(b, False, False, padding=2)
            if withFuzzy:
                b = SemiStockButton("", gtk.STOCK_PROPERTIES, _("Send Request to Fuzzy Editor"))
                b.connect("clicked", self._send_request, FuzzyRequests)
                self.request.childButtons.append(b)
                b.show()
                hbox.pack_start(b, False, False, padding=2)
            if withCompare:
                b = SemiStockButton("", gtk.STOCK_ZOOM_100, _("Send Request and Response to Compare Tool"))
                b.connect("clicked", self._sendReqResp)
                self.response.childButtons.append(b)
                b.show()
                hbox.pack_start(b, False, False, padding=2)
        # I always can export requests
        b = SemiStockButton("", gtk.STOCK_COPY, _("Export Request"))
        b.connect("clicked", self._send_request, export_request)
        self.request.childButtons.append(b)
        b.show()
        hbox.pack_start(b, False, False, padding=2)
        self.pack_start(hbox, False, False, padding=5)
        hbox.show()

        if withAudit:
            # Add everything I need for the audit request thing:
            # The button that shows the menu
            b = SemiStockButton("", gtk.STOCK_EXECUTE, _("Audit Request with..."))
            b.connect("button-release-event", self._popupMenu)
            self.request.childButtons.append(b)
            b.show()
            hbox.pack_start(b, False, False, padding=2)

        # The throbber (hidden!)
        self.throbber = helpers.Throbber()
        hbox.pack_start(self.throbber, True, True)

        self.draw_area = helpers.DrawingAreaStringRepresentation()
        hbox.pack_end(self.draw_area, False, False)

        self.pack_start(hbox, False, False, padding=5)
        hbox.show()

    def _popupMenu(self, widget, event):
        """Show a Audit popup menu."""
        _time = event.time
        # Get the information about the click
        # requestId = self._lstore[path][0]
        # Create the popup menu
        gm = gtk.Menu()
        plugin_type = "audit"
        for plugin_name in sorted(self.w3af.plugins.get_plugin_list(plugin_type)):
            e = gtk.MenuItem(plugin_name)
            e.connect("activate", self._auditRequest, plugin_name, plugin_type)
            gm.append(e)
        # Add a separator
        gm.append(gtk.SeparatorMenuItem())
        # Add a special item
        e = gtk.MenuItem("All audit plugins")
        e.connect("activate", self._auditRequest, "All audit plugins", "audit_all")
        gm.append(e)
        # show
        gm.show_all()
        gm.popup(None, None, None, event.button, _time)

    def _auditRequest(self, menuItem, plugin_name, plugin_type):
        """
        Audit a request using one or more plugins.

        :param menuItem: The name of the audit plugin, or the 'All audit
                         plugins' wildcard
        :param plugin_name: The name of the plugin
        :param plugin_type: The type of plugin
        :return: None
        """
        # We show a throbber, and start it
        self.throbber.show()
        self.throbber.running(True)
        request = self.request.get_object()
        # Now I start the analysis of this request in a new thread,
        # threading game (copied from craftedRequests)
        event = threading.Event()
        impact = ThreadedURLImpact(self.w3af, request, plugin_name, plugin_type, event)
        impact.start()
        gobject.timeout_add(200, self._impact_done, event, impact)

    def _impact_done(self, event, impact):
        # Keep calling this from timeout_add until isSet
        if not event.isSet():
            return True
        # We stop the throbber, and hide it
        self.throbber.hide()
        self.throbber.running(False)

        # Analyze the impact
        if impact.ok:
            #   Lets check if we found any vulnerabilities
            #
            #   TODO: I should actually show ALL THE REQUESTS generated by
            #         audit plugins... not just the ones with vulnerabilities.
            #
            for result in impact.result:
                if result.get_id() is None:
                    continue

                for itemId in result.get_id():
                    historyItem = HistoryItem()
                    historyItem.load(itemId)
                    historyItem.update_tag(historyItem.tag + result.plugin_name)
                    historyItem.info = result.get_desc()
                    historyItem.save()
        else:
            if isinstance(impact.exception, HTTPRequestException):
                msg = "Exception found while sending HTTP request. Original" ' exception is: "%s"' % impact.exception
            elif isinstance(impact.exception, ScanMustStopException):
                msg = "Multiple exceptions found while sending HTTP requests." ' Exception: "%s"' % impact.exception
            elif isinstance(impact.exception, BaseFrameworkException):
                msg = str(impact.exception)
            else:
                raise impact.exception

            # We stop the throbber, and hide it
            self.throbber.hide()
            self.throbber.running(False)
            gtk.gdk.threads_enter()
            helpers.FriendlyExceptionDlg(msg)
            gtk.gdk.threads_leave()

        return False

    def _send_request(self, widg, func):
        """Sends the texts to the manual or fuzzy request.

        :param func: where to send the request.
        """
        headers, data = self.request.get_both_texts()
        func(self.w3af, (headers, data))

    def _sendReqResp(self, widg):
        """Sends the texts to the compare tool."""
        headers, data = self.request.get_both_texts()
        self.w3af.mainwin.commCompareTool((headers, data, self.response.get_object()))

    def set_sensitive(self, how):
        """Sets the pane on/off."""
        self.request.set_sensitive(how)
        self.response.set_sensitive(how)
Exemple #6
0
class reqResViewer(gtk.VBox):
    """
    A widget with the request and the response inside.

    :author: Andres Riancho ([email protected])
    :author: Facundo Batista ( [email protected] )

    """
    def __init__(self,
                 w3af,
                 enableWidget=None,
                 withManual=True,
                 withFuzzy=True,
                 withCompare=True,
                 withAudit=True,
                 editableRequest=False,
                 editableResponse=False,
                 widgname="default",
                 layout='Tabbed'):

        super(reqResViewer, self).__init__()
        self.w3af = w3af
        # Request
        self.request = requestPart(self,
                                   w3af,
                                   enableWidget,
                                   editableRequest,
                                   widgname=widgname)
        self.request.show()
        # Response
        self.response = responsePart(self,
                                     w3af,
                                     editableResponse,
                                     widgname=widgname)
        self.response.show()
        self.layout = layout
        if layout == 'Tabbed':
            self._initTabbedLayout()
        else:
            self._initSplittedLayout()
        # Init req toolbox
        self._initToolBox(withManual, withFuzzy, withCompare, withAudit)
        self.show()

    def _initTabbedLayout(self):
        """Init Tabbed layout. It's more convenient for quick view."""
        nb = gtk.Notebook()
        nb.show()
        self.nb = nb
        self.pack_start(nb, True, True)
        nb.append_page(self.request, gtk.Label(_("Request")))
        nb.append_page(self.response, gtk.Label(_("Response")))
        # Info
        self.info = HttpEditor(self.w3af)
        self.info.set_editable(False)
        #self.info.show()
        nb.append_page(self.info, gtk.Label(_("Info")))

    def _initSplittedLayout(self):
        """Init Splitted layout. It's more convenient for intercept."""
        self._vpaned = RememberingVPaned(self.w3af, 'trap_view')
        self._vpaned.show()
        self.pack_start(self._vpaned, True, True)
        self._vpaned.add(self.request)
        self._vpaned.add(self.response)

    def focus_response(self):
        if self.layout == 'Tabbed':
            self.nb.set_current_page(1)

    def focus_request(self):
        if self.layout == 'Tabbed':
            self.nb.set_current_page(0)

    def _initToolBox(self, withManual, withFuzzy, withCompare, withAudit):
        # Buttons

        # This import needs to be here in order to avoid an import loop
        from w3af.core.ui.gui.tools.fuzzy_requests import FuzzyRequests
        from w3af.core.ui.gui.tools.manual_requests import ManualRequests

        hbox = gtk.HBox()
        if withManual or withFuzzy or withCompare:

            if withManual:
                b = SemiStockButton("", gtk.STOCK_INDEX,
                                    _("Send Request to Manual Editor"))
                b.connect("clicked", self._send_request, ManualRequests)
                self.request.childButtons.append(b)
                b.show()
                hbox.pack_start(b, False, False, padding=2)
            if withFuzzy:
                b = SemiStockButton("", gtk.STOCK_PROPERTIES,
                                    _("Send Request to Fuzzy Editor"))
                b.connect("clicked", self._send_request, FuzzyRequests)
                self.request.childButtons.append(b)
                b.show()
                hbox.pack_start(b, False, False, padding=2)
            if withCompare:
                b = SemiStockButton(
                    "", gtk.STOCK_ZOOM_100,
                    _("Send Request and Response to Compare Tool"))
                b.connect("clicked", self._sendReqResp)
                self.response.childButtons.append(b)
                b.show()
                hbox.pack_start(b, False, False, padding=2)
        # I always can export requests
        b = SemiStockButton("", gtk.STOCK_COPY, _("Export Request"))
        b.connect("clicked", self._send_request, export_request)
        self.request.childButtons.append(b)
        b.show()
        hbox.pack_start(b, False, False, padding=2)
        self.pack_start(hbox, False, False, padding=5)
        hbox.show()

        if withAudit:
            # Add everything I need for the audit request thing:
            # The button that shows the menu
            b = SemiStockButton("", gtk.STOCK_EXECUTE,
                                _("Audit Request with..."))
            b.connect("button-release-event", self._popupMenu)
            self.request.childButtons.append(b)
            b.show()
            hbox.pack_start(b, False, False, padding=2)

        # The throbber (hidden!)
        self.throbber = helpers.Throbber()
        hbox.pack_start(self.throbber, True, True)

        self.draw_area = helpers.DrawingAreaStringRepresentation()
        hbox.pack_end(self.draw_area, False, False)

        self.pack_start(hbox, False, False, padding=5)
        hbox.show()

    def _popupMenu(self, widget, event):
        """Show a Audit popup menu."""
        _time = event.time
        # Get the information about the click
        #requestId = self._lstore[path][0]
        # Create the popup menu
        gm = gtk.Menu()
        plugin_type = "audit"
        for plugin_name in sorted(
                self.w3af.plugins.get_plugin_list(plugin_type)):
            e = gtk.MenuItem(plugin_name)
            e.connect('activate', self._auditRequest, plugin_name, plugin_type)
            gm.append(e)
        # Add a separator
        gm.append(gtk.SeparatorMenuItem())
        # Add a special item
        e = gtk.MenuItem('All audit plugins')
        e.connect('activate', self._auditRequest, 'All audit plugins',
                  'audit_all')
        gm.append(e)
        # show
        gm.show_all()
        gm.popup(None, None, None, event.button, _time)

    def _auditRequest(self, menuItem, plugin_name, plugin_type):
        """
        Audit a request using one or more plugins.

        :param menuItem: The name of the audit plugin, or the 'All audit
                         plugins' wildcard
        :param plugin_name: The name of the plugin
        :param plugin_type: The type of plugin
        :return: None
        """
        # We show a throbber, and start it
        self.throbber.show()
        self.throbber.running(True)
        request = self.request.get_object()
        # Now I start the analysis of this request in a new thread,
        # threading game (copied from craftedRequests)
        event = threading.Event()
        impact = ThreadedURLImpact(self.w3af, request, plugin_name,
                                   plugin_type, event)
        impact.start()
        gobject.timeout_add(200, self._impact_done, event, impact)

    def _impact_done(self, event, impact):
        # Keep calling this from timeout_add until isSet
        if not event.isSet():
            return True
        # We stop the throbber, and hide it
        self.throbber.hide()
        self.throbber.running(False)

        # Analyze the impact
        if impact.ok:
            #   Lets check if we found any vulnerabilities
            #
            #   TODO: I should actually show ALL THE REQUESTS generated by
            #         audit plugins... not just the ones with vulnerabilities.
            #
            for result in impact.result:
                if result.get_id() is None:
                    continue

                for itemId in result.get_id():
                    historyItem = HistoryItem()
                    historyItem.load(itemId)
                    historyItem.update_tag(historyItem.tag +
                                           result.plugin_name)
                    historyItem.info = result.get_desc()
                    historyItem.save()
        else:
            if isinstance(impact.exception, HTTPRequestException):
                msg = 'Exception found while sending HTTP request. Original' \
                      ' exception is: "%s"' % impact.exception
            elif isinstance(impact.exception, ScanMustStopException):
                msg = 'Multiple exceptions found while sending HTTP requests.' \
                      ' Exception: "%s"' % impact.exception
            elif isinstance(impact.exception, BaseFrameworkException):
                msg = str(impact.exception)
            else:
                raise impact.exception

            # We stop the throbber, and hide it
            self.throbber.hide()
            self.throbber.running(False)
            gtk.gdk.threads_enter()
            helpers.FriendlyExceptionDlg(msg)
            gtk.gdk.threads_leave()

        return False

    def _send_request(self, widg, func):
        """Sends the texts to the manual or fuzzy request.

        :param func: where to send the request.
        """
        headers, data = self.request.get_both_texts()
        func(self.w3af, (headers, data))

    def _sendReqResp(self, widg):
        """Sends the texts to the compare tool."""
        headers, data = self.request.get_both_texts()
        self.w3af.mainwin.commCompareTool(
            (headers, data, self.response.get_object()))

    def set_sensitive(self, how):
        """Sets the pane on/off."""
        self.request.set_sensitive(how)
        self.response.set_sensitive(how)
Exemple #7
0
    def __init__(self, w3af, parentView, editable=False):
        """Make object."""
        RememberingVPaned.__init__(self, w3af, 'headers_view')
        self.id = 'HttpHeadersView'
        self.label = 'Headers'
        self.startLine = ''
        self.parentView = parentView
        self.is_request = True
        box = gtk.HBox()
        self._headersStore = gtk.ListStore(gobject.TYPE_STRING,
                                           gobject.TYPE_STRING)
        self._headersTreeview = gtk.TreeView(self._headersStore)
        # Column for Name
        renderer = gtk.CellRendererText()
        renderer.set_property('editable', editable)
        renderer.connect('edited', self._headerNameEdited, self._headersStore)
        column = gtk.TreeViewColumn(_('Name'), renderer, text=0)
        column.set_sort_column_id(0)
        column.set_resizable(True)
        self._headersTreeview.append_column(column)
        # Column for Value
        renderer = gtk.CellRendererText()
        renderer.set_property('editable', editable)
        renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
        renderer.connect('edited', self._headerValueEdited, self._headersStore)
        column = gtk.TreeViewColumn(_('Value'), renderer, text=1)
        column.set_resizable(True)
        column.set_expand(True)
        column.set_sort_column_id(1)
        self._headersTreeview.append_column(column)
        self._scrolled = gtk.ScrolledWindow()
        self._scrolled.add(self._headersTreeview)
        self._scrolled.show_all()
        box.pack_start(self._scrolled)
        # Buttons area
        buttons = [(gtk.STOCK_GO_UP, self._moveHeaderUp),
                   (gtk.STOCK_GO_DOWN, self._moveHeaderDown),
                   (gtk.STOCK_ADD, self._addHeader),
                   (gtk.STOCK_DELETE, self._deleteHeader)]

        buttonBox = gtk.VBox()
        for button in buttons:
            b = gtk.Button(stock=button[0])
            b.connect("clicked", button[1])
            b.show()
            buttonBox.pack_start(b, False, False)
        buttonBox.show()

        if editable:
            box.pack_start(buttonBox, False, False)
        box.show()
        self.add(box)

        self._raw = HttpEditor(w3af)
        self._raw.show()
        self._raw.set_editable(editable)
        self._raw.set_wrap(True)
        self._raw.set_highlight_syntax(False)
        self._raw.set_highlight_current_line(False)
        self.initial = False
        if editable:
            buf = self._raw.get_buffer()
            buf.connect("changed", self._changed)
        self.add(self._raw)
Exemple #8
0
class httpLogTab(RememberingHPaned):
    """
    A tab that shows all HTTP requests and responses made by the framework.

    :author: Andres Riancho ([email protected])
    """
    def __init__(self, w3af, padding=10, time_refresh=False):
        """Init object."""
        super(httpLogTab, self).__init__(w3af, "pane-httplogtab", 300)
        self.w3af = w3af
        self._padding = padding
        self._lastId = 0
        self._historyItem = HistoryItem()
        if time_refresh:
            gobject.timeout_add(1000, self.refresh_results)
        # Create the main container
        mainvbox = gtk.VBox()
        mainvbox.set_spacing(self._padding)
        # Add the menuHbox, Req/Res viewer and the R/R selector on the bottom
        self._initSearchBox(mainvbox)
        self._initFilterBox(mainvbox)
        self._initReqResViewer(mainvbox)
        mainvbox.show()
        # Add everything
        self.add(mainvbox)
        self.show()

    def _initReqResViewer(self, mainvbox):
        """Create the req/res viewer."""
        self._req_res_viewer = ReqResViewer(self.w3af,
                                            editableRequest=False,
                                            editableResponse=False)
        self._req_res_viewer.set_sensitive(False)
        # Create the req/res selector (when a search with more
        # than one result is done, this window appears)
        self._sw = gtk.ScrolledWindow()
        self._sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self._lstore = gtk.ListStore(gobject.TYPE_UINT, gobject.TYPE_BOOLEAN,
                                     gobject.TYPE_STRING, gobject.TYPE_STRING,
                                     gobject.TYPE_STRING, gobject.TYPE_UINT,
                                     gobject.TYPE_STRING, gobject.TYPE_UINT,
                                     gobject.TYPE_STRING, gobject.TYPE_FLOAT)
        # Create tree view
        self._lstoreTreeview = gtk.TreeView(self._lstore)
        self._lstoreTreeview.set_rules_hint(True)
        self._lstoreTreeview.set_search_column(0)
        self.__add_columns(self._lstoreTreeview)
        self._lstoreTreeview.show()
        self._lstoreTreeview.connect('cursor-changed',
                                     self._view_in_req_res_viewer)
        # Popup menu
        self._rightButtonMenu = None
        self._lstoreTreeview.connect('button-press-event', self._popupMenu)
        #
        #
        # Selection
        #
        treeselection = self._lstoreTreeview.get_selection()
        treeselection.set_mode(gtk.SELECTION_MULTIPLE)

        self._sw.add(self._lstoreTreeview)
        #self._sw.set_sensitive(False)
        self._sw.show_all()
        # I want all sections to be resizable
        self._vpan = RememberingVPaned(self.w3af, "pane-swandrRV", 100)
        self._vpan.pack1(self._sw)
        self._vpan.pack2(self._req_res_viewer)
        self._vpan.show()
        mainvbox.pack_start(self._vpan)

    def _popupMenu(self, tv, event):
        """Generate and show popup menu."""
        if event.button != 3:
            return
        # creates the whole menu only once
        if self._rightButtonMenu is None:
            gm = gtk.Menu()
            self._rightButtonMenu = gm
            # the items
            e = gtk.MenuItem(_("Delete selected items"))
            e.connect('activate', self._deleteSelected)
            gm.append(e)
            gm.show_all()
        else:
            gm = self._rightButtonMenu
        gm.popup(None, None, None, event.button, event.time)
        return True

    def _deleteSelected(self, widg=None):
        """Delete selected transactions."""
        ids = []
        iters = []
        sel = self._lstoreTreeview.get_selection()
        (model, pathlist) = sel.get_selected_rows()
        for path in pathlist:
            iters.append(self._lstore.get_iter(path))
            itemNumber = path[0]
            iid = self._lstore[itemNumber][0]
            ids.append(iid)
        for i in iters:
            self._lstore.remove(i)
        #  TODO Move this action to separate thread
        for iid in ids:
            self._historyItem.delete(iid)

    def _initSearchBox(self, mainvbox):
        """Init Search box."""
        # The search entry
        self._searchText = gtk.Entry()
        self._searchText.connect("activate", self.find_request_response)
        # The button that is used to advanced search
        filterBtn = gtk.ToggleButton(label=_("_Filter Options"))
        filterBtn.connect("toggled", self._showHideFilterBox)
        filterImg = gtk.Image()
        filterImg.set_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU)
        filterBtn.set_image(filterImg)
        # Clear button
        close = gtk.Image()
        close.set_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU)
        clearBox = gtk.EventBox()
        clearBox.add(close)
        clearBox.connect("button-release-event", self._showAllRequestResponses)
        # Create the container that has the menu
        menuHbox = gtk.HBox()
        menuHbox.set_spacing(self._padding)
        menuHbox.pack_start(gtk.Label(_("Search:")), False)
        menuHbox.pack_start(self._searchText)
        menuHbox.pack_start(clearBox, False)
        menuHbox.pack_start(filterBtn, False)
        menuHbox.show_all()
        mainvbox.pack_start(menuHbox, False, True)

    def _initFilterBox(self, mainvbox):
        """Init advanced search options."""
        self._advSearchBox = gtk.HBox()
        self._advSearchBox.set_spacing(self._padding)
        self.pref = FilterOptions(self)
        # Filter options
        self._filterMethods = [
            ('GET', 'GET', False),
            ('POST', 'POST', False),
        ]
        filterMethods = OptionList()
        for method in self._filterMethods:
            filterMethods.add(
                opt_factory(method[0], method[2], method[1], "boolean"))
        self.pref.add_section('methods', _('Request Method'), filterMethods)
        filterId = OptionList()
        filterId.add(opt_factory("min", "0", "Min ID", "string"))
        filterId.add(opt_factory("max", "0", "Max ID", "string"))
        self.pref.add_section('trans_id', _('Transaction ID'), filterId)
        filterCodes = OptionList()
        codes = [
            ("1xx", "1xx", False),
            ("2xx", "2xx", False),
            ("3xx", "3xx", False),
            ("4xx", "4xx", False),
            ("5xx", "5xx", False),
        ]
        for code in codes:
            filterCodes.add(opt_factory(code[0], code[2], code[1], "boolean"))
        self.pref.add_section('codes', _('Response Code'), filterCodes)
        filterMisc = OptionList()
        filterMisc.add(opt_factory("tag", False, "Tag", "boolean"))
        filterMisc.add(
            opt_factory("has_qs", False, "Request has Query String",
                        "boolean"))
        self.pref.add_section('misc', _('Misc'), filterMisc)
        filterTypes = OptionList()
        self._filterTypes = [
            ('html', 'HTML', False),
            ('javascript', 'JavaScript', False),
            ('image', 'Images', False),
            ('flash', 'Flash', False),
            ('css', 'CSS', False),
            ('text', 'Text', False),
        ]
        for filterType in self._filterTypes:
            filterTypes.add(
                opt_factory(filterType[0], filterType[2], filterType[1],
                            "boolean"))
        self.pref.add_section('types', _('Response Content Type'), filterTypes)
        filterSize = OptionList()
        filterSize.add(opt_factory("resp_size", False, "Not Null", "boolean"))
        self.pref.add_section('sizes', _('Response Size'), filterSize)
        self.pref.show()
        self._advSearchBox.pack_start(self.pref, False, False)
        self._advSearchBox.hide_all()
        mainvbox.pack_start(self._advSearchBox, False, False)

    def __add_columns(self, treeview):
        """Add columns to main log table."""
        model = treeview.get_model()
        # Column for id's
        column = gtk.TreeViewColumn(_('ID'), gtk.CellRendererText(), text=0)
        column.set_sort_column_id(0)
        treeview.append_column(column)

        # Column for bookmark
        #TODO: Find a better way to do this. The "B" and the checkbox aren't nice
        #what we aim for is something like the stars in gmail.
        """
        renderer = gtk.CellRendererToggle()
        renderer.set_property('activatable', True)
        renderer.connect('toggled', self.toggle_bookmark, model)
        column = gtk.TreeViewColumn(_('B'), renderer)
        column.add_attribute(renderer, "active", 1)
        column.set_sort_column_id(1)
        treeview.append_column(column)
        """

        # Column for METHOD
        column = gtk.TreeViewColumn(_('Method'),
                                    gtk.CellRendererText(),
                                    text=2)
        column.set_sort_column_id(2)
        treeview.append_column(column)
        # Column for URI
        renderer = gtk.CellRendererText()
        renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
        column = gtk.TreeViewColumn('URI', renderer, text=3)
        column.set_sort_column_id(3)
        column.set_expand(True)
        column.set_resizable(True)
        treeview.append_column(column)
        # Column for Tag
        renderer = gtk.CellRendererText()
        #renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
        renderer.set_property('editable', True)
        renderer.connect('edited', self.edit_tag, model)
        column = gtk.TreeViewColumn(_('Tag'), renderer, text=4)
        column.set_sort_column_id(4)
        column.set_resizable(True)
        column.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY)
        treeview.append_column(column)
        extColumns = [
            (5, _('Code')),
            (6, _('Message')),
            (7, _('Content-Length')),
            (8, _('Content-Type')),
            (9, _('Time (ms)')),
        ]
        for n, title in extColumns:
            column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=n)
            column.set_sort_column_id(n)
            treeview.append_column(column)

    def toggle_bookmark(self, cell, path, model):
        """Toggle bookmark."""
        model[path][1] = not model[path][1]
        historyItem = HistoryItem()
        historyItem.load(model[path][0])
        historyItem.toggle_mark(True)
        return

    def edit_tag(self, cell, path, new_text, model):
        """Edit tag."""
        model[path][4] = new_text
        historyItem = HistoryItem()
        historyItem.load(model[path][0])
        historyItem.update_tag(new_text, True)
        return

    def _showHideFilterBox(self, widget):
        """Show/hide advanced options."""
        if not widget.get_active():
            self._advSearchBox.hide_all()
        else:
            self._advSearchBox.show_all()

    def _showAllRequestResponses(self, widget=None, event=None):
        """Show all results."""
        self._searchText.set_text("")
        try:
            self.find_request_response()
        except BaseFrameworkException as w3:
            self._empty_results()
        return

    def refresh_results(self):
        """
        TODO: IMPROVEMENT: The find_request_response will read all items from
                           the DB again. If there are no new requests BUT we're
                           already showing 1K of them, all will be read. Not
                           good for performance.
        """
        self.find_request_response(refresh=True)
        return True

    def find_request_response(self, widget=None, refresh=False):
        """Find entries (req/res)."""
        searchText = self._searchText.get_text()
        searchText = searchText.strip()
        search_data = []
        #
        #  Search part
        #
        if searchText:
            likePieces = [('url', "%" + searchText + "%", 'like'),
                          ('tag', "%" + searchText + "%", 'like')]
            search_data.append((likePieces, 'OR'))
        #
        # Filter part
        #
        # Codes
        codes = self.pref.get_options('codes')
        filterCodes = []
        for opt in codes:
            if opt.get_value():
                codef = opt.get_name()
                filterCodes.append(('codef', int(codef[0]), '='))
        search_data.append((filterCodes, 'OR'))
        # IDs
        try:
            minId = int(self.pref.get_value('trans_id', 'min'))
        except:
            minId = 0
        try:
            maxId = int(self.pref.get_value('trans_id', 'max'))
        except:
            maxId = 0
        if maxId > 0:
            search_data.append(('id', maxId, "<"))
        if minId > 0:
            search_data.append(('id', minId, ">"))
        if refresh:
            search_data.append(('id', self._lastId, ">"))
        # Sizes
        if self.pref.get_value('sizes', 'resp_size'):
            search_data.append(('response_size', 0, ">"))
        # Tags
        if self.pref.get_value('misc', 'tag'):
            search_data.append(('tag', '', "!="))
        # has_query_string
        if self.pref.get_value('misc', 'has_qs'):
            search_data.append(('has_qs', 0, ">"))
        # Content type
        filterTypes = []
        for filterType in self._filterTypes:
            if self.pref.get_value('types', filterType[0]):
                filterTypes.append(
                    ('content_type', "%" + filterType[0] + "%", 'like'))
        search_data.append((filterTypes, 'OR'))
        # Method
        filterMethods = []
        for method in self._filterMethods:
            if self.pref.get_value('methods', method[0]):
                filterTypes.append(('method', method[0], '='))
        search_data.append((filterMethods, 'OR'))

        try:
            # Please see the 5000 below
            searchResultObjects = self._historyItem.find(search_data,
                                                         result_limit=5001,
                                                         order_data=[("id", "")
                                                                     ])
        except BaseFrameworkException, w3:

            self._empty_results()
            return
        if len(searchResultObjects) == 0:
            if not refresh:
                self._empty_results()
            return
        # Please see the 5001 above
        elif len(searchResultObjects) > 5000:
            self._empty_results()
            msg = _('The search you performed returned too many results (') +\
                str(len(searchResultObjects)) + ').\n'
            msg += _('Please refine your search and try again.')
            self._show_message('Too many results', msg)
            return
        else:
            # show the results in the list view (when first row is selected
            # that just triggers the req/resp filling.
            lastItem = searchResultObjects[-1]
            self._lastId = int(lastItem.id)
            self._show_list_view(searchResultObjects, appendMode=refresh)

            self._sw.set_sensitive(True)
            self._req_res_viewer.set_sensitive(True)

            if not refresh:
                self._lstoreTreeview.set_cursor((0, ))

            return
Exemple #9
0
class httpLogTab(RememberingHPaned):
    """
    A tab that shows all HTTP requests and responses made by the framework.

    :author: Andres Riancho ([email protected])
    """
    def __init__(self, w3af, padding=10, time_refresh=False):
        """Init object."""
        super(httpLogTab, self).__init__(w3af, "pane-httplogtab", 300)
        self.w3af = w3af
        self._padding = padding
        self._lastId = 0
        self._historyItem = HistoryItem()
        if time_refresh:
            gobject.timeout_add(1000, self.refresh_results)
        # Create the main container
        mainvbox = gtk.VBox()
        mainvbox.set_spacing(self._padding)
        # Add the menuHbox, Req/Res viewer and the R/R selector on the bottom
        self._initSearchBox(mainvbox)
        self._initFilterBox(mainvbox)
        self._initReqResViewer(mainvbox)
        mainvbox.show()
        # Add everything
        self.add(mainvbox)
        self.show()

    def _initReqResViewer(self, mainvbox):
        """Create the req/res viewer."""
        self._req_res_viewer = ReqResViewer(self.w3af, editableRequest=False,
                                            editableResponse=False)
        self._req_res_viewer.set_sensitive(False)
        # Create the req/res selector (when a search with more
        # than one result is done, this window appears)
        self._sw = gtk.ScrolledWindow()
        self._sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self._lstore = gtk.ListStore(gobject.TYPE_UINT, gobject.TYPE_BOOLEAN,
                                     gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING,
                                     gobject.TYPE_UINT, gobject.TYPE_STRING,
                                     gobject.TYPE_UINT, gobject.TYPE_STRING, gobject.TYPE_FLOAT)
        # Create tree view
        self._lstoreTreeview = gtk.TreeView(self._lstore)
        self._lstoreTreeview.set_rules_hint(True)
        self._lstoreTreeview.set_search_column(0)
        self.__add_columns(self._lstoreTreeview)
        self._lstoreTreeview.show()
        self._lstoreTreeview.connect(
            'cursor-changed', self._view_in_req_res_viewer)
        # Popup menu
        self._rightButtonMenu = None
        self._lstoreTreeview.connect('button-press-event', self._popupMenu)
        #
        #
        # Selection
        #
        treeselection = self._lstoreTreeview.get_selection()
        treeselection.set_mode(gtk.SELECTION_MULTIPLE)

        self._sw.add(self._lstoreTreeview)
        #self._sw.set_sensitive(False)
        self._sw.show_all()
        # I want all sections to be resizable
        self._vpan = RememberingVPaned(self.w3af, "pane-swandrRV", 100)
        self._vpan.pack1(self._sw)
        self._vpan.pack2(self._req_res_viewer)
        self._vpan.show()
        mainvbox.pack_start(self._vpan)

    def _popupMenu(self, tv, event):
        """Generate and show popup menu."""
        if event.button != 3:
            return
        # creates the whole menu only once
        if self._rightButtonMenu is None:
            gm = gtk.Menu()
            self._rightButtonMenu = gm
            # the items
            e = gtk.MenuItem(_("Delete selected items"))
            e.connect('activate', self._deleteSelected)
            gm.append(e)
            gm.show_all()
        else:
            gm = self._rightButtonMenu
        gm.popup(None, None, None, event.button, event.time)
        return True

    def _deleteSelected(self, widg=None):
        """Delete selected transactions."""
        ids = []
        iters = []
        sel = self._lstoreTreeview.get_selection()
        (model, pathlist) = sel.get_selected_rows()
        for path in pathlist:
            iters.append(self._lstore.get_iter(path))
            itemNumber = path[0]
            iid = self._lstore[itemNumber][0]
            ids.append(iid)
        for i in iters:
            self._lstore.remove(i)
        #  TODO Move this action to separate thread
        for iid in ids:
            self._historyItem.delete(iid)

    def _initSearchBox(self, mainvbox):
        """Init Search box."""
        # The search entry
        self._searchText = gtk.Entry()
        self._searchText.connect("activate", self.find_request_response)
        # The button that is used to advanced search
        filterBtn = gtk.ToggleButton(label=_("_Filter Options"))
        filterBtn.connect("toggled", self._showHideFilterBox)
        filterImg = gtk.Image()
        filterImg.set_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU)
        filterBtn.set_image(filterImg)
        # Clear button
        close = gtk.Image()
        close.set_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU)
        clearBox = gtk.EventBox()
        clearBox.add(close)
        clearBox.connect("button-release-event", self._showAllRequestResponses)
        # Create the container that has the menu
        menuHbox = gtk.HBox()
        menuHbox.set_spacing(self._padding)
        menuHbox.pack_start(gtk.Label(_("Search:")), False)
        menuHbox.pack_start(self._searchText)
        menuHbox.pack_start(clearBox, False)
        menuHbox.pack_start(filterBtn, False)
        menuHbox.show_all()
        mainvbox.pack_start(menuHbox, False, True)

    def _initFilterBox(self, mainvbox):
        """Init advanced search options."""
        self._advSearchBox = gtk.HBox()
        self._advSearchBox.set_spacing(self._padding)
        self.pref = FilterOptions(self)
        # Filter options
        self._filterMethods = [
            ('GET', 'GET', False),
            ('POST', 'POST', False),
        ]
        filterMethods = OptionList()
        for method in self._filterMethods:
            filterMethods.add(
                opt_factory(method[0], method[2], method[1], "boolean"))
        self.pref.add_section('methods', _('Request Method'), filterMethods)
        filterId = OptionList()
        filterId.add(opt_factory("min", "0", "Min ID", "string"))
        filterId.add(opt_factory("max", "0", "Max ID", "string"))
        self.pref.add_section('trans_id', _('Transaction ID'), filterId)
        filterCodes = OptionList()
        codes = [
            ("1xx", "1xx", False),
            ("2xx", "2xx", False),
            ("3xx", "3xx", False),
            ("4xx", "4xx", False),
            ("5xx", "5xx", False),
        ]
        for code in codes:
            filterCodes.add(opt_factory(code[0], code[2], code[1], "boolean"))
        self.pref.add_section('codes', _('Response Code'), filterCodes)
        filterMisc = OptionList()
        filterMisc.add(opt_factory("tag", False, "Tag", "boolean"))
        filterMisc.add(opt_factory(
            "has_qs", False, "Request has Query String", "boolean"))
        self.pref.add_section('misc', _('Misc'), filterMisc)
        filterTypes = OptionList()
        self._filterTypes = [
            ('html', 'HTML', False),
            ('javascript', 'JavaScript', False),
            ('image', 'Images', False),
            ('flash', 'Flash', False),
            ('css', 'CSS', False),
            ('text', 'Text', False),
        ]
        for filterType in self._filterTypes:
            filterTypes.add(opt_factory(
                filterType[0], filterType[2], filterType[1], "boolean"))
        self.pref.add_section('types', _('Response Content Type'), filterTypes)
        filterSize = OptionList()
        filterSize.add(opt_factory("resp_size", False, "Not Null", "boolean"))
        self.pref.add_section('sizes', _('Response Size'), filterSize)
        self.pref.show()
        self._advSearchBox.pack_start(self.pref, False, False)
        self._advSearchBox.hide_all()
        mainvbox.pack_start(self._advSearchBox, False, False)

    def __add_columns(self, treeview):
        """Add columns to main log table."""
        model = treeview.get_model()
        # Column for id's
        column = gtk.TreeViewColumn(_('ID'), gtk.CellRendererText(), text=0)
        column.set_sort_column_id(0)
        treeview.append_column(column)

        # Column for bookmark
        #TODO: Find a better way to do this. The "B" and the checkbox aren't nice
        #what we aim for is something like the stars in gmail.
        """
        renderer = gtk.CellRendererToggle()
        renderer.set_property('activatable', True)
        renderer.connect('toggled', self.toggle_bookmark, model)
        column = gtk.TreeViewColumn(_('B'), renderer)
        column.add_attribute(renderer, "active", 1)
        column.set_sort_column_id(1)
        treeview.append_column(column)
        """

        # Column for METHOD
        column = gtk.TreeViewColumn(
            _('Method'), gtk.CellRendererText(), text=2)
        column.set_sort_column_id(2)
        treeview.append_column(column)
        # Column for URI
        renderer = gtk.CellRendererText()
        renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
        column = gtk.TreeViewColumn('URI', renderer, text=3)
        column.set_sort_column_id(3)
        column.set_expand(True)
        column.set_resizable(True)
        treeview.append_column(column)
        # Column for Tag
        renderer = gtk.CellRendererText()
        #renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
        renderer.set_property('editable', True)
        renderer.connect('edited', self.edit_tag, model)
        column = gtk.TreeViewColumn(_('Tag'), renderer, text=4)
        column.set_sort_column_id(4)
        column.set_resizable(True)
        column.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY)
        treeview.append_column(column)
        extColumns = [
            (5, _('Code')),
            (6, _('Message')),
            (7, _('Content-Length')),
            (8, _('Content-Type')),
            (9, _('Time (ms)')),
        ]
        for n, title in extColumns:
            column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=n)
            column.set_sort_column_id(n)
            treeview.append_column(column)

    def toggle_bookmark(self, cell, path, model):
        """Toggle bookmark."""
        model[path][1] = not model[path][1]
        historyItem = HistoryItem()
        historyItem.load(model[path][0])
        historyItem.toggle_mark(True)
        return

    def edit_tag(self, cell, path, new_text, model):
        """Edit tag."""
        model[path][4] = new_text
        historyItem = HistoryItem()
        historyItem.load(model[path][0])
        historyItem.update_tag(new_text, True)
        return

    def _showHideFilterBox(self, widget):
        """Show/hide advanced options."""
        if not widget.get_active():
            self._advSearchBox.hide_all()
        else:
            self._advSearchBox.show_all()

    def _showAllRequestResponses(self, widget=None, event=None):
        """Show all results."""
        self._searchText.set_text("")
        try:
            self.find_request_response()
        except BaseFrameworkException, w3:
            self._empty_results()
        return
Exemple #10
0
    def __init__(self, w3af, parentView, editable=False):
        """Make object."""
        RememberingVPaned.__init__(self, w3af, 'headers_view')
        self.id = 'HttpHeadersView'
        self.label = 'Headers'
        self.startLine = ''
        self.parentView = parentView
        self.is_request = True
        box = gtk.HBox()
        self._header_store = gtk.ListStore(gobject.TYPE_STRING,
                                           gobject.TYPE_STRING)
        self._headersTreeview = gtk.TreeView(self._header_store)
        # Column for Name
        renderer = gtk.CellRendererText()
        renderer.set_property('editable', editable)
        renderer.connect('edited', self._header_name_edited, self._header_store)
        column = gtk.TreeViewColumn(_('Name'), renderer, text=0)
        column.set_sort_column_id(0)
        column.set_resizable(True)
        self._headersTreeview.append_column(column)
        # Column for Value
        renderer = gtk.CellRendererText()
        renderer.set_property('editable', editable)
        renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
        renderer.connect('edited', self._header_value_edited, self._header_store)
        column = gtk.TreeViewColumn(_('Value'), renderer, text=1)
        column.set_resizable(True)
        column.set_expand(True)
        column.set_sort_column_id(1)
        self._headersTreeview.append_column(column)
        self._scrolled = gtk.ScrolledWindow()
        self._scrolled.add(self._headersTreeview)
        self._scrolled.show_all()
        box.pack_start(self._scrolled)
        # Buttons area
        buttons = [
            (gtk.STOCK_GO_UP, self._move_header_up),
            (gtk.STOCK_GO_DOWN, self._move_header_down),
            (gtk.STOCK_ADD, self._add_header),
            (gtk.STOCK_DELETE, self._delete_header)
        ]

        buttonBox = gtk.VBox()
        for button in buttons:
            b = gtk.Button(stock=button[0])
            b.connect("clicked", button[1])
            b.show()
            buttonBox.pack_start(b, False, False)
        buttonBox.show()

        if editable:
            box.pack_start(buttonBox, False, False)
        box.show()
        self.add(box)

        self._raw = HttpEditor(w3af)
        self._raw.show()
        self._raw.set_editable(editable)
        self._raw.set_wrap(True)
        self._raw.set_highlight_syntax(False)
        self._raw.set_highlight_current_line(False)
        self.initial = False
        if editable:
            buf = self._raw.get_buffer()
            buf.connect("changed", self._changed)
        self.add(self._raw)