├── .appveyor.yml
├── .codecov.yml
├── .env
├── .gitattributes
├── .gitignore
├── .landscape.yml
├── .travis.yml
├── CHANGELOG
├── CONTRIBUTORS
├── LICENSE
├── MANIFEST.in
├── README.rst
├── dev.ps1
├── dev.sh
├── docs
├── .gitignore
├── Makefile
├── _static
│ └── theme_overrides.css
├── _templates
│ └── page.html
├── certinstall-webapp.png
├── certinstall.rst
├── conf.py
├── config.rst
├── custom-routing.txt
├── dev
│ ├── addingviews.html
│ ├── architecture.rst
│ ├── sslkeylogfile.rst
│ └── testing.rst
├── favicon.ico
├── features
│ ├── anticache.rst
│ ├── clientreplay.rst
│ ├── filters.rst
│ ├── passthrough.rst
│ ├── proxyauth.rst
│ ├── replacements.rst
│ ├── responsestreaming.rst
│ ├── reverseproxy.rst
│ ├── serverreplay.rst
│ ├── setheaders.rst
│ ├── socksproxy.rst
│ ├── sticky.rst
│ ├── tcpproxy.rst
│ ├── upstreamcerts.rst
│ └── upstreamproxy.rst
├── howmitmproxy.rst
├── index.rst
├── install.rst
├── introduction.rst
├── mitmdump.rst
├── mitmproxy-docs.png
├── mitmproxy.rst
├── modd.conf
├── modes.rst
├── pathod
│ ├── intro.rst
│ ├── language.rst
│ ├── library.rst
│ └── test.rst
├── schematics
│ ├── _explicit.graffle
│ │ ├── data.plist
│ │ ├── image3.icns
│ │ └── image6.tiff
│ ├── _explicit_https.graffle
│ │ ├── data.plist
│ │ ├── image3.icns
│ │ └── image6.tiff
│ ├── _transparent.graffle
│ │ ├── data.plist
│ │ ├── image3.icns
│ │ └── image6.tiff
│ ├── _transparent_https.graffle
│ │ ├── data.plist
│ │ ├── image3.icns
│ │ └── image6.tiff
│ ├── architecture.pdf
│ ├── architecture.png
│ ├── architecture.vsdx
│ ├── how-mitmproxy-works-explicit-https.png
│ ├── how-mitmproxy-works-explicit.png
│ ├── how-mitmproxy-works-transparent-https.png
│ ├── how-mitmproxy-works-transparent.png
│ ├── proxy-modes-flowchart.png
│ ├── proxy-modes-regular.png
│ ├── proxy-modes-reverse.png
│ ├── proxy-modes-transparent-1.png
│ ├── proxy-modes-transparent-2.png
│ ├── proxy-modes-transparent-3.png
│ ├── proxy-modes-transparent-wrong.png
│ ├── proxy-modes-upstream.png
│ ├── proxy-modes.pdf
│ └── proxy-modes.vsdx
├── screenshots
│ ├── firefox3-import.jpg
│ ├── firefox3-trust.jpg
│ ├── firefox3.jpg
│ ├── ios-gateway.png
│ ├── ios-installed.png
│ ├── ios-manual.png
│ ├── ios-profile.png
│ ├── ios-reverse.png
│ ├── ios-warning.png
│ ├── mitmproxy-flowview.png
│ ├── mitmproxy-intercept-filt.png
│ ├── mitmproxy-intercept-mid.png
│ ├── mitmproxy-intercept-options.png
│ ├── mitmproxy-intercept-result.png
│ ├── mitmproxy-kveditor-editmode.png
│ ├── mitmproxy-kveditor.png
│ ├── mitmproxy.png
│ ├── osx-addcert-alwaystrust.png
│ ├── win7-certstore-trustedroot.png
│ ├── win7-certstore.png
│ ├── win7-wizard.png
│ └── winpythoninstaller.jpg
├── scripting
│ ├── api.rst
│ ├── events.rst
│ └── overview.rst
├── transparent.rst
├── transparent
│ ├── linux.rst
│ └── osx.rst
└── tutorials
│ ├── 30second.rst
│ ├── gamecenter.rst
│ ├── leaderboard.png
│ ├── one.png
│ ├── supermega.png
│ ├── transparent-dhcp.rst
│ └── transparent-dhcp
│ ├── step1_proxy.png
│ ├── step1_vbox_eth0.png
│ ├── step1_vbox_eth1.png
│ └── step2_proxied_vm.png
├── examples
├── README
├── add_header.py
├── arguments.py
├── change_upstream_proxy.py
├── classes.py
├── custom_contentviews.py
├── dns_spoofing.py
├── dup_and_replay.py
├── fail_with_500.py
├── flowbasic
├── flowfilter.py
├── flowwriter.py
├── full_transparency_shim.c
├── har_dump.py
├── iframe_injector.py
├── logging.py
├── mitmproxywrapper.py
├── modify_form.py
├── modify_querystring.py
├── nonblocking.py
├── pathod
│ ├── libpathod_pathoc.py
│ ├── test_context.py
│ ├── test_setup.py
│ └── test_setupall.py
├── proxapp.py
├── read_dumpfile
├── redirect_requests.py
├── remote_debug.py
├── sslstrip.py
├── stickycookies
├── stream.py
├── stream_modify.py
├── stub.py
├── tcp_message.py
├── tls_passthrough.py
└── upsidedownternet.py
├── issue_template.md
├── mitmproxy
├── __init__.py
├── addonmanager.py
├── addons
│ ├── __init__.py
│ ├── anticache.py
│ ├── anticomp.py
│ ├── clientplayback.py
│ ├── dumper.py
│ ├── filestreamer.py
│ ├── onboarding.py
│ ├── onboardingapp
│ │ ├── __init__.py
│ │ ├── app.py
│ │ ├── static
│ │ │ ├── bootstrap.min.css
│ │ │ ├── fontawesome
│ │ │ │ ├── css
│ │ │ │ │ ├── font-awesome.css
│ │ │ │ │ └── font-awesome.min.css
│ │ │ │ └── fonts
│ │ │ │ │ ├── FontAwesome.otf
│ │ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ │ ├── fontawesome-webfont.svg
│ │ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ │ └── fontawesome-webfont.woff
│ │ │ └── mitmproxy.css
│ │ └── templates
│ │ │ ├── frame.html
│ │ │ ├── index.html
│ │ │ └── layout.html
│ ├── replace.py
│ ├── script.py
│ ├── serverplayback.py
│ ├── setheaders.py
│ ├── state.py
│ ├── stickyauth.py
│ ├── stickycookie.py
│ ├── streambodies.py
│ ├── termlog.py
│ └── wsgiapp.py
├── certs.py
├── connections.py
├── contentviews.py
├── contrib
│ ├── README
│ ├── __init__.py
│ ├── tls
│ │ ├── __init__.py
│ │ ├── _constructs.py
│ │ └── utils.py
│ ├── tnetstring.py
│ └── wbxml
│ │ ├── ASCommandResponse.py
│ │ ├── ASWBXML.py
│ │ ├── ASWBXMLByteQueue.py
│ │ ├── ASWBXMLCodePage.py
│ │ ├── GlobalTokens.py
│ │ ├── InvalidDataException.py
│ │ └── __init__.py
├── controller.py
├── ctx.py
├── events.py
├── exceptions.py
├── export.py
├── flow.py
├── flowfilter.py
├── http.py
├── io.py
├── io_compat.py
├── log.py
├── master.py
├── net
│ ├── __init__.py
│ ├── check.py
│ ├── http
│ │ ├── __init__.py
│ │ ├── authentication.py
│ │ ├── cookies.py
│ │ ├── encoding.py
│ │ ├── headers.py
│ │ ├── http1
│ │ │ ├── __init__.py
│ │ │ ├── assemble.py
│ │ │ └── read.py
│ │ ├── http2
│ │ │ ├── __init__.py
│ │ │ ├── framereader.py
│ │ │ └── utils.py
│ │ ├── message.py
│ │ ├── multipart.py
│ │ ├── request.py
│ │ ├── response.py
│ │ ├── status_codes.py
│ │ ├── url.py
│ │ └── user_agents.py
│ ├── socks.py
│ ├── tcp.py
│ ├── websockets
│ │ ├── __init__.py
│ │ ├── frame.py
│ │ ├── masker.py
│ │ └── utils.py
│ └── wsgi.py
├── options.py
├── optmanager.py
├── platform
│ ├── __init__.py
│ ├── linux.py
│ ├── osx.py
│ ├── pf.py
│ └── windows.py
├── proxy
│ ├── __init__.py
│ ├── config.py
│ ├── modes
│ │ ├── __init__.py
│ │ ├── http_proxy.py
│ │ ├── reverse_proxy.py
│ │ ├── socks_proxy.py
│ │ └── transparent_proxy.py
│ ├── protocol
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── http.py
│ │ ├── http1.py
│ │ ├── http2.py
│ │ ├── http_replay.py
│ │ ├── rawtcp.py
│ │ ├── tls.py
│ │ └── websockets.py
│ ├── root_context.py
│ └── server.py
├── script
│ ├── __init__.py
│ └── concurrent.py
├── stateobject.py
├── tcp.py
├── test
│ └── tutils.py
├── tools
│ ├── __init__.py
│ ├── cmdline.py
│ ├── console
│ │ ├── __init__.py
│ │ ├── common.py
│ │ ├── flowdetailview.py
│ │ ├── flowlist.py
│ │ ├── flowview.py
│ │ ├── grideditor
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── col_bytes.py
│ │ │ ├── col_subgrid.py
│ │ │ ├── col_text.py
│ │ │ └── editors.py
│ │ ├── help.py
│ │ ├── master.py
│ │ ├── options.py
│ │ ├── palettepicker.py
│ │ ├── palettes.py
│ │ ├── pathedit.py
│ │ ├── searchable.py
│ │ ├── select.py
│ │ ├── signals.py
│ │ ├── statusbar.py
│ │ ├── tabs.py
│ │ └── window.py
│ ├── dump.py
│ ├── main.py
│ └── web
│ │ ├── __init__.py
│ │ ├── app.py
│ │ ├── master.py
│ │ ├── static
│ │ ├── app.css
│ │ ├── app.js
│ │ ├── fonts
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.svg
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ └── fontawesome-webfont.woff
│ │ ├── images
│ │ │ ├── chrome-devtools
│ │ │ │ ├── LICENSE
│ │ │ │ ├── resourceCSSIcon.png
│ │ │ │ ├── resourceDocumentIcon.png
│ │ │ │ ├── resourceJSIcon.png
│ │ │ │ └── resourcePlainIcon.png
│ │ │ ├── favicon.ico
│ │ │ ├── resourceExecutableIcon.png
│ │ │ ├── resourceFlashIcon.png
│ │ │ ├── resourceImageIcon.png
│ │ │ ├── resourceJavaIcon.png
│ │ │ ├── resourceNotModifiedIcon.png
│ │ │ └── resourceRedirectIcon.png
│ │ ├── vendor.css
│ │ └── vendor.js
│ │ └── templates
│ │ └── index.html
├── types
│ ├── __init__.py
│ ├── basethread.py
│ ├── bidi.py
│ ├── multidict.py
│ └── serializable.py
├── utils
│ ├── __init__.py
│ ├── bits.py
│ ├── data.py
│ ├── debug.py
│ ├── human.py
│ ├── strutils.py
│ ├── typecheck.py
│ └── version_check.py
└── version.py
├── pathod
├── __init__.py
├── language
│ ├── __init__.py
│ ├── actions.py
│ ├── base.py
│ ├── exceptions.py
│ ├── generators.py
│ ├── http.py
│ ├── http2.py
│ ├── message.py
│ ├── websockets.py
│ └── writer.py
├── log.py
├── pathoc.py
├── pathoc_cmdline.py
├── pathod.py
├── pathod_cmdline.py
├── protocols
│ ├── __init__.py
│ ├── http.py
│ ├── http2.py
│ └── websockets.py
├── test.py
└── utils.py
├── release
├── .gitignore
├── README.md
├── rtool.pem
├── rtool.py
├── setup.py
└── specs
│ ├── icon.ico
│ ├── mitmdump
│ ├── mitmdump.spec
│ ├── mitmproxy
│ ├── mitmproxy.spec
│ ├── mitmweb
│ ├── mitmweb.spec
│ ├── pathoc
│ ├── pathoc.spec
│ ├── pathod
│ └── pathod.spec
├── requirements.txt
├── setup.cfg
├── setup.py
├── test
├── __init__.py
├── mitmproxy
│ ├── __init__.py
│ ├── addons
│ │ ├── __init__.py
│ │ ├── test_anticache.py
│ │ ├── test_anticomp.py
│ │ ├── test_clientplayback.py
│ │ ├── test_dumper.py
│ │ ├── test_filestreamer.py
│ │ ├── test_onboarding.py
│ │ ├── test_replace.py
│ │ ├── test_script.py
│ │ ├── test_serverplayback.py
│ │ ├── test_setheaders.py
│ │ ├── test_state.py
│ │ ├── test_stickyauth.py
│ │ ├── test_stickycookie.py
│ │ ├── test_streambodies.py
│ │ ├── test_termlog.py
│ │ └── test_wsgiapp.py
│ ├── completion
│ │ ├── aaa
│ │ ├── aab
│ │ ├── aac
│ │ └── bbb
│ │ │ └── Readme.md
│ ├── console
│ │ ├── __init__.py
│ │ ├── test_common.py
│ │ ├── test_help.py
│ │ ├── test_master.py
│ │ ├── test_palettes.py
│ │ └── test_pathedit.py
│ ├── data
│ │ ├── 1.css
│ │ ├── addonscripts
│ │ │ ├── addon.py
│ │ │ ├── concurrent_decorator.py
│ │ │ ├── concurrent_decorator_err.py
│ │ │ ├── duplicate_flow.py
│ │ │ ├── error.py
│ │ │ ├── recorder.py
│ │ │ ├── stream_modify.py
│ │ │ └── tcp_stream_modify.py
│ │ ├── amf01
│ │ ├── amf02
│ │ ├── amf03
│ │ ├── clientcert
│ │ │ ├── .gitignore
│ │ │ ├── 127.0.0.1.pem
│ │ │ ├── client.cnf
│ │ │ ├── client.pem
│ │ │ └── make
│ │ ├── confdir
│ │ │ ├── mitmproxy-ca-cert.cer
│ │ │ ├── mitmproxy-ca-cert.p12
│ │ │ ├── mitmproxy-ca-cert.pem
│ │ │ └── mitmproxy-ca.pem
│ │ ├── dercert
│ │ ├── dumpfile-010
│ │ ├── dumpfile-011
│ │ ├── har_extractor.har
│ │ ├── htpasswd
│ │ ├── htpasswd.invalid
│ │ ├── image-err1.jpg
│ │ ├── image.gif
│ │ ├── image.ico
│ │ ├── image.jpg
│ │ ├── image.png
│ │ ├── no_common_name.pem
│ │ ├── pf01
│ │ ├── pf02
│ │ ├── protobuf01
│ │ ├── replace
│ │ ├── scripts
│ │ │ └── all.py
│ │ ├── servercert
│ │ │ ├── 9da13359.0
│ │ │ ├── self-signed.pem
│ │ │ ├── trusted-leaf.pem
│ │ │ └── trusted-root.pem
│ │ ├── test_flow_export
│ │ │ ├── locust_get.py
│ │ │ ├── locust_patch.py
│ │ │ ├── locust_post.py
│ │ │ ├── locust_task_get.py
│ │ │ ├── locust_task_patch.py
│ │ │ ├── locust_task_post.py
│ │ │ ├── python_get.py
│ │ │ ├── python_patch.py
│ │ │ ├── python_post.py
│ │ │ └── python_post_json.py
│ │ └── testkey.pem
│ ├── fuzzing
│ │ ├── .env
│ │ ├── README
│ │ ├── client_patterns
│ │ ├── go_proxy
│ │ ├── reverse_patterns
│ │ ├── straight_stream
│ │ ├── straight_stream_patterns
│ │ └── straight_stream_ssl
│ ├── mastertest.py
│ ├── mock_urwid.py
│ ├── net
│ │ ├── __init__.py
│ │ ├── data
│ │ │ ├── clientcert
│ │ │ │ ├── .gitignore
│ │ │ │ ├── client.cnf
│ │ │ │ ├── client.pem
│ │ │ │ └── make
│ │ │ ├── dercert
│ │ │ ├── dhparam.pem
│ │ │ ├── htpasswd
│ │ │ ├── server.crt
│ │ │ ├── server.key
│ │ │ ├── text_cert
│ │ │ ├── text_cert_2
│ │ │ ├── text_cert_weird1
│ │ │ └── verificationcerts
│ │ │ │ ├── 9da13359.0
│ │ │ │ ├── generate.py
│ │ │ │ ├── self-signed.crt
│ │ │ │ ├── self-signed.key
│ │ │ │ ├── trusted-leaf.crt
│ │ │ │ ├── trusted-leaf.key
│ │ │ │ ├── trusted-root.crt
│ │ │ │ ├── trusted-root.key
│ │ │ │ └── trusted-root.srl
│ │ ├── http
│ │ │ ├── __init__.py
│ │ │ ├── http1
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_assemble.py
│ │ │ │ └── test_read.py
│ │ │ ├── http2
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_framereader.py
│ │ │ ├── test_authentication.py
│ │ │ ├── test_cookies.py
│ │ │ ├── test_encoding.py
│ │ │ ├── test_headers.py
│ │ │ ├── test_message.py
│ │ │ ├── test_multipart.py
│ │ │ ├── test_request.py
│ │ │ ├── test_response.py
│ │ │ ├── test_status_codes.py
│ │ │ ├── test_url.py
│ │ │ └── test_user_agents.py
│ │ ├── test_check.py
│ │ ├── test_imports.py
│ │ ├── test_socks.py
│ │ ├── test_tcp.py
│ │ ├── test_wsgi.py
│ │ ├── tools
│ │ │ └── getcertnames
│ │ ├── tservers.py
│ │ └── websockets
│ │ │ ├── __init__.py
│ │ │ ├── test_frame.py
│ │ │ ├── test_masker.py
│ │ │ └── test_utils.py
│ ├── protocol
│ │ ├── __init__.py
│ │ ├── test_http1.py
│ │ ├── test_http2.py
│ │ └── test_websockets.py
│ ├── script
│ │ ├── __init__.py
│ │ └── test_concurrent.py
│ ├── test_addonmanager.py
│ ├── test_certs.py
│ ├── test_cmdline.py
│ ├── test_contentview.py
│ ├── test_contrib_tnetstring.py
│ ├── test_controller.py
│ ├── test_custom_contentview.py
│ ├── test_dump.py
│ ├── test_examples.py
│ ├── test_flow.py
│ ├── test_flow_export.py
│ ├── test_flow_format_compat.py
│ ├── test_flowfilter.py
│ ├── test_fuzzing.py
│ ├── test_optmanager.py
│ ├── test_platform_pf.py
│ ├── test_proxy.py
│ ├── test_proxy_config.py
│ ├── test_server.py
│ ├── test_stateobject.py
│ ├── test_types_bidi.py
│ ├── test_types_multidict.py
│ ├── test_types_serializable.py
│ ├── test_web_app.py
│ ├── test_web_master.py
│ ├── tools
│ │ ├── 1024example
│ │ ├── ab.exe
│ │ ├── bench.py
│ │ ├── benchtool.py
│ │ ├── getcert
│ │ ├── inspect_dumpfile.py
│ │ ├── memoryleak.py
│ │ ├── passive_close.py
│ │ └── testpatt
│ ├── tservers.py
│ ├── tutils.py
│ └── utils
│ │ ├── __init__.py
│ │ ├── test_data.py
│ │ ├── test_debug.py
│ │ ├── test_human.py
│ │ ├── test_strutils.py
│ │ ├── test_typecheck.py
│ │ └── test_version_check.py
└── pathod
│ ├── __init__.py
│ ├── data
│ ├── clientcert
│ │ ├── .gitignore
│ │ ├── client.cnf
│ │ ├── client.pem
│ │ └── make
│ ├── file
│ ├── request
│ ├── response
│ └── testkey.pem
│ ├── scripts
│ ├── generate.sh
│ └── openssl.cnf
│ ├── test_language_actions.py
│ ├── test_language_base.py
│ ├── test_language_generators.py
│ ├── test_language_http.py
│ ├── test_language_http2.py
│ ├── test_language_websocket.py
│ ├── test_language_writer.py
│ ├── test_log.py
│ ├── test_pathoc.py
│ ├── test_pathoc_cmdline.py
│ ├── test_pathod.py
│ ├── test_pathod_cmdline.py
│ ├── test_protocols_http2.py
│ ├── test_test.py
│ ├── test_utils.py
│ └── tutils.py
├── tox.ini
└── web
├── .babelrc
├── .editorconfig
├── .eslintrc.yml
├── README
├── conf.js
├── gulpfile.js
├── package.json
└── src
├── css
├── app.less
├── codemirror.less
├── contentview.less
├── dropdown.less
├── eventlog.less
├── flowdetail.less
├── flowtable.less
├── flowview.less
├── footer.less
├── header.less
├── layout.less
├── prompt.less
├── sprites.less
├── tabs.less
├── vendor-bootstrap-variables.less
├── vendor-bootstrap.less
└── vendor.less
├── fonts
├── FontAwesome.otf
├── README
├── font-awesome.css
├── fontawesome-webfont.eot
├── fontawesome-webfont.svg
├── fontawesome-webfont.ttf
└── fontawesome-webfont.woff
├── images
├── chrome-devtools
│ ├── LICENSE
│ ├── resourceCSSIcon.png
│ ├── resourceDocumentIcon.png
│ ├── resourceJSIcon.png
│ └── resourcePlainIcon.png
├── favicon.ico
├── resourceExecutableIcon.png
├── resourceFlashIcon.png
├── resourceImageIcon.png
├── resourceJavaIcon.png
├── resourceNotModifiedIcon.png
└── resourceRedirectIcon.png
├── js
├── __tests__
│ └── ducks
│ │ ├── flowViewSpec.js
│ │ ├── flowsSpec.js
│ │ ├── tutils.js
│ │ ├── ui
│ │ ├── flowSpec.js
│ │ └── headerSpec.js
│ │ └── utils
│ │ ├── listSpec.js
│ │ └── viewSpec.js
├── actions.js
├── app.jsx
├── components
│ ├── ContentView.jsx
│ ├── ContentView
│ │ ├── CodeEditor.jsx
│ │ ├── ContentLoader.jsx
│ │ ├── ContentViewOptions.jsx
│ │ ├── ContentViews.jsx
│ │ ├── DownloadContentButton.jsx
│ │ ├── MetaViews.jsx
│ │ ├── ShowFullContentButton.jsx
│ │ ├── UploadContentButton.jsx
│ │ └── ViewSelector.jsx
│ ├── EventLog.jsx
│ ├── EventLog
│ │ └── EventList.jsx
│ ├── FlowTable.jsx
│ ├── FlowTable
│ │ ├── FlowColumns.jsx
│ │ ├── FlowRow.jsx
│ │ └── FlowTableHead.jsx
│ ├── FlowView.jsx
│ ├── FlowView
│ │ ├── Details.jsx
│ │ ├── Headers.jsx
│ │ ├── Messages.jsx
│ │ ├── Nav.jsx
│ │ └── ToggleEdit.jsx
│ ├── Footer.jsx
│ ├── Header.jsx
│ ├── Header
│ │ ├── FileMenu.jsx
│ │ ├── FilterDocs.jsx
│ │ ├── FilterInput.jsx
│ │ ├── FlowMenu.jsx
│ │ ├── MainMenu.jsx
│ │ ├── OptionMenu.jsx
│ │ └── ViewMenu.jsx
│ ├── MainView.jsx
│ ├── Prompt.jsx
│ ├── ProxyApp.jsx
│ ├── ValueEditor
│ │ ├── ValidateEditor.jsx
│ │ └── ValueEditor.jsx
│ ├── common
│ │ ├── Button.jsx
│ │ ├── Dropdown.jsx
│ │ ├── FileChooser.jsx
│ │ ├── Splitter.jsx
│ │ ├── ToggleButton.jsx
│ │ └── ToggleInputButton.jsx
│ └── helpers
│ │ ├── AutoScroll.js
│ │ └── VirtualScroll.js
├── dispatcher.js
├── ducks
│ ├── README.md
│ ├── app.js
│ ├── eventLog.js
│ ├── flowView.js
│ ├── flows.js
│ ├── index.js
│ ├── msgQueue.js
│ ├── settings.js
│ ├── ui
│ │ ├── flow.js
│ │ ├── header.js
│ │ ├── index.js
│ │ └── keyboard.js
│ ├── utils
│ │ ├── list.js
│ │ └── view.js
│ └── websocket.js
├── filt
│ ├── filt.js
│ └── filt.peg
├── flow
│ └── utils.js
└── utils.js
└── templates
└── index.html
/.codecov.yml:
--------------------------------------------------------------------------------
1 | comment: off
2 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | DIR="$( dirname "${BASH_SOURCE[0]}" )"
2 | ACTIVATE_DIR="$(if [ -f "$DIR/venv/bin/activate" ]; then echo 'bin'; else echo 'Scripts'; fi;)"
3 | if [ -z "$VIRTUAL_ENV" ] && [ -f "$DIR/venv/$ACTIVATE_DIR/activate" ]; then
4 | echo "Activating mitmproxy virtualenv..."
5 | source "$DIR/venv/$ACTIVATE_DIR/activate"
6 | fi
7 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | mitmproxy/web/static/**/* -diff
2 | web/src/js/filt/filt.js -diff
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | MANIFEST
3 | */tmp
4 | /venv*
5 | *.py[cdo]
6 | *.swp
7 | *.swo
8 | *.egg-info/
9 | .coverage*
10 | .idea
11 | .cache/
12 | .tox*/
13 | build/
14 |
15 | # UI
16 |
17 | node_modules
18 | bower_components
19 | *.map
20 | sslkeylogfile.log
21 | .tox/
22 |
--------------------------------------------------------------------------------
/.landscape.yml:
--------------------------------------------------------------------------------
1 | ignore-paths:
2 | - docs
3 | - examples
4 | - mitmproxy/contrib
5 | - web
6 | max-line-length: 140
7 | pylint:
8 | options:
9 | dummy-variables-rgx: _$|.+_$|dummy_.+
10 | disable:
11 | - missing-docstring
12 | - protected-access
13 | - too-few-public-methods
14 | - too-many-arguments
15 | - too-many-instance-attributes
16 | - too-many-locals
17 | - too-many-public-methods
18 | - too-many-return-statements
19 | - too-many-statements
20 | - unpacking-non-sequence
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, Aldo Cortesi. All rights reserved.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | graft mitmproxy
2 | graft pathod
3 | recursive-exclude * *.pyc *.pyo *.swo *.swp *.map
4 |
--------------------------------------------------------------------------------
/dev.ps1:
--------------------------------------------------------------------------------
1 | $ErrorActionPreference = "Stop"
2 | $VENV = ".\venv"
3 |
4 | virtualenv $VENV --always-copy
5 | & $VENV\Scripts\activate.ps1
6 |
7 | python -m pip install --disable-pip-version-check -U pip
8 | cmd /c "pip install -r requirements.txt 2>&1"
9 |
10 | echo @"
11 |
12 | * Created virtualenv environment in $VENV.
13 | * Installed all dependencies into the virtualenv.
14 | * Activated virtualenv environment.
15 |
16 | "@
--------------------------------------------------------------------------------
/dev.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -x
4 |
5 | PYVERSION=3.5
6 | VENV="venv$PYVERSION"
7 |
8 | echo "Creating dev environment in $VENV using Python $PYVERSION"
9 |
10 | python$PYVERSION -m virtualenv "$VENV" --always-copy
11 | . "$VENV/bin/activate"
12 | pip$PYVERSION install -U pip setuptools
13 | pip$PYVERSION install -r requirements.txt
14 |
15 | echo ""
16 | echo "* Virtualenv created in $VENV and all dependencies installed."
17 | echo "* You can now activate the $(python --version) virtualenv with this command: \`. $VENV/bin/activate\`"
18 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _build/
2 |
--------------------------------------------------------------------------------
/docs/_static/theme_overrides.css:
--------------------------------------------------------------------------------
1 |
2 | /* override table width restrictions */
3 | .wy-table-responsive table td, .wy-table-responsive table th {
4 | white-space: normal;
5 | }
6 |
7 | .wy-table-responsive > table > tbody > tr > td {
8 | vertical-align: top !important;
9 | }
10 |
11 | .wy-table-responsive {
12 | margin-bottom: 24px;
13 | max-width: 100%;
14 | overflow: visible;
15 | }
16 |
17 | .wy-menu-vertical header, .wy-menu-vertical p.caption {
18 | color: #e0e0e0;
19 | }
20 |
21 | .code-block-caption {
22 | height: 1.5em;
23 | }
24 |
25 | .code-block-caption .caption-text {
26 | font-size: 0.8em;
27 | float: right;
28 | }
29 |
30 | .code-block-caption .headerlink {
31 | display: none !important;
32 | }
33 |
34 | .function .headerlink {
35 | display: none !important;
36 | }
37 |
38 | dl .reference.internal {
39 | display: none !important;
40 | }
41 |
42 | dl .headerlink {
43 | display: none !important;
44 | }
45 |
--------------------------------------------------------------------------------
/docs/_templates/page.html:
--------------------------------------------------------------------------------
1 | {% extends "!page.html" %}
2 | {% block sidebartitle %}
3 |
4 |
5 |
6 | Return to mitmproxy.org
7 |
8 |
9 | {{ super() }}
10 | {% endblock %}
--------------------------------------------------------------------------------
/docs/certinstall-webapp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/certinstall-webapp.png
--------------------------------------------------------------------------------
/docs/custom-routing.txt:
--------------------------------------------------------------------------------
1 | # Adapted from http://tldp.org/HOWTO/TransparentProxy-6.html (6.2 Second method)
2 | # Note that the choice of firewall mark (3) and routing table (2) was fairly arbitrary.
3 | # If you are already using policy routing or firewall marking for some other purpose,
4 | # make sure you choose unique numbers here. Otherwise, don't worry about it.
5 |
6 |
7 |
8 | # On the router, run
9 |
10 | PROXY_IP=192.168.1.100
11 | TARGET_IP=192.168.1.110
12 |
13 | iptables -t mangle -A PREROUTING -j ACCEPT -p tcp -m multiport --dports 80,443 -s ! $TARGET_IP
14 | # Alternative to MITM the whole network:
15 | # iptables -t mangle -A PREROUTING -j ACCEPT -p tcp -m multiport --dports 80,443 -s $PROXY_IP
16 | iptables -t mangle -A PREROUTING -j MARK --set-mark 3 -p tcp -m multiport --dports 80,443
17 | ip rule add fwmark 3 table 2
18 | ip route add default via $PROXY_IP dev br0 table 2
19 |
20 |
21 |
22 | # On the proxy machine, run
23 |
24 | iptables -A PREROUTING -t nat -i eth0 -p tcp -m multiport --dports 80,443 -j REDIRECT --to-port 8080
25 |
--------------------------------------------------------------------------------
/docs/dev/architecture.rst:
--------------------------------------------------------------------------------
1 | .. _architecture:
2 |
3 | Architecture
4 | ============
5 |
6 | To give you a better understanding of how mitmproxy works, mitmproxy's
7 | high-level architecture is detailed in the following graphic:
8 |
9 | .. image:: ../schematics/architecture.png
10 |
11 | :download:`architecture.pdf <../schematics/architecture.pdf>`
12 |
13 | Please don't refrain from asking any further
14 | questions on the mailing list, the Slack channel or the GitHub issue tracker.
15 |
--------------------------------------------------------------------------------
/docs/dev/sslkeylogfile.rst:
--------------------------------------------------------------------------------
1 | .. _sslkeylogfile:
2 |
3 | TLS Master Secrets
4 | ==================
5 |
6 | The SSL master keys can be logged by mitmproxy so that external programs can decrypt TLS
7 | connections both from and to the proxy. Key logging is enabled by setting the environment variable
8 | :envvar:`SSLKEYLOGFILE` so that it points to a writable text file.
9 | Recent versions of WireShark can use these log files to decrypt packets.
10 | You can specify the key file path in WireShark via
11 |
12 | :samp:`Edit -> Preferences -> Protocols -> SSL -> (Pre)-Master-Secret log filename`.
13 |
14 | Note that :envvar:`SSLKEYLOGFILE` is respected by other programs as well, e.g. Firefox and Chrome.
15 | If this creates any issues, you can set :envvar:`MITMPROXY_SSLKEYLOGFILE` alternatively.
16 |
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/features/anticache.rst:
--------------------------------------------------------------------------------
1 | .. _anticache:
2 |
3 | Anticache
4 | =========
5 | When the ``--anticache`` option is passed to mitmproxy, it removes headers
6 | (``if-none-match`` and ``if-modified-since``) that might elicit a
7 | ``304 not modified`` response from the server. This is useful when you want to make
8 | sure you capture an HTTP exchange in its totality. It's also often used during
9 | :ref:`clientreplay`, when you want to make sure the server responds with complete data.
10 |
11 |
12 | ================== ======================
13 | command-line ``--anticache``
14 | mitmproxy shortcut :kbd:`o` then :kbd:`a`
15 | ================== ======================
16 |
--------------------------------------------------------------------------------
/docs/features/clientreplay.rst:
--------------------------------------------------------------------------------
1 | .. _clientreplay:
2 |
3 | Client-side replay
4 | ==================
5 |
6 | Client-side replay does what it says on the tin: you provide a previously saved
7 | HTTP conversation, and mitmproxy replays the client requests one by one. Note
8 | that mitmproxy serializes the requests, waiting for a response from the server
9 | before starting the next request. This might differ from the recorded
10 | conversation, where requests may have been made concurrently.
11 |
12 | You may want to use client-side replay in conjunction with the
13 | :ref:`anticache` option, to make sure the server responds with complete data.
14 |
15 | ================== ===========
16 | command-line ``-c path``
17 | mitmproxy shortcut :kbd:`R` then :kbd:`c`
18 | ================== ===========
19 |
--------------------------------------------------------------------------------
/docs/features/filters.rst:
--------------------------------------------------------------------------------
1 | .. _filters:
2 |
3 | Filter expressions
4 | ==================
5 |
6 | Many commands in :program:`mitmproxy` and :program:`mitmdump` take a filter expression.
7 | Filter expressions consist of the following operators:
8 |
9 | .. documentedlist::
10 | :header: "Expression" "Description"
11 | :listobject: mitmproxy.flowfilter.help
12 |
13 | - Regexes are Python-style
14 | - Regexes can be specified as quoted strings
15 | - Header matching (~h, ~hq, ~hs) is against a string of the form "name: value".
16 | - Strings with no operators are matched against the request URL.
17 | - The default binary operator is &.
18 |
19 | Examples
20 | --------
21 |
22 | URL containing "google.com":
23 |
24 | .. code-block:: none
25 |
26 | google\.com
27 |
28 | Requests whose body contains the string "test":
29 |
30 | .. code-block:: none
31 |
32 | ~q ~b test
33 |
34 | Anything but requests with a text/html content type:
35 |
36 | .. code-block:: none
37 |
38 | !(~q & ~t "text/html")
39 |
--------------------------------------------------------------------------------
/docs/features/proxyauth.rst:
--------------------------------------------------------------------------------
1 | .. _proxyauth:
2 |
3 | Proxy Authentication
4 | ====================
5 |
6 |
7 | Asks the user for authentication before they are permitted to use the proxy.
8 | Authentication headers are stripped from the flows, so they are not passed to
9 | upstream servers. For now, only HTTP Basic authentication is supported. The
10 | proxy auth options are not compatible with the transparent, socks or reverse proxy
11 | mode.
12 |
13 | ================== ======================
14 | command-line ``--nonanonymous``,
15 | ``--singleuser USER``,
16 | ``--htpasswd PATH``
17 | ================== ======================
18 |
--------------------------------------------------------------------------------
/docs/features/setheaders.rst:
--------------------------------------------------------------------------------
1 | .. _setheaders:
2 |
3 | Set Headers
4 | ===========
5 |
6 | This feature lets you specify a set of headers to be added to requests or
7 | responses, based on a filter pattern. You can specify these either on the
8 | command-line, or through an interactive editor in mitmproxy.
9 |
10 | Example: Set the **Host** header to "example.com" for all requests.
11 |
12 | .. code-block:: none
13 |
14 | mitmdump -R http://example.com --setheader :~q:Host:example.com
15 |
16 | ================== =======================
17 | command-line ``--setheader PATTERN``
18 | mitmproxy shortcut :kbd:`o` then :kbd:`H`
19 | ================== =======================
20 |
--------------------------------------------------------------------------------
/docs/features/socksproxy.rst:
--------------------------------------------------------------------------------
1 | .. _socksproxy:
2 |
3 | SOCKS Mode
4 | ==========
5 |
6 | In this mode, mitmproxy acts as a SOCKS5 proxy server.
7 |
8 | ================== ===========
9 | command-line ``--socks``
10 | ================== ===========
11 |
--------------------------------------------------------------------------------
/docs/features/tcpproxy.rst:
--------------------------------------------------------------------------------
1 | .. _tcpproxy:
2 |
3 | TCP Proxy
4 | =========
5 |
6 | WebSockets or other non-HTTP protocols are not supported by mitmproxy yet. However, you can exempt
7 | hostnames from processing, so that mitmproxy acts as a generic TCP forwarder.
8 | This feature is closely related to the :ref:`passthrough` functionality,
9 | but differs in two important aspects:
10 |
11 | - The raw TCP messages are printed to the event log.
12 | - SSL connections will be intercepted.
13 |
14 | Please note that message interception or modification are not possible yet.
15 | If you are not interested in the raw TCP messages, you should use the ignore domains feature.
16 |
17 | How it works
18 | ------------
19 |
20 | ================== ======================
21 | command-line ``--tcp HOST``
22 | mitmproxy shortcut :kbd:`o` then :kbd:`T`
23 | ================== ======================
24 |
25 | For a detailed description how the hostname pattern works, please look at the :ref:`passthrough`
26 | feature.
27 |
28 | .. seealso::
29 |
30 | - :ref:`passthrough`
31 | - :ref:`responsestreaming`
32 |
--------------------------------------------------------------------------------
/docs/features/upstreamcerts.rst:
--------------------------------------------------------------------------------
1 | .. _upstreamcerts:
2 |
3 | Upstream Certificates
4 | =====================
5 |
6 | When mitmproxy receives a connection destined for an SSL-protected service, it
7 | freezes the connection before reading its request data, and makes a connection
8 | to the upstream server to "sniff" the contents of its SSL certificate. The
9 | information gained - the **Common Name** and **Subject Alternative Names** - is
10 | then used to generate the interception certificate, which is sent to the client
11 | so the connection can continue.
12 |
13 | This rather intricate little dance lets us seamlessly generate correct
14 | certificates even if the client has specified only an IP address rather than the
15 | hostname. It also means that we don't need to sniff additional data to generate
16 | certs in transparent mode.
17 |
18 | Upstream cert sniffing is on by default, and can optionally be turned off.
19 |
20 | ================== ======================
21 | command-line ``--no-upstream-cert``
22 | mitmproxy shortcut :kbd:`o` then :kbd:`U`
23 | ================== ======================
24 |
--------------------------------------------------------------------------------
/docs/features/upstreamproxy.rst:
--------------------------------------------------------------------------------
1 | .. _upstreamproxy:
2 |
3 | Upstream proxy mode
4 | ===================
5 |
6 | In this mode, mitmproxy accepts proxy requests and unconditionally forwards all
7 | requests to a specified upstream proxy server. This is in contrast to :ref:`reverseproxy`,
8 | in which mitmproxy forwards ordinary HTTP requests to an upstream server.
9 |
10 | ================== =============================
11 | command-line ``-U http://hostname[:port]``
12 | ================== =============================
13 |
--------------------------------------------------------------------------------
/docs/introduction.rst:
--------------------------------------------------------------------------------
1 | Introduction
2 | ============
3 |
4 | **mitmproxy** is an interactive man-in-the-middle proxy for HTTP and HTTPS
5 | with a console interface.
6 |
7 | **mitmdump** is the command-line version of mitmproxy. Think tcpdump for HTTP.
8 |
9 | Documentation, tutorials and distribution packages can be found on the
10 | mitmproxy website: `mitmproxy.org `_
11 |
12 |
13 | .. rubric:: Features
14 |
15 | - Intercept HTTP & HTTPS requests and responses and modify them on the fly
16 | - Save complete HTTP conversations for later replay and analysis
17 | - Replay the client-side of an HTTP conversations
18 | - Replay HTTP responses of a previously recorded server
19 | - Reverse proxy mode to forward traffic to a specified server
20 | - Transparent proxy mode on OSX and Linux
21 | - Make scripted changes to HTTP traffic using Python
22 | - SSL/TLS certificates for interception are generated on the fly
23 | - And much, much more...
24 |
--------------------------------------------------------------------------------
/docs/mitmproxy-docs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/mitmproxy-docs.png
--------------------------------------------------------------------------------
/docs/modd.conf:
--------------------------------------------------------------------------------
1 | @build = ./_build
2 |
3 | ** !_build/** ../mitmproxy/**/*.py {
4 | prep: sphinx-build -W -d @build/doctrees -b html . @build/html
5 | daemon: devd -m @build/html
6 | }
7 |
--------------------------------------------------------------------------------
/docs/pathod/library.rst:
--------------------------------------------------------------------------------
1 | .. _library:
2 |
3 | pathod library
4 | ==============
5 |
6 | Behind the pathod and pathoc command-line tools lurks the **pathod** library, a
7 | powerful way to manipulate and serve HTTP requests and responses from code. The
8 | canonical documentation for the library is in the code, and can be accessed
9 | using pydoc.
10 |
11 |
12 | .. literalinclude:: ../../examples/pathod/libpathod_pathoc.py
13 | :caption: examples/pathod/libpathod_pathoc.py
14 | :language: python
15 |
--------------------------------------------------------------------------------
/docs/pathod/test.rst:
--------------------------------------------------------------------------------
1 | .. _test:
2 |
3 | pathod.test
4 | ===========
5 |
6 | The **pathod.test** module is a light, flexible testing layer for HTTP clients.
7 | It works by firing up a Pathod instance in a separate thread, letting you use
8 | Pathod's full abilities to generate responses, and then query Pathod's internal
9 | logs to establish what happened. All the mechanics of startup, shutdown, finding
10 | free ports and so forth are taken care of for you.
11 |
12 | The canonical docs can be accessed using pydoc:
13 |
14 | >>> pydoc pathod.test
15 |
16 | The remainder of this page demonstrates some common interaction patterns using
17 | nose . These examples are
18 | also applicable with only minor modification to most commonly used Python testing
19 | engines.
20 |
21 |
22 | Context Manager
23 | ---------------
24 |
25 | .. literalinclude:: ../../examples/pathod/test_context.py
26 | :caption: examples/pathod/test_context.py
27 | :language: python
28 |
29 |
30 | One instance per test
31 | ---------------------
32 |
33 | .. literalinclude:: ../../examples/pathod/test_setup.py
34 | :caption: examples/pathod/test_setup.py
35 | :language: python
36 |
--------------------------------------------------------------------------------
/docs/schematics/_explicit.graffle/image3.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/_explicit.graffle/image3.icns
--------------------------------------------------------------------------------
/docs/schematics/_explicit.graffle/image6.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/_explicit.graffle/image6.tiff
--------------------------------------------------------------------------------
/docs/schematics/_explicit_https.graffle/image3.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/_explicit_https.graffle/image3.icns
--------------------------------------------------------------------------------
/docs/schematics/_explicit_https.graffle/image6.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/_explicit_https.graffle/image6.tiff
--------------------------------------------------------------------------------
/docs/schematics/_transparent.graffle/image3.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/_transparent.graffle/image3.icns
--------------------------------------------------------------------------------
/docs/schematics/_transparent.graffle/image6.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/_transparent.graffle/image6.tiff
--------------------------------------------------------------------------------
/docs/schematics/_transparent_https.graffle/image3.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/_transparent_https.graffle/image3.icns
--------------------------------------------------------------------------------
/docs/schematics/_transparent_https.graffle/image6.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/_transparent_https.graffle/image6.tiff
--------------------------------------------------------------------------------
/docs/schematics/architecture.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/architecture.pdf
--------------------------------------------------------------------------------
/docs/schematics/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/architecture.png
--------------------------------------------------------------------------------
/docs/schematics/architecture.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/architecture.vsdx
--------------------------------------------------------------------------------
/docs/schematics/how-mitmproxy-works-explicit-https.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/how-mitmproxy-works-explicit-https.png
--------------------------------------------------------------------------------
/docs/schematics/how-mitmproxy-works-explicit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/how-mitmproxy-works-explicit.png
--------------------------------------------------------------------------------
/docs/schematics/how-mitmproxy-works-transparent-https.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/how-mitmproxy-works-transparent-https.png
--------------------------------------------------------------------------------
/docs/schematics/how-mitmproxy-works-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/how-mitmproxy-works-transparent.png
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes-flowchart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes-flowchart.png
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes-regular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes-regular.png
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes-reverse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes-reverse.png
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes-transparent-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes-transparent-1.png
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes-transparent-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes-transparent-2.png
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes-transparent-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes-transparent-3.png
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes-transparent-wrong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes-transparent-wrong.png
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes-upstream.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes-upstream.png
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes.pdf
--------------------------------------------------------------------------------
/docs/schematics/proxy-modes.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/schematics/proxy-modes.vsdx
--------------------------------------------------------------------------------
/docs/screenshots/firefox3-import.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/firefox3-import.jpg
--------------------------------------------------------------------------------
/docs/screenshots/firefox3-trust.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/firefox3-trust.jpg
--------------------------------------------------------------------------------
/docs/screenshots/firefox3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/firefox3.jpg
--------------------------------------------------------------------------------
/docs/screenshots/ios-gateway.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/ios-gateway.png
--------------------------------------------------------------------------------
/docs/screenshots/ios-installed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/ios-installed.png
--------------------------------------------------------------------------------
/docs/screenshots/ios-manual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/ios-manual.png
--------------------------------------------------------------------------------
/docs/screenshots/ios-profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/ios-profile.png
--------------------------------------------------------------------------------
/docs/screenshots/ios-reverse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/ios-reverse.png
--------------------------------------------------------------------------------
/docs/screenshots/ios-warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/ios-warning.png
--------------------------------------------------------------------------------
/docs/screenshots/mitmproxy-flowview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/mitmproxy-flowview.png
--------------------------------------------------------------------------------
/docs/screenshots/mitmproxy-intercept-filt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/mitmproxy-intercept-filt.png
--------------------------------------------------------------------------------
/docs/screenshots/mitmproxy-intercept-mid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/mitmproxy-intercept-mid.png
--------------------------------------------------------------------------------
/docs/screenshots/mitmproxy-intercept-options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/mitmproxy-intercept-options.png
--------------------------------------------------------------------------------
/docs/screenshots/mitmproxy-intercept-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/mitmproxy-intercept-result.png
--------------------------------------------------------------------------------
/docs/screenshots/mitmproxy-kveditor-editmode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/mitmproxy-kveditor-editmode.png
--------------------------------------------------------------------------------
/docs/screenshots/mitmproxy-kveditor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/mitmproxy-kveditor.png
--------------------------------------------------------------------------------
/docs/screenshots/mitmproxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/mitmproxy.png
--------------------------------------------------------------------------------
/docs/screenshots/osx-addcert-alwaystrust.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/osx-addcert-alwaystrust.png
--------------------------------------------------------------------------------
/docs/screenshots/win7-certstore-trustedroot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/win7-certstore-trustedroot.png
--------------------------------------------------------------------------------
/docs/screenshots/win7-certstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/win7-certstore.png
--------------------------------------------------------------------------------
/docs/screenshots/win7-wizard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/win7-wizard.png
--------------------------------------------------------------------------------
/docs/screenshots/winpythoninstaller.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/screenshots/winpythoninstaller.jpg
--------------------------------------------------------------------------------
/docs/scripting/api.rst:
--------------------------------------------------------------------------------
1 | .. _api:
2 |
3 |
4 | API
5 | ===
6 |
7 | - Errors
8 | - `mitmproxy.flow.Error <#mitmproxy.flow.Error>`_
9 | - HTTP
10 | - `mitmproxy.http.HTTPRequest <#mitmproxy.http.HTTPRequest>`_
11 | - `mitmproxy.http.HTTPResponse <#mitmproxy.http.HTTPResponse>`_
12 | - `mitmproxy.http.HTTPFlow <#mitmproxy.http.HTTPFlow>`_
13 | - Logging
14 | - `mitmproxy.log.Log <#mitmproxy.controller.Log>`_
15 | - `mitmproxy.log.LogEntry <#mitmproxy.controller.LogEntry>`_
16 |
17 |
18 | Errors
19 | ------
20 |
21 | .. autoclass:: mitmproxy.flow.Error
22 | :inherited-members:
23 |
24 | HTTP
25 | ----
26 |
27 | .. autoclass:: mitmproxy.http.HTTPRequest
28 | :inherited-members:
29 |
30 | .. autoclass:: mitmproxy.http.HTTPResponse
31 | :inherited-members:
32 |
33 | .. autoclass:: mitmproxy.http.HTTPFlow
34 | :inherited-members:
35 |
36 | Logging
37 | --------
38 |
39 | .. autoclass:: mitmproxy.log.Log
40 | :inherited-members:
41 | .. autoclass:: mitmproxy.log.LogEntry
42 | :inherited-members:
43 |
--------------------------------------------------------------------------------
/docs/tutorials/leaderboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/tutorials/leaderboard.png
--------------------------------------------------------------------------------
/docs/tutorials/one.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/tutorials/one.png
--------------------------------------------------------------------------------
/docs/tutorials/supermega.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/tutorials/supermega.png
--------------------------------------------------------------------------------
/docs/tutorials/transparent-dhcp/step1_proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/tutorials/transparent-dhcp/step1_proxy.png
--------------------------------------------------------------------------------
/docs/tutorials/transparent-dhcp/step1_vbox_eth0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/tutorials/transparent-dhcp/step1_vbox_eth0.png
--------------------------------------------------------------------------------
/docs/tutorials/transparent-dhcp/step1_vbox_eth1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/tutorials/transparent-dhcp/step1_vbox_eth1.png
--------------------------------------------------------------------------------
/docs/tutorials/transparent-dhcp/step2_proxied_vm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/docs/tutorials/transparent-dhcp/step2_proxied_vm.png
--------------------------------------------------------------------------------
/examples/add_header.py:
--------------------------------------------------------------------------------
1 | def response(flow):
2 | flow.response.headers["newheader"] = "foo"
3 |
--------------------------------------------------------------------------------
/examples/arguments.py:
--------------------------------------------------------------------------------
1 | import argparse
2 |
3 |
4 | class Replacer:
5 | def __init__(self, src, dst):
6 | self.src, self.dst = src, dst
7 |
8 | def response(self, flow):
9 | flow.response.replace(self.src, self.dst)
10 |
11 |
12 | def start():
13 | parser = argparse.ArgumentParser()
14 | parser.add_argument("src", type=str)
15 | parser.add_argument("dst", type=str)
16 | args = parser.parse_args()
17 | return Replacer(args.src, args.dst)
18 |
--------------------------------------------------------------------------------
/examples/change_upstream_proxy.py:
--------------------------------------------------------------------------------
1 | # This scripts demonstrates how mitmproxy can switch to a second/different upstream proxy
2 | # in upstream proxy mode.
3 | #
4 | # Usage: mitmdump -U http://default-upstream-proxy.local:8080/ -s change_upstream_proxy.py
5 | #
6 | # If you want to change the target server, you should modify flow.request.host and flow.request.port
7 |
8 |
9 | def proxy_address(flow):
10 | # Poor man's loadbalancing: route every second domain through the alternative proxy.
11 | if hash(flow.request.host) % 2 == 1:
12 | return ("localhost", 8082)
13 | else:
14 | return ("localhost", 8081)
15 |
16 |
17 | def request(flow):
18 | if flow.request.method == "CONNECT":
19 | # If the decision is done by domain, one could also modify the server address here.
20 | # We do it after CONNECT here to have the request data available as well.
21 | return
22 | address = proxy_address(flow)
23 | if flow.live:
24 | flow.live.change_upstream_proxy_server(address)
25 |
--------------------------------------------------------------------------------
/examples/classes.py:
--------------------------------------------------------------------------------
1 | class AddHeader:
2 | def response(self, flow):
3 | flow.response.headers["newheader"] = "foo"
4 |
5 |
6 | def start():
7 | return AddHeader()
8 |
--------------------------------------------------------------------------------
/examples/dup_and_replay.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import ctx
2 |
3 |
4 | def request(flow):
5 | f = ctx.master.state.duplicate_flow(flow)
6 | f.request.path = "/changed"
7 | ctx.master.replay_request(f, block=True, run_scripthooks=False)
8 |
--------------------------------------------------------------------------------
/examples/fail_with_500.py:
--------------------------------------------------------------------------------
1 | def response(flow):
2 | flow.response.status_code = 500
3 | flow.response.content = b""
4 |
--------------------------------------------------------------------------------
/examples/flowbasic:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | This example shows how to build a proxy based on mitmproxy's Flow
4 | primitives.
5 |
6 | Heads Up: In the majority of cases, you want to use inline scripts.
7 |
8 | Note that request and response messages are not automatically replied to,
9 | so we need to implement handlers to do this.
10 | """
11 | from mitmproxy import controller, options, master
12 | from mitmproxy.proxy import ProxyServer, ProxyConfig
13 |
14 |
15 | class MyMaster(master.Master):
16 | def run(self):
17 | try:
18 | master.Master.run(self)
19 | except KeyboardInterrupt:
20 | self.shutdown()
21 |
22 | @controller.handler
23 | def request(self, f):
24 | print("request", f)
25 |
26 | @controller.handler
27 | def response(self, f):
28 | print("response", f)
29 |
30 | @controller.handler
31 | def error(self, f):
32 | print("error", f)
33 |
34 | @controller.handler
35 | def log(self, l):
36 | print("log", l.msg)
37 |
38 | opts = options.Options(cadir="~/.mitmproxy/")
39 | config = ProxyConfig(opts)
40 | server = ProxyServer(config)
41 | m = MyMaster(opts, server)
42 | m.run()
43 |
--------------------------------------------------------------------------------
/examples/flowfilter.py:
--------------------------------------------------------------------------------
1 | # This scripts demonstrates how to use mitmproxy's filter pattern in scripts.
2 | # Usage: mitmdump -s "flowfilter.py FILTER"
3 |
4 | import sys
5 | from mitmproxy import flowfilter
6 |
7 |
8 | class Filter:
9 | def __init__(self, spec):
10 | self.filter = flowfilter.parse(spec)
11 |
12 | def response(self, flow):
13 | if flowfilter.match(self.filter, flow):
14 | print("Flow matches filter:")
15 | print(flow)
16 |
17 |
18 | def start():
19 | if len(sys.argv) != 2:
20 | raise ValueError("Usage: -s 'filt.py FILTER'")
21 | return Filter(sys.argv[1])
22 |
--------------------------------------------------------------------------------
/examples/flowwriter.py:
--------------------------------------------------------------------------------
1 | import random
2 | import sys
3 | from mitmproxy import io
4 |
5 |
6 | class Writer:
7 | def __init__(self, path):
8 | if path == "-":
9 | f = sys.stdout
10 | else:
11 | f = open(path, "wb")
12 | self.w = io.FlowWriter(f)
13 |
14 | def response(self, flow):
15 | if random.choice([True, False]):
16 | self.w.add(flow)
17 |
18 |
19 | def start():
20 | if len(sys.argv) != 2:
21 | raise ValueError('Usage: -s "flowriter.py filename"')
22 | return Writer(sys.argv[1])
23 |
--------------------------------------------------------------------------------
/examples/iframe_injector.py:
--------------------------------------------------------------------------------
1 | # Usage: mitmdump -s "iframe_injector.py url"
2 | # (this script works best with --anticache)
3 | import sys
4 | from bs4 import BeautifulSoup
5 |
6 |
7 | class Injector:
8 | def __init__(self, iframe_url):
9 | self.iframe_url = iframe_url
10 |
11 | def response(self, flow):
12 | if flow.request.host in self.iframe_url:
13 | return
14 | html = BeautifulSoup(flow.response.content, "lxml")
15 | if html.body:
16 | iframe = html.new_tag(
17 | "iframe",
18 | src=self.iframe_url,
19 | frameborder=0,
20 | height=0,
21 | width=0)
22 | html.body.insert(0, iframe)
23 | flow.response.content = str(html).encode("utf8")
24 |
25 |
26 | def start():
27 | if len(sys.argv) != 2:
28 | raise ValueError('Usage: -s "iframe_injector.py url"')
29 | return Injector(sys.argv[1])
30 |
--------------------------------------------------------------------------------
/examples/logging.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import ctx
2 |
3 |
4 | def start():
5 | ctx.log.info("This is some informative text.")
6 | ctx.log.error("This is an error.")
7 |
--------------------------------------------------------------------------------
/examples/modify_form.py:
--------------------------------------------------------------------------------
1 | def request(flow):
2 | if flow.request.urlencoded_form:
3 | flow.request.urlencoded_form["mitmproxy"] = "rocks"
4 | else:
5 | # This sets the proper content type and overrides the body.
6 | flow.request.urlencoded_form = [
7 | ("foo", "bar")
8 | ]
9 |
--------------------------------------------------------------------------------
/examples/modify_querystring.py:
--------------------------------------------------------------------------------
1 | def request(flow):
2 | flow.request.query["mitmproxy"] = "rocks"
3 |
--------------------------------------------------------------------------------
/examples/nonblocking.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | from mitmproxy.script import concurrent
4 |
5 |
6 | @concurrent # Remove this and see what happens
7 | def request(flow):
8 | # You don't want to use mitmproxy.ctx from a different thread
9 | print("handle request: %s%s" % (flow.request.host, flow.request.path))
10 | time.sleep(5)
11 | print("start request: %s%s" % (flow.request.host, flow.request.path))
12 |
--------------------------------------------------------------------------------
/examples/pathod/libpathod_pathoc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from pathod import pathoc
3 |
4 | p = pathoc.Pathoc(("google.com", 80))
5 | p.connect()
6 | print(p.request("get:/"))
7 | print(p.request("get:/foo"))
8 |
--------------------------------------------------------------------------------
/examples/pathod/test_context.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from pathod import test
3 |
4 |
5 | def test_simple():
6 | """
7 | Testing the requests module with
8 | a pathod context manager.
9 | """
10 | # Start pathod in a separate thread
11 | with test.Daemon() as d:
12 | # Get a URL for a pathod spec
13 | url = d.p("200:b@100")
14 | # ... and request it
15 | r = requests.put(url)
16 |
17 | # Check the returned data
18 | assert r.status_code == 200
19 | assert len(r.content) == 100
20 |
21 | # Check pathod's internal log
22 | log = d.last_log()["request"]
23 | assert log["method"] == "PUT"
24 |
--------------------------------------------------------------------------------
/examples/pathod/test_setup.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from pathod import test
3 |
4 |
5 | class Test:
6 | """
7 | Testing the requests module with
8 | a pathod instance started for
9 | each test.
10 | """
11 |
12 | def setup(self):
13 | self.d = test.Daemon()
14 |
15 | def teardown(self):
16 | self.d.shutdown()
17 |
18 | def test_simple(self):
19 | # Get a URL for a pathod spec
20 | url = self.d.p("200:b@100")
21 | # ... and request it
22 | r = requests.put(url)
23 |
24 | # Check the returned data
25 | assert r.status_code == 200
26 | assert len(r.content) == 100
27 |
28 | # Check pathod's internal log
29 | log = self.d.last_log()["request"]
30 | assert log["method"] == "PUT"
31 |
--------------------------------------------------------------------------------
/examples/pathod/test_setupall.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from pathod import test
3 |
4 |
5 | class Test:
6 | """
7 | Testing the requests module with
8 | a single pathod instance started
9 | for the test suite.
10 | """
11 |
12 | @classmethod
13 | def setup_class(cls):
14 | cls.d = test.Daemon()
15 |
16 | @classmethod
17 | def teardown_class(cls):
18 | cls.d.shutdown()
19 |
20 | def setup(self):
21 | # Clear the pathod logs between tests
22 | self.d.clear_log()
23 |
24 | def test_simple(self):
25 | # Get a URL for a pathod spec
26 | url = self.d.p("200:b@100")
27 | # ... and request it
28 | r = requests.put(url)
29 |
30 | # Check the returned data
31 | assert r.status_code == 200
32 | assert len(r.content) == 100
33 |
34 | # Check pathod's internal log
35 | log = self.d.last_log()["request"]
36 | assert log["method"] == "PUT"
37 |
38 | def test_two(self):
39 | assert not self.d.log()
40 |
--------------------------------------------------------------------------------
/examples/proxapp.py:
--------------------------------------------------------------------------------
1 | """
2 | This example shows how to graft a WSGI app onto mitmproxy. In this
3 | instance, we're using the Flask framework (http://flask.pocoo.org/) to expose
4 | a single simplest-possible page.
5 | """
6 | from flask import Flask
7 | from mitmproxy.addons import wsgiapp
8 |
9 | app = Flask("proxapp")
10 |
11 |
12 | @app.route('/')
13 | def hello_world():
14 | return 'Hello World!'
15 |
16 |
17 | def start():
18 | # Host app at the magic domain "proxapp" on port 80. Requests to this
19 | # domain and port combination will now be routed to the WSGI app instance.
20 | return wsgiapp.WSGIApp(app, "proxapp", 80)
21 |
22 | # SSL works too, but the magic domain needs to be resolvable from the mitmproxy machine due to mitmproxy's design.
23 | # mitmproxy will connect to said domain and use serve its certificate (unless --no-upstream-cert is set)
24 | # but won't send any data.
25 | # mitmproxy.ctx.master.apps.add(app, "example.com", 443)
26 |
--------------------------------------------------------------------------------
/examples/read_dumpfile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Simple script showing how to read a mitmproxy dump file
4 | #
5 |
6 | from mitmproxy import flow
7 | from mitmproxy.exceptions import FlowReadException
8 | import pprint
9 | import sys
10 |
11 | with open(sys.argv[1], "rb") as logfile:
12 | freader = io.FlowReader(logfile)
13 | pp = pprint.PrettyPrinter(indent=4)
14 | try:
15 | for f in freader.stream():
16 | print(f)
17 | print(f.request.host)
18 | pp.pprint(f.get_state())
19 | print("")
20 | except FlowReadException as e:
21 | print("Flow file corrupted: {}".format(e))
22 |
--------------------------------------------------------------------------------
/examples/redirect_requests.py:
--------------------------------------------------------------------------------
1 | """
2 | This example shows two ways to redirect flows to other destinations.
3 | """
4 | from mitmproxy import http
5 |
6 |
7 | def request(flow):
8 | # pretty_host takes the "Host" header of the request into account,
9 | # which is useful in transparent mode where we usually only have the IP
10 | # otherwise.
11 |
12 | # Method 1: Answer with a locally generated response
13 | if flow.request.pretty_host.endswith("example.com"):
14 | flow.response = http.HTTPResponse.make(200, b"Hello World", {"Content-Type": "text/html"})
15 |
16 | # Method 2: Redirect the request to a different server
17 | if flow.request.pretty_host.endswith("example.org"):
18 | flow.request.host = "mitmproxy.org"
19 |
--------------------------------------------------------------------------------
/examples/remote_debug.py:
--------------------------------------------------------------------------------
1 | """
2 | This script enables remote debugging of the mitmproxy *UI* with PyCharm.
3 | For general debugging purposes, it is easier to just debug mitmdump within PyCharm.
4 |
5 | Usage:
6 | - pip install pydevd on the mitmproxy machine
7 | - Open the Run/Debug Configuration dialog box in PyCharm, and select the Python Remote Debug configuration type.
8 | - Debugging works in the way that mitmproxy connects to the debug server on startup.
9 | Specify host and port that mitmproxy can use to reach your PyCharm instance on startup.
10 | - Adjust this inline script accordingly.
11 | - Start debug server in PyCharm
12 | - Set breakpoints
13 | - Start mitmproxy -s remote_debug.py
14 | """
15 |
16 |
17 | def start():
18 | import pydevd
19 | pydevd.settrace("localhost", port=5678, stdoutToServer=True, stderrToServer=True)
20 |
--------------------------------------------------------------------------------
/examples/stream.py:
--------------------------------------------------------------------------------
1 | def responseheaders(flow):
2 | """
3 | Enables streaming for all responses.
4 | """
5 | flow.response.stream = True
6 |
--------------------------------------------------------------------------------
/examples/stream_modify.py:
--------------------------------------------------------------------------------
1 | """
2 | This inline script modifies a streamed response.
3 | If you do not need streaming, see the modify_response_body example.
4 | Be aware that content replacement isn't trivial:
5 | - If the transfer encoding isn't chunked, you cannot simply change the content length.
6 | - If you want to replace all occurences of "foobar", make sure to catch the cases
7 | where one chunk ends with [...]foo" and the next starts with "bar[...].
8 | """
9 |
10 |
11 | def modify(chunks):
12 | """
13 | chunks is a generator that can be used to iterate over all chunks.
14 | """
15 | for chunk in chunks:
16 | yield chunk.replace("foo", "bar")
17 |
18 |
19 | def responseheaders(flow):
20 | flow.response.stream = modify
21 |
--------------------------------------------------------------------------------
/examples/tcp_message.py:
--------------------------------------------------------------------------------
1 | """
2 | tcp_message Inline Script Hook API Demonstration
3 | ------------------------------------------------
4 |
5 | * modifies packets containing "foo" to "bar"
6 | * prints various details for each packet.
7 |
8 | example cmdline invocation:
9 | mitmdump -T --host --tcp ".*" -q -s examples/tcp_message.py
10 | """
11 | from mitmproxy.utils import strutils
12 |
13 |
14 | def tcp_message(tcp_msg):
15 | modified_msg = tcp_msg.message.replace("foo", "bar")
16 |
17 | is_modified = False if modified_msg == tcp_msg.message else True
18 | tcp_msg.message = modified_msg
19 |
20 | print(
21 | "[tcp_message{}] from {} {} to {} {}:\r\n{}".format(
22 | " (modified)" if is_modified else "",
23 | "client" if tcp_msg.sender == tcp_msg.client_conn else "server",
24 | tcp_msg.sender.address,
25 | "server" if tcp_msg.receiver == tcp_msg.server_conn else "client",
26 | tcp_msg.receiver.address, strutils.bytes_to_escaped_str(tcp_msg.message))
27 | )
28 |
--------------------------------------------------------------------------------
/examples/upsidedownternet.py:
--------------------------------------------------------------------------------
1 | import io
2 | from PIL import Image
3 |
4 |
5 | def response(flow):
6 | if flow.response.headers.get("content-type", "").startswith("image"):
7 | try:
8 | s = io.StringIO(flow.response.content)
9 | img = Image.open(s).rotate(180)
10 | s2 = io.StringIO()
11 | img.save(s2, "png")
12 | flow.response.content = s2.getvalue()
13 | flow.response.headers["content-type"] = "image/png"
14 | except: # Unknown image types etc.
15 | pass
16 |
--------------------------------------------------------------------------------
/issue_template.md:
--------------------------------------------------------------------------------
1 | ##### Steps to reproduce the problem:
2 |
3 | 1.
4 | 2.
5 | 3.
6 |
7 |
8 | ##### Any other comments? What have you tried so far?
9 |
10 |
11 |
12 | ##### System information
13 |
14 |
15 |
21 |
--------------------------------------------------------------------------------
/mitmproxy/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/__init__.py
--------------------------------------------------------------------------------
/mitmproxy/addons/__init__.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.addons import anticache
2 | from mitmproxy.addons import anticomp
3 | from mitmproxy.addons import clientplayback
4 | from mitmproxy.addons import filestreamer
5 | from mitmproxy.addons import onboarding
6 | from mitmproxy.addons import replace
7 | from mitmproxy.addons import script
8 | from mitmproxy.addons import setheaders
9 | from mitmproxy.addons import serverplayback
10 | from mitmproxy.addons import stickyauth
11 | from mitmproxy.addons import stickycookie
12 | from mitmproxy.addons import streambodies
13 |
14 |
15 | def default_addons():
16 | return [
17 | onboarding.Onboarding(),
18 | anticache.AntiCache(),
19 | anticomp.AntiComp(),
20 | stickyauth.StickyAuth(),
21 | stickycookie.StickyCookie(),
22 | script.ScriptLoader(),
23 | filestreamer.FileStreamer(),
24 | streambodies.StreamBodies(),
25 | replace.Replace(),
26 | setheaders.SetHeaders(),
27 | serverplayback.ServerPlayback(),
28 | clientplayback.ClientPlayback(),
29 | ]
30 |
--------------------------------------------------------------------------------
/mitmproxy/addons/anticache.py:
--------------------------------------------------------------------------------
1 | class AntiCache:
2 | def __init__(self):
3 | self.enabled = False
4 |
5 | def configure(self, options, updated):
6 | self.enabled = options.anticache
7 |
8 | def request(self, flow):
9 | if self.enabled:
10 | flow.request.anticache()
11 |
--------------------------------------------------------------------------------
/mitmproxy/addons/anticomp.py:
--------------------------------------------------------------------------------
1 | class AntiComp:
2 | def __init__(self):
3 | self.enabled = False
4 |
5 | def configure(self, options, updated):
6 | self.enabled = options.anticomp
7 |
8 | def request(self, flow):
9 | if self.enabled:
10 | flow.request.anticomp()
11 |
--------------------------------------------------------------------------------
/mitmproxy/addons/onboarding.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.addons import wsgiapp
2 | from mitmproxy.addons.onboardingapp import app
3 |
4 |
5 | class Onboarding(wsgiapp.WSGIApp):
6 | def __init__(self):
7 | super().__init__(app.Adapter(app.application), None, None)
8 | self.enabled = False
9 |
10 | def configure(self, options, updated):
11 | self.host = options.app_host
12 | self.port = options.app_port
13 | self.enabled = options.app
14 |
15 | def request(self, f):
16 | if self.enabled:
17 | super().request(f)
18 |
--------------------------------------------------------------------------------
/mitmproxy/addons/onboardingapp/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/addons/onboardingapp/__init__.py
--------------------------------------------------------------------------------
/mitmproxy/addons/onboardingapp/static/fontawesome/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/addons/onboardingapp/static/fontawesome/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/mitmproxy/addons/onboardingapp/static/fontawesome/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/addons/onboardingapp/static/fontawesome/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/mitmproxy/addons/onboardingapp/static/fontawesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/addons/onboardingapp/static/fontawesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/mitmproxy/addons/onboardingapp/static/fontawesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/addons/onboardingapp/static/fontawesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/mitmproxy/addons/onboardingapp/static/mitmproxy.css:
--------------------------------------------------------------------------------
1 |
2 | #certbank div {
3 | text-align: center;
4 |
5 |
6 | }
7 |
8 | .fronttable {
9 | }
10 |
11 | .bigtitle {
12 | font-weight: bold;
13 | font-size: 50px;
14 | line-height: 55px;
15 | text-align: center;
16 | display: table;
17 | height: 300px;
18 | }
19 |
20 | .bigtitle>div {
21 | display: table-cell;
22 | vertical-align: middle;
23 | }
24 |
25 | section {
26 | margin-top: 50px;
27 | }
28 |
29 | .example {
30 | margin-top: 10px;
31 | margin-bottom: 10px;
32 | }
33 |
34 | .innerlink {
35 | text-decoration: none;
36 | border-bottom:1px dotted;
37 | margin-bottom: 15px;
38 | }
39 |
40 | .masthead {
41 | padding: 50px 0 60px;
42 | text-align: center;
43 |
44 | }
45 |
46 | .header {
47 | font-size: 1.5em;
48 | }
49 |
--------------------------------------------------------------------------------
/mitmproxy/addons/onboardingapp/templates/frame.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% block content %}
3 |
4 |
5 | {% block body %}
6 | {% end %}
7 |
8 |
9 | {% end %}
10 |
--------------------------------------------------------------------------------
/mitmproxy/addons/onboardingapp/templates/index.html:
--------------------------------------------------------------------------------
1 | {% extends "frame.html" %}
2 | {% block body %}
3 |
4 |
5 | Click to install the mitmproxy certificate:
6 |
7 |
25 |
26 |
27 |
28 | Other mitmproxy users cannot intercept your connection.
29 |
30 |
31 | This page is served by your local mitmproxy instance. The certificate you are about to install has been uniquely generated on mitmproxy's first run and is not shared
32 | between mitmproxy installations.
33 |
34 |
35 | {% end %}
36 |
--------------------------------------------------------------------------------
/mitmproxy/addons/onboardingapp/templates/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | mitmproxy
12 |
13 |
14 |
15 |
16 |
17 |
18 |
25 |
26 |
27 | {% block content %}
28 | {% end %}
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/mitmproxy/addons/stickyauth.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import exceptions
2 | from mitmproxy import flowfilter
3 |
4 |
5 | class StickyAuth:
6 | def __init__(self):
7 | self.flt = None
8 | self.hosts = {}
9 |
10 | def configure(self, options, updated):
11 | if options.stickyauth:
12 | flt = flowfilter.parse(options.stickyauth)
13 | if not flt:
14 | raise exceptions.OptionsError(
15 | "stickyauth: invalid filter expression: %s" % options.stickyauth
16 | )
17 | self.flt = flt
18 |
19 | def request(self, flow):
20 | host = flow.request.host
21 | if "authorization" in flow.request.headers:
22 | self.hosts[host] = flow.request.headers["authorization"]
23 | elif flowfilter.match(self.flt, flow):
24 | if host in self.hosts:
25 | flow.request.headers["authorization"] = self.hosts[host]
26 |
--------------------------------------------------------------------------------
/mitmproxy/addons/termlog.py:
--------------------------------------------------------------------------------
1 | import click
2 |
3 | from mitmproxy import log
4 |
5 |
6 | class TermLog:
7 | def __init__(self):
8 | self.options = None
9 |
10 | def configure(self, options, updated):
11 | self.options = options
12 |
13 | def log(self, e):
14 | if self.options.verbosity >= log.log_tier(e.level):
15 | click.secho(
16 | e.msg,
17 | file=self.options.tfile,
18 | fg=dict(error="red", warn="yellow").get(e.level),
19 | dim=(e.level == "debug"),
20 | err=(e.level == "error")
21 | )
22 |
--------------------------------------------------------------------------------
/mitmproxy/addons/wsgiapp.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import ctx
2 | from mitmproxy import exceptions
3 |
4 | from mitmproxy.net import wsgi
5 | from mitmproxy import version
6 |
7 |
8 | class WSGIApp:
9 | """
10 | An addon that hosts a WSGI app withing mitproxy, at a specified
11 | hostname and port.
12 | """
13 | def __init__(self, app, host, port):
14 | self.app, self.host, self.port = app, host, port
15 |
16 | def serve(self, app, flow):
17 | """
18 | Serves app on flow, and prevents further handling of the flow.
19 | """
20 | app = wsgi.WSGIAdaptor(
21 | app,
22 | flow.request.pretty_host,
23 | flow.request.port,
24 | version.MITMPROXY
25 | )
26 | err = app.serve(
27 | flow,
28 | flow.client_conn.wfile,
29 | **{"mitmproxy.master": ctx.master}
30 | )
31 | if err:
32 | ctx.log.error("Error in wsgi app. %s" % err)
33 | flow.reply.kill()
34 | raise exceptions.AddonHalt()
35 |
36 | def request(self, f):
37 | if (f.request.pretty_host, f.request.port) == (self.host, self.port):
38 | self.serve(self.app, f)
39 |
--------------------------------------------------------------------------------
/mitmproxy/contrib/README:
--------------------------------------------------------------------------------
1 |
2 | Contribs:
3 |
4 | jsbeautifier, git checkout 25/03/12, MIT license
5 | - Removed test directories
6 | - Disabled packers through a single-line modification (see "# CORTESI"
7 | comment)
8 |
9 | wbxml
10 | - https://github.com/davidpshaw/PyWBXMLDecoder
11 |
12 | tls, BSD license
13 | - https://github.com/mhils/tls/tree/mitmproxy
14 | - limited to required files.
--------------------------------------------------------------------------------
/mitmproxy/contrib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/contrib/__init__.py
--------------------------------------------------------------------------------
/mitmproxy/contrib/tls/__init__.py:
--------------------------------------------------------------------------------
1 | # This file is dual licensed under the terms of the Apache License, Version
2 | # 2.0, and the BSD License. See the LICENSE file in the root of this repository
3 | # for complete details.
4 |
5 |
--------------------------------------------------------------------------------
/mitmproxy/contrib/tls/utils.py:
--------------------------------------------------------------------------------
1 | # This file is dual licensed under the terms of the Apache License, Version
2 | # 2.0, and the BSD License. See the LICENSE file in the root of this repository
3 | # for complete details.
4 |
5 |
6 | import construct
7 |
8 | class _UBInt24(construct.Adapter):
9 | def _encode(self, obj, context):
10 | return bytes(
11 | (obj & 0xFF0000) >> 16,
12 | (obj & 0x00FF00) >> 8,
13 | obj & 0x0000FF
14 | )
15 |
16 | def _decode(self, obj, context):
17 | obj = bytearray(obj)
18 | return (obj[0] << 16 | obj[1] << 8 | obj[2])
19 |
20 |
21 | def UBInt24(name): # noqa
22 | return _UBInt24(construct.Bytes(name, 3))
23 |
--------------------------------------------------------------------------------
/mitmproxy/contrib/wbxml/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/contrib/wbxml/__init__.py
--------------------------------------------------------------------------------
/mitmproxy/ctx.py:
--------------------------------------------------------------------------------
1 | master = None # type: "mitmproxy.master.Master"
2 | log = None # type: "mitmproxy.log.Log"
3 |
--------------------------------------------------------------------------------
/mitmproxy/log.py:
--------------------------------------------------------------------------------
1 |
2 | class LogEntry:
3 | def __init__(self, msg, level):
4 | self.msg = msg
5 | self.level = level
6 |
7 |
8 | class Log:
9 | """
10 | The central logger, exposed to scripts as mitmproxy.ctx.log.
11 | """
12 | def __init__(self, master):
13 | self.master = master
14 |
15 | def debug(self, txt):
16 | """
17 | Log with level debug.
18 | """
19 | self(txt, "debug")
20 |
21 | def info(self, txt):
22 | """
23 | Log with level info.
24 | """
25 | self(txt, "info")
26 |
27 | def warn(self, txt):
28 | """
29 | Log with level warn.
30 | """
31 | self(txt, "warn")
32 |
33 | def error(self, txt):
34 | """
35 | Log with level error.
36 | """
37 | self(txt, "error")
38 |
39 | def __call__(self, text, level="info"):
40 | self.master.add_log(text, level)
41 |
42 |
43 | def log_tier(level):
44 | return dict(error=0, warn=1, info=2, debug=3).get(level)
45 |
--------------------------------------------------------------------------------
/mitmproxy/net/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/net/__init__.py
--------------------------------------------------------------------------------
/mitmproxy/net/check.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | _label_valid = re.compile(b"(?!-)[A-Z\d-]{1,63}(? bool:
7 | """
8 | Checks if a hostname is valid.
9 | """
10 | try:
11 | host.decode("idna")
12 | except ValueError:
13 | return False
14 | if len(host) > 255:
15 | return False
16 | if host and host[-1:] == b".":
17 | host = host[:-1]
18 | return all(_label_valid.match(x) for x in host.split(b"."))
19 |
20 |
21 | def is_valid_port(port):
22 | return 0 <= port <= 65535
23 |
--------------------------------------------------------------------------------
/mitmproxy/net/http/__init__.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.net.http.request import Request
2 | from mitmproxy.net.http.response import Response
3 | from mitmproxy.net.http.message import Message
4 | from mitmproxy.net.http.headers import Headers, parse_content_type
5 | from mitmproxy.net.http.message import decoded
6 | from mitmproxy.net.http import http1, http2, status_codes, multipart
7 |
8 | __all__ = [
9 | "Request",
10 | "Response",
11 | "Message",
12 | "Headers", "parse_content_type",
13 | "decoded",
14 | "http1", "http2", "status_codes", "multipart",
15 | ]
16 |
--------------------------------------------------------------------------------
/mitmproxy/net/http/http1/__init__.py:
--------------------------------------------------------------------------------
1 | from .read import (
2 | read_request, read_request_head,
3 | read_response, read_response_head,
4 | read_body,
5 | connection_close,
6 | expected_http_body_size,
7 | )
8 | from .assemble import (
9 | assemble_request, assemble_request_head,
10 | assemble_response, assemble_response_head,
11 | assemble_body,
12 | )
13 |
14 |
15 | __all__ = [
16 | "read_request", "read_request_head",
17 | "read_response", "read_response_head",
18 | "read_body",
19 | "connection_close",
20 | "expected_http_body_size",
21 | "assemble_request", "assemble_request_head",
22 | "assemble_response", "assemble_response_head",
23 | "assemble_body",
24 | ]
25 |
--------------------------------------------------------------------------------
/mitmproxy/net/http/http2/__init__.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.net.http.http2.framereader import read_raw_frame, parse_frame
2 | from mitmproxy.net.http.http2.utils import parse_headers
3 |
4 | __all__ = [
5 | "read_raw_frame",
6 | "parse_frame",
7 | "parse_headers",
8 | ]
9 |
--------------------------------------------------------------------------------
/mitmproxy/net/http/http2/framereader.py:
--------------------------------------------------------------------------------
1 | import codecs
2 |
3 | import hyperframe
4 | from mitmproxy import exceptions
5 |
6 |
7 | def read_raw_frame(rfile):
8 | header = rfile.safe_read(9)
9 | length = int(codecs.encode(header[:3], 'hex_codec'), 16)
10 |
11 | if length == 4740180:
12 | raise exceptions.HttpException("Length field looks more like HTTP/1.1:\n{}".format(rfile.read(-1)))
13 |
14 | body = rfile.safe_read(length)
15 | return [header, body]
16 |
17 |
18 | def parse_frame(header, body=None):
19 | if body is None:
20 | body = header[9:]
21 | header = header[:9]
22 |
23 | frame, length = hyperframe.frame.Frame.parse_frame_header(header)
24 | frame.parse_body(memoryview(body))
25 | return frame
26 |
--------------------------------------------------------------------------------
/mitmproxy/net/http/http2/utils.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.net.http import url
2 |
3 |
4 | def parse_headers(headers):
5 | authority = headers.get(':authority', '').encode()
6 | method = headers.get(':method', 'GET').encode()
7 | scheme = headers.get(':scheme', 'https').encode()
8 | path = headers.get(':path', '/').encode()
9 |
10 | headers.pop(":method", None)
11 | headers.pop(":scheme", None)
12 | headers.pop(":path", None)
13 |
14 | host = None
15 | port = None
16 |
17 | if path == b'*' or path.startswith(b"/"):
18 | first_line_format = "relative"
19 | elif method == b'CONNECT': # pragma: no cover
20 | raise NotImplementedError("CONNECT over HTTP/2 is not implemented.")
21 | else: # pragma: no cover
22 | first_line_format = "absolute"
23 | # FIXME: verify if path or :host contains what we need
24 | scheme, host, port, _ = url.parse(path)
25 |
26 | if authority:
27 | host, _, port = authority.partition(b':')
28 |
29 | if not host:
30 | host = b'localhost'
31 |
32 | if not port:
33 | port = 443 if scheme == b'https' else 80
34 |
35 | port = int(port)
36 |
37 | return first_line_format, method, scheme, host, port, path
38 |
--------------------------------------------------------------------------------
/mitmproxy/net/http/multipart.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from mitmproxy.net.http import headers
4 |
5 |
6 | def decode(hdrs, content):
7 | """
8 | Takes a multipart boundary encoded string and returns list of (key, value) tuples.
9 | """
10 | v = hdrs.get("content-type")
11 | if v:
12 | v = headers.parse_content_type(v)
13 | if not v:
14 | return []
15 | try:
16 | boundary = v[2]["boundary"].encode("ascii")
17 | except (KeyError, UnicodeError):
18 | return []
19 |
20 | rx = re.compile(br'\bname="([^"]+)"')
21 | r = []
22 |
23 | for i in content.split(b"--" + boundary):
24 | parts = i.splitlines()
25 | if len(parts) > 1 and parts[0][0:2] != b"--":
26 | match = rx.search(parts[1])
27 | if match:
28 | key = match.group(1)
29 | value = b"".join(parts[3 + parts[2:].index(b""):])
30 | r.append((key, value))
31 | return r
32 | return []
33 |
--------------------------------------------------------------------------------
/mitmproxy/net/websockets/__init__.py:
--------------------------------------------------------------------------------
1 | from .frame import FrameHeader
2 | from .frame import Frame
3 | from .frame import OPCODE
4 | from .frame import CLOSE_REASON
5 | from .masker import Masker
6 | from .utils import MAGIC
7 | from .utils import VERSION
8 | from .utils import client_handshake_headers
9 | from .utils import server_handshake_headers
10 | from .utils import check_handshake
11 | from .utils import check_client_version
12 | from .utils import create_server_nonce
13 | from .utils import get_extensions
14 | from .utils import get_protocol
15 | from .utils import get_client_key
16 | from .utils import get_server_accept
17 |
18 | __all__ = [
19 | "FrameHeader",
20 | "Frame",
21 | "OPCODE",
22 | "CLOSE_REASON",
23 | "Masker",
24 | "MAGIC",
25 | "VERSION",
26 | "client_handshake_headers",
27 | "server_handshake_headers",
28 | "check_handshake",
29 | "check_client_version",
30 | "create_server_nonce",
31 | "get_extensions",
32 | "get_protocol",
33 | "get_client_key",
34 | "get_server_accept",
35 | ]
36 |
--------------------------------------------------------------------------------
/mitmproxy/net/websockets/masker.py:
--------------------------------------------------------------------------------
1 | class Masker:
2 | """
3 | Data sent from the server must be masked to prevent malicious clients
4 | from sending data over the wire in predictable patterns.
5 |
6 | Servers do not have to mask data they send to the client.
7 | https://tools.ietf.org/html/rfc6455#section-5.3
8 | """
9 |
10 | def __init__(self, key):
11 | self.key = key
12 | self.offset = 0
13 |
14 | def mask(self, offset, data):
15 | result = bytearray(data)
16 | for i in range(len(data)):
17 | result[i] ^= self.key[offset % 4]
18 | offset += 1
19 | result = bytes(result)
20 | return result
21 |
22 | def __call__(self, data):
23 | ret = self.mask(self.offset, data)
24 | self.offset += len(ret)
25 | return ret
26 |
--------------------------------------------------------------------------------
/mitmproxy/platform/__init__.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import re
3 |
4 | resolver = None
5 |
6 | if re.match(r"linux(?:2)?", sys.platform):
7 | from . import linux
8 | resolver = linux.Resolver
9 | elif sys.platform == "darwin":
10 | from . import osx
11 | resolver = osx.Resolver
12 | elif sys.platform.startswith("freebsd"):
13 | from . import osx
14 | resolver = osx.Resolver
15 | elif sys.platform == "win32":
16 | from . import windows
17 | resolver = windows.Resolver
18 |
--------------------------------------------------------------------------------
/mitmproxy/platform/linux.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import struct
3 |
4 | # Python socket module does not have this constant
5 | SO_ORIGINAL_DST = 80
6 |
7 |
8 | class Resolver:
9 |
10 | def original_addr(self, csock):
11 | odestdata = csock.getsockopt(socket.SOL_IP, SO_ORIGINAL_DST, 16)
12 | _, port, a1, a2, a3, a4 = struct.unpack("!HHBBBBxxxxxxxx", odestdata)
13 | address = "%d.%d.%d.%d" % (a1, a2, a3, a4)
14 | return address, port
15 |
--------------------------------------------------------------------------------
/mitmproxy/platform/pf.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 |
4 | def lookup(address, port, s):
5 | """
6 | Parse the pfctl state output s, to look up the destination host
7 | matching the client (address, port).
8 |
9 | Returns an (address, port) tuple, or None.
10 | """
11 | s = s.decode()
12 | spec = "%s:%s" % (address, port)
13 | for i in s.split("\n"):
14 | if "ESTABLISHED:ESTABLISHED" in i and spec in i:
15 | s = i.split()
16 | if len(s) > 4:
17 | if sys.platform.startswith("freebsd"):
18 | # strip parentheses for FreeBSD pfctl
19 | s = s[3][1:-1].split(":")
20 | else:
21 | s = s[4].split(":")
22 |
23 | if len(s) == 2:
24 | return s[0], int(s[1])
25 | raise RuntimeError("Could not resolve original destination.")
26 |
--------------------------------------------------------------------------------
/mitmproxy/proxy/__init__.py:
--------------------------------------------------------------------------------
1 | from .config import ProxyConfig
2 | from .root_context import RootContext
3 | from .server import ProxyServer, DummyServer
4 |
5 | __all__ = [
6 | "ProxyServer", "DummyServer",
7 | "ProxyConfig",
8 | "RootContext"
9 | ]
10 |
--------------------------------------------------------------------------------
/mitmproxy/proxy/modes/__init__.py:
--------------------------------------------------------------------------------
1 | from .http_proxy import HttpProxy, HttpUpstreamProxy
2 | from .reverse_proxy import ReverseProxy
3 | from .socks_proxy import Socks5Proxy
4 | from .transparent_proxy import TransparentProxy
5 |
6 | __all__ = [
7 | "HttpProxy", "HttpUpstreamProxy",
8 | "ReverseProxy",
9 | "Socks5Proxy",
10 | "TransparentProxy"
11 | ]
12 |
--------------------------------------------------------------------------------
/mitmproxy/proxy/modes/http_proxy.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.proxy import protocol
2 |
3 |
4 | class HttpProxy(protocol.Layer, protocol.ServerConnectionMixin):
5 |
6 | def __call__(self):
7 | layer = self.ctx.next_layer(self)
8 | try:
9 | layer()
10 | finally:
11 | if self.server_conn:
12 | self.disconnect()
13 |
14 |
15 | class HttpUpstreamProxy(protocol.Layer, protocol.ServerConnectionMixin):
16 |
17 | def __init__(self, ctx, server_address):
18 | super().__init__(ctx, server_address=server_address)
19 |
20 | def __call__(self):
21 | layer = self.ctx.next_layer(self)
22 | try:
23 | layer()
24 | finally:
25 | if self.server_conn:
26 | self.disconnect()
27 |
--------------------------------------------------------------------------------
/mitmproxy/proxy/modes/reverse_proxy.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.proxy import protocol
2 |
3 |
4 | class ReverseProxy(protocol.Layer, protocol.ServerConnectionMixin):
5 |
6 | def __init__(self, ctx, server_address, server_tls):
7 | super().__init__(ctx, server_address=server_address)
8 | self.server_tls = server_tls
9 |
10 | def __call__(self):
11 | layer = self.ctx.next_layer(self)
12 | try:
13 | layer()
14 | finally:
15 | if self.server_conn:
16 | self.disconnect()
17 |
--------------------------------------------------------------------------------
/mitmproxy/proxy/modes/transparent_proxy.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import exceptions
2 | from mitmproxy import platform
3 | from mitmproxy.proxy import protocol
4 |
5 |
6 | class TransparentProxy(protocol.Layer, protocol.ServerConnectionMixin):
7 |
8 | def __init__(self, ctx):
9 | super().__init__(ctx)
10 | self.resolver = platform.resolver()
11 |
12 | def __call__(self):
13 | try:
14 | self.server_conn.address = self.resolver.original_addr(self.client_conn.connection)
15 | except Exception as e:
16 | raise exceptions.ProtocolException("Transparent mode failure: %s" % repr(e))
17 |
18 | layer = self.ctx.next_layer(self)
19 | try:
20 | layer()
21 | finally:
22 | if self.server_conn:
23 | self.disconnect()
24 |
--------------------------------------------------------------------------------
/mitmproxy/script/__init__.py:
--------------------------------------------------------------------------------
1 | from .concurrent import concurrent
2 |
3 | __all__ = [
4 | "concurrent",
5 | ]
6 |
--------------------------------------------------------------------------------
/mitmproxy/script/concurrent.py:
--------------------------------------------------------------------------------
1 | """
2 | This module provides a @concurrent decorator primitive to
3 | offload computations from mitmproxy's main master thread.
4 | """
5 |
6 | from mitmproxy import events
7 | from mitmproxy.types import basethread
8 |
9 |
10 | class ScriptThread(basethread.BaseThread):
11 | name = "ScriptThread"
12 |
13 |
14 | def concurrent(fn):
15 | if fn.__name__ not in events.Events - {"start", "configure", "tick"}:
16 | raise NotImplementedError(
17 | "Concurrent decorator not supported for '%s' method." % fn.__name__
18 | )
19 |
20 | def _concurrent(obj):
21 | def run():
22 | fn(obj)
23 | if obj.reply.state == "taken":
24 | if not obj.reply.has_message:
25 | obj.reply.ack()
26 | obj.reply.commit()
27 | obj.reply.take()
28 | ScriptThread(
29 | "script.concurrent (%s)" % fn.__name__,
30 | target=run
31 | ).start()
32 | return _concurrent
33 |
--------------------------------------------------------------------------------
/mitmproxy/tools/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/__init__.py
--------------------------------------------------------------------------------
/mitmproxy/tools/console/__init__.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.tools.console import master
2 |
3 |
4 | __all__ = ["master"]
5 |
--------------------------------------------------------------------------------
/mitmproxy/tools/console/grideditor/__init__.py:
--------------------------------------------------------------------------------
1 | from .editors import * # noqa
2 | from . import base # noqa
3 |
--------------------------------------------------------------------------------
/mitmproxy/tools/console/signals.py:
--------------------------------------------------------------------------------
1 | import blinker
2 |
3 | # Show a status message in the action bar
4 | sig_add_log = blinker.Signal()
5 |
6 |
7 | def add_log(e, level):
8 | sig_add_log.send(
9 | None,
10 | e=e,
11 | level=level
12 | )
13 |
14 | # Show a status message in the action bar
15 | status_message = blinker.Signal()
16 |
17 | # Prompt for input
18 | status_prompt = blinker.Signal()
19 |
20 | # Prompt for a path
21 | status_prompt_path = blinker.Signal()
22 |
23 | # Prompt for a single keystroke
24 | status_prompt_onekey = blinker.Signal()
25 |
26 | # Call a callback in N seconds
27 | call_in = blinker.Signal()
28 |
29 | # Focus the body, footer or header of the main window
30 | focus = blinker.Signal()
31 |
32 | # Fired when settings change
33 | update_settings = blinker.Signal()
34 |
35 | # Fired when a flow changes
36 | flow_change = blinker.Signal()
37 |
38 | # Fired when the flow list or focus changes
39 | flowlist_change = blinker.Signal()
40 |
41 | # Pop and push view state onto a stack
42 | pop_view_state = blinker.Signal()
43 | push_view_state = blinker.Signal()
44 | replace_view_state = blinker.Signal()
45 |
--------------------------------------------------------------------------------
/mitmproxy/tools/web/__init__.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.tools.web import master
2 | __all__ = ["master"]
3 |
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/chrome-devtools/resourceCSSIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/chrome-devtools/resourceCSSIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/chrome-devtools/resourceDocumentIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/chrome-devtools/resourceDocumentIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/chrome-devtools/resourceJSIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/chrome-devtools/resourceJSIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/chrome-devtools/resourcePlainIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/chrome-devtools/resourcePlainIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/favicon.ico
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/resourceExecutableIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/resourceExecutableIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/resourceFlashIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/resourceFlashIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/resourceImageIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/resourceImageIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/resourceJavaIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/resourceJavaIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/resourceNotModifiedIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/resourceNotModifiedIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/static/images/resourceRedirectIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/tools/web/static/images/resourceRedirectIcon.png
--------------------------------------------------------------------------------
/mitmproxy/tools/web/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | mitmproxy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/mitmproxy/types/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/types/__init__.py
--------------------------------------------------------------------------------
/mitmproxy/types/basethread.py:
--------------------------------------------------------------------------------
1 | import time
2 | import threading
3 |
4 |
5 | class BaseThread(threading.Thread):
6 | def __init__(self, name, *args, **kwargs):
7 | super().__init__(name=name, *args, **kwargs)
8 | self._thread_started = time.time()
9 |
10 | def _threadinfo(self):
11 | return "%s - age: %is" % (
12 | self.name,
13 | int(time.time() - self._thread_started)
14 | )
15 |
--------------------------------------------------------------------------------
/mitmproxy/types/bidi.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class BiDi:
4 |
5 | """
6 | A wee utility class for keeping bi-directional mappings, like field
7 | constants in protocols. Names are attributes on the object, dict-like
8 | access maps values to names:
9 |
10 | CONST = BiDi(a=1, b=2)
11 | assert CONST.a == 1
12 | assert CONST.get_name(1) == "a"
13 | """
14 |
15 | def __init__(self, **kwargs):
16 | self.names = kwargs
17 | self.values = {}
18 | for k, v in kwargs.items():
19 | self.values[v] = k
20 | if len(self.names) != len(self.values):
21 | raise ValueError("Duplicate values not allowed.")
22 |
23 | def __getattr__(self, k):
24 | if k in self.names:
25 | return self.names[k]
26 | raise AttributeError("No such attribute: %s", k)
27 |
28 | def get_name(self, n, default=None):
29 | return self.values.get(n, default)
30 |
--------------------------------------------------------------------------------
/mitmproxy/types/serializable.py:
--------------------------------------------------------------------------------
1 | import abc
2 |
3 |
4 | class Serializable(metaclass=abc.ABCMeta):
5 | """
6 | Abstract Base Class that defines an API to save an object's state and restore it later on.
7 | """
8 |
9 | @classmethod
10 | @abc.abstractmethod
11 | def from_state(cls, state):
12 | """
13 | Create a new object from the given state.
14 | """
15 | raise NotImplementedError()
16 |
17 | @abc.abstractmethod
18 | def get_state(self):
19 | """
20 | Retrieve object state.
21 | """
22 | raise NotImplementedError()
23 |
24 | @abc.abstractmethod
25 | def set_state(self, state):
26 | """
27 | Set object state to the given state.
28 | """
29 | raise NotImplementedError()
30 |
31 | def copy(self):
32 | return self.from_state(self.get_state())
33 |
--------------------------------------------------------------------------------
/mitmproxy/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/mitmproxy/utils/__init__.py
--------------------------------------------------------------------------------
/mitmproxy/utils/bits.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | def setbit(byte, offset, value):
4 | """
5 | Set a bit in a byte to 1 if value is truthy, 0 if not.
6 | """
7 | if value:
8 | return byte | (1 << offset)
9 | else:
10 | return byte & ~(1 << offset)
11 |
12 |
13 | def getbit(byte, offset):
14 | mask = 1 << offset
15 | return bool(byte & mask)
16 |
--------------------------------------------------------------------------------
/mitmproxy/utils/data.py:
--------------------------------------------------------------------------------
1 | import os.path
2 | import importlib
3 | import inspect
4 |
5 |
6 | class Data:
7 |
8 | def __init__(self, name):
9 | m = importlib.import_module(name)
10 | dirname = os.path.dirname(inspect.getsourcefile(m))
11 | self.dirname = os.path.abspath(dirname)
12 |
13 | def push(self, subpath):
14 | """
15 | Change the data object to a path relative to the module.
16 | """
17 | self.dirname = os.path.join(self.dirname, subpath)
18 | return self
19 |
20 | def path(self, path):
21 | """
22 | Returns a path to the package data housed at 'path' under this
23 | module.Path can be a path to a file, or to a directory.
24 |
25 | This function will raise ValueError if the path does not exist.
26 | """
27 | fullpath = os.path.join(self.dirname, path)
28 | if not os.path.exists(fullpath):
29 | raise ValueError("dataPath: %s does not exist." % fullpath)
30 | return fullpath
31 |
32 |
33 | pkg_data = Data(__name__).push("..")
34 |
--------------------------------------------------------------------------------
/mitmproxy/version.py:
--------------------------------------------------------------------------------
1 | IVERSION = (0, 19)
2 | VERSION = ".".join(str(i) for i in IVERSION)
3 | PATHOD = "pathod " + VERSION
4 | MITMPROXY = "mitmproxy " + VERSION
5 |
--------------------------------------------------------------------------------
/pathod/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/pathod/__init__.py
--------------------------------------------------------------------------------
/pathod/language/exceptions.py:
--------------------------------------------------------------------------------
1 | class RenderError(Exception):
2 | pass
3 |
4 |
5 | class FileAccessDenied(RenderError):
6 | pass
7 |
8 |
9 | class ParseException(Exception):
10 |
11 | def __init__(self, msg, s, col):
12 | Exception.__init__(self)
13 | self.msg = msg
14 | self.s = s
15 | self.col = col
16 |
17 | def marked(self):
18 | return "%s\n%s" % (self.s, " " * (self.col - 1) + "^")
19 |
20 | def __str__(self):
21 | return "%s at char %s" % (self.msg, self.col)
22 |
--------------------------------------------------------------------------------
/pathod/protocols/__init__.py:
--------------------------------------------------------------------------------
1 | from . import http, http2, websockets
2 |
3 | __all__ = [
4 | "http",
5 | "http2",
6 | "websockets",
7 | ]
8 |
--------------------------------------------------------------------------------
/pathod/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | from mitmproxy.utils import data as mdata
4 |
5 |
6 | class MemBool:
7 |
8 | """
9 | Truth-checking with a memory, for use in chained if statements.
10 | """
11 |
12 | def __init__(self):
13 | self.v = None
14 |
15 | def __call__(self, v):
16 | self.v = v
17 | return bool(v)
18 |
19 |
20 | # FIXME: change this name
21 | data = mdata.Data(__name__)
22 |
23 |
24 | def daemonize(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): # pragma: no cover
25 | try:
26 | pid = os.fork()
27 | if pid > 0:
28 | sys.exit(0)
29 | except OSError as e:
30 | sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
31 | sys.exit(1)
32 | os.chdir("/")
33 | os.umask(0)
34 | os.setsid()
35 | try:
36 | pid = os.fork()
37 | if pid > 0:
38 | sys.exit(0)
39 | except OSError as e:
40 | sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
41 | sys.exit(1)
42 | si = open(stdin, 'rb')
43 | so = open(stdout, 'a+b')
44 | se = open(stderr, 'a+b', 0)
45 | os.dup2(si.fileno(), sys.stdin.fileno())
46 | os.dup2(so.fileno(), sys.stdout.fileno())
47 | os.dup2(se.fileno(), sys.stderr.fileno())
48 |
--------------------------------------------------------------------------------
/release/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /dist
3 |
--------------------------------------------------------------------------------
/release/README.md:
--------------------------------------------------------------------------------
1 | # Release Checklist
2 |
3 | - Verify that all CI tests pass for current master
4 | - Tag the release, and push to Github
5 | - Wait for tag CI to complete
6 | - Download assets from snapshots.mitmproxy.org
7 | - Create release notice on Github
8 | - Upload wheel to pypi
9 |
--------------------------------------------------------------------------------
/release/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | setup(
4 | name='mitmproxy-rtool',
5 | version="1.0",
6 | py_modules=["rtool"],
7 | install_requires=[
8 | "click>=6.2, <7.0",
9 | "twine>=1.6.5, <1.8",
10 | "virtualenv>=14.0.5, <15.1",
11 | "wheel>=0.29.0, <0.30",
12 | "pysftp>=0.2.8, !=0.2.9, <0.3",
13 | ],
14 | entry_points={
15 | "console_scripts": [
16 | "rtool=rtool:cli",
17 | ],
18 | },
19 | )
20 |
--------------------------------------------------------------------------------
/release/specs/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/release/specs/icon.ico
--------------------------------------------------------------------------------
/release/specs/mitmdump:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from mitmproxy.tools.main import mitmdump
3 | mitmdump()
4 |
--------------------------------------------------------------------------------
/release/specs/mitmdump.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | from PyInstaller.utils.hooks import collect_data_files
4 |
5 | a = Analysis(['mitmdump'],
6 | binaries=None,
7 | datas=collect_data_files("mitmproxy.addons.onboardingapp"),
8 | hiddenimports=[],
9 | hookspath=None,
10 | runtime_hooks=None,
11 | excludes=None)
12 | pyz = PYZ(a.pure, a.zipped_data)
13 | exe = EXE(pyz,
14 | a.scripts,
15 | a.binaries,
16 | a.zipfiles,
17 | a.datas,
18 | name='mitmdump',
19 | debug=False,
20 | strip=None,
21 | upx=True,
22 | console=True,
23 | icon='icon.ico' )
24 |
--------------------------------------------------------------------------------
/release/specs/mitmproxy:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from mitmproxy.tools.main import mitmproxy
3 | mitmproxy()
4 |
--------------------------------------------------------------------------------
/release/specs/mitmproxy.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | from PyInstaller.utils.hooks import collect_data_files
4 |
5 | a = Analysis(['mitmproxy'],
6 | binaries=None,
7 | datas=collect_data_files("mitmproxy.addons.onboardingapp"),
8 | hiddenimports=[],
9 | hookspath=None,
10 | runtime_hooks=None,
11 | excludes=None)
12 | pyz = PYZ(a.pure, a.zipped_data)
13 | exe = EXE(pyz,
14 | a.scripts,
15 | a.binaries,
16 | a.zipfiles,
17 | a.datas,
18 | name='mitmproxy',
19 | debug=False,
20 | strip=None,
21 | upx=True,
22 | console=True,
23 | icon='icon.ico' )
24 |
--------------------------------------------------------------------------------
/release/specs/mitmweb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from mitmproxy.tools.main import mitmweb
3 |
4 | mitmweb()
5 |
--------------------------------------------------------------------------------
/release/specs/mitmweb.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | from PyInstaller.utils.hooks import collect_data_files
4 |
5 | a = Analysis(['mitmweb'],
6 | binaries=None,
7 | datas=collect_data_files("mitmproxy"),
8 | hiddenimports=[],
9 | hookspath=None,
10 | runtime_hooks=None,
11 | excludes=None)
12 | pyz = PYZ(a.pure, a.zipped_data)
13 | exe = EXE(pyz,
14 | a.scripts,
15 | a.binaries,
16 | a.zipfiles,
17 | a.datas,
18 | name='mitmweb',
19 | debug=False,
20 | strip=None,
21 | upx=True,
22 | console=True,
23 | icon='icon.ico' )
24 |
--------------------------------------------------------------------------------
/release/specs/pathoc:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from pathod import pathoc_cmdline as cmdline
4 |
5 | if __name__ == "__main__":
6 | cmdline.go_pathoc()
7 |
--------------------------------------------------------------------------------
/release/specs/pathoc.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | from PyInstaller.utils.hooks import collect_data_files
4 |
5 | a = Analysis(['pathoc'],
6 | binaries=None,
7 | datas=None,
8 | hiddenimports=['_cffi_backend'],
9 | hookspath=None,
10 | runtime_hooks=None,
11 | excludes=None)
12 | pyz = PYZ(a.pure, a.zipped_data)
13 | exe = EXE(pyz,
14 | a.scripts,
15 | a.binaries,
16 | a.zipfiles,
17 | a.datas,
18 | name='pathoc',
19 | debug=False,
20 | strip=None,
21 | upx=True,
22 | console=True,
23 | icon='icon.ico' )
24 |
--------------------------------------------------------------------------------
/release/specs/pathod:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from pathod import pathod_cmdline as cmdline
4 |
5 | if __name__ == "__main__":
6 | cmdline.go_pathod()
7 |
--------------------------------------------------------------------------------
/release/specs/pathod.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | from PyInstaller.utils.hooks import collect_data_files
4 |
5 | a = Analysis(['pathod'],
6 | binaries=None,
7 | datas=collect_data_files("pathod"),
8 | hiddenimports=['_cffi_backend'],
9 | hookspath=None,
10 | runtime_hooks=None,
11 | excludes=None)
12 | pyz = PYZ(a.pure, a.zipped_data)
13 | exe = EXE(pyz,
14 | a.scripts,
15 | a.binaries,
16 | a.zipfiles,
17 | a.datas,
18 | name='pathod',
19 | debug=False,
20 | strip=None,
21 | upx=True,
22 | console=True,
23 | icon='icon.ico' )
24 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | https://snapshots.mitmproxy.org/misc/lxml-3.6.0-cp35-cp35m-win32.whl; sys_platform == 'win32' and python_version == '3.5'
2 | -e .[dev,examples,contentviews]
3 | -e ./release
4 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 140
3 | max-complexity = 25
4 | ignore = E251,C901,W503
5 | exclude = mitmproxy/contrib/*,test/mitmproxy/data/*
6 | addons = file,open,basestring,xrange,unicode,long,cmp
7 |
8 | [tool:pytest]
9 | testpaths = test
10 | addopts = --capture=no --color=yes
11 |
12 | [coverage:run]
13 | branch = True
14 | omit = *contrib*, *tnetstring*, *platform*, *main.py
15 |
16 | [coverage:report]
17 | show_missing = True
18 | exclude_lines =
19 | pragma: no cover
20 | raise NotImplementedError()
21 |
--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/__init__.py:
--------------------------------------------------------------------------------
1 | # Silence third-party modules
2 | import logging
3 | logging.getLogger("hyper").setLevel(logging.WARNING)
4 | logging.getLogger("requests").setLevel(logging.WARNING)
5 | logging.getLogger("passlib").setLevel(logging.WARNING)
6 | logging.getLogger("PIL").setLevel(logging.WARNING)
7 | logging.getLogger("tornado").setLevel(logging.WARNING)
8 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/addons/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_anticache.py:
--------------------------------------------------------------------------------
1 | from .. import tutils, mastertest
2 | from mitmproxy.addons import anticache
3 | from mitmproxy import master
4 | from mitmproxy import options
5 | from mitmproxy import proxy
6 |
7 |
8 | class TestAntiCache(mastertest.MasterTest):
9 | def test_simple(self):
10 | o = options.Options(anticache = True)
11 | m = master.Master(o, proxy.DummyServer())
12 | sa = anticache.AntiCache()
13 | m.addons.add(sa)
14 |
15 | f = tutils.tflow(resp=True)
16 | m.request(f)
17 |
18 | f = tutils.tflow(resp=True)
19 | f.request.headers["if-modified-since"] = "test"
20 | f.request.headers["if-none-match"] = "test"
21 | m.request(f)
22 | assert "if-modified-since" not in f.request.headers
23 | assert "if-none-match" not in f.request.headers
24 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_anticomp.py:
--------------------------------------------------------------------------------
1 | from .. import tutils, mastertest
2 | from mitmproxy.addons import anticomp
3 | from mitmproxy import master
4 | from mitmproxy import options
5 | from mitmproxy import proxy
6 |
7 |
8 | class TestAntiComp(mastertest.MasterTest):
9 | def test_simple(self):
10 | o = options.Options(anticomp = True)
11 | m = master.Master(o, proxy.DummyServer())
12 | sa = anticomp.AntiComp()
13 | m.addons.add(sa)
14 |
15 | f = tutils.tflow(resp=True)
16 | m.request(f)
17 |
18 | f = tutils.tflow(resp=True)
19 |
20 | f.request.headers["Accept-Encoding"] = "foobar"
21 | m.request(f)
22 | assert f.request.headers["Accept-Encoding"] == "identity"
23 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_clientplayback.py:
--------------------------------------------------------------------------------
1 | import mock
2 |
3 | from mitmproxy.addons import clientplayback
4 | from mitmproxy import options
5 |
6 | from .. import tutils, mastertest
7 |
8 |
9 | class TestClientPlayback:
10 | def test_playback(self):
11 | cp = clientplayback.ClientPlayback()
12 | cp.configure(options.Options(), [])
13 | assert cp.count() == 0
14 | f = tutils.tflow(resp=True)
15 | cp.load([f])
16 | assert cp.count() == 1
17 | RP = "mitmproxy.proxy.protocol.http_replay.RequestReplayThread"
18 | with mock.patch(RP) as rp:
19 | assert not cp.current
20 | with mastertest.mockctx():
21 | cp.tick()
22 | rp.assert_called()
23 | assert cp.current
24 |
25 | cp.keepserving = False
26 | cp.flows = None
27 | cp.current = None
28 | with mock.patch("mitmproxy.master.Master.shutdown") as sd:
29 | with mastertest.mockctx():
30 | cp.tick()
31 | sd.assert_called()
32 |
33 | def test_configure(self):
34 | cp = clientplayback.ClientPlayback()
35 | cp.configure(
36 | options.Options(), []
37 | )
38 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_filestreamer.py:
--------------------------------------------------------------------------------
1 | from .. import tutils, mastertest
2 |
3 | import os.path
4 |
5 | from mitmproxy.addons import filestreamer
6 | from mitmproxy import master
7 | from mitmproxy import io
8 | from mitmproxy import options
9 | from mitmproxy import proxy
10 |
11 |
12 | class TestStream(mastertest.MasterTest):
13 | def test_stream(self):
14 | with tutils.tmpdir() as tdir:
15 | p = os.path.join(tdir, "foo")
16 |
17 | def r():
18 | r = io.FlowReader(open(p, "rb"))
19 | return list(r.stream())
20 |
21 | o = options.Options(
22 | outfile = (p, "wb")
23 | )
24 | m = master.Master(o, proxy.DummyServer())
25 | sa = filestreamer.FileStreamer()
26 |
27 | m.addons.add(sa)
28 | f = tutils.tflow(resp=True)
29 | m.request(f)
30 | m.response(f)
31 | m.addons.remove(sa)
32 |
33 | assert r()[0].response
34 |
35 | m.options.outfile = (p, "ab")
36 |
37 | m.addons.add(sa)
38 | f = tutils.tflow()
39 | m.request(f)
40 | m.addons.remove(sa)
41 | assert not r()[1].response
42 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_onboarding.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.addons import onboarding
2 | from .. import tservers
3 |
4 |
5 | class TestApp(tservers.HTTPProxyTest):
6 | def addons(self):
7 | return [onboarding.Onboarding()]
8 |
9 | def test_basic(self):
10 | assert self.app("/").status_code == 200
11 |
12 | def test_cert(self):
13 | for ext in ["pem", "p12"]:
14 | resp = self.app("/cert/%s" % ext)
15 | assert resp.status_code == 200
16 | assert resp.content
17 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_state.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import proxy
2 | from mitmproxy import master
3 | from mitmproxy.addons import state
4 |
5 | from .. import tutils
6 |
7 |
8 | class TestState:
9 | def test_duplicate_flow(self):
10 | s = state.State()
11 | fm = master.Master(None, proxy.DummyServer())
12 | fm.addons.add(s)
13 | f = tutils.tflow(resp=True)
14 | fm.load_flow(f)
15 | assert s.flow_count() == 1
16 |
17 | f2 = s.duplicate_flow(f)
18 | assert f2.response
19 | assert s.flow_count() == 2
20 | assert s.index(f2) == 1
21 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_stickyauth.py:
--------------------------------------------------------------------------------
1 | from .. import tutils, mastertest
2 | from mitmproxy.addons import stickyauth
3 | from mitmproxy import master
4 | from mitmproxy import options
5 | from mitmproxy import proxy
6 |
7 |
8 | class TestStickyAuth(mastertest.MasterTest):
9 | def test_simple(self):
10 | o = options.Options(stickyauth = ".*")
11 | m = master.Master(o, proxy.DummyServer())
12 | sa = stickyauth.StickyAuth()
13 | m.addons.add(sa)
14 |
15 | f = tutils.tflow(resp=True)
16 | f.request.headers["authorization"] = "foo"
17 | m.request(f)
18 |
19 | assert "address" in sa.hosts
20 |
21 | f = tutils.tflow(resp=True)
22 | m.request(f)
23 | assert f.request.headers["authorization"] == "foo"
24 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_streambodies.py:
--------------------------------------------------------------------------------
1 | from .. import tutils, mastertest
2 | from mitmproxy import master
3 | from mitmproxy import options
4 | from mitmproxy import proxy
5 |
6 | from mitmproxy.addons import streambodies
7 |
8 |
9 | class TestStreamBodies(mastertest.MasterTest):
10 | def test_simple(self):
11 | o = options.Options(stream_large_bodies = 10)
12 | m = master.Master(o, proxy.DummyServer())
13 | sa = streambodies.StreamBodies()
14 | m.addons.add(sa)
15 |
16 | f = tutils.tflow()
17 | f.request.content = b""
18 | f.request.headers["Content-Length"] = "1024"
19 | assert not f.request.stream
20 | m.requestheaders(f)
21 | assert f.request.stream
22 |
23 | f = tutils.tflow(resp=True)
24 | f.response.content = b""
25 | f.response.headers["Content-Length"] = "1024"
26 | assert not f.response.stream
27 | m.responseheaders(f)
28 | assert f.response.stream
29 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_termlog.py:
--------------------------------------------------------------------------------
1 | from .. import mastertest
2 | import io
3 |
4 | from mitmproxy.addons import termlog
5 | from mitmproxy import log
6 | from mitmproxy.tools import dump
7 |
8 |
9 | class TestTermLog(mastertest.MasterTest):
10 | def test_simple(self):
11 | t = termlog.TermLog()
12 | sio = io.StringIO()
13 | t.configure(dump.Options(tfile = sio, verbosity = 2), set([]))
14 | t.log(log.LogEntry("one", "info"))
15 | assert "one" in sio.getvalue()
16 | t.log(log.LogEntry("two", "debug"))
17 | assert "two" not in sio.getvalue()
18 |
--------------------------------------------------------------------------------
/test/mitmproxy/addons/test_wsgiapp.py:
--------------------------------------------------------------------------------
1 | import flask
2 |
3 | from .. import tservers
4 | from mitmproxy.addons import wsgiapp
5 |
6 | tapp = flask.Flask(__name__)
7 |
8 |
9 | @tapp.route("/")
10 | def hello():
11 | return "testapp"
12 |
13 |
14 | @tapp.route("/error")
15 | def error():
16 | raise ValueError("An exception...")
17 |
18 |
19 | def errapp(environ, start_response):
20 | raise ValueError("errapp")
21 |
22 |
23 | class TestApp(tservers.HTTPProxyTest):
24 | def addons(self):
25 | return [
26 | wsgiapp.WSGIApp(tapp, "testapp", 80),
27 | wsgiapp.WSGIApp(errapp, "errapp", 80)
28 | ]
29 |
30 | def test_simple(self):
31 | p = self.pathoc()
32 | with p.connect():
33 | ret = p.request("get:'http://testapp/'")
34 | assert ret.status_code == 200
35 |
36 | def test_app_err(self):
37 | p = self.pathoc()
38 | with p.connect():
39 | ret = p.request("get:'http://errapp/'")
40 | assert ret.status_code == 500
41 | assert b"ValueError" in ret.content
42 |
--------------------------------------------------------------------------------
/test/mitmproxy/completion/aaa:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/completion/aaa
--------------------------------------------------------------------------------
/test/mitmproxy/completion/aab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/completion/aab
--------------------------------------------------------------------------------
/test/mitmproxy/completion/aac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/completion/aac
--------------------------------------------------------------------------------
/test/mitmproxy/completion/bbb/Readme.md:
--------------------------------------------------------------------------------
1 |
2 | This empty directory has been added so that we can hit [this line](https://codecov.io/gh/mitmproxy/mitmproxy/src/ba13fda10d3065a0c8dfd95d55680675b3bf08c2/mitmproxy/console/pathedit.py#L43) while testing pathedit completion.
3 |
--------------------------------------------------------------------------------
/test/mitmproxy/console/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/console/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/console/test_common.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.tools.console import common
2 | from .. import tutils
3 |
4 |
5 | @tutils.skip_appveyor
6 | def test_format_flow():
7 | f = tutils.tflow(resp=True)
8 | assert common.format_flow(f, True)
9 | assert common.format_flow(f, True, hostheader=True)
10 | assert common.format_flow(f, True, extended=True)
11 |
--------------------------------------------------------------------------------
/test/mitmproxy/console/test_help.py:
--------------------------------------------------------------------------------
1 | import mitmproxy.tools.console.help as help
2 | from .. import tutils
3 |
4 |
5 | @tutils.skip_appveyor
6 | class TestHelp:
7 |
8 | def test_helptext(self):
9 | h = help.HelpView(None)
10 | assert h.helptext()
11 |
12 | def test_keypress(self):
13 | h = help.HelpView([1, 2, 3])
14 | assert not h.keypress((0, 0), "q")
15 | assert not h.keypress((0, 0), "?")
16 | assert h.keypress((0, 0), "o") == "o"
17 |
--------------------------------------------------------------------------------
/test/mitmproxy/console/test_palettes.py:
--------------------------------------------------------------------------------
1 | import mitmproxy.tools.console.palettes as palettes
2 | from .. import tutils
3 |
4 |
5 | @tutils.skip_appveyor
6 | class TestPalette:
7 |
8 | def test_helptext(self):
9 | for i in palettes.palettes.values():
10 | assert i.palette(False)
11 | for i in palettes.palettes.values():
12 | assert i.palette(True)
13 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/1.css:
--------------------------------------------------------------------------------
1 | body,html{height:100%}body{font-family:'Open Sans',sans-serif;font-size:1.5em;padding-top:80px}
2 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/addonscripts/addon.py:
--------------------------------------------------------------------------------
1 | event_log = []
2 |
3 |
4 | class Addon:
5 | @property
6 | def event_log(self):
7 | return event_log
8 |
9 | def start(self):
10 | event_log.append("addonstart")
11 |
12 | def configure(self, options, updated):
13 | event_log.append("addonconfigure")
14 |
15 |
16 | def configure(options, updated):
17 | event_log.append("addonconfigure")
18 |
19 |
20 | def start():
21 | event_log.append("scriptstart")
22 | return Addon()
23 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/addonscripts/concurrent_decorator.py:
--------------------------------------------------------------------------------
1 | import time
2 | from mitmproxy.script import concurrent
3 |
4 | @concurrent
5 | def request(flow):
6 | time.sleep(0.1)
7 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/addonscripts/concurrent_decorator_err.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.script import concurrent
2 |
3 |
4 | @concurrent
5 | def start():
6 | pass
7 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/addonscripts/duplicate_flow.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import ctx
2 |
3 |
4 | def request(flow):
5 | f = ctx.master.state.duplicate_flow(flow)
6 | ctx.master.replay_request(f, block=True)
7 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/addonscripts/error.py:
--------------------------------------------------------------------------------
1 | def mkerr():
2 | raise ValueError("Error!")
3 |
4 |
5 | def request(flow):
6 | mkerr()
7 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/addonscripts/recorder.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import controller
2 | from mitmproxy import events
3 | from mitmproxy import ctx
4 | import sys
5 |
6 |
7 | class CallLogger:
8 | call_log = []
9 |
10 | def __init__(self, name = "solo"):
11 | self.name = name
12 |
13 | def __getattr__(self, attr):
14 | if attr in events.Events:
15 | def prox(*args, **kwargs):
16 | lg = (self.name, attr, args, kwargs)
17 | if attr != "log":
18 | ctx.log.info(str(lg))
19 | self.call_log.append(lg)
20 | ctx.log.debug("%s %s" % (self.name, attr))
21 | return prox
22 | raise AttributeError
23 |
24 |
25 | def start():
26 | return CallLogger(*sys.argv[1:])
27 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/addonscripts/stream_modify.py:
--------------------------------------------------------------------------------
1 | def modify(chunks):
2 | for chunk in chunks:
3 | yield chunk.replace(b"foo", b"bar")
4 |
5 |
6 | def responseheaders(flow):
7 | flow.response.stream = modify
8 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/addonscripts/tcp_stream_modify.py:
--------------------------------------------------------------------------------
1 | def tcp_message(flow):
2 | message = flow.messages[-1]
3 | if not message.from_client:
4 | message.content = message.content.replace(b"foo", b"bar")
5 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/amf01:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/amf01
--------------------------------------------------------------------------------
/test/mitmproxy/data/amf02:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/amf02
--------------------------------------------------------------------------------
/test/mitmproxy/data/amf03:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/amf03
--------------------------------------------------------------------------------
/test/mitmproxy/data/clientcert/.gitignore:
--------------------------------------------------------------------------------
1 | client.crt
2 | client.key
3 | client.req
4 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/clientcert/client.cnf:
--------------------------------------------------------------------------------
1 | [ ssl_client ]
2 | basicConstraints = CA:FALSE
3 | nsCertType = client
4 | keyUsage = digitalSignature, keyEncipherment
5 | extendedKeyUsage = clientAuth
6 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/clientcert/make:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | openssl genrsa -out client.key 2048
4 | openssl req -key client.key -new -out client.req
5 | openssl x509 -req -days 365 -in client.req -signkey client.key -out client.crt -extfile client.cnf -extensions ssl_client
6 | openssl x509 -req -days 1000 -in client.req -CA ~/.mitmproxy/mitmproxy-ca.pem -CAkey ~/.mitmproxy/mitmproxy-ca.pem -set_serial 00001 -out client.crt -extensions ssl_client
7 | cat client.key client.crt > 127.0.0.1.pem
8 | openssl x509 -text -noout -in 127.0.0.1.pem
9 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/confdir/mitmproxy-ca-cert.cer:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICnzCCAgigAwIBAgIGDKiSwuJOMA0GCSqGSIb3DQEBBQUAMCgxEjAQBgNVBAMT
3 | CW1pdG1wcm94eTESMBAGA1UEChMJbWl0bXByb3h5MB4XDTE0MDIwNzIzMjcwOFoX
4 | DTE2MDEyODIzMjcwOFowKDESMBAGA1UEAxMJbWl0bXByb3h5MRIwEAYDVQQKEwlt
5 | aXRtcHJveHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKsZ+XnBvjCjAJ00
6 | 9M+v41AT91h7v7cF1UG0BpS3y4MOysN88btHM/IWRCllnmY+zx5LTMAEtbnqyOIk
7 | nkgJ0sU3CFWHRIfwkinssEtMM2mOAFXm0wqffECxwe1p5z84M7nOolzuuw4FtkaK
8 | G9/UqANdRVs6uOwz+CuyOSY7illTAgMBAAGjgdMwgdAwDwYDVR0TAQH/BAUwAwEB
9 | /zAUBglghkgBhvhCAQEBAf8EBAMCAgQwewYDVR0lAQH/BHEwbwYIKwYBBQUHAwEG
10 | CCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQB
11 | gjcCARYGCisGAQQBgjcKAwEGCisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG
12 | +EIEATALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFFKVDIF+w2Ns4KsJx6tJZpILqWwG
13 | MA0GCSqGSIb3DQEBBQUAA4GBABWYxoYFLgZh/ujz/0jrNsx0pvSNVTU1T669374z
14 | PhO+ScvzuxVbgI2NQv86aqih35pzakK/DyKaTck85QduDiSiLNw2Yb5UfJvO4C0d
15 | dPzQMIKNTInFFiLBjbvxx9cuDwAPyYOF247Xj9M6C2x6e/gq1L+GR75wT5288x9h
16 | rFTJ
17 | -----END CERTIFICATE-----
18 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/confdir/mitmproxy-ca-cert.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/confdir/mitmproxy-ca-cert.p12
--------------------------------------------------------------------------------
/test/mitmproxy/data/confdir/mitmproxy-ca-cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICnzCCAgigAwIBAgIGDKiSwuJOMA0GCSqGSIb3DQEBBQUAMCgxEjAQBgNVBAMT
3 | CW1pdG1wcm94eTESMBAGA1UEChMJbWl0bXByb3h5MB4XDTE0MDIwNzIzMjcwOFoX
4 | DTE2MDEyODIzMjcwOFowKDESMBAGA1UEAxMJbWl0bXByb3h5MRIwEAYDVQQKEwlt
5 | aXRtcHJveHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKsZ+XnBvjCjAJ00
6 | 9M+v41AT91h7v7cF1UG0BpS3y4MOysN88btHM/IWRCllnmY+zx5LTMAEtbnqyOIk
7 | nkgJ0sU3CFWHRIfwkinssEtMM2mOAFXm0wqffECxwe1p5z84M7nOolzuuw4FtkaK
8 | G9/UqANdRVs6uOwz+CuyOSY7illTAgMBAAGjgdMwgdAwDwYDVR0TAQH/BAUwAwEB
9 | /zAUBglghkgBhvhCAQEBAf8EBAMCAgQwewYDVR0lAQH/BHEwbwYIKwYBBQUHAwEG
10 | CCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQB
11 | gjcCARYGCisGAQQBgjcKAwEGCisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG
12 | +EIEATALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFFKVDIF+w2Ns4KsJx6tJZpILqWwG
13 | MA0GCSqGSIb3DQEBBQUAA4GBABWYxoYFLgZh/ujz/0jrNsx0pvSNVTU1T669374z
14 | PhO+ScvzuxVbgI2NQv86aqih35pzakK/DyKaTck85QduDiSiLNw2Yb5UfJvO4C0d
15 | dPzQMIKNTInFFiLBjbvxx9cuDwAPyYOF247Xj9M6C2x6e/gq1L+GR75wT5288x9h
16 | rFTJ
17 | -----END CERTIFICATE-----
18 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/dercert:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/dercert
--------------------------------------------------------------------------------
/test/mitmproxy/data/dumpfile-010:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/dumpfile-010
--------------------------------------------------------------------------------
/test/mitmproxy/data/htpasswd:
--------------------------------------------------------------------------------
1 | test:$apr1$/LkYxy3x$WI4.YbiJlu537jLGEW2eu1
2 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/htpasswd.invalid:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/image-err1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/image-err1.jpg
--------------------------------------------------------------------------------
/test/mitmproxy/data/image.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/image.gif
--------------------------------------------------------------------------------
/test/mitmproxy/data/image.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/image.ico
--------------------------------------------------------------------------------
/test/mitmproxy/data/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/image.jpg
--------------------------------------------------------------------------------
/test/mitmproxy/data/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/data/image.png
--------------------------------------------------------------------------------
/test/mitmproxy/data/no_common_name.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIBOQIBAAJBAKVJ43C+8SjOvN9/pP/8HwzmHGQmRvdK/R6KlWdr7He6iiXDQNfH
3 | RAp+gqX0hBRT80eRjGhSmTTBLCWiXVny4UUCAwEAAQJAUQ8nZ0d85VJd9g2XUaLH
4 | Z4ACNGtBKk2wTKYSFyIqWZxsF5qhh7HGshJIAP6tYiX8ZW+mMSfme+zsJzWe8ChL
5 | gQIhAM8QpAgUHnNteZvkv0XqceX1GILEWifMt+hO9yTp4dY5AiEAzFnKr77CKCri
6 | /DPig4R/5q4KMpMx9EqJufHdGNmIA20CICMARxnufK86RCIr6oEg/hvG8Fu6YRr1
7 | Kekk3/XnavtRAiBVLVQ7vwKE5aNpRmMzOKZrS736aLpYvjz8IaFr+zgjXQIgdad5
8 | QZoTD49NTyMEgyZp70gTXcXQLrX2PgQKL4uNmoU=
9 | -----END RSA PRIVATE KEY-----
10 | -----BEGIN CERTIFICATE-----
11 | MIIBgTCCASugAwIBAgIJAKlcXsPLQAQuMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
12 | BAYTAkFVMB4XDTEzMTIxMjAxMzA1NVoXDTE0MDExMTAxMzA1NVowDTELMAkGA1UE
13 | BhMCQVUwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApUnjcL7xKM6833+k//wfDOYc
14 | ZCZG90r9HoqVZ2vsd7qKJcNA18dECn6CpfSEFFPzR5GMaFKZNMEsJaJdWfLhRQID
15 | AQABo24wbDAdBgNVHQ4EFgQUJm8BXcVRsROy0PVt5stkB3eVnEgwPQYDVR0jBDYw
16 | NIAUJm8BXcVRsROy0PVt5stkB3eVnEihEaQPMA0xCzAJBgNVBAYTAkFVggkAqVxe
17 | w8tABC4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAHHxcBEpWrIqtLVH
18 | m6Yn1hgqrAbfMj9IK6zY9C5Cbad/DfUj3AZMb5u758WJK0x9brmckgqdrQsuf9He
19 | Ef51/SU=
20 | -----END CERTIFICATE-----
21 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/pf01:
--------------------------------------------------------------------------------
1 | No ALTQ support in kernel
2 | ALTQ related functions disabled
3 | ALL tcp 127.0.0.1:8080 <- 5.5.5.6:80 <- 192.168.1.111:40001 FIN_WAIT_2:FIN_WAIT_2
4 | ALL tcp 127.0.0.1:8080 <- 5.5.5.5:80 <- 192.168.1.111:40000 ESTABLISHED:ESTABLISHED
5 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/pf02:
--------------------------------------------------------------------------------
1 | No ALTQ support in kernel
2 | ALTQ related functions disabled
3 | all tcp 127.0.0.1:8080 (5.5.5.6:80) <- 192.168.1.111:40001 FIN_WAIT_2:FIN_WAIT_2
4 | all tcp 127.0.0.1:8080 (5.5.5.5:80) <- 192.168.1.111:40000 ESTABLISHED:ESTABLISHED
5 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/protobuf01:
--------------------------------------------------------------------------------
1 |
2 | $3bbc333c-e61c-433b-819a-0b9a8cc103b8
--------------------------------------------------------------------------------
/test/mitmproxy/data/replace:
--------------------------------------------------------------------------------
1 | replacecontents
2 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/scripts/all.py:
--------------------------------------------------------------------------------
1 | import mitmproxy
2 | record = []
3 |
4 |
5 | def clientconnect(cc):
6 | mitmproxy.ctx.log("XCLIENTCONNECT")
7 | record.append("clientconnect")
8 |
9 |
10 | def serverconnect(cc):
11 | mitmproxy.ctx.log("XSERVERCONNECT")
12 | record.append("serverconnect")
13 |
14 |
15 | def request(f):
16 | mitmproxy.ctx.log("XREQUEST")
17 | record.append("request")
18 |
19 |
20 | def response(f):
21 | mitmproxy.ctx.log("XRESPONSE")
22 | record.append("response")
23 |
24 |
25 | def responseheaders(f):
26 | mitmproxy.ctx.log("XRESPONSEHEADERS")
27 | record.append("responseheaders")
28 |
29 |
30 | def clientdisconnect(cc):
31 | mitmproxy.ctx.log("XCLIENTDISCONNECT")
32 | record.append("clientdisconnect")
33 |
34 |
35 | def error(cc):
36 | mitmproxy.ctx.log("XERROR")
37 | record.append("error")
38 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/servercert/9da13359.0:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDXTCCAkWgAwIBAgIJAPAfPQGCV/Z4MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
3 | BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
4 | aWRnaXRzIFB0eSBMdGQwHhcNMTUxMTAxMTY0ODAxWhcNMTgwODIxMTY0ODAxWjBF
5 | MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
6 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
7 | CgKCAQEArp8LD34JhKCwcQbwIYQMg4+eCgLVN8fwB7+/qOfJbArPs0djFBN+F7c6
8 | HGvMr24BKUk5u8pn4dPtNurm/vPC8ovNGmcXz62BQJpcMX2veVdRsF7yNwhNacNJ
9 | Arq+70zNMwYBznx0XUxMF6j6nVFf3AW6SU04ylT4Mp3SY/BUUDAdfl1eRo0mPLNS
10 | 8rpsN+8YBw1Q7SCuBRVqpOgVIsL88svgQUSOlzvMZPBpG/cmB3BNKNrltwb5iFEI
11 | 1jAV7uSj5IcIuNO/246kfsDVPTFMJIzav/CUoidd5UNw+SoFDlzh8sA7L1Bm7D1/
12 | 3KHYSKswGsSR3kynAl10w/SJKDtn8wIDAQABo1AwTjAdBgNVHQ4EFgQUgOcrtxBX
13 | LxbpnOT65d+vpfyWUkgwHwYDVR0jBBgwFoAUgOcrtxBXLxbpnOT65d+vpfyWUkgw
14 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAEE9bFmUCA+6cvESKPoi2
15 | TGSpV652d0xd2U66LpEXeiWRJFLz8YGgoJCx3QFGBscJDXxrLxrBBBV/tCpEqypo
16 | pYIqsawH7M66jpOr83Us3M8JC2eFBZJocMpXxdytWqHik5VKZNx6VQFT8bS7+yVC
17 | VoUKePhlgcg+pmo41qjqieBNKRMh/1tXS77DI1lgO5wZLVrLXcdqWuDpmaQOKJeq
18 | G/nxytCW/YJA7bFn/8Gjy8DYypJSeeaKu7o3P3+ONJHdIMHb+MdcheDBS9AOFSeo
19 | xI0D5EbO9F873O77l7nbD7B0X34HFN0nGczC4poexIpbDFG3hAPekwZ5KC6VwJLc
20 | 1Q==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/locust_get.py:
--------------------------------------------------------------------------------
1 | from locust import HttpLocust, TaskSet, task
2 |
3 | class UserBehavior(TaskSet):
4 | def on_start(self):
5 | ''' on_start is called when a Locust start before any task is scheduled '''
6 | self.path()
7 |
8 | @task()
9 | def path(self):
10 | url = self.locust.host + '/path'
11 |
12 | headers = {
13 | 'header': 'qvalue',
14 | 'content-length': '7',
15 | }
16 |
17 | params = {
18 | 'a': ['foo', 'bar'],
19 | 'b': 'baz',
20 | }
21 |
22 | self.response = self.client.request(
23 | method='GET',
24 | url=url,
25 | headers=headers,
26 | params=params,
27 | )
28 |
29 | ### Additional tasks can go here ###
30 |
31 |
32 | class WebsiteUser(HttpLocust):
33 | task_set = UserBehavior
34 | min_wait = 1000
35 | max_wait = 3000
36 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/locust_patch.py:
--------------------------------------------------------------------------------
1 | from locust import HttpLocust, TaskSet, task
2 |
3 | class UserBehavior(TaskSet):
4 | def on_start(self):
5 | ''' on_start is called when a Locust start before any task is scheduled '''
6 | self.path()
7 |
8 | @task()
9 | def path(self):
10 | url = self.locust.host + '/path'
11 |
12 | headers = {
13 | 'header': 'qvalue',
14 | 'content-length': '7',
15 | }
16 |
17 | params = {
18 | 'query': 'param',
19 | }
20 |
21 | data = '''content'''
22 |
23 | self.response = self.client.request(
24 | method='PATCH',
25 | url=url,
26 | headers=headers,
27 | params=params,
28 | data=data,
29 | )
30 |
31 | ### Additional tasks can go here ###
32 |
33 |
34 | class WebsiteUser(HttpLocust):
35 | task_set = UserBehavior
36 | min_wait = 1000
37 | max_wait = 3000
38 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/locust_post.py:
--------------------------------------------------------------------------------
1 | from locust import HttpLocust, TaskSet, task
2 |
3 | class UserBehavior(TaskSet):
4 | def on_start(self):
5 | ''' on_start is called when a Locust start before any task is scheduled '''
6 | self.path()
7 |
8 | @task()
9 | def path(self):
10 | url = self.locust.host + '/path'
11 |
12 | data = '''content'''
13 |
14 | self.response = self.client.request(
15 | method='POST',
16 | url=url,
17 | data=data,
18 | )
19 |
20 | ### Additional tasks can go here ###
21 |
22 |
23 | class WebsiteUser(HttpLocust):
24 | task_set = UserBehavior
25 | min_wait = 1000
26 | max_wait = 3000
27 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/locust_task_get.py:
--------------------------------------------------------------------------------
1 | @task()
2 | def path(self):
3 | url = self.locust.host + '/path'
4 |
5 | headers = {
6 | 'header': 'qvalue',
7 | 'content-length': '7',
8 | }
9 |
10 | params = {
11 | 'a': ['foo', 'bar'],
12 | 'b': 'baz',
13 | }
14 |
15 | self.response = self.client.request(
16 | method='GET',
17 | url=url,
18 | headers=headers,
19 | params=params,
20 | )
21 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/locust_task_patch.py:
--------------------------------------------------------------------------------
1 | @task()
2 | def path(self):
3 | url = self.locust.host + '/path'
4 |
5 | headers = {
6 | 'header': 'qvalue',
7 | 'content-length': '7',
8 | }
9 |
10 | params = {
11 | 'query': 'param',
12 | }
13 |
14 | data = '''content'''
15 |
16 | self.response = self.client.request(
17 | method='PATCH',
18 | url=url,
19 | headers=headers,
20 | params=params,
21 | data=data,
22 | )
23 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/locust_task_post.py:
--------------------------------------------------------------------------------
1 | @task()
2 | def path(self):
3 | url = self.locust.host + '/path'
4 |
5 | data = '''content'''
6 |
7 | self.response = self.client.request(
8 | method='POST',
9 | url=url,
10 | data=data,
11 | )
12 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/python_get.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | response = requests.get(
4 | 'http://address:22/path',
5 | params=[('a', 'foo'), ('a', 'bar'), ('b', 'baz')],
6 | headers={'header': 'qvalue'}
7 | )
8 |
9 | print(response.text)
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/python_patch.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | response = requests.patch(
4 | 'http://address:22/path',
5 | params=[('query', 'param')],
6 | headers={'header': 'qvalue'},
7 | data=b'content'
8 | )
9 |
10 | print(response.text)
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/python_post.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | response = requests.post(
4 | 'http://address:22/path',
5 | data=b'content'
6 | )
7 |
8 | print(response.text)
9 |
--------------------------------------------------------------------------------
/test/mitmproxy/data/test_flow_export/python_post_json.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | response = requests.post(
4 | 'http://address:22/path',
5 | headers={'content-type': 'application/json'},
6 | json={'email': 'example@example.com', 'name': 'example'}
7 | )
8 |
9 | print(response.text)
--------------------------------------------------------------------------------
/test/mitmproxy/fuzzing/.env:
--------------------------------------------------------------------------------
1 | MITMDUMP=mitmdump
2 | PATHOD=pathod
3 | PATHOC=pathoc
4 | FUZZ_SETTINGS="-remTt 1 -n 0"
5 |
--------------------------------------------------------------------------------
/test/mitmproxy/fuzzing/README:
--------------------------------------------------------------------------------
1 |
2 | A fuzzing architecture for mitmproxy
3 | ====================================
4 |
5 | Quick start:
6 |
7 | honcho -f ./straight_stream start
8 |
9 |
10 | Notes:
11 |
12 | - Processes are managed using honcho (pip install honcho)
13 | - Paths and common settings live in .env
14 |
15 |
--------------------------------------------------------------------------------
/test/mitmproxy/fuzzing/client_patterns:
--------------------------------------------------------------------------------
1 | get:'http://localhost:9999/p/200':ir,"\n"
2 | get:'http://localhost:9999/p/200':ir,"\0"
3 | get:'http://localhost:9999/p/200':ir,@5
4 | get:'http://localhost:9999/p/200':dr
5 |
--------------------------------------------------------------------------------
/test/mitmproxy/fuzzing/go_proxy:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Assuming:
3 | # mitmproxy/mitmdump is running on port 8080 in straight proxy mode.
4 | # pathod is running on port 9999
5 |
6 | BASE="../../../"
7 | BASE_HTTP=$BASE"/pathod/pathoc -Tt 1 -e -I 200,400,405,502 -p 8080 localhost "
8 | BASE_HTTPS=$BASE"/pathod/pathoc -sc localhost:9999 -Tt 1 -eo -I 200,400,404,405,502,800 -p 8080 localhost "
9 |
10 | #$BASE_HTTP -n 10000 "get:'http://localhost:9999':ir,@1"
11 | #$BASE_HTTP -n 100 "get:'http://localhost:9999':dr"
12 | #$BASE_HTTP -n 10000 "get:'http://localhost:9999/p/200':ir,@300"
13 |
14 | #$BASE_HTTP -n 10000 "get:'http://localhost:9999/p/200:ir,@1'"
15 | #$BASE_HTTP -n 100 "get:'http://localhost:9999/p/200:dr'"
16 | #$BASE_HTTP -n 10000 "get:'http://localhost:9999/p/200:ir,@100'"
17 |
18 |
19 | # Assuming:
20 | # mitmproxy/mitmdump is running on port 8080 in straight proxy mode.
21 | # pathod with SSL enabled is running on port 9999
22 |
23 | #$BASE_HTTPS -en 10000 "get:'/p/200:b@100:ir,@1'"
24 | #$BASE_HTTPS -en 10000 "get:'/p/200:ir,@1'"
25 |
26 | #$BASE_HTTPS -n 100 "get:'/p/200:dr'"
27 | #$BASE_HTTPS -n 10000 "get:'/p/200:ir,@3000'"
28 | #$BASE_HTTPS -n 10000 "get:'/p/200:ir,\"\\n\"'"
29 |
30 |
--------------------------------------------------------------------------------
/test/mitmproxy/fuzzing/reverse_patterns:
--------------------------------------------------------------------------------
1 | get:'/p/200':b@10:ir,"\n"
2 | get:'/p/200':b@10:ir,"\r\n"
3 | get:'/p/200':b@10:ir,"\0"
4 | get:'/p/200':b@10:ir,@5
5 | get:'/p/200':b@10:dr
6 |
7 | get:'/p/200:b@10:ir,@1'
8 | get:'/p/200:b@10:dr'
9 | get:'/p/200:b@10:ir,@100'
10 |
--------------------------------------------------------------------------------
/test/mitmproxy/fuzzing/straight_stream:
--------------------------------------------------------------------------------
1 |
2 | mitmdump: $MITMDUMP
3 | pathod: $PATHOD
4 | pathoc: sleep 2 && $PATHOC $FUZZ_SETTINGS localhost:8080 ./straight_stream_patterns
5 | #pathoc: sleep 2 && $PATHOC localhost:8080 /tmp/err
6 |
7 |
--------------------------------------------------------------------------------
/test/mitmproxy/fuzzing/straight_stream_patterns:
--------------------------------------------------------------------------------
1 | get:'http://localhost:9999/p/':s'200:b"foo"':ir,'\n'
2 | get:'http://localhost:9999/p/':s'200:b"foo"':ir,'a'
3 | get:'http://localhost:9999/p/':s'200:b"foo"':ir,'9'
4 | get:'http://localhost:9999/p/':s'200:b"foo"':ir,':'
5 | get:'http://localhost:9999/p/':s'200:b"foo"':ir,'"'
6 | get:'http://localhost:9999/p/':s'200:b"foo"':ir,'-'
7 |
8 | get:'http://localhost:9999/p/':s'200:b"foo":ir,"\n"'
9 | get:'http://localhost:9999/p/':s'200:b"foo":ir,"a"'
10 | get:'http://localhost:9999/p/':s'200:b"foo":ir,"9"'
11 | get:'http://localhost:9999/p/':s'200:b"foo":ir,":"'
12 | get:'http://localhost:9999/p/':s'200:b"foo":ir,"-"'
13 | get:'http://localhost:9999/p/':s'200:b"foo":dr'
14 |
15 | get:'http://localhost:9999/p/':s'200:b"foo"':ir,@2
16 | get:'http://localhost:9999/p/':s'200:b"foo":ir,@2'
17 |
--------------------------------------------------------------------------------
/test/mitmproxy/fuzzing/straight_stream_ssl:
--------------------------------------------------------------------------------
1 |
2 | mitmdump: $MITMDUMP -q --stream 1
3 | pathod: $PATHOD
4 | pathoc: sleep 2 && $PATHOC $FUZZ_SETTINGS localhost:8080 ./straight_stream_patterns
5 | #pathoc: sleep 2 && $PATHOC localhost:8080 /tmp/err
6 |
7 |
--------------------------------------------------------------------------------
/test/mitmproxy/mock_urwid.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import mock
4 | if os.name == "nt":
5 | m = mock.Mock()
6 | m.__version__ = "1.1.1"
7 | m.Widget = mock.Mock
8 | m.WidgetWrap = mock.Mock
9 | sys.modules['urwid'] = m
10 | sys.modules['urwid.util'] = mock.Mock()
11 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/net/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/clientcert/.gitignore:
--------------------------------------------------------------------------------
1 | client.crt
2 | client.key
3 | client.req
4 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/clientcert/client.cnf:
--------------------------------------------------------------------------------
1 | [ ssl_client ]
2 | basicConstraints = CA:FALSE
3 | nsCertType = client
4 | keyUsage = digitalSignature, keyEncipherment
5 | extendedKeyUsage = clientAuth
6 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/clientcert/make:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | openssl genrsa -out client.key 2048
4 | openssl req -key client.key -new -out client.req
5 | openssl x509 -req -days 365 -in client.req -signkey client.key -out client.crt -extfile client.cnf -extensions ssl_client
6 | openssl x509 -req -days 1000 -in client.req -CA ~/.mitmproxy/mitmproxy-ca.pem -CAkey ~/.mitmproxy/mitmproxy-ca.pem -set_serial 00001 -out client.crt -extensions ssl_client
7 | cat client.key client.crt > client.pem
8 | openssl x509 -text -noout -in client.pem
9 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/dercert:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/net/data/dercert
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/dhparam.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN DH PARAMETERS-----
2 | MIICCAKCAgEAyT6LzpwVFS3gryIo29J5icvgxCnCebcdSe/NHMkD8dKJf8suFCg3
3 | O2+dguLakSVif/t6dhImxInJk230HmfC8q93hdcg/j8rLGJYDKu3ik6H//BAHKIv
4 | j5O9yjU3rXCfmVJQic2Nne39sg3CreAepEts2TvYHhVv3TEAzEqCtOuTjgDv0ntJ
5 | Gwpj+BJBRQGG9NvprX1YGJ7WOFBP/hWU7d6tgvE6Xa7T/u9QIKpYHMIkcN/l3ZFB
6 | chZEqVlyrcngtSXCROTPcDOQ6Q8QzhaBJS+Z6rcsd7X+haiQqvoFcmaJ08Ks6LQC
7 | ZIL2EtYJw8V8z7C0igVEBIADZBI6OTbuuhDwRw//zU1uq52Oc48CIZlGxTYG/Evq
8 | o9EWAXUYVzWkDSTeBH1r4z/qLPE2cnhtMxbFxuvK53jGB0emy2y1Ei6IhKshJ5qX
9 | IB/aE7SSHyQ3MDHHkCmQJCsOd4Mo26YX61NZ+n501XjqpCBQ2+DfZCBh8Va2wDyv
10 | A2Ryg9SUz8j0AXViRNMJgJrr446yro/FuJZwnQcO3WQnXeqSBnURqKjmqkeFP+d8
11 | 6mk2tqJaY507lRNqtGlLnj7f5RNoBFJDCLBNurVgfvq9TCVWKDIFD4vZRjCrnl6I
12 | rD693XKIHUCWOjMh1if6omGXKHH40QuME2gNa50+YPn1iYDl88uDbbMCAQI=
13 | -----END DH PARAMETERS-----
14 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/htpasswd:
--------------------------------------------------------------------------------
1 | test:$apr1$/LkYxy3x$WI4.YbiJlu537jLGEW2eu1
2 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/server.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICOzCCAaQCCQDC7f5GsEpo9jANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJO
3 | WjEOMAwGA1UECBMFT3RhZ28xEDAOBgNVBAcTB0R1bmVkaW4xDzANBgNVBAoTBm5l
4 | dGxpYjEPMA0GA1UECxMGbmV0bGliMQ8wDQYDVQQDEwZuZXRsaWIwHhcNMTIwNjI0
5 | MjI0MTU0WhcNMjIwNjIyMjI0MTU0WjBiMQswCQYDVQQGEwJOWjEOMAwGA1UECBMF
6 | T3RhZ28xEDAOBgNVBAcTB0R1bmVkaW4xDzANBgNVBAoTBm5ldGxpYjEPMA0GA1UE
7 | CxMGbmV0bGliMQ8wDQYDVQQDEwZuZXRsaWIwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
8 | MIGJAoGBALJSVEl9y3QUSYuXTH0UjBOPQgS0nHmNWej9hjqnA0KWvEnGY+c6yQeP
9 | /rmwswlKw1iVV5o8kRK9Wej88YWQl/hl/xruyeJgGic0+yqY/FcueZxRudwBcWu2
10 | 7+46aEftwLLRF0GwHZxX/HwWME+TcCXGpXGSG2qs921M4iVeBn5hAgMBAAEwDQYJ
11 | KoZIhvcNAQEFBQADgYEAODZCihEv2yr8zmmQZDrfqg2ChxAoOXWF5+W2F/0LAUBf
12 | 2bHP+K4XE6BJWmadX1xKngj7SWrhmmTDp1gBAvXURoDaScOkB1iOCOHoIyalscTR
13 | 0FvSHKqFF8fgSlfqS6eYaSbXU3zQolvwP+URzIVnGDqgQCWPtjMqLD3Kd5tuwos=
14 | -----END CERTIFICATE-----
15 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/server.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIICXAIBAAKBgQCyUlRJfct0FEmLl0x9FIwTj0IEtJx5jVno/YY6pwNClrxJxmPn
3 | OskHj/65sLMJSsNYlVeaPJESvVno/PGFkJf4Zf8a7sniYBonNPsqmPxXLnmcUbnc
4 | AXFrtu/uOmhH7cCy0RdBsB2cV/x8FjBPk3AlxqVxkhtqrPdtTOIlXgZ+YQIDAQAB
5 | AoGAQEpGcSiVTYhy64zk2sOprPOdTa0ALSK1I7cjycmk90D5KXAJXLho+f0ETVZT
6 | dioqO6m8J7NmamcyHznyqcDzyNRqD2hEBDGVRJWmpOjIER/JwWLNNbpeVjsMHV8I
7 | 40P5rZMOhBPYlwECSC5NtMwaN472fyGNNze8u37IZKiER/ECQQDe1iY5AG3CgkP3
8 | tEZB3Vtzcn4PoOr3Utyn1YER34lPqAmeAsWUhmAVEfR3N1HDe1VFD9s2BidhBn1a
9 | /Bgqxz4DAkEAzNw0m+uO0WkD7aEYRBW7SbXCX+3xsbVToIWC1jXFG+XDzSWn++c1
10 | DMXEElzEJxPDA+FzQUvRTml4P92bTAbGywJAS9H7wWtm7Ubbj33UZfbGdhqfz/uF
11 | 109naufXedhgZS0c0JnK1oV+Tc0FLEczV9swIUaK5O/lGDtYDcw3AN84NwJBAIw5
12 | /1jrOOtm8uVp6+5O4dBmthJsEZEPCZtLSG/Qhoe+EvUN3Zq0fL+tb7USAsKs6ERz
13 | wizj9PWzhDhTPMYhrVkCQGIponZHx6VqiFyLgYUH9+gDTjBhYyI+6yMTYzcRweyL
14 | 9Suc2NkS3X2Lp+wCjvVZdwGtStp6Vo8z02b3giIsAIY=
15 | -----END RSA PRIVATE KEY-----
16 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/verificationcerts/9da13359.0:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDXTCCAkWgAwIBAgIJAPAfPQGCV/Z4MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
3 | BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
4 | aWRnaXRzIFB0eSBMdGQwHhcNMTUxMTAxMTY0ODAxWhcNMTgwODIxMTY0ODAxWjBF
5 | MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
6 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
7 | CgKCAQEArp8LD34JhKCwcQbwIYQMg4+eCgLVN8fwB7+/qOfJbArPs0djFBN+F7c6
8 | HGvMr24BKUk5u8pn4dPtNurm/vPC8ovNGmcXz62BQJpcMX2veVdRsF7yNwhNacNJ
9 | Arq+70zNMwYBznx0XUxMF6j6nVFf3AW6SU04ylT4Mp3SY/BUUDAdfl1eRo0mPLNS
10 | 8rpsN+8YBw1Q7SCuBRVqpOgVIsL88svgQUSOlzvMZPBpG/cmB3BNKNrltwb5iFEI
11 | 1jAV7uSj5IcIuNO/246kfsDVPTFMJIzav/CUoidd5UNw+SoFDlzh8sA7L1Bm7D1/
12 | 3KHYSKswGsSR3kynAl10w/SJKDtn8wIDAQABo1AwTjAdBgNVHQ4EFgQUgOcrtxBX
13 | LxbpnOT65d+vpfyWUkgwHwYDVR0jBBgwFoAUgOcrtxBXLxbpnOT65d+vpfyWUkgw
14 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAEE9bFmUCA+6cvESKPoi2
15 | TGSpV652d0xd2U66LpEXeiWRJFLz8YGgoJCx3QFGBscJDXxrLxrBBBV/tCpEqypo
16 | pYIqsawH7M66jpOr83Us3M8JC2eFBZJocMpXxdytWqHik5VKZNx6VQFT8bS7+yVC
17 | VoUKePhlgcg+pmo41qjqieBNKRMh/1tXS77DI1lgO5wZLVrLXcdqWuDpmaQOKJeq
18 | G/nxytCW/YJA7bFn/8Gjy8DYypJSeeaKu7o3P3+ONJHdIMHb+MdcheDBS9AOFSeo
19 | xI0D5EbO9F873O77l7nbD7B0X34HFN0nGczC4poexIpbDFG3hAPekwZ5KC6VwJLc
20 | 1Q==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/verificationcerts/self-signed.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDEzCCAfugAwIBAgIJAJ945xt1FRsfMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNV
3 | BAMMFWV4YW1wbGUubWl0bXByb3h5Lm9yZzAeFw0xNTExMDExNjQ4MDJaFw0xODA4
4 | MjExNjQ4MDJaMCAxHjAcBgNVBAMMFWV4YW1wbGUubWl0bXByb3h5Lm9yZzCCASIw
5 | DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALFxyzPfjgIghOMMnJlW80yB84xC
6 | nJtko3tuyOdozgTCyha2W+NdIKPNZJtWrzN4P0B5PlozCDwfcSYffLs0WZs8LRWv
7 | BfZX8+oX+14qQjKFsiqgO65cTLP3qlPySYPJQQ37vOP1Y5Yf8nQq2mwQdC18hLtT
8 | QOANG6OFoSplpBLsYF+QeoMgqCTa6hrl/5GLmQoDRTjXkv3Sj379AUDMybuBqccm
9 | q5EIqCrE4+xJ8JywJclAVn2YP14baiFrrYCsYYg4sS1Od6xFj+xtpLe7My3AYjB9
10 | /aeHd8vDiob0cqOW1TFwhqgJKuErfFyg8lZ2hJmStJKyfofWuY/gl/vnvX0CAwEA
11 | AaNQME4wHQYDVR0OBBYEFB8d32zK8eqZIoKw4jXzYzhw4amPMB8GA1UdIwQYMBaA
12 | FB8d32zK8eqZIoKw4jXzYzhw4amPMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL
13 | BQADggEBAJmo2oKv1OEjZ0Q4yELO6BAnHAkmBKpW+zmLyQa8idxtLVkI9uXk3iqY
14 | GWugkmcUZCTVFRWv/QXQQSex+00IY3x2rdHbtuZwcyKiz2u8WEmfW1rOIwBaFJ1i
15 | v7+SA2aZs6vepN2sE56X54c/YbwQooaKZtOb+djWXYMJrc/Ezj0J7oQIJTptYV8v
16 | /3216yCHRp/KCL7yTLtiw25xKuXNu/gkcd8wZOY9rS2qMUD897MJF0MvgJoauRBd
17 | d4XEYCNKkrIRmfqrkiRQfAZpvpoutH6NCk7KuQYcI0BlOHlsnHHcs/w72EEqHwFq
18 | x6476tW/t8GJDZVD74+pNBcLifXxArE=
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/verificationcerts/trusted-leaf.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIC4TCCAckCCQCj6D9oVylb8jANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
3 | VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
4 | cyBQdHkgTHRkMB4XDTE1MTEwMTE2NDgwMloXDTE4MDgyMTE2NDgwMlowIDEeMBwG
5 | A1UEAwwVZXhhbXBsZS5taXRtcHJveHkub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC
6 | AQ8AMIIBCgKCAQEAy/L5JYHS7QFhSIsjmd6bJTgs2rdqEn6tsmPBVZKZ7SqCAVjW
7 | hPpEu7Q23akmU6Zm9Fp/vENc3jzxQLlEKhrv7eWmFYSOrCYtbJOz3RQorlwjjfdY
8 | LlNQh1wYUXQX3PN3r3dyYtt5vTtXKc8+aP4M4vX7qlbW+4j4LrQfmPjS0XOdYpu3
9 | wh+i1ZMIhZye3hpCjwnpjTf7/ff45ZFxtkoi1uzEC/+swr1RSvamY8Foe12Re17Z
10 | 5ij8ZB0NIdoSk1tDkY3sJ8iNi35+qartl0UYeG9IUXRwDRrPsEKpF4RxY1+X2bdZ
11 | r6PKb/E4CA5JlMvS5SVmrvxjCVqTQBmTjXfxqwIDAQABMA0GCSqGSIb3DQEBCwUA
12 | A4IBAQBmpSZJrTDvzSlo6P7P7x1LoETzHyVjwgPeqGYw6ndGXeJMN9rhhsFvRsiB
13 | I/aHh58MIlSjti7paikDAoFHB3dBvFHR+JUa/ailWEbcZReWRSE3lV6wFiN3G3lU
14 | OyofR7MKnPW7bv8hSqOLqP1mbupXuQFB5M6vPLRwg5VgiCHI/XBiTvzMamzvNAR3
15 | UHHZtsJkRqzogYm6K9YJaga7jteSx2nNo+ujLwrxeXsLChTyFMJGnVkp5IyKeNfc
16 | qwlzNncb3y+4KnUdNkPEtuydgAxAfuyXufiFBYRcUWbQ5/9ycgF7131ySaj9f/Y2
17 | kMsv2jg+soKvwwVYCABsk1KSHtfz
18 | -----END CERTIFICATE-----
19 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/verificationcerts/trusted-root.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDXTCCAkWgAwIBAgIJAPAfPQGCV/Z4MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
3 | BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
4 | aWRnaXRzIFB0eSBMdGQwHhcNMTUxMTAxMTY0ODAxWhcNMTgwODIxMTY0ODAxWjBF
5 | MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
6 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
7 | CgKCAQEArp8LD34JhKCwcQbwIYQMg4+eCgLVN8fwB7+/qOfJbArPs0djFBN+F7c6
8 | HGvMr24BKUk5u8pn4dPtNurm/vPC8ovNGmcXz62BQJpcMX2veVdRsF7yNwhNacNJ
9 | Arq+70zNMwYBznx0XUxMF6j6nVFf3AW6SU04ylT4Mp3SY/BUUDAdfl1eRo0mPLNS
10 | 8rpsN+8YBw1Q7SCuBRVqpOgVIsL88svgQUSOlzvMZPBpG/cmB3BNKNrltwb5iFEI
11 | 1jAV7uSj5IcIuNO/246kfsDVPTFMJIzav/CUoidd5UNw+SoFDlzh8sA7L1Bm7D1/
12 | 3KHYSKswGsSR3kynAl10w/SJKDtn8wIDAQABo1AwTjAdBgNVHQ4EFgQUgOcrtxBX
13 | LxbpnOT65d+vpfyWUkgwHwYDVR0jBBgwFoAUgOcrtxBXLxbpnOT65d+vpfyWUkgw
14 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAEE9bFmUCA+6cvESKPoi2
15 | TGSpV652d0xd2U66LpEXeiWRJFLz8YGgoJCx3QFGBscJDXxrLxrBBBV/tCpEqypo
16 | pYIqsawH7M66jpOr83Us3M8JC2eFBZJocMpXxdytWqHik5VKZNx6VQFT8bS7+yVC
17 | VoUKePhlgcg+pmo41qjqieBNKRMh/1tXS77DI1lgO5wZLVrLXcdqWuDpmaQOKJeq
18 | G/nxytCW/YJA7bFn/8Gjy8DYypJSeeaKu7o3P3+ONJHdIMHb+MdcheDBS9AOFSeo
19 | xI0D5EbO9F873O77l7nbD7B0X34HFN0nGczC4poexIpbDFG3hAPekwZ5KC6VwJLc
20 | 1Q==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/data/verificationcerts/trusted-root.srl:
--------------------------------------------------------------------------------
1 | A3E83F6857295BF2
2 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/http/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/net/http/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/net/http/http1/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/net/http/http1/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/net/http/http2/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/net/http/http2/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/net/http/http2/test_framereader.py:
--------------------------------------------------------------------------------
1 | # foobar
2 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/http/test_multipart.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.net.http import Headers
2 | from mitmproxy.net.http import multipart
3 |
4 |
5 | def test_decode():
6 | boundary = 'somefancyboundary'
7 | headers = Headers(
8 | content_type='multipart/form-data; boundary=' + boundary
9 | )
10 | content = (
11 | "--{0}\n"
12 | "Content-Disposition: form-data; name=\"field1\"\n\n"
13 | "value1\n"
14 | "--{0}\n"
15 | "Content-Disposition: form-data; name=\"field2\"\n\n"
16 | "value2\n"
17 | "--{0}--".format(boundary).encode()
18 | )
19 |
20 | form = multipart.decode(headers, content)
21 |
22 | assert len(form) == 2
23 | assert form[0] == (b"field1", b"value1")
24 | assert form[1] == (b"field2", b"value2")
25 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/http/test_status_codes.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.net.http import status_codes
2 |
3 |
4 | def test_simple():
5 | assert status_codes.IM_A_TEAPOT == 418
6 | assert status_codes.RESPONSES[418] == "I'm a teapot"
7 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/http/test_user_agents.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.net.http import user_agents
2 |
3 |
4 | def test_get_shortcut():
5 | assert user_agents.get_by_shortcut("c")[0] == "chrome"
6 | assert not user_agents.get_by_shortcut("_")
7 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/test_check.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | from mitmproxy.net import check
4 |
5 |
6 | def test_is_valid_host():
7 | assert not check.is_valid_host(b"")
8 | assert check.is_valid_host(b"one.two")
9 | assert not check.is_valid_host(b"one" * 255)
10 | assert check.is_valid_host(b"one.two.")
11 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/test_imports.py:
--------------------------------------------------------------------------------
1 | # These are actually tests!
2 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/tools/getcertnames:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import sys
3 | sys.path.insert(0, "../../")
4 | from mitmproxy.net import tcp
5 |
6 |
7 | def get_remote_cert(host, port, sni):
8 | c = tcp.TCPClient((host, port))
9 | c.connect()
10 | c.convert_to_ssl(sni=sni)
11 | return c.cert
12 |
13 | if len(sys.argv) > 2:
14 | port = int(sys.argv[2])
15 | else:
16 | port = 443
17 | if len(sys.argv) > 3:
18 | sni = sys.argv[3]
19 | else:
20 | sni = None
21 |
22 | cert = get_remote_cert(sys.argv[1], port, sni)
23 | print("CN:", cert.cn)
24 | if cert.altnames:
25 | print("SANs:")
26 | for i in cert.altnames:
27 | print("\t", i)
28 |
--------------------------------------------------------------------------------
/test/mitmproxy/net/websockets/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/net/websockets/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/net/websockets/test_masker.py:
--------------------------------------------------------------------------------
1 | import codecs
2 | import pytest
3 |
4 | from mitmproxy.net import websockets
5 |
6 |
7 | class TestMasker:
8 |
9 | @pytest.mark.parametrize("input,expected", [
10 | ([b"a"], '00'),
11 | ([b"four"], '070d1616'),
12 | ([b"fourf"], '070d161607'),
13 | ([b"fourfive"], '070d1616070b1501'),
14 | ([b"a", b"aasdfasdfa", b"asdf"], '000302170504021705040205120605'),
15 | ([b"a" * 50, b"aasdfasdfa", b"asdf"], '00030205000302050003020500030205000302050003020500030205000302050003020500030205000302050003020500030205120605051206050500110702'), # noqa
16 | ])
17 | def test_masker(self, input, expected):
18 | m = websockets.Masker(b"abcd")
19 | data = b"".join([m(t) for t in input])
20 | assert data == codecs.decode(expected, 'hex')
21 |
22 | data = websockets.Masker(b"abcd")(data)
23 | assert data == b"".join(input)
24 |
--------------------------------------------------------------------------------
/test/mitmproxy/protocol/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/protocol/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/script/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/script/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/test_addonmanager.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import addonmanager
2 | from mitmproxy import options
3 | from mitmproxy import master
4 | from mitmproxy import proxy
5 |
6 |
7 | class TAddon:
8 | def __init__(self, name):
9 | self.name = name
10 |
11 | def __repr__(self):
12 | return "Addon(%s)" % self.name
13 |
14 |
15 | def test_simple():
16 | o = options.Options()
17 | m = master.Master(o, proxy.DummyServer(o))
18 | a = addonmanager.AddonManager(m)
19 | a.add(TAddon("one"))
20 | assert a.get("one")
21 | assert not a.get("two")
22 | a.clear()
23 | assert not a.chain
24 |
--------------------------------------------------------------------------------
/test/mitmproxy/test_custom_contentview.py:
--------------------------------------------------------------------------------
1 | import mitmproxy.contentviews as cv
2 | from mitmproxy.net.http import Headers
3 |
4 |
5 | def test_custom_views():
6 | class ViewNoop(cv.View):
7 | name = "noop"
8 | prompt = ("noop", "n")
9 | content_types = ["text/none"]
10 |
11 | def __call__(self, data, **metadata):
12 | return "noop", cv.format_text(data)
13 |
14 | view_obj = ViewNoop()
15 |
16 | cv.add(view_obj)
17 |
18 | assert cv.get("noop")
19 |
20 | r = cv.get_content_view(
21 | cv.get("noop"),
22 | "[1, 2, 3]",
23 | headers=Headers(
24 | content_type="text/plain"
25 | )
26 | )
27 | assert "noop" in r[0]
28 |
29 | # now try content-type matching
30 | r = cv.get_content_view(
31 | cv.get("Auto"),
32 | "[1, 2, 3]",
33 | headers=Headers(
34 | content_type="text/none"
35 | )
36 | )
37 | assert "noop" in r[0]
38 |
39 | # now try removing the custom view
40 | cv.remove(view_obj)
41 | r = cv.get_content_view(
42 | cv.get("Auto"),
43 | b"[1, 2, 3]",
44 | headers=Headers(
45 | content_type="text/none"
46 | )
47 | )
48 | assert "noop" not in r[0]
49 |
--------------------------------------------------------------------------------
/test/mitmproxy/test_flow_format_compat.py:
--------------------------------------------------------------------------------
1 | from mitmproxy import io
2 | from mitmproxy import exceptions
3 | from . import tutils
4 |
5 |
6 | def test_load():
7 | with open(tutils.test_data.path("data/dumpfile-011"), "rb") as f:
8 | flow_reader = io.FlowReader(f)
9 | flows = list(flow_reader.stream())
10 | assert len(flows) == 1
11 | assert flows[0].request.url == "https://example.com/"
12 |
13 |
14 | def test_cannot_convert():
15 | with open(tutils.test_data.path("data/dumpfile-010"), "rb") as f:
16 | flow_reader = io.FlowReader(f)
17 | with tutils.raises(exceptions.FlowReadException):
18 | list(flow_reader.stream())
19 |
--------------------------------------------------------------------------------
/test/mitmproxy/test_platform_pf.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from mitmproxy.platform import pf
3 | from . import tutils
4 |
5 |
6 | class TestLookup:
7 |
8 | def test_simple(self):
9 | if sys.platform == "freebsd10":
10 | p = tutils.test_data.path("data/pf02")
11 | d = open(p, "rb").read()
12 | else:
13 | p = tutils.test_data.path("data/pf01")
14 | d = open(p, "rb").read()
15 | assert pf.lookup("192.168.1.111", 40000, d) == ("5.5.5.5", 80)
16 | tutils.raises(
17 | "Could not resolve original destination",
18 | pf.lookup,
19 | "192.168.1.112",
20 | 40000,
21 | d)
22 | tutils.raises(
23 | "Could not resolve original destination",
24 | pf.lookup,
25 | "192.168.1.111",
26 | 40001,
27 | d)
28 |
--------------------------------------------------------------------------------
/test/mitmproxy/test_types_bidi.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.types import bidi
2 | from mitmproxy.test import tutils
3 |
4 |
5 | def test_bidi():
6 | b = bidi.BiDi(a=1, b=2)
7 | assert b.a == 1
8 | assert b.get_name(1) == "a"
9 | assert b.get_name(5) is None
10 | tutils.raises(AttributeError, getattr, b, "c")
11 | tutils.raises(ValueError, bidi.BiDi, one=1, two=1)
12 |
--------------------------------------------------------------------------------
/test/mitmproxy/test_types_serializable.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.types import serializable
2 |
3 |
4 | class SerializableDummy(serializable.Serializable):
5 | def __init__(self, i):
6 | self.i = i
7 |
8 | def get_state(self):
9 | return self.i
10 |
11 | def set_state(self, i):
12 | self.i = i
13 |
14 | def from_state(self, state):
15 | return type(self)(state)
16 |
17 |
18 | class TestSerializable:
19 |
20 | def test_copy(self):
21 | a = SerializableDummy(42)
22 | assert a.i == 42
23 | b = a.copy()
24 | assert b.i == 42
25 |
26 | a.set_state(1)
27 | assert a.i == 1
28 | assert b.i == 42
29 |
--------------------------------------------------------------------------------
/test/mitmproxy/test_web_app.py:
--------------------------------------------------------------------------------
1 | import tornado.testing
2 |
3 | from mitmproxy import proxy
4 | from mitmproxy.tools.web import app
5 | from mitmproxy.tools.web import master as webmaster
6 |
7 |
8 | class TestApp(tornado.testing.AsyncHTTPTestCase):
9 | def get_app(self):
10 | o = webmaster.Options()
11 | m = webmaster.WebMaster(o, proxy.DummyServer())
12 | return app.Application(m, None, None)
13 |
14 | def test_index(self):
15 | assert self.fetch("/").code == 200
16 |
17 | def test_filter_help(self):
18 | assert self.fetch("/filter-help").code == 200
19 |
20 | def test_events(self):
21 | assert self.fetch("/events").code == 200
22 |
23 | def test_flows(self):
24 | assert self.fetch("/flows").code == 200
25 |
--------------------------------------------------------------------------------
/test/mitmproxy/test_web_master.py:
--------------------------------------------------------------------------------
1 | from mitmproxy.tools.web import master
2 | from mitmproxy import proxy
3 | from . import mastertest
4 |
5 |
6 | class TestWebMaster(mastertest.MasterTest):
7 | def mkmaster(self, **options):
8 | o = master.Options(**options)
9 | return master.WebMaster(o, proxy.DummyServer(o))
10 |
11 | def test_basic(self):
12 | m = self.mkmaster()
13 | for i in (1, 2, 3):
14 | self.dummy_cycle(m, 1, b"")
15 | assert len(m.state.flows) == i
16 |
--------------------------------------------------------------------------------
/test/mitmproxy/tools/ab.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/tools/ab.exe
--------------------------------------------------------------------------------
/test/mitmproxy/tools/bench.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import time
3 |
4 | n = 100
5 | url = "http://192.168.1.1/"
6 | proxy = "http://192.168.1.115:8080/"
7 |
8 | start = time.time()
9 | for _ in range(n):
10 | requests.get(url, allow_redirects=False, proxies=dict(http=proxy))
11 | print(".", end="")
12 | t_mitmproxy = time.time() - start
13 |
14 | print("\r\nTotal time with mitmproxy: {}".format(t_mitmproxy))
15 |
16 |
17 | start = time.time()
18 | for _ in range(n):
19 | requests.get(url, allow_redirects=False)
20 | print(".", end="")
21 | t_without = time.time() - start
22 |
23 | print("\r\nTotal time without mitmproxy: {}".format(t_without))
24 |
--------------------------------------------------------------------------------
/test/mitmproxy/tools/getcert:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import sys
3 | sys.path.insert(0, "../..")
4 | import socket
5 | import tempfile
6 | import ssl
7 | import subprocess
8 |
9 | addr = socket.gethostbyname(sys.argv[1])
10 | print(ssl.get_server_certificate((addr, 443)))
11 |
--------------------------------------------------------------------------------
/test/mitmproxy/tools/inspect_dumpfile.py:
--------------------------------------------------------------------------------
1 | from pprint import pprint
2 |
3 | import click
4 |
5 | from mitmproxy import tnetstring
6 |
7 |
8 | def read_tnetstring(input):
9 | # tnetstring throw a ValueError on EOF, which is hard to catch
10 | # because they raise ValueErrors for a couple of other reasons.
11 | # Check for EOF to avoid this.
12 | if not input.read(1):
13 | return None
14 | else:
15 | input.seek(-1, 1)
16 | return tnetstring.load(input)
17 |
18 |
19 | @click.command()
20 | @click.argument("input", type=click.File('rb'))
21 | def inspect(input):
22 | """
23 | pretty-print a dumpfile
24 | """
25 | while True:
26 | data = read_tnetstring(input)
27 | if not data:
28 | break
29 | pprint(data)
30 |
31 |
32 | if __name__ == "__main__":
33 | inspect()
34 |
--------------------------------------------------------------------------------
/test/mitmproxy/tools/memoryleak.py:
--------------------------------------------------------------------------------
1 | import gc
2 | import threading
3 | from pympler import muppy, refbrowser
4 | from OpenSSL import SSL
5 | # import os
6 | # os.environ["TK_LIBRARY"] = r"C:\Python27\tcl\tcl8.5"
7 | # os.environ["TCL_LIBRARY"] = r"C:\Python27\tcl\tcl8.5"
8 |
9 | # Also noteworthy: guppy, objgraph
10 |
11 | step = 0
12 | __memory_locals__ = True
13 |
14 |
15 | def str_fun(obj):
16 | if isinstance(obj, dict):
17 | if "__memory_locals__" in obj:
18 | return "(-locals-)"
19 | if "self" in obj and isinstance(obj["self"], refbrowser.InteractiveBrowser):
20 | return "(-browser-)"
21 | return str(id(obj)) + ": " + str(obj)[:100].replace("\r\n", "\\r\\n").replace("\n", "\\n")
22 |
23 |
24 | def request(ctx, flow):
25 | global step, ssl
26 | print("==========")
27 | print("GC: {}".format(gc.collect()))
28 | print("Threads: {}".format(threading.active_count()))
29 |
30 | step += 1
31 | if step == 1:
32 | all_objects = muppy.get_objects()
33 | ssl = muppy.filter(all_objects, SSL.Connection)[0]
34 | if step == 2:
35 | ib = refbrowser.InteractiveBrowser(ssl, 2, str_fun, repeat=False)
36 | del ssl # do this to unpollute view
37 | ib.main(True)
38 | # print("\r\n".join(str(x)[:100] for x in gc.get_referrers(ssl)))
39 |
--------------------------------------------------------------------------------
/test/mitmproxy/tools/passive_close.py:
--------------------------------------------------------------------------------
1 | import socketserver
2 | from time import sleep
3 |
4 |
5 | class service(socketserver.BaseRequestHandler):
6 |
7 | def handle(self):
8 | data = 'dummy'
9 | print("Client connected with ", self.client_address)
10 | while True:
11 | self.request.send(
12 | "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 7\r\n\r\ncontent")
13 | data = self.request.recv(1024)
14 | if not len(data):
15 | print("Connection closed by remote: ", self.client_address)
16 | sleep(3600)
17 |
18 |
19 | class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
20 | pass
21 |
22 | server = ThreadedTCPServer(('', 1520), service)
23 | server.serve_forever()
24 |
--------------------------------------------------------------------------------
/test/mitmproxy/tools/testpatt:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Generate a test pattern with pathoc
4 | PATHOD=localhost:9999
5 | pathoc -s -c $PATHOD localhost:8080 "get:'/p/200:p0,1:b@2048b':b@2048b"
6 | pathoc -s -c $PATHOD localhost:8080 "get:'/p/300:p0,1:b@2048b':b@2048b"
7 | pathoc -s -c $PATHOD localhost:8080 "get:'/p/400:p0,1:b@2048b':b@2048b"
8 | pathoc -s -c $PATHOD localhost:8080 "get:'/p/500:p0,1:b@2048b':b@2048b"
9 | pathoc -s -c $PATHOD localhost:8080 "get:'/p/600:p0,1:b@2048b':b@2048b"
10 |
--------------------------------------------------------------------------------
/test/mitmproxy/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/mitmproxy/utils/__init__.py
--------------------------------------------------------------------------------
/test/mitmproxy/utils/test_data.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from mitmproxy.utils import data
3 |
4 |
5 | def test_pkg_data():
6 | assert data.pkg_data.path("tools/console")
7 | with pytest.raises(ValueError):
8 | data.pkg_data.path("nonexistent")
9 |
--------------------------------------------------------------------------------
/test/mitmproxy/utils/test_debug.py:
--------------------------------------------------------------------------------
1 | import io
2 |
3 | from mitmproxy.utils import debug
4 |
5 |
6 | def test_dump_info():
7 | cs = io.StringIO()
8 | debug.dump_info(None, None, file=cs, testing=True)
9 | assert cs.getvalue()
10 |
11 |
12 | def test_dump_stacks():
13 | cs = io.StringIO()
14 | debug.dump_stacks(None, None, file=cs, testing=True)
15 | assert cs.getvalue()
16 |
17 |
18 | def test_sysinfo():
19 | assert debug.sysinfo()
20 |
21 |
22 | def test_register_info_dumpers():
23 | debug.register_info_dumpers()
24 |
--------------------------------------------------------------------------------
/test/mitmproxy/utils/test_version_check.py:
--------------------------------------------------------------------------------
1 | import io
2 | import mock
3 | from mitmproxy.utils import version_check
4 |
5 |
6 | @mock.patch("sys.exit")
7 | def test_check_pyopenssl_version(sexit):
8 | fp = io.StringIO()
9 | version_check.check_pyopenssl_version(fp=fp)
10 | assert not fp.getvalue()
11 | assert not sexit.called
12 |
13 | version_check.check_pyopenssl_version((9999,), fp=fp)
14 | assert "outdated" in fp.getvalue()
15 | assert sexit.called
16 |
17 |
18 | @mock.patch("sys.exit")
19 | @mock.patch("OpenSSL.__version__")
20 | def test_unparseable_pyopenssl_version(version, sexit):
21 | version.split.return_value = ["foo", "bar"]
22 | fp = io.StringIO()
23 | version_check.check_pyopenssl_version(fp=fp)
24 | assert "Cannot parse" in fp.getvalue()
25 | assert not sexit.called
26 |
--------------------------------------------------------------------------------
/test/pathod/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/test/pathod/__init__.py
--------------------------------------------------------------------------------
/test/pathod/data/clientcert/.gitignore:
--------------------------------------------------------------------------------
1 | client.crt
2 | client.key
3 | client.req
4 |
--------------------------------------------------------------------------------
/test/pathod/data/clientcert/client.cnf:
--------------------------------------------------------------------------------
1 | [ ssl_client ]
2 | basicConstraints = CA:FALSE
3 | nsCertType = client
4 | keyUsage = digitalSignature, keyEncipherment
5 | extendedKeyUsage = clientAuth
6 |
--------------------------------------------------------------------------------
/test/pathod/data/clientcert/make:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | openssl genrsa -out client.key 2048
4 | openssl req -key client.key -new -out client.req
5 | openssl x509 -req -days 365 -in client.req -signkey client.key -out client.crt -extfile client.cnf -extensions ssl_client
6 | openssl x509 -req -days 1000 -in client.req -CA ~/.mitmproxy/mitmproxy-ca.pem -CAkey ~/.mitmproxy/mitmproxy-ca.pem -set_serial 00001 -out client.crt -extensions ssl_client
7 | cat client.key client.crt > client.pem
8 | openssl x509 -text -noout -in client.pem
9 |
--------------------------------------------------------------------------------
/test/pathod/data/file:
--------------------------------------------------------------------------------
1 | testfile
2 |
--------------------------------------------------------------------------------
/test/pathod/data/request:
--------------------------------------------------------------------------------
1 | get:/foo
2 |
--------------------------------------------------------------------------------
/test/pathod/data/response:
--------------------------------------------------------------------------------
1 | 202
2 |
--------------------------------------------------------------------------------
/test/pathod/scripts/generate.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ ! -f ./private.key ]
4 | then
5 | openssl genrsa -out private.key 3072
6 | fi
7 | openssl req \
8 | -batch \
9 | -new -x509 \
10 | -key private.key \
11 | -sha256 \
12 | -out cert.pem \
13 | -days 9999 \
14 | -config ./openssl.cnf
15 | openssl x509 -in cert.pem -text -noout
16 | cat ./private.key ./cert.pem > testcert.pem
17 | rm ./private.key ./cert.pem
18 |
--------------------------------------------------------------------------------
/test/pathod/scripts/openssl.cnf:
--------------------------------------------------------------------------------
1 | [ req ]
2 | default_bits = 1024
3 | default_keyfile = privkey.pem
4 | distinguished_name = req_distinguished_name
5 | x509_extensions = v3_ca
6 |
7 | [ req_distinguished_name ]
8 | countryName = Country Name (2 letter code)
9 | countryName_default = NZ
10 | countryName_min = 2
11 | countryName_max = 2
12 | stateOrProvinceName = State or Province Name (full name)
13 | stateOrProvinceName_default = Otago
14 | localityName = Locality Name (eg, city)
15 | 0.organizationName = Organization Name (eg, company)
16 | 0.organizationName_default = Pathod
17 | commonName = Common Name (e.g. server FQDN or YOUR name)
18 | commonName_default = test.com
19 | commonName_max = 64
20 |
21 | [ v3_req ]
22 |
23 | basicConstraints = CA:FALSE
24 | keyUsage = nonRepudiation, digitalSignature, keyEncipherment
25 |
26 | [ v3_ca ]
27 |
28 | keyUsage = digitalSignature, keyEncipherment
29 | subjectKeyIdentifier=hash
30 | authorityKeyIdentifier=keyid:always,issuer:always
31 | basicConstraints = CA:true
32 | subjectAltName = @alternate_names
33 |
34 |
35 | [ alternate_names ]
36 |
37 | DNS.1 = test.com
38 | DNS.2 = test2.com
39 | DNS.3 = test3.com
40 |
--------------------------------------------------------------------------------
/test/pathod/test_log.py:
--------------------------------------------------------------------------------
1 | import io
2 |
3 | from pathod import log
4 | from mitmproxy import exceptions
5 |
6 |
7 | class DummyIO(io.StringIO):
8 |
9 | def start_log(self, *args, **kwargs):
10 | pass
11 |
12 | def get_log(self, *args, **kwargs):
13 | return ""
14 |
15 |
16 | def test_disconnect():
17 | outf = DummyIO()
18 | rw = DummyIO()
19 | l = log.ConnectionLogger(outf, False, True, rw, rw)
20 | try:
21 | with l.ctx() as lg:
22 | lg("Test")
23 | except exceptions.TcpDisconnect:
24 | pass
25 | assert "Test" in outf.getvalue()
26 |
--------------------------------------------------------------------------------
/test/pathod/test_utils.py:
--------------------------------------------------------------------------------
1 | from pathod import utils
2 |
3 | from . import tutils
4 |
5 |
6 | def test_membool():
7 | m = utils.MemBool()
8 | assert not m.v
9 | assert m(1)
10 | assert m.v == 1
11 | assert m(2)
12 | assert m.v == 2
13 |
14 |
15 | def test_data_path():
16 | tutils.raises(ValueError, utils.data.path, "nonexistent")
17 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py35, docs, lint
3 | skipsdist = True
4 | toxworkdir={env:TOX_WORK_DIR:.tox}
5 |
6 | [testenv]
7 | deps =
8 | {env:CI_DEPS:}
9 | -rrequirements.txt
10 | passenv = CODECOV_TOKEN CI CI_* TRAVIS TRAVIS_* APPVEYOR APPVEYOR_*
11 | setenv = HOME = {envtmpdir}
12 | commands =
13 | py.test --timeout 60 {posargs}
14 | {env:CI_COMMANDS:python -c ""}
15 |
16 | [testenv:docs]
17 | changedir = docs
18 | commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
19 |
20 | [testenv:lint]
21 | commands =
22 | flake8 --jobs 8 --count mitmproxy pathod examples test
23 | rstcheck README.rst
24 | mypy -s ./mitmproxy/addonmanager.py
25 |
--------------------------------------------------------------------------------
/web/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react"],
3 | "plugins": ["transform-class-properties", "transform-object-rest-spread"]
4 | }
--------------------------------------------------------------------------------
/web/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | indent_style = space
3 | indent_size = 4
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 | end_of_line = lf
7 |
--------------------------------------------------------------------------------
/web/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint"
3 | }
--------------------------------------------------------------------------------
/web/README:
--------------------------------------------------------------------------------
1 |
2 | Starting up
3 |
4 | - npm install
5 | - gulp
6 | - run mitmweb and open http://localhost:8081/
7 |
--------------------------------------------------------------------------------
/web/conf.js:
--------------------------------------------------------------------------------
1 |
2 | var conf = {
3 | src: "src/",
4 | dist: "../mitmproxy/web",
5 | static: "../mitmproxy/web/static",
6 | js: {
7 | // Don't package these in the vendor distribution
8 | vendor_excludes: [
9 | "bootstrap" // We only use Bootstrap's CSS.
10 | ],
11 | // Package these as well as the dependencies
12 | vendor_includes: [
13 | ],
14 | app: 'src/js/app',
15 | eslint: ["src/js/**/*.js", "!src/js/filt/filt.js"]
16 | },
17 | css: {
18 | vendor: ["src/css/vendor.less"],
19 | app: ["src/css/app.less"]
20 | },
21 | copy: [
22 | "src/images/**", "src/fonts/fontawesome-webfont.*"
23 | ],
24 | templates: [
25 | "src/templates/*"
26 | ],
27 | peg: ["src/js/filt/filt.peg"]
28 | };
29 |
30 | module.exports = conf;
31 |
--------------------------------------------------------------------------------
/web/src/css/app.less:
--------------------------------------------------------------------------------
1 | // www.paulirish.com/2012/box-sizing-border-box-ftw/
2 | html {
3 | box-sizing: border-box;
4 | }
5 |
6 | *, *:before, *:after {
7 | box-sizing: inherit;
8 | }
9 |
10 | @import (less) "sprites.less";
11 | @import (less) "layout.less";
12 | @import (less) "tabs.less";
13 | @import (less) "header.less";
14 | @import (less) "flowtable.less";
15 | @import (less) "flowdetail.less";
16 | @import (less) "flowview.less";
17 | @import (less) "prompt.less";
18 | @import (less) "eventlog.less";
19 | @import (less) "footer.less";
20 | @import (less) "codemirror.less";
21 | @import (less) "contentview.less";
22 |
--------------------------------------------------------------------------------
/web/src/css/codemirror.less:
--------------------------------------------------------------------------------
1 | .CodeMirror {
2 | border: 1px solid #ccc;
3 | height: auto !important;
4 | max-height: 2048px !important;
5 | }
6 |
7 | @import (inline) "../../node_modules/codemirror/lib/codemirror.css";
8 |
--------------------------------------------------------------------------------
/web/src/css/contentview.less:
--------------------------------------------------------------------------------
1 | .contentview {
2 | .header {
3 | font-weight: bold;
4 | }
5 | .highlight{
6 | font-weight: bold;
7 | }
8 | .offset{
9 | color: blue
10 | }
11 | .text{
12 |
13 | }
14 | .codeeditor{
15 | margin-bottom: 12px;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/css/dropdown.less:
--------------------------------------------------------------------------------
1 | hr.divider {
2 | margin-top: 5px;
3 | margin-bottom: 5px;
4 | }
5 |
--------------------------------------------------------------------------------
/web/src/css/eventlog.less:
--------------------------------------------------------------------------------
1 | .eventlog {
2 |
3 | height: 200px;
4 | flex: 0 0 auto;
5 |
6 | display: flex;
7 | flex-direction: column;
8 |
9 | > div {
10 | background-color: #F2F2F2;
11 | padding: 0 5px;
12 | flex: 0 0 auto;
13 | border-top: 1px solid #aaa;
14 | cursor: row-resize;
15 | }
16 |
17 | > pre {
18 | flex: 1 1 auto;
19 |
20 | margin: 0;
21 | border-radius: 0;
22 | overflow-x: auto;
23 | overflow-y: scroll;
24 | background-color: #fcfcfc;
25 | }
26 |
27 | .fa-close {
28 | cursor: pointer;
29 | float: right;
30 | color: grey;
31 | padding: 3px 0;
32 | padding-left: 10px;
33 | &:hover {
34 | color: black;
35 | }
36 | }
37 |
38 | .btn-toggle {
39 | margin-top: -2px;
40 | margin-left: 3px;
41 | padding: 2px 2px;
42 | font-size: 10px;
43 | line-height: 10px;
44 | border-radius: 2px;
45 | }
46 | .label {
47 | cursor: pointer;
48 | vertical-align: middle;
49 | display: inline-block;
50 | margin-top: -2px;
51 | margin-left: 3px;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/web/src/css/flowview.less:
--------------------------------------------------------------------------------
1 | .flowview-image {
2 |
3 | text-align: center;
4 |
5 | img {
6 | max-width: 100%;
7 | max-height: 100%;
8 | }
9 | }
10 |
11 | .edit-flow-container {
12 | position: relative;
13 | }
14 |
15 | .edit-flow {
16 | cursor: pointer;
17 | position: absolute;
18 | right: 0;
19 | top: 5px;
20 | height: 40px;
21 | width: 40px;
22 | border-radius: 20px;
23 | z-index: 10000;
24 |
25 | background-color: rgba(255, 255, 255, 0.7);
26 | border: solid 2px rgba(248, 145, 59, 0.7);
27 |
28 | text-align: center;
29 | font-size: 22px;
30 | line-height: 37px;
31 |
32 | transition: all 100ms ease-in-out;
33 | }
34 |
35 | .edit-flow:hover {
36 | background-color: rgba(239, 108, 0, 0.7);
37 | color: rgba(0,0,0,0.8);
38 | border: solid 2px transparent;
39 | }
40 |
--------------------------------------------------------------------------------
/web/src/css/footer.less:
--------------------------------------------------------------------------------
1 | footer {
2 | box-shadow: 0 -1px 3px lightgray;
3 | padding: 0px 10px 3px;
4 |
5 | .label {
6 | margin-right: 3px;
7 | }
8 | }
--------------------------------------------------------------------------------
/web/src/css/header.less:
--------------------------------------------------------------------------------
1 | @import (reference) '../../node_modules/bootstrap/less/variables.less';
2 | @import (reference) '../../node_modules/bootstrap/less/mixins/grid.less';
3 |
4 | header {
5 | padding-top: 0.5em;
6 | background-color: white;
7 | @separator-color: lighten(grey, 15%);
8 | .menu {
9 | padding: 10px;
10 | border-bottom: solid @separator-color 1px;
11 | }
12 | }
13 |
14 | @menu-row-gutter-width: 5px;
15 | .menu-row {
16 | .make-row(@menu-row-gutter-width);
17 | }
18 |
19 | .filter-input {
20 | .make-sm-column(3, @menu-row-gutter-width);
21 | margin-bottom:5px;
22 | }
23 |
24 | .filter-input .popover {
25 | top: 27px;
26 | display: block;
27 | max-width: none;
28 | opacity: 0.9;
29 |
30 | .popover-content {
31 | max-height: 500px;
32 | overflow-y: auto;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/web/src/css/prompt.less:
--------------------------------------------------------------------------------
1 | .prompt-dialog {
2 | top: 0;
3 | bottom: 0;
4 | left: 0;
5 | right: 0;
6 | position: fixed;
7 | z-index: 100;
8 | background-color: rgba(0, 0, 0, 0.1);
9 | }
10 |
11 | .prompt-content {
12 | position: fixed;
13 | bottom: 0;
14 | left: 0;
15 | right: 0;
16 | height: 25px;
17 | padding: 2px 5px;
18 | background-color: white;
19 | box-shadow: 0 -1px 3px lightgray;
20 |
21 | .option {
22 | cursor: pointer;
23 | &:not(:last-child)::after {
24 | content: ", ";
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/web/src/css/sprites.less:
--------------------------------------------------------------------------------
1 | .resource-icon {
2 | width: 32px;
3 | height: 32px;
4 | }
5 |
6 | // From Chrome Dev Tools
7 | .resource-icon-css {
8 | background-image: url(images/chrome-devtools/resourceCSSIcon.png);
9 | }
10 |
11 | .resource-icon-document {
12 | background-image: url(images/chrome-devtools/resourceDocumentIcon.png);
13 | }
14 |
15 | .resource-icon-js {
16 | background-image: url(images/chrome-devtools/resourceJSIcon.png);
17 | }
18 |
19 | .resource-icon-plain {
20 | background-image: url(images/chrome-devtools/resourcePlainIcon.png);
21 | }
22 |
23 | // Own
24 | .resource-icon-executable {
25 | background-image: url(images/resourceExecutableIcon.png);
26 | }
27 |
28 | .resource-icon-flash {
29 | background-image: url(images/resourceFlashIcon.png);
30 | }
31 |
32 | .resource-icon-image {
33 | background-image: url(images/resourceImageIcon.png);
34 | }
35 |
36 | .resource-icon-java {
37 | background-image: url(images/resourceJavaIcon.png);
38 | }
39 |
40 | .resource-icon-not-modified {
41 | background-image: url(images/resourceNotModifiedIcon.png);
42 | }
43 |
44 | .resource-icon-redirect {
45 | background-image: url(images/resourceRedirectIcon.png);
46 | }
--------------------------------------------------------------------------------
/web/src/css/tabs.less:
--------------------------------------------------------------------------------
1 | .nav-tabs {
2 |
3 | @separator-color: lighten(grey, 15%);
4 |
5 | border-bottom: solid @separator-color 1px;
6 |
7 | a {
8 | display: inline-block;
9 | border: solid transparent 1px;
10 | text-decoration: none;
11 | //text-transform: uppercase;
12 | //font-family: Lato;
13 |
14 | &.active {
15 | background-color: white;
16 | border-color: @separator-color;
17 | border-bottom-color: white;
18 | }
19 | &.special {
20 | @special-color: #396cad;
21 | color: white;
22 | background-color: @special-color;
23 | border-bottom-color: @special-color;
24 | &:hover {
25 | background-color: lighten(@special-color, 10%);
26 | }
27 | }
28 | }
29 |
30 | }
31 |
32 | .nav-tabs-lg {
33 | a {
34 | padding: 3px 14px;
35 | margin: 0 2px -1px;
36 | }
37 | }
38 |
39 | .nav-tabs-sm {
40 | a {
41 | padding: 0px 7px;
42 | margin: 2px 2px -1px;
43 | }
44 | a.nav-action {
45 | float: right;
46 | padding: 0;
47 | margin: 1px 0 0px;
48 | }
49 | }
--------------------------------------------------------------------------------
/web/src/css/vendor-bootstrap-variables.less:
--------------------------------------------------------------------------------
1 | @navbar-height: 32px;
2 | @navbar-default-link-color: #303030;
3 | @navbar-default-color: #303030;
4 | @navbar-default-bg: #ffffff;
5 | @navbar-default-border: #e0e0e0;
6 |
--------------------------------------------------------------------------------
/web/src/css/vendor.less:
--------------------------------------------------------------------------------
1 | // Bootstrap
2 | @import 'vendor-bootstrap.less';
3 | @import (less) '../fonts/font-awesome.css';
4 |
--------------------------------------------------------------------------------
/web/src/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/web/src/fonts/README:
--------------------------------------------------------------------------------
1 |
2 | From a rendered version of the FontAwesome github repo.
3 |
--------------------------------------------------------------------------------
/web/src/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/web/src/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/web/src/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/web/src/images/chrome-devtools/resourceCSSIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/chrome-devtools/resourceCSSIcon.png
--------------------------------------------------------------------------------
/web/src/images/chrome-devtools/resourceDocumentIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/chrome-devtools/resourceDocumentIcon.png
--------------------------------------------------------------------------------
/web/src/images/chrome-devtools/resourceJSIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/chrome-devtools/resourceJSIcon.png
--------------------------------------------------------------------------------
/web/src/images/chrome-devtools/resourcePlainIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/chrome-devtools/resourcePlainIcon.png
--------------------------------------------------------------------------------
/web/src/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/favicon.ico
--------------------------------------------------------------------------------
/web/src/images/resourceExecutableIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/resourceExecutableIcon.png
--------------------------------------------------------------------------------
/web/src/images/resourceFlashIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/resourceFlashIcon.png
--------------------------------------------------------------------------------
/web/src/images/resourceImageIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/resourceImageIcon.png
--------------------------------------------------------------------------------
/web/src/images/resourceJavaIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/resourceJavaIcon.png
--------------------------------------------------------------------------------
/web/src/images/resourceNotModifiedIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/resourceNotModifiedIcon.png
--------------------------------------------------------------------------------
/web/src/images/resourceRedirectIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openai/mitmproxy/11d266419c29ca26a4671f8170b0c36c32036389/web/src/images/resourceRedirectIcon.png
--------------------------------------------------------------------------------
/web/src/js/__tests__/ducks/flowsSpec.js:
--------------------------------------------------------------------------------
1 | jest.unmock('../../ducks/flows');
2 |
3 | import reduceFlows, * as flowActions from '../../ducks/flows'
4 |
5 |
6 | describe('select flow', () => {
7 |
8 | let state = reduceFlows(undefined, {})
9 | for (let i of [1, 2, 3, 4]) {
10 | state = reduceFlows(state, flowActions.addFlow({ id: i }))
11 | }
12 |
13 | it('should be possible to select a single flow', () => {
14 | expect(reduceFlows(state, flowActions.select(2))).toEqual(
15 | {
16 | ...state,
17 | selected: [2],
18 | }
19 | )
20 | })
21 |
22 | it('should be possible to deselect a flow', () => {
23 | expect(reduceFlows({ ...state, selected: [1] }, flowActions.select())).toEqual(
24 | {
25 | ...state,
26 | selected: [],
27 | }
28 | )
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/web/src/js/__tests__/ducks/tutils.js:
--------------------------------------------------------------------------------
1 | jest.unmock('redux')
2 | jest.unmock('redux-thunk')
3 |
4 | import { combineReducers, applyMiddleware, createStore as createReduxStore } from 'redux'
5 | import thunk from 'redux-thunk'
6 |
7 | export function createStore(parts) {
8 | return createReduxStore(
9 | combineReducers(parts),
10 | applyMiddleware(...[thunk])
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/web/src/js/actions.js:
--------------------------------------------------------------------------------
1 | import {AppDispatcher} from "./dispatcher.js";
2 |
3 | export var ActionTypes = {
4 | // Connection
5 | CONNECTION_OPEN: "connection_open",
6 | CONNECTION_CLOSE: "connection_close",
7 | CONNECTION_ERROR: "connection_error",
8 |
9 | // Stores
10 | SETTINGS_STORE: "settings",
11 | EVENT_STORE: "events",
12 | FLOW_STORE: "flows"
13 | };
14 |
15 | export var StoreCmds = {
16 | ADD: "add",
17 | UPDATE: "update",
18 | REMOVE: "remove",
19 | RESET: "reset"
20 | };
21 |
22 | export var ConnectionActions = {
23 | open: function () {
24 | AppDispatcher.dispatchViewAction({
25 | type: ActionTypes.CONNECTION_OPEN
26 | });
27 | },
28 | close: function () {
29 | AppDispatcher.dispatchViewAction({
30 | type: ActionTypes.CONNECTION_CLOSE
31 | });
32 | },
33 | error: function () {
34 | AppDispatcher.dispatchViewAction({
35 | type: ActionTypes.CONNECTION_ERROR
36 | });
37 | }
38 | };
39 |
40 | export var Query = {
41 | SEARCH: "s",
42 | HIGHLIGHT: "h",
43 | SHOW_EVENTLOG: "e"
44 | };
45 |
--------------------------------------------------------------------------------
/web/src/js/app.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { render } from 'react-dom'
3 | import { applyMiddleware, createStore } from 'redux'
4 | import { Provider } from 'react-redux'
5 | import thunk from 'redux-thunk'
6 |
7 | import ProxyApp from './components/ProxyApp'
8 | import rootReducer from './ducks/index'
9 | import { add as addLog } from './ducks/eventLog'
10 |
11 | const middlewares = [thunk];
12 |
13 | if (process.env.NODE_ENV !== 'production') {
14 | const createLogger = require('redux-logger');
15 | middlewares.push(createLogger());
16 | }
17 |
18 | // logger must be last
19 | const store = createStore(
20 | rootReducer,
21 | applyMiddleware(...middlewares)
22 | )
23 |
24 | // @todo move to ProxyApp
25 | window.addEventListener('error', msg => {
26 | store.dispatch(addLog(msg))
27 | })
28 |
29 | // @todo remove this
30 | document.addEventListener('DOMContentLoaded', () => {
31 | render(
32 |
33 |
34 | ,
35 | document.getElementById("mitmproxy")
36 | )
37 | })
38 |
--------------------------------------------------------------------------------
/web/src/js/components/ContentView/CodeEditor.jsx:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react'
2 | import Codemirror from 'react-codemirror';
3 |
4 |
5 | CodeEditor.propTypes = {
6 | content: PropTypes.string.isRequired,
7 | onChange: PropTypes.func.isRequired,
8 | }
9 |
10 | export default function CodeEditor ( { content, onChange} ){
11 |
12 | let options = {
13 | lineNumbers: true
14 | };
15 | return (
16 | e.stopPropagation()}>
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/web/src/js/components/ContentView/ContentViewOptions.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 | import { connect } from 'react-redux'
3 | import ViewSelector from './ViewSelector'
4 | import UploadContentButton from './UploadContentButton'
5 | import DownloadContentButton from './DownloadContentButton'
6 |
7 | ContentViewOptions.propTypes = {
8 | flow: React.PropTypes.object.isRequired,
9 | message: React.PropTypes.object.isRequired,
10 | }
11 |
12 | function ContentViewOptions(props) {
13 | const { flow, message, uploadContent, readonly, contentViewDescription } = props
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {contentViewDescription}
23 |
24 | )
25 | }
26 |
27 | export default connect(
28 | state => ({
29 | contentViewDescription: state.ui.flow.viewDescription
30 | })
31 | )(ContentViewOptions)
32 |
--------------------------------------------------------------------------------
/web/src/js/components/ContentView/DownloadContentButton.jsx:
--------------------------------------------------------------------------------
1 | import { MessageUtils } from "../../flow/utils"
2 | import { PropTypes } from 'react'
3 |
4 | DownloadContentButton.propTypes = {
5 | flow: PropTypes.object.isRequired,
6 | message: PropTypes.object.isRequired,
7 | }
8 |
9 | export default function DownloadContentButton({ flow, message }) {
10 |
11 | return (
12 |
15 |
16 |
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/js/components/ContentView/ShowFullContentButton.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react'
2 | import { connect } from 'react-redux'
3 | import { render } from 'react-dom';
4 | import Button from '../common/Button';
5 | import { setShowFullContent } from '../../ducks/ui/flow'
6 |
7 |
8 |
9 | ShowFullContentButton.propTypes = {
10 | setShowFullContent: PropTypes.func.isRequired,
11 | showFullContent: PropTypes.bool.isRequired
12 | }
13 |
14 | function ShowFullContentButton ( {setShowFullContent, showFullContent, visibleLines, contentLines} ){
15 |
16 | return (
17 | !showFullContent &&
18 |
19 | setShowFullContent()} text="Show full content"/>
20 | {visibleLines}/{contentLines} are visible
21 |
22 | )
23 | }
24 |
25 | export default connect(
26 | state => ({
27 | showFullContent: state.ui.flow.showFullContent,
28 | visibleLines: state.ui.flow.maxContentLines,
29 | contentLines: state.ui.flow.content.length
30 |
31 | }),
32 | {
33 | setShowFullContent
34 | }
35 | )(ShowFullContentButton)
36 |
37 |
--------------------------------------------------------------------------------
/web/src/js/components/ContentView/UploadContentButton.jsx:
--------------------------------------------------------------------------------
1 | import { PropTypes } from 'react'
2 | import FileChooser from '../common/FileChooser'
3 |
4 | UploadContentButton.propTypes = {
5 | uploadContent: PropTypes.func.isRequired,
6 | }
7 |
8 | export default function UploadContentButton({ uploadContent }) {
9 |
10 | return (
11 |
16 | )
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/web/src/js/components/FlowTable/FlowRow.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 | import classnames from 'classnames'
3 | import columns from './FlowColumns'
4 | import { pure } from '../../utils'
5 |
6 | FlowRow.propTypes = {
7 | onSelect: PropTypes.func.isRequired,
8 | flow: PropTypes.object.isRequired,
9 | highlighted: PropTypes.bool,
10 | selected: PropTypes.bool,
11 | }
12 |
13 | function FlowRow({ flow, selected, highlighted, onSelect }) {
14 | const className = classnames({
15 | 'selected': selected,
16 | 'highlighted': highlighted,
17 | 'intercepted': flow.intercepted,
18 | 'has-request': flow.request,
19 | 'has-response': flow.response,
20 | })
21 |
22 | return (
23 | onSelect(flow.id)}>
24 | {columns.map(Column => (
25 |
26 | ))}
27 |
28 | )
29 | }
30 |
31 | export default pure(FlowRow)
32 |
--------------------------------------------------------------------------------
/web/src/js/components/FlowTable/FlowTableHead.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 | import { connect } from 'react-redux'
3 | import classnames from 'classnames'
4 | import columns from './FlowColumns'
5 |
6 | import { updateSort } from '../../ducks/flowView'
7 |
8 | FlowTableHead.propTypes = {
9 | updateSort: PropTypes.func.isRequired,
10 | sortDesc: React.PropTypes.bool.isRequired,
11 | sortColumn: React.PropTypes.string,
12 | }
13 |
14 | function FlowTableHead({ sortColumn, sortDesc, updateSort }) {
15 | const sortType = sortDesc ? 'sort-desc' : 'sort-asc'
16 |
17 | return (
18 |
19 | {columns.map(Column => (
20 | updateSort(Column.name, Column.name !== sortColumn ? false : !sortDesc)}>
23 | {Column.headerName}
24 |
25 | ))}
26 |
27 | )
28 | }
29 |
30 | export default connect(
31 | state => ({
32 | sortDesc: state.flowView.sort.desc,
33 | sortColumn: state.flowView.sort.column,
34 | }),
35 | {
36 | updateSort
37 | }
38 | )(FlowTableHead)
39 |
--------------------------------------------------------------------------------
/web/src/js/components/Header/ViewMenu.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 | import { connect } from 'react-redux'
3 | import ToggleButton from '../common/ToggleButton'
4 | import { toggleVisibility } from '../../ducks/eventLog'
5 |
6 | ViewMenu.title = 'View'
7 | ViewMenu.route = 'flows'
8 |
9 | ViewMenu.propTypes = {
10 | eventLogVisible: PropTypes.bool.isRequired,
11 | toggleEventLog: PropTypes.func.isRequired,
12 | }
13 |
14 | function ViewMenu({ eventLogVisible, toggleEventLog }) {
15 | return (
16 |
22 | )
23 | }
24 |
25 | export default connect(
26 | state => ({
27 | eventLogVisible: state.eventLog.visible,
28 | }),
29 | {
30 | toggleEventLog: toggleVisibility,
31 | }
32 | )(ViewMenu)
33 |
--------------------------------------------------------------------------------
/web/src/js/components/common/Button.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 | import classnames from 'classnames'
3 |
4 | Button.propTypes = {
5 | onClick: PropTypes.func.isRequired,
6 | text: PropTypes.string,
7 | icon: PropTypes.string
8 | }
9 |
10 | export default function Button({ onClick, text, icon, disabled, className }) {
11 | return (
12 |
15 | {icon && ( )}
16 | {text && text}
17 |
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/web/src/js/components/common/FileChooser.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 |
3 | FileChooser.propTypes = {
4 | icon: PropTypes.string,
5 | text: PropTypes.string,
6 | className: PropTypes.string,
7 | title: PropTypes.string,
8 | onOpenFile: PropTypes.func.isRequired
9 | }
10 |
11 | export default function FileChooser({ icon, text, className, title, onOpenFile }) {
12 | let fileInput;
13 | return (
14 | fileInput.click()}
15 | className={className}
16 | title={title}>
17 |
18 | {text}
19 | fileInput = ref}
21 | className="hidden"
22 | type="file"
23 | onChange={e => { e.preventDefault(); if(e.target.files.length > 0) onOpenFile(e.target.files[0]); fileInput = "";}}
24 | />
25 |
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/web/src/js/components/common/ToggleButton.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react'
2 |
3 | ToggleButton.propTypes = {
4 | checked: PropTypes.bool.isRequired,
5 | onToggle: PropTypes.func.isRequired,
6 | text: PropTypes.string.isRequired
7 | }
8 |
9 | export default function ToggleButton({ checked, onToggle, text }) {
10 | return (
11 |
12 |
13 |
14 | {text}
15 |
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/js/components/helpers/AutoScroll.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 |
4 | const symShouldStick = Symbol("shouldStick");
5 | const isAtBottom = v => v.scrollTop + v.clientHeight === v.scrollHeight;
6 |
7 | export default Component => Object.assign(class AutoScrollWrapper extends Component {
8 |
9 | static displayName = Component.name;
10 |
11 | componentWillUpdate() {
12 | const viewport = ReactDOM.findDOMNode(this);
13 | this[symShouldStick] = viewport.scrollTop && isAtBottom(viewport);
14 | super.componentWillUpdate && super.componentWillUpdate();
15 | }
16 |
17 | componentDidUpdate() {
18 | const viewport = ReactDOM.findDOMNode(this);
19 | if (this[symShouldStick] && !isAtBottom(viewport)) {
20 | viewport.scrollTop = viewport.scrollHeight;
21 | }
22 | super.componentDidUpdate && super.componentDidUpdate();
23 | }
24 |
25 | }, Component);
26 |
--------------------------------------------------------------------------------
/web/src/js/dispatcher.js:
--------------------------------------------------------------------------------
1 |
2 | import flux from "flux";
3 |
4 | const PayloadSources = {
5 | VIEW: "view",
6 | SERVER: "server"
7 | };
8 |
9 |
10 | export var AppDispatcher = new flux.Dispatcher();
11 | AppDispatcher.dispatchViewAction = function (action) {
12 | action.source = PayloadSources.VIEW;
13 | this.dispatch(action);
14 | };
15 | AppDispatcher.dispatchServerAction = function (action) {
16 | action.source = PayloadSources.SERVER;
17 | this.dispatch(action);
18 | };
--------------------------------------------------------------------------------
/web/src/js/ducks/README.md:
--------------------------------------------------------------------------------
1 | https://github.com/erikras/ducks-modular-redux
--------------------------------------------------------------------------------
/web/src/js/ducks/app.js:
--------------------------------------------------------------------------------
1 | import { connect as wsConnect, disconnect as wsDisconnect } from './websocket'
2 |
3 | export const INIT = 'APP_INIT'
4 |
5 | const defaultState = {}
6 |
7 | export function reduce(state = defaultState, action) {
8 | switch (action.type) {
9 |
10 | default:
11 | return state
12 | }
13 | }
14 |
15 | export function init() {
16 | return dispatch => {
17 | dispatch(wsConnect())
18 | dispatch({ type: INIT })
19 | }
20 | }
21 |
22 | export function destruct() {
23 | return dispatch => {
24 | dispatch(wsDisconnect())
25 | dispatch({ type: DESTRUCT })
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/web/src/js/ducks/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux'
2 | import eventLog from './eventLog'
3 | import websocket from './websocket'
4 | import flows from './flows'
5 | import flowView from './flowView'
6 | import settings from './settings'
7 | import ui from './ui/index'
8 | import msgQueue from './msgQueue'
9 |
10 | export default combineReducers({
11 | eventLog,
12 | websocket,
13 | flows,
14 | flowView,
15 | settings,
16 | ui,
17 | msgQueue,
18 | })
19 |
--------------------------------------------------------------------------------
/web/src/js/ducks/ui/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux'
2 | import flow from './flow'
3 | import header from './header'
4 |
5 | export default combineReducers({
6 | flow,
7 | header,
8 | })
9 |
--------------------------------------------------------------------------------
/web/src/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | mitmproxy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------