sslutil: improve messaging around unsupported protocols (
issue5303)
There are various causes for the inability to negotiate common SSL/TLS
protocol between client and server. Previously, we had a single, not
very actionable warning message for all of them.
As people encountered TLS 1.0 servers in real life, it was quickly
obvious that the existing messaging was inadequate to help users
rectify the situation.
This patch makes the warning messages much more verbose in hopes of
making them more actionable while simultaneously encouraging users
and servers to adopt better security practices.
This messaging flirts with the anti-pattern of "never blame the
user" by signaling out poorly-configured servers. But if we're going to
disallow TLS 1.0 by default, I think we need to say *something* or
people are just going to blame Mercurial for not being able to connect.
The messaging tries to exonerate Mercurial from being the at fault
party by pointing out the server is the entity that doesn't support
proper security (when appropriate, of course).
from __future__ import absolute_import
import silenttestrunner
import unittest
from mercurial import util
class contextmanager(object):
def __init__(self, name, trace):
self.name = name
self.entered = False
self.exited = False
self.trace = trace
def __enter__(self):
self.entered = True
self.trace(('enter', self.name))
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.exited = exc_type, exc_val, exc_tb
self.trace(('exit', self.name))
def __repr__(self):
return '<ctx %r>' % self.name
class ctxerror(Exception):
pass
class raise_on_enter(contextmanager):
def __enter__(self):
self.trace(('raise', self.name))
raise ctxerror(self.name)
class raise_on_exit(contextmanager):
def __exit__(self, exc_type, exc_val, exc_tb):
self.trace(('raise', self.name))
raise ctxerror(self.name)
def ctxmgr(name, trace):
return lambda: contextmanager(name, trace)
class test_ctxmanager(unittest.TestCase):
def test_basics(self):
trace = []
addtrace = trace.append
with util.ctxmanager(ctxmgr('a', addtrace), ctxmgr('b', addtrace)) as c:
a, b = c.enter()
c.atexit(addtrace, ('atexit', 'x'))
c.atexit(addtrace, ('atexit', 'y'))
self.assertEqual(trace, [('enter', 'a'), ('enter', 'b'),
('atexit', 'y'), ('atexit', 'x'),
('exit', 'b'), ('exit', 'a')])
def test_raise_on_enter(self):
trace = []
addtrace = trace.append
def go():
with util.ctxmanager(ctxmgr('a', addtrace),
lambda: raise_on_enter('b', addtrace)) as c:
c.enter()
addtrace('unreachable')
self.assertRaises(ctxerror, go)
self.assertEqual(trace, [('enter', 'a'), ('raise', 'b'), ('exit', 'a')])
def test_raise_on_exit(self):
trace = []
addtrace = trace.append
def go():
with util.ctxmanager(ctxmgr('a', addtrace),
lambda: raise_on_exit('b', addtrace)) as c:
c.enter()
addtrace('running')
self.assertRaises(ctxerror, go)
self.assertEqual(trace, [('enter', 'a'), ('enter', 'b'), 'running',
('raise', 'b'), ('exit', 'a')])
if __name__ == '__main__':
silenttestrunner.main(__name__)