diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a86d30e8..d708834a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ ## Unreleased: mitmproxy next +* Add support for editing non text files in a hex editor + ([#6768](https://github.com/mitmproxy/mitmproxy/pull/6768), @wnyyyy) * Add section in mitmweb for rendering, adding and removing a comment ([#6709](https://github.com/mitmproxy/mitmproxy/pull/6709), @lups2000) * Fix multipart form content view being unusable. diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py index ee303ff5d..a0a1d73d1 100644 --- a/mitmproxy/tools/console/master.py +++ b/mitmproxy/tools/console/master.py @@ -29,6 +29,7 @@ from mitmproxy.tools.console import keymap from mitmproxy.tools.console import palettes from mitmproxy.tools.console import signals from mitmproxy.tools.console import window +from mitmproxy.utils import strutils T = TypeVar("T", str, bytes) @@ -120,12 +121,23 @@ class ConsoleMaster(master.Master): else: return "vi" + def get_hex_editor(self) -> str: + editors = ["ghex", "bless", "hexedit", "hxd", "hexer", "hexcurse"] + for editor in editors: + if shutil.which(editor): + return editor + return self.get_editor() + def spawn_editor(self, data: T) -> T: - text = not isinstance(data, bytes) + text = isinstance(data, str) fd, name = tempfile.mkstemp("", "mitmproxy", text=text) + with_hexeditor = isinstance(data, bytes) and strutils.is_mostly_bin(data) with open(fd, "w" if text else "wb") as f: f.write(data) - c = self.get_editor() + if with_hexeditor: + c = self.get_hex_editor() + else: + c = self.get_editor() cmd = shlex.split(c) cmd.append(name) with self.uistopped(): diff --git a/test/mitmproxy/tools/console/test_master.py b/test/mitmproxy/tools/console/test_master.py index e69de29bb..47651482c 100644 --- a/test/mitmproxy/tools/console/test_master.py +++ b/test/mitmproxy/tools/console/test_master.py @@ -0,0 +1,30 @@ +from unittest.mock import Mock + + +def test_spawn_editor(monkeypatch, console): + text_data = "text" + binary_data = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" + + console.get_editor = Mock() + console.get_editor.return_value = "editor" + console.get_hex_editor = Mock() + console.get_hex_editor.return_value = "editor" + monkeypatch.setattr("subprocess.call", (lambda _: None)) + + console.loop = Mock() + console.loop.stop = Mock() + console.loop.start = Mock() + console.loop.draw_screen = Mock() + + console.spawn_editor(text_data) + console.get_editor.assert_called_once() + + console.spawn_editor(binary_data) + console.get_hex_editor.assert_called_once() + + +def test_get_hex_editor(monkeypatch, console): + test_editor = "hexedit" + monkeypatch.setattr("shutil.which", lambda x: x == test_editor) + editor = console.get_hex_editor() + assert editor == test_editor