Add a basic built-in web app.

This commit is contained in:
Aldo Cortesi 2013-03-25 09:20:26 +13:00
parent 98e4421a90
commit e3fd0e838d
6 changed files with 68 additions and 10 deletions

8
libmproxy/app.py Normal file
View File

@ -0,0 +1,8 @@
import flask
mapp = flask.Flask(__name__)
@mapp.route("/")
def hello():
return "mitmproxy"

View File

@ -163,7 +163,7 @@ def get_common_options(options):
def common_options(parser): def common_options(parser):
parser.add_argument( parser.add_argument(
"-a", "-b",
action="store", type = str, dest="addr", default='', action="store", type = str, dest="addr", default='',
help = "Address to bind proxy to (defaults to all interfaces)" help = "Address to bind proxy to (defaults to all interfaces)"
) )
@ -261,6 +261,13 @@ def common_options(parser):
help="Don't connect to upstream server to look up certificate details." help="Don't connect to upstream server to look up certificate details."
) )
group = parser.add_argument_group("Web App")
group.add_argument(
"-a",
action="store_true", dest="app", default=False,
help="Enable the mitmproxy web app."
)
group = parser.add_argument_group("Client Replay") group = parser.add_argument_group("Client Replay")
group.add_argument( group.add_argument(
"-c", "-c",

View File

@ -23,6 +23,7 @@ import tnetstring, filt, script, utils, encoding, proxy
from email.utils import parsedate_tz, formatdate, mktime_tz from email.utils import parsedate_tz, formatdate, mktime_tz
from netlib import odict, http, certutils from netlib import odict, http, certutils
import controller, version import controller, version
import app
HDR_FORM_URLENCODED = "application/x-www-form-urlencoded" HDR_FORM_URLENCODED = "application/x-www-form-urlencoded"
CONTENT_MISSING = 0 CONTENT_MISSING = 0
@ -42,13 +43,13 @@ class ReplaceHooks:
def add(self, fpatt, rex, s): def add(self, fpatt, rex, s):
""" """
Add a replacement hook. add a replacement hook.
fpatt: A string specifying a filter pattern. fpatt: a string specifying a filter pattern.
rex: A regular expression. rex: a regular expression.
s: The replacement string s: the replacement string
Returns True if hook was added, False if the pattern could not be returns true if hook was added, false if the pattern could not be
parsed. parsed.
""" """
cpatt = filt.parse(fpatt) cpatt = filt.parse(fpatt)
@ -1352,6 +1353,7 @@ class FlowMaster(controller.Master):
self.setheaders = SetHeaders() self.setheaders = SetHeaders()
self.stream = None self.stream = None
app.mapp.config["PMASTER"] = self
def add_event(self, e, level="info"): def add_event(self, e, level="info"):
""" """

View File

@ -17,8 +17,11 @@ import shutil, tempfile, threading
import SocketServer import SocketServer
from OpenSSL import SSL from OpenSSL import SSL
from netlib import odict, tcp, http, wsgi, certutils, http_status, http_auth from netlib import odict, tcp, http, wsgi, certutils, http_status, http_auth
import utils, flow, version, platform, controller import utils, flow, version, platform, controller, app
APP_DOMAIN = "mitm"
APP_IP = "1.1.1.1"
KILL = 0 KILL = 0
@ -36,8 +39,8 @@ class Log:
class ProxyConfig: class ProxyConfig:
def __init__(self, certfile = None, cacert = None, clientcerts = None, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, transparent_proxy=None, certdir = None, authenticator=None): def __init__(self, app=False, certfile = None, cacert = None, clientcerts = None, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, transparent_proxy=None, certdir = None, authenticator=None):
assert not (reverse_proxy and transparent_proxy) self.app = app
self.certfile = certfile self.certfile = certfile
self.cacert = cacert self.cacert = cacert
self.clientcerts = clientcerts self.clientcerts = clientcerts
@ -85,6 +88,7 @@ class ServerConnection(tcp.TCPClient):
pass pass
class RequestReplayThread(threading.Thread): class RequestReplayThread(threading.Thread):
def __init__(self, config, flow, masterq): def __init__(self, config, flow, masterq):
self.config, self.flow, self.channel = config, flow, controller.Channel(masterq) self.config, self.flow, self.channel = config, flow, controller.Channel(masterq)
@ -497,6 +501,17 @@ class ProxyServer(tcp.TCPServer):
raise ProxyServerError('Error starting proxy server: ' + v.strerror) raise ProxyServerError('Error starting proxy server: ' + v.strerror)
self.channel = None self.channel = None
self.apps = AppRegistry() self.apps = AppRegistry()
if config.app:
self.apps.add(
app.mapp,
APP_DOMAIN,
80
)
self.apps.add(
app.mapp,
APP_IP,
80
)
def start_slave(self, klass, channel): def start_slave(self, klass, channel):
slave = klass(channel, self) slave = klass(channel, self)
@ -629,6 +644,7 @@ def process_proxy_options(parser, options):
authenticator = http_auth.NullProxyAuth(None) authenticator = http_auth.NullProxyAuth(None)
return ProxyConfig( return ProxyConfig(
app = options.app,
certfile = options.cert, certfile = options.cert,
cacert = cacert, cacert = cacert,
clientcerts = options.clientcerts, clientcerts = options.clientcerts,

View File

@ -53,7 +53,16 @@ class CommonMixin:
assert "Bad Request" in t.rfile.readline() assert "Bad Request" in t.rfile.readline()
class TestHTTP(tservers.HTTPProxTest, CommonMixin):
class AppMixin:
def test_app(self):
ret = self.app("/")
assert ret.status_code == 200
assert "mitmproxy" in ret.content
class TestHTTP(tservers.HTTPProxTest, CommonMixin, AppMixin):
def test_app_err(self): def test_app_err(self):
p = self.pathoc() p = self.pathoc()
ret = p.request("get:'http://errapp/'") ret = p.request("get:'http://errapp/'")
@ -135,6 +144,7 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin):
assert req.status_code == 400 assert req.status_code == 400
class TestHTTPAuth(tservers.HTTPProxTest): class TestHTTPAuth(tservers.HTTPProxTest):
authenticator = http_auth.BasicProxyAuth(http_auth.PassManSingleUser("test", "test"), "realm") authenticator = http_auth.BasicProxyAuth(http_auth.PassManSingleUser("test", "test"), "realm")
def test_auth(self): def test_auth(self):

View File

@ -84,6 +84,7 @@ class ProxTestBase:
no_upstream_cert = cls.no_upstream_cert, no_upstream_cert = cls.no_upstream_cert,
cacert = tutils.test_data.path("data/serverkey.pem"), cacert = tutils.test_data.path("data/serverkey.pem"),
authenticator = cls.authenticator, authenticator = cls.authenticator,
app = True,
**pconf **pconf
) )
tmaster = cls.masterclass(cls.tqueue, config) tmaster = cls.masterclass(cls.tqueue, config)
@ -156,6 +157,17 @@ class HTTPProxTest(ProxTestBase):
q = "get:'%s/p/%s'"%(self.server.urlbase, spec) q = "get:'%s/p/%s'"%(self.server.urlbase, spec)
return p.request(q) return p.request(q)
def app(self, page):
if self.ssl:
p = libpathod.pathoc.Pathoc("127.0.0.1", self.proxy.port, True)
print "PRE"
p.connect((proxy.APP_IP, 80))
print "POST"
return p.request("get:'/%s'"%page)
else:
p = self.pathoc()
return p.request("get:'http://%s/%s'"%(proxy.APP_DOMAIN, page))
class TResolver: class TResolver:
def __init__(self, port): def __init__(self, port):
@ -234,3 +246,6 @@ class ReverseProxTest(ProxTestBase):
q = "get:'/p/%s'"%spec q = "get:'/p/%s'"%spec
return p.request(q) return p.request(q)