diff options
author | Aldo Cortesi <aldo@corte.si> | 2018-05-03 13:05:11 +1200 |
---|---|---|
committer | Aldo Cortesi <aldo@corte.si> | 2018-05-10 11:30:51 +1200 |
commit | 3438912236a25d7d3bcbff3238156b9eae2bc3d5 (patch) | |
tree | 40ed31194a1f944d81ecf8f2fc86d1a526f86d66 /mitmproxy | |
parent | 0c101a4bccfb8460a11691cc17467d47d1974b2f (diff) | |
download | mitmproxy-3438912236a25d7d3bcbff3238156b9eae2bc3d5.tar.gz mitmproxy-3438912236a25d7d3bcbff3238156b9eae2bc3d5.tar.bz2 mitmproxy-3438912236a25d7d3bcbff3238156b9eae2bc3d5.zip |
console keybindings: define YAML-based format for console key binding persistence
Diffstat (limited to 'mitmproxy')
-rw-r--r-- | mitmproxy/tools/console/keymap.py | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/mitmproxy/tools/console/keymap.py b/mitmproxy/tools/console/keymap.py index fbb569a4..5f7cdb11 100644 --- a/mitmproxy/tools/console/keymap.py +++ b/mitmproxy/tools/console/keymap.py @@ -1,6 +1,18 @@ import typing +import os + +import ruamel.yaml + +from mitmproxy import command from mitmproxy.tools.console import commandexecutor from mitmproxy.tools.console import signals +from mitmproxy import ctx +from mitmproxy import exceptions +import mitmproxy.types + + +class KeyBindingError(Exception): + pass Contexts = { @@ -139,3 +151,82 @@ class Keymap: if b: return self.executor(b.command) return key + + +keyAttrs = { + "key": lambda x: isinstance(x, str), + "cmd": lambda x: isinstance(x, str), + "ctx": lambda x: isinstance(x, list) and [isinstance(v, str) for v in x], + "help": lambda x: isinstance(x, str), +} +requiredKeyAttrs = set(["key", "cmd"]) + + +class KeymapConfig: + @command.command("console.keymap.load") + def keymap_load_path(self, path: mitmproxy.types.Path) -> None: + try: + master = ctx.master # type: mitmproxy.tools.console.master.ConsoleMaster + self.load_path(master.keymap, path) + except (OSError, KeyBindingError) as e: + raise exceptions.CommandError( + "Could not load key bindings - %s" % e + ) from e + + def load_path(self, km, p): + if os.path.exists(p) and os.path.isfile(p): + with open(p, "rt", encoding="utf8") as f: + try: + txt = f.read() + except UnicodeDecodeError as e: + raise KeyBindingError( + "Encoding error - expected UTF8: %s: %s" % (p, e) + ) + try: + vals = self.parse(txt) + except KeyBindingError as e: + raise KeyBindingError( + "Error reading %s: %s" % (p, e) + ) from e + for v in vals: + try: + km.add( + key = v["key"], + command = v["cmd"], + contexts = v.get("ctx", None), + help = v.get("help", None), + ) + except ValueError as e: + raise KeyBindingError( + "Error reading %s: %s" % (p, e) + ) from e + + def parse(self, text): + try: + data = ruamel.yaml.safe_load(text) + except ruamel.yaml.error.YAMLError as v: + if hasattr(v, "problem_mark"): + snip = v.problem_mark.get_snippet() + raise KeyBindingError( + "Key binding config error at line %s:\n%s\n%s" % + (v.problem_mark.line + 1, snip, v.problem) + ) + else: + raise KeyBindingError("Could not parse key bindings.") + if not data: + return [] + if not isinstance(data, list): + raise KeyBindingError("Inalid keybinding config - expected a list of keys") + + for k in data: + unknown = k.keys() - keyAttrs.keys() + if unknown: + raise KeyBindingError("Unknown key attributes: %s" % unknown) + missing = requiredKeyAttrs - k.keys() + if missing: + raise KeyBindingError("Missing required key attributes: %s" % unknown) + for attr in k.keys(): + if not keyAttrs[attr](k[attr]): + raise KeyBindingError("Invalid type for %s" % attr) + + return data |