1import wx
2import wx.py
3import wx.grid
4import wx.aui
5import wx.html
6
7import wx.lib.agw.aui as aui
8import wx.dataview as dv
9import wx.html2 as webview
10
11if "2.8" in wx.version():
12    import wx.lib.pubsub.setupkwargs
13    from wx.lib.pubsub import pub
14else:
15    from wx.lib.pubsub import pub
16
17try:
18    from agw import pycollapsiblepane as PCP
19except ImportError:  # if it's not there locally, try the wxPython lib.
20    import wx.lib.agw.pycollapsiblepane as PCP
21
22# puedo no hacer paneles y devolverlos directamente como hace el treectrl, no se cual es la ventaja really
23
24# ----------------------------------------------------------------------
25# http://stackoverflow.com/questions/22265868/how-to-create-a-cmd-with-wxpython
26# esto puede hacer q meta cmd.cmd directamente https://www.blog.pythonlibrary.org/2009/01/01/wxpython-redirecting-stdout-stderr/
27
28
29class RedirectText(object):
30    def __init__(self, aWxTextCtrl):
31        self.out = aWxTextCtrl
32
33    def write(self, string):
34        self.out.WriteText(string)
35
36
37class ConsolePanel(wx.Panel):
38    def __init__(self, parent, interpreter):
39        # begin wxGlade: MyFrame.__init__
40        wx.Panel.__init__(self, parent, -1)
41
42        self.history = []
43        self.index = 0
44
45        self.prompt = ">>"
46        self.textctrl = wx.TextCtrl(
47            self,
48            -1,
49            "",
50            style=wx.TE_PROCESS_ENTER | wx.TE_MULTILINE | wx.TE_RICH,
51            size=(-1, 250),
52        )
53        self.textctrl.SetForegroundColour(wx.WHITE)
54        self.textctrl.SetBackgroundColour(wx.BLACK)
55
56        self.textctrl.AppendText(self.prompt)
57
58        self.textctrl.Bind(wx.EVT_CHAR, self.__bind_events)
59
60        sizer = wx.BoxSizer()
61        sizer.Add(self.textctrl, 1, wx.EXPAND)
62        self.SetSizer(sizer)
63
64        self._interp = interpreter
65        redir = RedirectText(self.textctrl)
66
67        import sys
68
69        # Create a replacement for stdin.
70        # self.reader = PseudoFileIn(self.readline, self.readlines)
71        # self.reader.input = ''
72        # self.reader.isreading = False
73
74        # sys.stdin=self.reader
75        sys.stdout = redir
76        sys.stderr = redir
77
78    def __bind_events(self, e):
79        if e.GetKeyCode() == 13:
80            self.index = len(self.history) - 1
81
82            self.value = self.textctrl.GetValue()
83            ln = self.get_last_line()
84
85            ln = ln.strip()
86            if ln not in self.history:
87                self.history.append(ln)
88            self.index += 1
89            if ln:
90                import shlex
91
92                cmd = shlex.split(ln)
93                # out en retvalue
94                retvalue = self._interp.onecmd(cmd)
95                if retvalue:
96                    self.textctrl.WriteText("\n")
97                    self.textctrl.AppendText(retvalue)
98
99            self.textctrl.WriteText("\n")
100            self.textctrl.WriteText(self.prompt)
101        # down
102        elif e.GetKeyCode() == 317:
103            self.index += 1
104
105            if self.index >= len(self.history):
106                self.index = len(self.history) - 1
107
108            self.textctrl.WriteText("\n")
109            self.textctrl.WriteText(self.prompt)
110            self.textctrl.WriteText(self.history[self.index])
111
112        # up
113        elif e.GetKeyCode() == 315:
114            self.index -= 1
115
116            if self.index < 0:
117                self.index = 0
118
119            self.textctrl.WriteText("\n")
120            self.textctrl.WriteText(self.prompt)
121            self.textctrl.WriteText(self.history[self.index])
122        else:
123            e.Skip()
124
125    def get_last_line(self):
126        nl = self.textctrl.GetNumberOfLines()
127        ln = self.textctrl.GetLineText(nl - 1)
128        ln = ln[len(self.prompt) :]
129
130        return ln
131
132
133# ----------------------------------------------------------------------
134
135
136class ListPanel(wx.Panel):
137    def __init__(self, parent, log, model, interpreter):
138        self.log = log
139        self._interp = interpreter
140        wx.Panel.__init__(self, parent, -1)
141
142        self.dvc = dv.DataViewCtrl(
143            self, style=wx.BORDER_THEME | dv.DV_ROW_LINES | dv.DV_VERT_RULES
144        )
145
146        self.model = model
147        self.dvc.AssociateModel(self.model)
148
149        for row in list(self.model.row_mapper.values()):
150            self.dvc.AppendTextColumn(row.title, row.colid, width=row.width)
151
152        for c in self.dvc.Columns:
153            c.Sortable = True
154            c.Reorderable = True
155
156        self.cp = cp = PCP.PyCollapsiblePane(
157            self, label="Show console", agwStyle=wx.CP_GTK_EXPANDER
158        )
159        self.MakePaneContent(cp.GetPane())
160
161        self.Sizer = wx.BoxSizer(wx.VERTICAL)
162        self.Sizer.Add(self.dvc, 1, wx.EXPAND)
163        self.Sizer.Add(cp, 0, wx.RIGHT | wx.LEFT | wx.EXPAND)
164        self.SetSizer(self.Sizer)
165        self.SetAutoLayout(True)
166
167        self.dvc.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.OnItemSelected)
168
169    def OnItemSelected(self, event):
170        try:
171            items = self.dvc.GetSelections()
172            item = self.model.GetRow(items[0])
173        except IndexError:
174            pass
175        else:
176            pub.sendMessage("selected_row", row=self.model.data[item])
177
178        event.Skip()
179
180    def MakePaneContent(self, pane):
181        border = wx.BoxSizer()
182        border.Add(ConsolePanel(pane, self._interp), wx.RIGHT | wx.LEFT | wx.EXPAND)
183        # border.Add(py.shell.Shell(pane, InterpClass=self._interp, size=(-1,250)),  wx.RIGHT|wx.LEFT|wx.EXPAND)
184
185        pane.SetSizer(border)
186
187
188class HttpRawPanel(wx.Panel):
189    def __init__(self, parent, frame):
190        self._frame = frame
191        wx.Panel.__init__(self, parent, -1)
192
193        # self.req_txt = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY)
194        self.req_txt = webview.WebView.New(self)
195        # self.resp_txt = webview.WebView.New(self)
196        self.resp_txt = wx.TextCtrl(
197            self, -1, "", style=wx.TE_MULTILINE | wx.TE_READONLY
198        )
199
200        sizer = wx.BoxSizer(wx.HORIZONTAL)
201
202        sizer.Add(self.req_txt, 1, wx.EXPAND)
203        sizer.Add(self.resp_txt, 1, wx.EXPAND)
204
205        self.SetSizer(sizer)
206        self.SetAutoLayout(True)
207
208    def CreateHTMLCtrl(self):
209        ctrl = wx.html.HtmlWindow(self, -1, wx.DefaultPosition, wx.Size(400, 300))
210        if "gtk2" in wx.PlatformInfo or "gtk3" in wx.PlatformInfo:
211            ctrl.SetStandardFonts()
212
213        ctrl.SetPage("")
214
215        return ctrl
216
217
218class MainNotebookPanel(wx.Panel):
219    def __init__(self, parent, frame, interpreter):
220        self._frame = frame
221        wx.Panel.__init__(self, parent, -1)
222
223        bookStyle = aui.AUI_NB_DEFAULT_STYLE
224        bookStyle &= ~(aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
225
226        self.rawpanel = HttpRawPanel(self, self)
227        self.renderpanel = self.create_web_view()
228
229        self.nb = aui.AuiNotebook(self, style=bookStyle)
230        self.nb.AddPage(self.rawpanel, "HTML Raw")
231        self.nb.AddPage(self.renderpanel, "HTML Render")
232
233        sizer = wx.BoxSizer()
234        sizer.Add(self.nb, 1, wx.EXPAND)
235        self.SetSizer(sizer)
236        wx.CallAfter(self.nb.SendSizeEvent)
237
238        pub.subscribe(self.on_selected_row, "selected_row")
239
240    def create_web_view(self):
241        return webview.WebView.New(self)
242
243    def on_selected_row(self, row):
244        from pygments import highlight
245        from pygments.lexers import get_lexer_by_name
246        from pygments.formatters import HtmlFormatter
247
248        result = highlight(
249            str(row.history), get_lexer_by_name("http"), HtmlFormatter(full=True)
250        )
251        # result2 = highlight(str(row.history.raw_content), get_lexer_by_name("http"), HtmlFormatter(full=True))
252
253        self.renderpanel.SetPage(row.history.content, row.url)
254        # self.rawpanel.req_txt.SetValue(str(row.history))
255        self.rawpanel.req_txt.SetPage(result, "")
256        # self.rawpanel.resp_txt.SetPage(result2, "")
257        self.rawpanel.resp_txt.SetValue(str(row.history.raw_content))
258
259
260# ----------------------------------------------------------------------
261
262
263ID_About = wx.NewId()
264
265
266class WfuzzFrame(wx.Frame):
267    def __init__(
268        self,
269        parent,
270        id=-1,
271        title="Wfuzz",
272        pos=wx.DefaultPosition,
273        size=wx.DefaultSize,
274        style=wx.DEFAULT_FRAME_STYLE | wx.SUNKEN_BORDER | wx.CLIP_CHILDREN,
275    ):
276        wx.Frame.__init__(self, parent, id, title, pos, size, style)
277
278    def start_gui(self, controller):
279        self.controller = controller
280        # tell FrameManager to manage this frame
281        self._mgr = wx.aui.AuiManager()
282        self._mgr.SetManagedWindow(self)
283
284        # create menu
285        mb = wx.MenuBar()
286
287        file_menu = wx.Menu()
288        file_menu.Append(wx.ID_EXIT, "Exit")
289
290        help_menu = wx.Menu()
291        help_menu.Append(ID_About, "About...")
292
293        mb.Append(file_menu, "File")
294        mb.Append(help_menu, "Help")
295
296        self.SetMenuBar(mb)
297
298        self.SetMinSize(wx.Size(400, 300))
299
300        # create some center panes
301        self._mgr.AddPane(
302            MainNotebookPanel(self, self, controller._interp),
303            wx.aui.AuiPaneInfo()
304            .Caption("Raw HTTP Content")
305            .Name("analysis_notebook")
306            .CenterPane(),
307        )
308        self._mgr.AddPane(
309            self.CreateNotebook(),
310            wx.aui.AuiPaneInfo().Name("main_notebook").CenterPane(),
311        )
312        self._mgr.Update()
313
314        self.Bind(wx.EVT_CLOSE, self.OnClose)
315        self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT)
316        self.Bind(wx.EVT_MENU, self.OnAbout, id=ID_About)
317
318        pub.subscribe(self.OnAddTab, "create_tab")
319
320    def OnClose(self, event):
321        pub.sendMessage("exit", msg="exiting...")
322        self._mgr.UnInit()
323        del self._mgr
324        self.Destroy()
325
326    def OnExit(self, event):
327        pub.sendMessage("exit", msg="exiting...")
328        self.Close()
329
330    def OnAbout(self, event):
331        msg = "WFuzz GUI\n(c) Copyright 2017, Xavi Mendez"
332        dlg = wx.MessageDialog(self, msg, "About", wx.OK | wx.ICON_INFORMATION)
333        dlg.ShowModal()
334        dlg.Destroy()
335
336    def CreateNotebook(self):
337        bookStyle = aui.AUI_NB_DEFAULT_STYLE
338        # bookStyle &= ~(aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
339
340        bookStyle = (
341            aui.AUI_NB_DEFAULT_STYLE | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER
342        )
343
344        client_size = self.GetClientSize()
345        nb = aui.AuiNotebook(
346            self,
347            -1,
348            wx.Point(client_size.x, client_size.y),
349            wx.Size(430, 200),
350            agwStyle=bookStyle,
351        )
352
353        nb.AddPage(
354            ListPanel(self, self, self.controller._model, self.controller._interp),
355            "Main",
356        )
357
358        return nb
359
360    def OnAddTab(self, name, model, interp):
361        auibook = self._mgr.GetPane("main_notebook").window
362
363        auibook.AddPage(ListPanel(self, self, model, interp), name, True)
364
365        self._mgr.Update()
366