Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
master.py264 linesDownload Raw Back to console
1import asyncio2import contextlib3import mimetypes4import os.path5import shlex6import shutil7import stat8import subprocess9import sys10import tempfile11import threading12from typing import TypeVar13 14import urwid15from tornado.platform.asyncio import AddThreadSelectorEventLoop16 17from mitmproxy import addons18from mitmproxy import log19from mitmproxy import master20from mitmproxy import options21from mitmproxy.addons import errorcheck22from mitmproxy.addons import eventstore23from mitmproxy.addons import intercept24from mitmproxy.addons import readfile25from mitmproxy.addons import view26from mitmproxy.tools.console import consoleaddons27from mitmproxy.tools.console import defaultkeys28from mitmproxy.tools.console import keymap29from mitmproxy.tools.console import palettes30from mitmproxy.tools.console import signals31from mitmproxy.tools.console import window32from mitmproxy.utils import strutils33 34T = TypeVar("T", str, bytes)35 36 37class ConsoleMaster(master.Master):38    def __init__(self, opts: options.Options) -> None:39        super().__init__(opts)40 41        self.view: view.View = view.View()42        self.events = eventstore.EventStore()43        self.events.sig_add.connect(self.sig_add_log)44 45        self.stream_path = None46        self.keymap = keymap.Keymap(self)47        defaultkeys.map(self.keymap)48        self.options.errored.connect(self.options_error)49 50        self.addons.add(*addons.default_addons())51        self.addons.add(52            intercept.Intercept(),53            self.view,54            self.events,55            readfile.ReadFile(),56            consoleaddons.ConsoleAddon(self),57            keymap.KeymapConfig(self),58            errorcheck.ErrorCheck(repeat_errors_on_stderr=True),59        )60 61        self.window: window.Window | None = None62 63    def __setattr__(self, name, value):64        super().__setattr__(name, value)65        signals.update_settings.send()66 67    def options_error(self, exc) -> None:68        signals.status_message.send(message=str(exc), expire=1)69 70    def prompt_for_user_choice(self, prompt, callback) -> None:71        signals.status_prompt_onekey.send(72            prompt=prompt,73            keys=[74                ("yes", "y"),75                ("no", "n"),76            ],77            callback=callback,78        )79 80    def prompt_for_exit(self) -> None:81        self.prompt_for_user_choice("Quit", self.quit)82 83    def sig_add_log(self, entry: log.LogEntry):84        if log.log_tier(self.options.console_eventlog_verbosity) < log.log_tier(85            entry.level86        ):87            return88        if entry.level in ("error", "warn", "alert"):89            signals.status_message.send(90                message=(91                    entry.level,92                    f"{entry.level.title()}: {entry.msg.lstrip()}",93                ),94                expire=5,95            )96 97    def sig_call_in(self, seconds, callback):98        def cb(*_):99            return callback()100 101        self.loop.set_alarm_in(seconds, cb)102 103    @contextlib.contextmanager104    def uistopped(self):105        self.loop.stop()106        try:107            yield108        finally:109            self.loop.start()110            self.loop.screen_size = None111            self.loop.draw_screen()112 113    def get_editor(self) -> str:114        # based upon https://github.com/pallets/click/blob/main/src/click/_termui_impl.py115        if m := os.environ.get("MITMPROXY_EDITOR"):116            return m117        if m := os.environ.get("EDITOR"):118            return m119        for editor in "sensible-editor", "nano", "vim":120            if shutil.which(editor):121                return editor122        if os.name == "nt":123            return "notepad"124        else:125            return "vi"126 127    def get_hex_editor(self) -> str:128        editors = ["ghex", "hexedit", "hxd", "hexer", "hexcurse"]129        for editor in editors:130            if shutil.which(editor):131                return editor132        return self.get_editor()133 134    def spawn_editor(self, data: T) -> T:135        text = isinstance(data, str)136        fd, name = tempfile.mkstemp("", "mitmproxy", text=text)137        with_hexeditor = isinstance(data, bytes) and strutils.is_mostly_bin(data)138        with open(fd, "w" if text else "wb") as f:139            f.write(data)140        if with_hexeditor:141            c = self.get_hex_editor()142        else:143            c = self.get_editor()144        cmd = shlex.split(c)145        cmd.append(name)146        with self.uistopped():147            try:148                subprocess.call(cmd)149            except Exception:150                signals.status_message.send(message="Can't start editor: %s" % c)151            else:152                with open(name, "r" if text else "rb") as f:153                    data = f.read()154        os.unlink(name)155        return data156 157    def spawn_external_viewer(self, data, contenttype):158        if contenttype:159            contenttype = contenttype.split(";")[0]160            ext = mimetypes.guess_extension(contenttype) or ""161        else:162            ext = ""163        fd, name = tempfile.mkstemp(ext, "mproxy")164        os.write(fd, data)165        os.close(fd)166 167        # read-only to remind the user that this is a view function168        os.chmod(name, stat.S_IREAD)169 170        # hm which one should get priority?171        c = (172            os.environ.get("MITMPROXY_EDITOR")173            or os.environ.get("PAGER")174            or os.environ.get("EDITOR")175        )176        if not c:177            c = "less"178        cmd = shlex.split(c)179        cmd.append(name)180 181        with self.uistopped():182            try:183                subprocess.call(cmd, shell=False)184            except Exception:185                signals.status_message.send(186                    message="Can't start external viewer: %s" % " ".join(c)187                )188        # add a small delay before deletion so that the file is not removed before being loaded by the viewer189        t = threading.Timer(1.0, os.unlink, args=[name])190        t.start()191 192    def set_palette(self, *_) -> None:193        self.ui.register_palette(194            palettes.palettes[self.options.console_palette].palette(195                self.options.console_palette_transparent196            )197        )198        self.ui.clear()199 200    def inject_key(self, key):201        self.loop.process_input([key])202 203    async def running(self) -> None:204        if not sys.stdout.isatty():205            print(206                "Error: mitmproxy's console interface requires a tty. "207                "Please run mitmproxy in an interactive shell environment.",208                file=sys.stderr,209            )210            sys.exit(1)211 212        detected_encoding = urwid.detected_encoding.lower()213        if os.name != "nt" and detected_encoding and "utf" not in detected_encoding:214            print(215                f"mitmproxy expects a UTF-8 console environment, not {urwid.detected_encoding!r}. "216                f"Set your LANG environment variable to something like en_US.UTF-8.",217                file=sys.stderr,218            )219            # Experimental (04/2022): We just don't exit here and see if/how that affects users.220            # sys.exit(1)221        urwid.set_encoding("utf8")222 223        signals.call_in.connect(self.sig_call_in)224        self.ui = window.Screen()225        self.ui.set_terminal_properties(256)226        self.set_palette(None)227        self.options.subscribe(228            self.set_palette, ["console_palette", "console_palette_transparent"]229        )230 231        loop = asyncio.get_running_loop()232        if isinstance(loop, getattr(asyncio, "ProactorEventLoop", tuple())):233            # fix for https://bugs.python.org/issue37373234            loop = AddThreadSelectorEventLoop(loop)  # type: ignore235        self.loop = urwid.MainLoop(236            urwid.SolidFill("x"),237            event_loop=urwid.AsyncioEventLoop(loop=loop),238            screen=self.ui,239            handle_mouse=self.options.console_mouse,240        )241        self.window = window.Window(self)242        self.loop.widget = self.window243        self.window.refresh()244 245        self.loop.start()246 247        await super().running()248 249    async def done(self):250        self.loop.stop()251        await super().done()252 253    def overlay(self, widget, **kwargs):254        assert self.window255        self.window.set_overlay(widget, **kwargs)256 257    def switch_view(self, name):258        assert self.window259        self.window.push(name)260 261    def quit(self, a):262        if a != "n":263            self.shutdown()264 
codekingpro/portable-devtools · Team Ai