diff --git a/mitmproxy/addonmanager.py b/mitmproxy/addonmanager.py index a9b76f7b4..5cfe79f52 100644 --- a/mitmproxy/addonmanager.py +++ b/mitmproxy/addonmanager.py @@ -94,7 +94,7 @@ class Loader: ) def add_command(self, path: str, func: typing.Callable) -> None: - self.master.commands.add_command(path, func) + self.master.commands.add(path, func) def traverse(chain): diff --git a/mitmproxy/command.py b/mitmproxy/command.py index 57ca05aef..e964353b7 100644 --- a/mitmproxy/command.py +++ b/mitmproxy/command.py @@ -44,7 +44,7 @@ class Command: Call the command with a set of arguments. At this point, all argumets are strings. """ if len(self.paramtypes) != len(args): - raise CommandError("SIGNATURE") + raise CommandError("Usage: %s" % self.signature_help()) args = [parsearg(args[i], self.paramtypes[i]) for i in range(len(args))] diff --git a/mitmproxy/tools/console/command.py b/mitmproxy/tools/console/command.py new file mode 100644 index 000000000..e6eabf3a1 --- /dev/null +++ b/mitmproxy/tools/console/command.py @@ -0,0 +1,26 @@ +import urwid + +from mitmproxy import command +from mitmproxy.tools.console import signals + + +class CommandEdit(urwid.Edit): + def __init__(self): + urwid.Edit.__init__(self, ":", "") + + def keypress(self, size, key): + return urwid.Edit.keypress(self, size, key) + + +class CommandExecutor: + def __init__(self, master): + self.master = master + + def __call__(self, cmd): + try: + ret = self.master.commands.call(cmd) + except command.CommandError as v: + signals.status_message.send(message=str(v)) + else: + if type(ret) == str: + signals.status_message.send(message=ret) diff --git a/mitmproxy/tools/console/flowlist.py b/mitmproxy/tools/console/flowlist.py index 044f8f05d..f1170f9f6 100644 --- a/mitmproxy/tools/console/flowlist.py +++ b/mitmproxy/tools/console/flowlist.py @@ -353,7 +353,9 @@ class FlowListBox(urwid.ListBox): def keypress(self, size, key): key = common.shortcuts(key) - if key == "A": + if key == ":": + signals.status_prompt_command.send() + elif key == "A": for f in self.master.view: if f.intercepted: f.resume() diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py index e7a2c6ae4..8727d1759 100644 --- a/mitmproxy/tools/console/master.py +++ b/mitmproxy/tools/console/master.py @@ -288,7 +288,7 @@ class ConsoleMaster(master.Master): screen = self.ui, handle_mouse = self.options.console_mouse, ) - self.ab = statusbar.ActionBar() + self.ab = statusbar.ActionBar(self) self.loop.set_alarm_in(0.01, self.ticker) self.loop.set_alarm_in( diff --git a/mitmproxy/tools/console/signals.py b/mitmproxy/tools/console/signals.py index 93f095776..91cb63b3c 100644 --- a/mitmproxy/tools/console/signals.py +++ b/mitmproxy/tools/console/signals.py @@ -24,6 +24,9 @@ status_prompt_path = blinker.Signal() # Prompt for a single keystroke status_prompt_onekey = blinker.Signal() +# Prompt for a command +status_prompt_command = blinker.Signal() + # Call a callback in N seconds call_in = blinker.Signal() diff --git a/mitmproxy/tools/console/statusbar.py b/mitmproxy/tools/console/statusbar.py index d3a3e1f22..d2424832e 100644 --- a/mitmproxy/tools/console/statusbar.py +++ b/mitmproxy/tools/console/statusbar.py @@ -5,6 +5,7 @@ import urwid from mitmproxy.tools.console import common from mitmproxy.tools.console import pathedit from mitmproxy.tools.console import signals +from mitmproxy.tools.console import command import mitmproxy.tools.console.master # noqa @@ -32,13 +33,15 @@ class PromptStub: class ActionBar(urwid.WidgetWrap): - def __init__(self): + def __init__(self, master): urwid.WidgetWrap.__init__(self, None) + self.master = master self.clear() signals.status_message.connect(self.sig_message) signals.status_prompt.connect(self.sig_prompt) signals.status_prompt_path.connect(self.sig_path_prompt) signals.status_prompt_onekey.connect(self.sig_prompt_onekey) + signals.status_prompt_command.connect(self.sig_prompt_command) self.last_path = "" @@ -66,6 +69,11 @@ class ActionBar(urwid.WidgetWrap): self._w = urwid.Edit(self.prep_prompt(prompt), text or "") self.prompting = PromptStub(callback, args) + def sig_prompt_command(self, sender): + signals.focus.send(self, section="footer") + self._w = command.CommandEdit() + self.prompting = command.CommandExecutor(self.master) + def sig_path_prompt(self, sender, prompt, callback, args=()): signals.focus.send(self, section="footer") self._w = pathedit.PathEdit(