Creating addons with positional arguments


#1

So , today I started on with my addon development for mitmproxy .
Firstly I started with seeing the simple examples , I saw the upsidedownternet and made somewhat similar to it called as censored .

from io import BytesIO
from PIL import Image

def response(flow):
    if flow.response.headers.get("content-type", "").startswith("image"):
        s = Image.open('/root/mitmproxy/scripts/photo.jpg')
        s2 = BytesIO()
        s.save(s2, "jpeg")
        flow.response.content = s2.getvalue()
        flow.response.headers["content-type"] = "image/jpeg"

It works fine but if I want to add a keyword argument path to it then how will it get it ?

Somewhat like this:

def response(flow, path):
    if flow.response.headers.get("content-type", "").startswith("image"):
        s = Image.open(path)
        s2 = BytesIO()

Cause it’s not working .
I dug deeper to find out the file responsible for sending options to the script and found this :
/mitmproxy/mitmproxy/addons/script.py
Inside this I found these two functions :

def scriptenv(path, args):
    oldargs = sys.argv
    sys.argv = [path] + args
    script_dir = os.path.dirname(os.path.abspath(path))
    sys.path.append(script_dir)
    try:
        yield
    except SystemExit as v:
        ctx.log.error("Script exited with code %s" % v.code)
    except Exception:
        etype, value, tb = sys.exc_info()
        tb = cut_traceback(tb, "scriptenv").tb_next
        ctx.log.error(
            "Script error: %s" % "".join(
                traceback.format_exception(etype, value, tb)
            )
        )
    finally:
        sys.argv = oldargs
        sys.path.pop()


def load_script(path, args):
    with open(path, "rb") as f:
        try:
            code = compile(f.read(), path, 'exec')
        except SyntaxError as e:
            ctx.log.error(
                "Script error: %s line %s: %s" % (
                    e.filename, e.lineno, e.msg
                )
            )
            return
    ns = {'__file__': os.path.abspath(path)}
    with scriptenv(path, args):
        exec(code, ns)
    return types.SimpleNamespace(**ns)

I could make out that these were being compiled and executed but couldn’t make out how was the arguments being sent to the script .
Any help would be appreciated.
Thanks.


#2

Actually I found out how to add arguments by taking hints from : /mitmproxy/examples/simple/modify_body_inject_iframe.py

My new code is :

from io import BytesIO

import sys
from PIL import Image


# ='/root/mitmproxy/scripts/photo.jpg'
class censored:
    def __init__(self, path):
        self.path = path

    def response(self, flow):
        if flow.response.headers.get("content-type", "").startswith("image"):
            s = Image.open(self.path)
            s2 = BytesIO()
            s.save(s2, "jpeg")
            flow.response.content = s2.getvalue()
            flow.response.headers["content-type"] = "image/jpeg"


def start(opts):
    if len(sys.argv) != 2:
        raise ValueError('Usage: -s "censored.py /path/to/image"')
    return censored(sys.argv[1])

But had this been not there How would I have proceeded ?


#3

We have an example script exactly for the purpose of demonstrating how arguments can be added: https://github.com/mitmproxy/mitmproxy/blob/master/examples/simple/script_arguments.py