Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/debugcommands.py @ 33493:9a9f95214f46
debug: add a method to check the state of, and built an SSL cert chain
This is only useful on Windows, and avoids the need to use Internet Explorer to
build the certificate chain. I can see this being extended in the future to
print information about the certificate(s) to help debug issues on any platform.
Maybe even perform some of the python checks listed on the secure connections
wiki page. But for now, all I need is 1) a command that can be invoked in a
setup script to ensure the certificate is installed, and 2) a command that the
user can run if/when a certificate changes in the future.
It would have been nice to leverage the sslutil library to pick up host specific
settings, but attempting to use sslutil.wrapsocket() failed the
'not sslsocket.cipher()' check in it and aborted.
The output is a little more chatty than some commands, but I've seen the update
take 10+ seconds, and this is only a debug command.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Thu, 30 Mar 2017 00:27:46 -0400 |
parents | 8056481caa81 |
children | e9672de52a23 |
comparison
equal
deleted
inserted
replaced
33492:14af04391fb9 | 33493:9a9f95214f46 |
---|---|
11 import errno | 11 import errno |
12 import operator | 12 import operator |
13 import os | 13 import os |
14 import random | 14 import random |
15 import socket | 15 import socket |
16 import ssl | |
16 import string | 17 import string |
17 import sys | 18 import sys |
18 import tempfile | 19 import tempfile |
19 import time | 20 import time |
20 | 21 |
2055 r2 = scmutil.revsingle(repo, rev2, 'null').node() | 2056 r2 = scmutil.revsingle(repo, rev2, 'null').node() |
2056 | 2057 |
2057 with repo.wlock(): | 2058 with repo.wlock(): |
2058 repo.setparents(r1, r2) | 2059 repo.setparents(r1, r2) |
2059 | 2060 |
2061 @command('debugssl', [], '[SOURCE]', optionalrepo=True) | |
2062 def debugssl(ui, repo, source=None, **opts): | |
2063 '''test a secure connection to a server | |
2064 | |
2065 This builds the certificate chain for the server on Windows, installing the | |
2066 missing intermediates and trusted root via Windows Update if necessary. It | |
2067 does nothing on other platforms. | |
2068 | |
2069 If SOURCE is omitted, the 'default' path will be used. If a URL is given, | |
2070 that server is used. See :hg:`help urls` for more information. | |
2071 | |
2072 If the update succeeds, retry the original operation. Otherwise, the cause | |
2073 of the SSL error is likely another issue. | |
2074 ''' | |
2075 if pycompat.osname != 'nt': | |
2076 raise error.Abort(_('Certificate chain building is only possible on ' | |
2077 'Windows')) | |
2078 | |
2079 if not source: | |
2080 source = "default" | |
2081 elif not repo: | |
2082 raise error.Abort(_("there is no Mercurial repository here, and no " | |
2083 "server specified")) | |
2084 | |
2085 source, branches = hg.parseurl(ui.expandpath(source)) | |
2086 url = util.url(source) | |
2087 addr = None | |
2088 | |
2089 if url.scheme == 'https': | |
2090 addr = (url.host, url.port or 443) | |
2091 elif url.scheme == 'ssh': | |
2092 addr = (url.host, url.port or 22) | |
2093 else: | |
2094 raise error.Abort(_("Only https and ssh connections are supported")) | |
2095 | |
2096 from . import win32 | |
2097 | |
2098 s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS, | |
2099 cert_reqs=ssl.CERT_NONE, ca_certs=None) | |
2100 | |
2101 try: | |
2102 s.connect(addr) | |
2103 cert = s.getpeercert(True) | |
2104 | |
2105 ui.status(_('Checking the certificate chain for %s.\n') % url.host) | |
2106 | |
2107 complete = win32.checkcertificatechain(cert, build=False) | |
2108 | |
2109 if not complete: | |
2110 ui.status(_('The certificate chain is incomplete. Updating... ')) | |
2111 | |
2112 if not win32.checkcertificatechain(cert): | |
2113 ui.status(_('Failed.\n')) | |
2114 else: | |
2115 ui.status(_('Done.\n')) | |
2116 else: | |
2117 ui.status(_('The full certificate chain is available.\n')) | |
2118 finally: | |
2119 s.close() | |
2120 | |
2060 @command('debugsub', | 2121 @command('debugsub', |
2061 [('r', 'rev', '', | 2122 [('r', 'rev', '', |
2062 _('revision to check'), _('REV'))], | 2123 _('revision to check'), _('REV'))], |
2063 _('[-r REV] [REV]')) | 2124 _('[-r REV] [REV]')) |
2064 def debugsub(ui, repo, rev=None): | 2125 def debugsub(ui, repo, rev=None): |