diff options
Diffstat (limited to 'libmproxy/console')
| -rw-r--r-- | libmproxy/console/__init__.py | 1 | ||||
| -rw-r--r-- | libmproxy/console/common.py | 121 | ||||
| -rw-r--r-- | libmproxy/console/flowdetailview.py | 5 | ||||
| -rw-r--r-- | libmproxy/console/flowlist.py | 19 | ||||
| -rw-r--r-- | libmproxy/console/flowview.py | 18 | ||||
| -rw-r--r-- | libmproxy/console/grideditor.py | 6 | ||||
| -rw-r--r-- | libmproxy/console/help.py | 1 | ||||
| -rw-r--r-- | libmproxy/console/options.py | 1 | ||||
| -rw-r--r-- | libmproxy/console/palettepicker.py | 1 | ||||
| -rw-r--r-- | libmproxy/console/palettes.py | 2 | ||||
| -rw-r--r-- | libmproxy/console/pathedit.py | 2 | ||||
| -rw-r--r-- | libmproxy/console/searchable.py | 2 | ||||
| -rw-r--r-- | libmproxy/console/select.py | 5 | ||||
| -rw-r--r-- | libmproxy/console/signals.py | 2 | ||||
| -rw-r--r-- | libmproxy/console/statusbar.py | 2 | ||||
| -rw-r--r-- | libmproxy/console/tabs.py | 3 | ||||
| -rw-r--r-- | libmproxy/console/window.py | 1 |
17 files changed, 151 insertions, 41 deletions
diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 3d0fb1aa..80a6e28a 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -22,6 +22,7 @@ EVENTLOG_SIZE = 500 class ConsoleState(flow.State): + def __init__(self): flow.State.__init__(self) self.focus = None diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 12fdfe27..276e45c2 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -207,7 +207,7 @@ def raw_format_flow(f, focus, extended, padding): # Save file to disk -def save_data(path, data, master, state): +def save_data(path, data): if not path: return try: @@ -217,32 +217,32 @@ def save_data(path, data, master, state): signals.status_message.send(message=v.strerror) -def ask_save_overwite(path, data, master, state): +def ask_save_overwrite(path, data): if not path: return path = os.path.expanduser(path) if os.path.exists(path): - def save_overwite(k): + def save_overwrite(k): if k == "y": - save_data(path, data, master, state) + save_data(path, data) signals.status_prompt_onekey.send( - prompt = "'" + path + "' already exists. Overwite?", + prompt = "'" + path + "' already exists. Overwrite?", keys = ( ("yes", "y"), ("no", "n"), ), - callback = save_overwite + callback = save_overwrite ) else: - save_data(path, data, master, state) + save_data(path, data) -def ask_save_path(prompt, data, master, state): +def ask_save_path(prompt, data): signals.status_prompt_path.send( prompt = prompt, - callback = ask_save_overwite, - args = (data, master, state) + callback = ask_save_overwrite, + args = (data, ) ) @@ -277,26 +277,60 @@ def copy_flow_format_data(part, scope, flow): return data, False -def copy_flow(part, scope, flow, master, state): - """ - part: _c_ontent, _h_eaders+content, _u_rl - scope: _a_ll, re_q_uest, re_s_ponse - """ - data, err = copy_flow_format_data(part, scope, flow) +def export_prompt(k, flow): + if k == "c": + copy_as_curl_command(flow) + elif k == "p": + copy_as_python_code(flow) + elif k == "r": + copy_as_raw_request(flow) - if err: - signals.status_message.send(message=err) - return - if not data: - if scope == "q": - signals.status_message.send(message="No request content to copy.") - elif scope == "s": - signals.status_message.send(message="No response content to copy.") - else: - signals.status_message.send(message="No contents to copy.") +def copy_as_curl_command(flow): + data = "curl " + + for k, v in flow.request.headers.fields: + data += "-H '%s:%s' " % (k, v) + + if flow.request.method != "GET": + data += "-X %s " % flow.request.method + + full_url = flow.request.scheme + "://" + flow.request.host + flow.request.path + data += "'%s'" % full_url + + if flow.request.content: + data += " --data-binary '%s'" % flow.request.content + + copy_to_clipboard_or_prompt(data) + + +def copy_as_python_code(flow): + if flow.request.method != "GET": + signals.status_message.send(message="Currently, only GET methods are supported") return + data = ("import requests\n" + "headers = {%s}\n" + "url = '%s'\n" + "resp = requests.get(url, headers=headers)") + + headers = "\n" + for k, v in flow.request.headers.fields: + headers += " '%s': '%s',\n" % (k, v) + + full_url = flow.request.scheme + "://" + flow.request.host + flow.request.path + + data = data % (headers, full_url) + + copy_to_clipboard_or_prompt(data) + + +def copy_as_raw_request(flow): + data = netlib.http.http1.assemble_request(flow.request) + copy_to_clipboard_or_prompt(data) + + +def copy_to_clipboard_or_prompt(data): # pyperclip calls encode('utf-8') on data to be copied without checking. # if data are already encoded that way UnicodeDecodeError is thrown. toclip = "" @@ -310,7 +344,7 @@ def copy_flow(part, scope, flow, master, state): except (RuntimeError, UnicodeDecodeError, AttributeError): def save(k): if k == "y": - ask_save_path("Save data", data, master, state) + ask_save_path("Save data", data) signals.status_prompt_onekey.send( prompt = "Cannot copy data to clipboard. Save as file?", keys = ( @@ -321,6 +355,29 @@ def copy_flow(part, scope, flow, master, state): ) +def copy_flow(part, scope, flow, master, state): + """ + part: _c_ontent, _h_eaders+content, _u_rl + scope: _a_ll, re_q_uest, re_s_ponse + """ + data, err = copy_flow_format_data(part, scope, flow) + + if err: + signals.status_message.send(message=err) + return + + if not data: + if scope == "q": + signals.status_message.send(message="No request content to copy.") + elif scope == "s": + signals.status_message.send(message="No response content to copy.") + else: + signals.status_message.send(message="No contents to copy.") + return + + copy_to_clipboard_or_prompt(data) + + def ask_copy_part(scope, flow, master, state): choices = [ ("content", "c"), @@ -367,16 +424,12 @@ def ask_save_body(part, master, state, flow): elif part == "q" and request_has_content: ask_save_path( "Save request content", - flow.request.get_decoded_content(), - master, - state + flow.request.get_decoded_content() ) elif part == "s" and response_has_content: ask_save_path( "Save response content", - flow.response.get_decoded_content(), - master, - state + flow.response.get_decoded_content() ) else: signals.status_message.send(message="No content to save.") @@ -386,7 +439,7 @@ flowcache = utils.LRUCache(800) def format_flow(f, focus, extended=False, hostheader=False, padding=2, - marked=False): + marked=False): d = dict( intercepted = f.intercepted, acked = f.reply.acked, diff --git a/libmproxy/console/flowdetailview.py b/libmproxy/console/flowdetailview.py index 40769c95..f4b4262e 100644 --- a/libmproxy/console/flowdetailview.py +++ b/libmproxy/console/flowdetailview.py @@ -9,7 +9,6 @@ def maybe_timestamp(base, attr): return utils.format_timestamp_with_milli(getattr(base, attr)) else: return "active" - pass def flowdetails(state, flow): @@ -20,7 +19,7 @@ def flowdetails(state, flow): req = flow.request resp = flow.response - if sc: + if sc is not None: text.append(urwid.Text([("head", "Server Connection:")])) parts = [ ["Address", "%s:%s" % sc.address()], @@ -76,7 +75,7 @@ def flowdetails(state, flow): common.format_keyvals(parts, key="key", val="text", indent=4) ) - if cc: + if cc is not None: text.append(urwid.Text([("head", "Client Connection:")])) parts = [ diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 2b77f4a3..c2201055 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -1,7 +1,6 @@ from __future__ import absolute_import import urwid -from netlib import http import netlib.utils from . import common, signals @@ -16,6 +15,7 @@ def _mkhelp(): ("C", "clear flow list or eventlog"), ("d", "delete flow"), ("D", "duplicate flow"), + ("E", "export"), ("e", "toggle eventlog"), ("F", "toggle follow flow list"), ("l", "set limit filter pattern"), @@ -43,6 +43,7 @@ footer = [ class EventListBox(urwid.ListBox): + def __init__(self, master): self.master = master urwid.ListBox.__init__(self, master.eventlist) @@ -60,6 +61,7 @@ class EventListBox(urwid.ListBox): class BodyPile(urwid.Pile): + def __init__(self, master): h = urwid.Text("Event log") h = urwid.Padding(h, align="left", width=("relative", 100)) @@ -103,6 +105,7 @@ class BodyPile(urwid.Pile): class ConnectionItem(urwid.WidgetWrap): + def __init__(self, master, state, flow, focus): self.master, self.state, self.flow = master, state, flow self.f = focus @@ -254,6 +257,18 @@ class ConnectionItem(urwid.WidgetWrap): ) elif key == "P": common.ask_copy_part("a", self.flow, self.master, self.state) + elif key == "E": + signals.status_prompt_onekey.send( + self, + prompt = "Export", + keys = ( + ("as curl command", "c"), + ("as python code", "p"), + ("as raw request", "r"), + ), + callback = common.export_prompt, + args = (self.flow,) + ) elif key == "b": common.ask_save_body(None, self.master, self.state, self.flow) else: @@ -261,6 +276,7 @@ class ConnectionItem(urwid.WidgetWrap): class FlowListWalker(urwid.ListWalker): + def __init__(self, master, state): self.master, self.state = master, state signals.flowlist_change.connect(self.sig_flowlist_change) @@ -289,6 +305,7 @@ class FlowListWalker(urwid.ListWalker): class FlowListBox(urwid.ListBox): + def __init__(self, master): self.master = master urwid.ListBox.__init__( diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 0038558b..8102de55 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -25,8 +25,9 @@ def _mkhelp(): ("A", "accept all intercepted flows"), ("a", "accept this intercepted flow"), ("b", "save request/response body"), - ("d", "delete flow"), ("D", "duplicate flow"), + ("d", "delete flow"), + ("E", "export"), ("e", "edit request/response"), ("f", "load full body data"), ("m", "change body display mode for this entity"), @@ -95,6 +96,7 @@ footer = [ class FlowViewHeader(urwid.WidgetWrap): + def __init__(self, master, f): self.master, self.flow = master, f self._w = common.format_flow( @@ -217,7 +219,7 @@ class FlowView(tabs.Tabs): txt = [] for (style, text) in line: if total_chars + len(text) > max_chars: - text = text[:max_chars-total_chars] + text = text[:max_chars - total_chars] txt.append((style, text)) total_chars += len(text) if total_chars == max_chars: @@ -574,6 +576,18 @@ class FlowView(tabs.Tabs): callback = self.master.save_one_flow, args = (self.flow,) ) + elif key == "E": + signals.status_prompt_onekey.send( + self, + prompt = "Export", + keys = ( + ("as curl command", "c"), + ("as python code", "p"), + ("as raw request", "r"), + ), + callback = common.export_prompt, + args = (self.flow,) + ) elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", diff --git a/libmproxy/console/grideditor.py b/libmproxy/console/grideditor.py index 237eea28..a11c962c 100644 --- a/libmproxy/console/grideditor.py +++ b/libmproxy/console/grideditor.py @@ -63,6 +63,7 @@ class TextColumn: class SubgridColumn: + def __init__(self, heading, subeditor): self.heading = heading self.subeditor = subeditor @@ -97,6 +98,7 @@ class SubgridColumn: class SEscaped(urwid.WidgetWrap): + def __init__(self, txt): txt = txt.encode("string-escape") w = urwid.Text(txt, wrap="any") @@ -113,6 +115,7 @@ class SEscaped(urwid.WidgetWrap): class SEdit(urwid.WidgetWrap): + def __init__(self, txt): txt = txt.encode("string-escape") w = urwid.Edit(edit_text=txt, wrap="any", multiline=True) @@ -127,6 +130,7 @@ class SEdit(urwid.WidgetWrap): class GridRow(urwid.WidgetWrap): + def __init__(self, focused, editing, editor, values): self.focused, self.editing, self.editor = focused, editing, editor @@ -172,6 +176,7 @@ class GridRow(urwid.WidgetWrap): class GridWalker(urwid.ListWalker): + """ Stores rows as a list of (rows, errors) tuples, where rows is a list and errors is a set with an entry of each offset in rows that is an @@ -311,6 +316,7 @@ class GridWalker(urwid.ListWalker): class GridListBox(urwid.ListBox): + def __init__(self, lw): urwid.ListBox.__init__(self, lw) diff --git a/libmproxy/console/help.py b/libmproxy/console/help.py index 74748030..0c264ebf 100644 --- a/libmproxy/console/help.py +++ b/libmproxy/console/help.py @@ -12,6 +12,7 @@ footer = [ class HelpView(urwid.ListBox): + def __init__(self, help_context): self.help_context = help_context or [] urwid.ListBox.__init__( diff --git a/libmproxy/console/options.py b/libmproxy/console/options.py index a365a78c..5c9e0cc9 100644 --- a/libmproxy/console/options.py +++ b/libmproxy/console/options.py @@ -22,6 +22,7 @@ help_context = _mkhelp() class Options(urwid.WidgetWrap): + def __init__(self, master): self.master = master self.lb = select.Select( diff --git a/libmproxy/console/palettepicker.py b/libmproxy/console/palettepicker.py index 7e2c10cd..51ad0606 100644 --- a/libmproxy/console/palettepicker.py +++ b/libmproxy/console/palettepicker.py @@ -18,6 +18,7 @@ help_context = _mkhelp() class PalettePicker(urwid.WidgetWrap): + def __init__(self, master): self.master = master low, high = [], [] diff --git a/libmproxy/console/palettes.py b/libmproxy/console/palettes.py index d897a0a2..bd370181 100644 --- a/libmproxy/console/palettes.py +++ b/libmproxy/console/palettes.py @@ -65,6 +65,7 @@ class Palette: class LowDark(Palette): + """ Low-color dark background """ @@ -129,6 +130,7 @@ class Dark(LowDark): class LowLight(Palette): + """ Low-color light background """ diff --git a/libmproxy/console/pathedit.py b/libmproxy/console/pathedit.py index dccec14a..4447070b 100644 --- a/libmproxy/console/pathedit.py +++ b/libmproxy/console/pathedit.py @@ -5,6 +5,7 @@ import urwid class _PathCompleter: + def __init__(self, _testing=False): """ _testing: disables reloading of the lookup table to make testing @@ -55,6 +56,7 @@ class _PathCompleter: class PathEdit(urwid.Edit, _PathCompleter): + def __init__(self, *args, **kwargs): urwid.Edit.__init__(self, *args, **kwargs) _PathCompleter.__init__(self) diff --git a/libmproxy/console/searchable.py b/libmproxy/console/searchable.py index dea0ac7f..cff1f0a1 100644 --- a/libmproxy/console/searchable.py +++ b/libmproxy/console/searchable.py @@ -4,6 +4,7 @@ from . import signals class Highlight(urwid.AttrMap): + def __init__(self, t): urwid.AttrMap.__init__( self, @@ -14,6 +15,7 @@ class Highlight(urwid.AttrMap): class Searchable(urwid.ListBox): + def __init__(self, state, contents): self.walker = urwid.SimpleFocusListWalker(contents) urwid.ListBox.__init__(self, self.walker) diff --git a/libmproxy/console/select.py b/libmproxy/console/select.py index bf96a785..928a7ca5 100644 --- a/libmproxy/console/select.py +++ b/libmproxy/console/select.py @@ -4,6 +4,7 @@ from . import common class _OptionWidget(urwid.WidgetWrap): + def __init__(self, option, text, shortcut, active, focus): self.option = option textattr = "text" @@ -36,6 +37,7 @@ class _OptionWidget(urwid.WidgetWrap): class OptionWalker(urwid.ListWalker): + def __init__(self, options): urwid.ListWalker.__init__(self) self.options = options @@ -59,6 +61,7 @@ class OptionWalker(urwid.ListWalker): class Heading: + def __init__(self, text): self.text = text @@ -73,6 +76,7 @@ _neg = lambda: False class Option: + def __init__(self, text, shortcut, getstate=None, activate=None): self.text = text self.shortcut = shortcut @@ -89,6 +93,7 @@ class Option: class Select(urwid.ListBox): + def __init__(self, options): self.walker = OptionWalker(options) urwid.ListBox.__init__( diff --git a/libmproxy/console/signals.py b/libmproxy/console/signals.py index 52f72d34..6a439bf3 100644 --- a/libmproxy/console/signals.py +++ b/libmproxy/console/signals.py @@ -2,6 +2,8 @@ import blinker # Show a status message in the action bar sig_add_event = blinker.Signal() + + def add_event(e, level): sig_add_event.send( None, diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py index fd084f8c..4cc63a54 100644 --- a/libmproxy/console/statusbar.py +++ b/libmproxy/console/statusbar.py @@ -7,6 +7,7 @@ from . import pathedit, signals, common class ActionBar(urwid.WidgetWrap): + def __init__(self): urwid.WidgetWrap.__init__(self, None) self.clear() @@ -108,6 +109,7 @@ class ActionBar(urwid.WidgetWrap): class StatusBar(urwid.WidgetWrap): + def __init__(self, master, helptext): self.master, self.helptext = master, helptext self.ab = ActionBar() diff --git a/libmproxy/console/tabs.py b/libmproxy/console/tabs.py index fea9bbde..b5423038 100644 --- a/libmproxy/console/tabs.py +++ b/libmproxy/console/tabs.py @@ -1,8 +1,8 @@ import urwid -import signals class Tab(urwid.WidgetWrap): + def __init__(self, offset, content, attr, onclick): """ onclick is called on click with the tab offset as argument @@ -21,6 +21,7 @@ class Tab(urwid.WidgetWrap): class Tabs(urwid.WidgetWrap): + def __init__(self, tabs, tab_offset=0): urwid.WidgetWrap.__init__(self, "") self.tab_offset = tab_offset diff --git a/libmproxy/console/window.py b/libmproxy/console/window.py index 69d5e242..47c284e4 100644 --- a/libmproxy/console/window.py +++ b/libmproxy/console/window.py @@ -3,6 +3,7 @@ from . import signals class Window(urwid.Frame): + def __init__(self, master, body, header, footer, helpctx): urwid.Frame.__init__( self, |
