aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2017-01-23 21:22:38 +0100
committerGitHub <noreply@github.com>2017-01-23 21:22:38 +0100
commit2eaac31344da93fa8c8e2d245d81193aa65db346 (patch)
tree98d2b794e107325e04944fec17a3fe30ccd69e95
parentc512f095aefd83e0fc977fe14ba20e641452dc21 (diff)
parent006eb39cc562ff3f8b741f9d022503081861827f (diff)
downloadmitmproxy-2eaac31344da93fa8c8e2d245d81193aa65db346.tar.gz
mitmproxy-2eaac31344da93fa8c8e2d245d81193aa65db346.tar.bz2
mitmproxy-2eaac31344da93fa8c8e2d245d81193aa65db346.zip
Merge pull request #1945 from Kriechi/ca-expired
fix #939
-rw-r--r--mitmproxy/addons/__init__.py28
-rw-r--r--mitmproxy/addons/check_alpn.py17
-rw-r--r--mitmproxy/addons/check_ca.py24
-rw-r--r--mitmproxy/addons/termlog.py4
-rw-r--r--mitmproxy/certs.py4
-rw-r--r--mitmproxy/tools/console/master.py12
-rw-r--r--mitmproxy/tools/dump.py18
-rw-r--r--test/mitmproxy/addons/test_check_alpn.py23
-rw-r--r--test/mitmproxy/addons/test_check_ca.py19
-rw-r--r--test/mitmproxy/test_tools_dump.py21
-rw-r--r--test/mitmproxy/test_web_master.py5
11 files changed, 133 insertions, 42 deletions
diff --git a/mitmproxy/addons/__init__.py b/mitmproxy/addons/__init__.py
index 8a2f2974..2e1d1c67 100644
--- a/mitmproxy/addons/__init__.py
+++ b/mitmproxy/addons/__init__.py
@@ -1,35 +1,39 @@
from mitmproxy.addons import anticache
from mitmproxy.addons import anticomp
+from mitmproxy.addons import check_alpn
+from mitmproxy.addons import check_ca
from mitmproxy.addons import clientplayback
-from mitmproxy.addons import streamfile
+from mitmproxy.addons import disable_h2c_upgrade
from mitmproxy.addons import onboarding
from mitmproxy.addons import proxyauth
from mitmproxy.addons import replace
from mitmproxy.addons import script
-from mitmproxy.addons import setheaders
from mitmproxy.addons import serverplayback
+from mitmproxy.addons import setheaders
from mitmproxy.addons import stickyauth
from mitmproxy.addons import stickycookie
from mitmproxy.addons import streambodies
+from mitmproxy.addons import streamfile
from mitmproxy.addons import upstream_auth
-from mitmproxy.addons import disable_h2c_upgrade
def default_addons():
return [
- onboarding.Onboarding(),
- proxyauth.ProxyAuth(),
anticache.AntiCache(),
anticomp.AntiComp(),
+ check_alpn.CheckALPN(),
+ check_ca.CheckCA(),
+ clientplayback.ClientPlayback(),
+ disable_h2c_upgrade.DisableH2CleartextUpgrade(),
+ onboarding.Onboarding(),
+ proxyauth.ProxyAuth(),
+ replace.Replace(),
+ script.ScriptLoader(),
+ serverplayback.ServerPlayback(),
+ setheaders.SetHeaders(),
stickyauth.StickyAuth(),
stickycookie.StickyCookie(),
- script.ScriptLoader(),
- streamfile.StreamFile(),
streambodies.StreamBodies(),
- replace.Replace(),
- setheaders.SetHeaders(),
- serverplayback.ServerPlayback(),
- clientplayback.ClientPlayback(),
+ streamfile.StreamFile(),
upstream_auth.UpstreamAuth(),
- disable_h2c_upgrade.DisableH2CleartextUpgrade(),
]
diff --git a/mitmproxy/addons/check_alpn.py b/mitmproxy/addons/check_alpn.py
new file mode 100644
index 00000000..c288d788
--- /dev/null
+++ b/mitmproxy/addons/check_alpn.py
@@ -0,0 +1,17 @@
+import mitmproxy
+from mitmproxy.net import tcp
+
+
+class CheckALPN:
+ def __init__(self):
+ self.failed = False
+
+ def configure(self, options, updated):
+ self.failed = mitmproxy.ctx.master.options.http2 and not tcp.HAS_ALPN
+ if self.failed:
+ mitmproxy.ctx.master.add_log(
+ "HTTP/2 is disabled because ALPN support missing!\n"
+ "OpenSSL 1.0.2+ required to support HTTP/2 connections.\n"
+ "Use --no-http2 to silence this warning.",
+ "warn",
+ )
diff --git a/mitmproxy/addons/check_ca.py b/mitmproxy/addons/check_ca.py
new file mode 100644
index 00000000..a83ab8e1
--- /dev/null
+++ b/mitmproxy/addons/check_ca.py
@@ -0,0 +1,24 @@
+import mitmproxy
+
+
+class CheckCA:
+ def __init__(self):
+ self.failed = False
+
+ def configure(self, options, updated):
+ has_ca = (
+ mitmproxy.ctx.master.server and
+ mitmproxy.ctx.master.server.config and
+ mitmproxy.ctx.master.server.config.certstore and
+ mitmproxy.ctx.master.server.config.certstore.default_ca
+ )
+ if has_ca:
+ self.failed = mitmproxy.ctx.master.server.config.certstore.default_ca.has_expired()
+ if self.failed:
+ mitmproxy.ctx.master.add_log(
+ "The mitmproxy certificate authority has expired!\n"
+ "Please delete all CA-related files in your ~/.mitmproxy folder.\n"
+ "The CA will be regenerated automatically after restarting mitmproxy.\n"
+ "Then make sure all your clients have the new CA installed.",
+ "warn",
+ )
diff --git a/mitmproxy/addons/termlog.py b/mitmproxy/addons/termlog.py
index b75f5f5a..f7739efe 100644
--- a/mitmproxy/addons/termlog.py
+++ b/mitmproxy/addons/termlog.py
@@ -5,9 +5,9 @@ from mitmproxy import log
class TermLog:
- def __init__(self, outfile=sys.stdout):
+ def __init__(self, outfile=None):
self.options = None
- self.outfile = outfile
+ self.outfile = outfile or sys.stdout
def configure(self, options, updated):
self.options = options
diff --git a/mitmproxy/certs.py b/mitmproxy/certs.py
index 4e4eb4d1..4b939c80 100644
--- a/mitmproxy/certs.py
+++ b/mitmproxy/certs.py
@@ -3,8 +3,8 @@ import ssl
import time
import datetime
import ipaddress
-
import sys
+
from pyasn1.type import univ, constraint, char, namedtype, tag
from pyasn1.codec.der.decoder import decode
from pyasn1.error import PyAsn1Error
@@ -13,8 +13,8 @@ import OpenSSL
from mitmproxy.types import serializable
# Default expiry must not be too long: https://github.com/mitmproxy/mitmproxy/issues/815
-
DEFAULT_EXP = 94608000 # = 24 * 60 * 60 * 365 * 3
+
# Generated with "openssl dhparam". It's too slow to generate this on startup.
DEFAULT_DHPARAM = b"""
-----BEGIN DH PARAMETERS-----
diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py
index 8afdce2c..10f8cbf5 100644
--- a/mitmproxy/tools/console/master.py
+++ b/mitmproxy/tools/console/master.py
@@ -33,8 +33,6 @@ from mitmproxy.tools.console import statusbar
from mitmproxy.tools.console import window
from mitmproxy.utils import strutils
-from mitmproxy.net import tcp
-
EVENTLOG_SIZE = 10000
@@ -272,16 +270,6 @@ class ConsoleMaster(master.Master):
print("Could not load file: {}".format(ret), file=sys.stderr)
sys.exit(1)
- self.loop.set_alarm_in(0.01, self.ticker)
- if self.options.http2 and not tcp.HAS_ALPN: # pragma: no cover
- def http2err(*args, **kwargs):
- signals.status_message.send(
- message = "HTTP/2 disabled - OpenSSL 1.0.2+ required."
- " Use --no-http2 to silence this warning.",
- expire=5
- )
- self.loop.set_alarm_in(0.01, http2err)
-
self.loop.set_alarm_in(
0.0001,
lambda *args: self.view_flowlist()
diff --git a/mitmproxy/tools/dump.py b/mitmproxy/tools/dump.py
index 4e2844a1..e1e40fb0 100644
--- a/mitmproxy/tools/dump.py
+++ b/mitmproxy/tools/dump.py
@@ -6,7 +6,6 @@ from mitmproxy import addons
from mitmproxy import options
from mitmproxy import master
from mitmproxy.addons import dumper, termlog
-from mitmproxy.net import tcp
class DumpError(Exception):
@@ -30,7 +29,13 @@ class Options(options.Options):
class DumpMaster(master.Master):
- def __init__(self, options, server, with_termlog=True, with_dumper=True):
+ def __init__(
+ self,
+ options: Options,
+ server,
+ with_termlog=True,
+ with_dumper=True,
+ ) -> None:
master.Master.__init__(self, options, server)
self.has_errored = False
if with_termlog:
@@ -38,8 +43,6 @@ class DumpMaster(master.Master):
self.addons.add(*addons.default_addons())
if with_dumper:
self.addons.add(dumper.Dumper())
- # This line is just for type hinting
- self.options = self.options # type: Options
if not self.options.no_server:
self.add_log(
@@ -47,13 +50,6 @@ class DumpMaster(master.Master):
"info"
)
- if self.server and self.options.http2 and not tcp.HAS_ALPN: # pragma: no cover
- self.add_log(
- "ALPN support missing (OpenSSL 1.0.2+ required)!\n"
- "HTTP/2 is disabled. Use --no-http2 to silence this warning.",
- "error"
- )
-
if options.rfile:
try:
self.load_flows_file(options.rfile)
diff --git a/test/mitmproxy/addons/test_check_alpn.py b/test/mitmproxy/addons/test_check_alpn.py
new file mode 100644
index 00000000..2dc0c835
--- /dev/null
+++ b/test/mitmproxy/addons/test_check_alpn.py
@@ -0,0 +1,23 @@
+from mitmproxy.addons import check_alpn
+from mitmproxy.test import taddons
+from ...conftest import requires_alpn
+
+
+class TestCheckALPN:
+
+ @requires_alpn
+ def test_check_alpn(self):
+ msg = 'ALPN support missing'
+
+ with taddons.context() as tctx:
+ a = check_alpn.CheckALPN()
+ tctx.configure(a)
+ assert not any(msg in m for l, m in tctx.master.event_log)
+
+ def test_check_no_alpn(self, disable_alpn):
+ msg = 'ALPN support missing'
+
+ with taddons.context() as tctx:
+ a = check_alpn.CheckALPN()
+ tctx.configure(a)
+ assert any(msg in m for l, m in tctx.master.event_log)
diff --git a/test/mitmproxy/addons/test_check_ca.py b/test/mitmproxy/addons/test_check_ca.py
new file mode 100644
index 00000000..fc64621c
--- /dev/null
+++ b/test/mitmproxy/addons/test_check_ca.py
@@ -0,0 +1,19 @@
+import pytest
+from unittest import mock
+
+from mitmproxy.addons import check_ca
+from mitmproxy.test import taddons
+
+
+class TestCheckCA:
+
+ @pytest.mark.parametrize('expired', [False, True])
+ def test_check_ca(self, expired):
+ msg = 'The mitmproxy certificate authority has expired!'
+
+ with taddons.context() as tctx:
+ tctx.master.server = mock.MagicMock()
+ tctx.master.server.config.certstore.default_ca.has_expired = mock.MagicMock(return_value=expired)
+ a = check_ca.CheckCA()
+ tctx.configure(a)
+ assert any(msg in m for l, m in tctx.master.event_log) is expired
diff --git a/test/mitmproxy/test_tools_dump.py b/test/mitmproxy/test_tools_dump.py
index 2e64d2d2..505f514b 100644
--- a/test/mitmproxy/test_tools_dump.py
+++ b/test/mitmproxy/test_tools_dump.py
@@ -1,10 +1,13 @@
import os
+import pytest
+from unittest import mock
-from mitmproxy.tools import dump
from mitmproxy import proxy
-from mitmproxy.test import tutils
from mitmproxy import log
from mitmproxy import controller
+from mitmproxy.tools import dump
+
+from mitmproxy.test import tutils
from . import mastertest
@@ -37,3 +40,17 @@ class TestDumpMaster(mastertest.MasterTest):
ent.reply = controller.DummyReply()
m.log(ent)
assert m.has_errored
+
+ @pytest.mark.parametrize("termlog", [False, True])
+ def test_addons_termlog(self, termlog):
+ with mock.patch('sys.stdout'):
+ o = dump.Options()
+ m = dump.DumpMaster(o, proxy.DummyServer(), with_termlog=termlog)
+ assert (m.addons.get('termlog') is not None) == termlog
+
+ @pytest.mark.parametrize("dumper", [False, True])
+ def test_addons_dumper(self, dumper):
+ with mock.patch('sys.stdout'):
+ o = dump.Options()
+ m = dump.DumpMaster(o, proxy.DummyServer(), with_dumper=dumper)
+ assert (m.addons.get('dumper') is not None) == dumper
diff --git a/test/mitmproxy/test_web_master.py b/test/mitmproxy/test_web_master.py
index 08dce8f3..3591284d 100644
--- a/test/mitmproxy/test_web_master.py
+++ b/test/mitmproxy/test_web_master.py
@@ -1,13 +1,16 @@
from mitmproxy.tools.web import master
from mitmproxy import proxy
from mitmproxy import options
+from mitmproxy.proxy.config import ProxyConfig
+
from . import mastertest
class TestWebMaster(mastertest.MasterTest):
def mkmaster(self, **opts):
o = options.Options(**opts)
- return master.WebMaster(o, proxy.DummyServer(o))
+ c = ProxyConfig(o)
+ return master.WebMaster(o, proxy.DummyServer(c))
def test_basic(self):
m = self.mkmaster()