Bring back the certificate check callback

This was implemented for clone, but not for fetch or push, so it was
deleted during the conversion, which shows why we need to unify these
callback structures.
This commit is contained in:
Carlos Martín Nieto
2015-09-26 23:40:01 +02:00
parent ac2e363d04
commit 563cb9018e

View File

@@ -122,6 +122,25 @@ class RemoteCallbacks(object):
"""
raise Passthrough
def certificate_check(self, certificate, valid, host):
"""Certificate callback
Override with your own function to determine whether the accept
the server's certificate.
:param None certificate: The certificate. It is currently always None
while we figure out how to represent it cross-platform
:param bool valid: Whether the TLS/SSH library thinks the certificate
is valid
:param str host: The hostname we want to connect to
Return value: True to connect, False to abort
"""
raise Passthrough
def transfer_progress(self, stats):
"""Transfer progress callback
@@ -156,6 +175,7 @@ class RemoteCallbacks(object):
fetch_opts.callbacks.transfer_progress = self._transfer_progress_cb
fetch_opts.callbacks.update_tips = self._update_tips_cb
fetch_opts.callbacks.credentials = self._credentials_cb
fetch_opts.callbacks.certificate_check = self._certificate_cb
# We need to make sure that this handle stays alive
self._self_handle = ffi.new_handle(self)
fetch_opts.callbacks.payload = self._self_handle
@@ -167,6 +187,7 @@ class RemoteCallbacks(object):
push_opts.callbacks.transfer_progress = self._transfer_progress_cb
push_opts.callbacks.update_tips = self._update_tips_cb
push_opts.callbacks.credentials = self._credentials_cb
push_opts.callbacks.certificate_check = self._certificate_cb
push_opts.callbacks.push_update_reference = self._push_update_reference_cb
# We need to make sure that this handle stays alive
self._self_handle = ffi.new_handle(self)
@@ -266,6 +287,39 @@ class RemoteCallbacks(object):
return 0
@ffi.callback('int (*git_transport_certificate_check_cb)'
'(git_cert *cert, int valid, const char *host, void *payload)')
def _certificate_cb(cert_i, valid, host, data):
self = ffi.from_handle(data)
# We want to simulate what should happen if libgit2 supported pass-through for
# this callback. For SSH, 'valid' is always False, because it doesn't look
# at known_hosts, but we do want to let it through in order to do what libgit2 would
# if the callback were not set.
try:
is_ssh = cert_i.cert_type == C.GIT_CERT_HOSTKEY_LIBSSH2
if not hasattr(self, 'certificate_check') or not self.certificate_check:
raise Passthrough
# python's parsing is deep in the libraries and assumes an OpenSSL-owned cert
val = self.certificate_check(None, bool(valid), ffi.string(host))
if not val:
return C.GIT_ECERTIFICATE
except Exception as e:
if e is Passthrough:
if is_ssh:
return 0
elif valid:
return 0
else:
return C.GIT_ECERTIFICATE
self._stored_exception = e
return C.GIT_EUSER
return 0
class Remote(object):
def __init__(self, repo, ptr):
"""The constructor is for internal use only"""