diff options
-rw-r--r-- | mitmproxy/addons/core.py | 17 | ||||
-rw-r--r-- | mitmproxy/addons/view.py | 26 | ||||
-rw-r--r-- | mitmproxy/command.py | 27 | ||||
-rw-r--r-- | mitmproxy/tools/console/commander/commander.py | 8 | ||||
-rw-r--r-- | mitmproxy/tools/console/commands.py | 2 | ||||
-rw-r--r-- | mitmproxy/tools/console/consoleaddons.py | 11 | ||||
-rw-r--r-- | test/mitmproxy/tools/console/test_commander.py | 4 |
7 files changed, 55 insertions, 40 deletions
diff --git a/mitmproxy/addons/core.py b/mitmproxy/addons/core.py index 1fbeb1e0..55e2e129 100644 --- a/mitmproxy/addons/core.py +++ b/mitmproxy/addons/core.py @@ -83,15 +83,15 @@ class Core: ) @command.command("set") - def set(self, *options: str) -> None: + def set(self, option: str, *value: str) -> None: """ - Set an option of the form "key[=value]". When the value is omitted, - booleans are set to true, strings and integers are set to None (if - permitted), and sequences are emptied. Boolean values can be true, - false or toggle. If multiple specs are passed, they are joined - into one separated by spaces. + Set an option. When the value is omitted, booleans are set to true, + strings and integers are set to None (if permitted), and sequences + are emptied. Boolean values can be true, false or toggle. + Multiple values are concatenated with a single space. """ - strspec = " ".join(options) + value = " ".join(value) + strspec = f"{option}={value}" try: ctx.options.set(strspec) except exceptions.OptionsError as e: @@ -168,8 +168,7 @@ class Core: "reason", ] - @command.command( - "flow.set") + @command.command("flow.set") @command.argument("attr", type=mitmproxy.types.Choice("flow.set.options")) def flow_set( self, diff --git a/mitmproxy/addons/view.py b/mitmproxy/addons/view.py index c57c34c8..1d57d781 100644 --- a/mitmproxy/addons/view.py +++ b/mitmproxy/addons/view.py @@ -298,16 +298,16 @@ class View(collections.abc.Sequence): # Filter @command.command("view.filter.set") - def set_filter_cmd(self, filtstr: str) -> None: + def set_filter_cmd(self, filter_expr: str) -> None: """ Sets the current view filter. """ filt = None - if filtstr: - filt = flowfilter.parse(filtstr) + if filter_expr: + filt = flowfilter.parse(filter_expr) if not filt: raise exceptions.CommandError( - "Invalid interception filter: %s" % filtstr + "Invalid interception filter: %s" % filter_expr ) self.set_filter(filt) @@ -412,26 +412,26 @@ class View(collections.abc.Sequence): ctx.log.alert("Removed %s flows" % len(flows)) @command.command("view.flows.resolve") - def resolve(self, flowspec: str) -> typing.Sequence[mitmproxy.flow.Flow]: + def resolve(self, flow_spec: str) -> typing.Sequence[mitmproxy.flow.Flow]: """ Resolve a flow list specification to an actual list of flows. """ - if flowspec == "@all": + if flow_spec == "@all": return [i for i in self._store.values()] - if flowspec == "@focus": + if flow_spec == "@focus": return [self.focus.flow] if self.focus.flow else [] - elif flowspec == "@shown": + elif flow_spec == "@shown": return [i for i in self] - elif flowspec == "@hidden": + elif flow_spec == "@hidden": return [i for i in self._store.values() if i not in self._view] - elif flowspec == "@marked": + elif flow_spec == "@marked": return [i for i in self._store.values() if i.marked] - elif flowspec == "@unmarked": + elif flow_spec == "@unmarked": return [i for i in self._store.values() if not i.marked] else: - filt = flowfilter.parse(flowspec) + filt = flowfilter.parse(flow_spec) if not filt: - raise exceptions.CommandError("Invalid flow filter: %s" % flowspec) + raise exceptions.CommandError("Invalid flow filter: %s" % flow_spec) return [i for i in self._store.values() if filt(i)] @command.command("view.flows.create") diff --git a/mitmproxy/command.py b/mitmproxy/command.py index 00238f46..7203fe42 100644 --- a/mitmproxy/command.py +++ b/mitmproxy/command.py @@ -3,6 +3,7 @@ """ import functools import inspect +import re import sys import textwrap import types @@ -284,13 +285,27 @@ class CommandManager: def unquote(x: str) -> str: - if x.startswith("'") and x.endswith("'"): - return x[1:-1] - if x.startswith('"') and x.endswith('"'): - return x[1:-1] + quoted = ( + (x.startswith('"') and x.endswith('"')) + or + (x.startswith("'") and x.endswith("'")) + ) + if quoted: + x = x[1:-1] + # not sure if this is the right place, but pypyarsing doesn't process escape sequences. + x = re.sub(r"\\(.)", r"\g<1>", x) + return x return x +def quote(val: str) -> str: + if not val: + return '""' + if all(ws not in val for ws in " \r\n\t"): + return val + return repr(val) + + def parsearg(manager: CommandManager, spec: str, argtype: type) -> typing.Any: """ Convert a string to a argument to the appropriate type. @@ -304,14 +319,14 @@ def parsearg(manager: CommandManager, spec: str, argtype: type) -> typing.Any: raise exceptions.CommandError from e -def command(name: typing.Optional[str]): +def command(name: typing.Optional[str] = None): def decorator(function): @functools.wraps(function) def wrapper(*args, **kwargs): verify_arg_signature(function, args, kwargs) return function(*args, **kwargs) - wrapper.__dict__["command_name"] = name or function.__name__ + wrapper.__dict__["command_name"] = name or function.__name__.replace("_", ".") return wrapper return decorator diff --git a/mitmproxy/tools/console/commander/commander.py b/mitmproxy/tools/console/commander/commander.py index f826b984..d751422b 100644 --- a/mitmproxy/tools/console/commander/commander.py +++ b/mitmproxy/tools/console/commander/commander.py @@ -14,7 +14,7 @@ import mitmproxy.types class Completer: @abc.abstractmethod - def cycle(self, forward: bool) -> str: + def cycle(self, forward: bool = True) -> str: raise NotImplementedError() @@ -32,7 +32,7 @@ class ListCompleter(Completer): self.options.sort() self.offset = 0 - def cycle(self, forward: bool) -> str: + def cycle(self, forward: bool = True) -> str: if not self.options: return self.start ret = self.options[self.offset] @@ -98,7 +98,7 @@ class CommandBuffer: def right(self) -> None: self.cursor = self.cursor + 1 - def cycle_completion(self, forward: bool) -> None: + def cycle_completion(self, forward: bool = True) -> None: if not self.completion: parts, remaining = self.master.commands.parse_partial(self.text[:self.cursor]) if parts and parts[-1].type != mitmproxy.types.Space: @@ -211,7 +211,7 @@ class CommandEdit(urwid.WidgetWrap): elif key == "shift tab": self.cbuf.cycle_completion(False) elif key == "tab": - self.cbuf.cycle_completion(True) + self.cbuf.cycle_completion() elif len(key) == 1: self.cbuf.insert(key) self.update() diff --git a/mitmproxy/tools/console/commands.py b/mitmproxy/tools/console/commands.py index d35a6b8a..26a99b14 100644 --- a/mitmproxy/tools/console/commands.py +++ b/mitmproxy/tools/console/commands.py @@ -25,7 +25,7 @@ class CommandItem(urwid.WidgetWrap): if self.cmd.parameters: parts += [ ("text", " "), - ("text", " ".join(name for name, t in self.cmd.parameters)), + ("text", " ".join(str(param) for param in self.cmd.parameters)), ] if self.cmd.return_type: parts += [ diff --git a/mitmproxy/tools/console/consoleaddons.py b/mitmproxy/tools/console/consoleaddons.py index b5263f6f..4288696a 100644 --- a/mitmproxy/tools/console/consoleaddons.py +++ b/mitmproxy/tools/console/consoleaddons.py @@ -287,21 +287,22 @@ class ConsoleAddon: ) @command.command("console.command") - def console_command(self, *cmdstr: str) -> None: + def console_command(self, *cmd_str: str) -> None: """ Prompt the user to edit a command with a (possibly empty) starting value. """ - signals.status_prompt_command.send(partial=" ".join(cmdstr)) # type: ignore + cmd_str = (command.quote(x) if x else "" for x in cmd_str) + signals.status_prompt_command.send(partial=" ".join(cmd_str)) # type: ignore @command.command("console.command.set") def console_command_set(self, option_name: str) -> None: """ - Prompt the user to set an option of the form "key[=value]". + Prompt the user to set an option. """ option_value = getattr(self.master.options, option_name, None) - current_value = option_value if option_value else "" + option_value = command.quote(option_value) self.master.commands.execute( - "console.command set %s=%s" % (option_name, current_value) + f"console.command set {option_name} {option_value}" ) @command.command("console.view.keybindings") diff --git a/test/mitmproxy/tools/console/test_commander.py b/test/mitmproxy/tools/console/test_commander.py index ce789d30..6b42de76 100644 --- a/test/mitmproxy/tools/console/test_commander.py +++ b/test/mitmproxy/tools/console/test_commander.py @@ -25,7 +25,7 @@ class TestListCompleter: for start, options, cycle in tests: c = commander.ListCompleter(start, options) for expected in cycle: - assert c.cycle(True) == expected + assert c.cycle() == expected class TestCommandEdit: @@ -252,7 +252,7 @@ class TestCommandBuffer: cb = commander.CommandBuffer(tctx.master) cb.text = "foo bar" cb.cursor = len(cb.text) - cb.cycle_completion(True) + cb.cycle_completion() ch = commander.CommandHistory(tctx.master, 30) ce = commander.CommandEdit(tctx.master, "se", ch) |