comparison sat/plugins/plugin_xep_0077.py @ 2838:8018cf9aa55b

plugin XEP-0077: correctly report invalid certificate + errback on unexpected stream close
author Goffi <goffi@goffi.org>
date Sun, 03 Mar 2019 19:18:45 +0100
parents 003b8b4b56a7
children ab2696e34d29
comparison
equal deleted inserted replaced
2837:e2005dd39c92 2838:8018cf9aa55b
21 from sat.core.constants import Const as C 21 from sat.core.constants import Const as C
22 from sat.core import exceptions 22 from sat.core import exceptions
23 from sat.core.log import getLogger 23 from sat.core.log import getLogger
24 24
25 log = getLogger(__name__) 25 log = getLogger(__name__)
26 from twisted.words.protocols.jabber import jid, xmlstream, client 26 from twisted.words.protocols.jabber import jid, xmlstream, client, error as jabber_error
27 from twisted.internet import defer, reactor 27 from twisted.internet import defer, reactor
28 from sat.tools import xml_tools 28 from sat.tools import xml_tools
29 29
30 from wokkel import data_form 30 from wokkel import data_form
31 31
48 # FIXME: request IQ is not send to check available fields, 48 # FIXME: request IQ is not send to check available fields,
49 # while XEP recommand to use it 49 # while XEP recommand to use it
50 # FIXME: doesn't handle data form or oob 50 # FIXME: doesn't handle data form or oob
51 namespace = 'jabber:client' 51 namespace = 'jabber:client'
52 52
53 def __init__(self, jid_, password, email=None): 53 def __init__(self, jid_, password, email=None, check_certificate=True):
54 log.debug(_(u"Registration asked for {jid}").format(jid=jid_)) 54 log.debug(_(u"Registration asked for {jid}").format(jid=jid_))
55 xmlstream.ConnectAuthenticator.__init__(self, jid_.host) 55 xmlstream.ConnectAuthenticator.__init__(self, jid_.host)
56 self.jid = jid_ 56 self.jid = jid_
57 self.password = password 57 self.password = password
58 self.email = email 58 self.email = email
59 self.check_certificate = check_certificate
59 self.registered = defer.Deferred() 60 self.registered = defer.Deferred()
60 61
61 def associateWithStream(self, xs): 62 def associateWithStream(self, xs):
62 xmlstream.ConnectAuthenticator.associateWithStream(self, xs) 63 xmlstream.ConnectAuthenticator.associateWithStream(self, xs)
63 xs.addObserver(xmlstream.STREAM_AUTHD_EVENT, self.register) 64 xs.addObserver(xmlstream.STREAM_AUTHD_EVENT, self.register)
64 65
65 xs.initializers = [client.CheckVersionInitializer(xs)] 66 xs.initializers = [client.CheckVersionInitializer(xs)]
66 inits = [ (xmlstream.TLSInitiatingInitializer, False), 67 tls_init = xmlstream.TLSInitiatingInitializer(xs)
67 ] 68 tls_init.required = False
68 69 tls_init.check_certificate = self.check_certificate
69 for initClass, required in inits: 70 xs.initializers.append(tls_init)
70 init = initClass(xs)
71 init.required = required
72 xs.initializers.append(init)
73 71
74 def register(self, xmlstream): 72 def register(self, xmlstream):
75 log.debug(_(u"Stream started with {server}, now registering" 73 log.debug(_(u"Stream started with {server}, now registering"
76 .format(server=self.jid.host))) 74 .format(server=self.jid.host)))
77 iq = XEP_0077.buildRegisterIQ(self.xmlstream, self.jid, self.password, self.email) 75 iq = XEP_0077.buildRegisterIQ(self.xmlstream, self.jid, self.password, self.email)
84 82
85 def registrationEb(self, failure_): 83 def registrationEb(self, failure_):
86 log.info(_("Registration failure: {}").format(unicode(failure_.value))) 84 log.info(_("Registration failure: {}").format(unicode(failure_.value)))
87 self.xmlstream.sendFooter() 85 self.xmlstream.sendFooter()
88 raise failure_ 86 raise failure_
87
88
89 class ServerRegister(xmlstream.XmlStreamFactory):
90
91 def __init__(self, *args, **kwargs):
92 xmlstream.XmlStreamFactory.__init__(self, *args, **kwargs)
93 self.addBootstrap(xmlstream.STREAM_END_EVENT, self._disconnected)
94
95 def clientConnectionLost(self, connector, reason):
96 connector.disconnect()
97
98 def _disconnected(self, reason):
99 if not self.authenticator.registered.called:
100 err = jabber_error.StreamError(u"Server unexpectedly closed the connection")
101 try:
102 if reason.value.args[0][0][2] == "certificate verify failed":
103 err = exceptions.InvalidCertificate()
104 except (IndexError, TypeError):
105 pass
106 self.authenticator.registered.errback(err)
89 107
90 108
91 class XEP_0077(object): 109 class XEP_0077(object):
92 def __init__(self, host): 110 def __init__(self, host):
93 log.info(_("Plugin XEP_0077 initialization")) 111 log.info(_("Plugin XEP_0077 initialization"))
235 @param password(unicode): password of the account 253 @param password(unicode): password of the account
236 @param email(unicode): email of the account 254 @param email(unicode): email of the account
237 @param host(unicode): host of the server to register to 255 @param host(unicode): host of the server to register to
238 @param port(int): port of the server to register to 256 @param port(int): port of the server to register to
239 """ 257 """
240 authenticator = RegisteringAuthenticator(jid_, password, email) 258 check_certificate = host != u"127.0.0.1"
259 authenticator = RegisteringAuthenticator(
260 jid_, password, email, check_certificate=check_certificate)
241 registered_d = authenticator.registered 261 registered_d = authenticator.registered
242 serverRegistrer = xmlstream.XmlStreamFactory(authenticator) 262 server_register = ServerRegister(authenticator)
243 connector = reactor.connectTCP(host, port, serverRegistrer) 263 reactor.connectTCP(host, port, server_register)
244 serverRegistrer.clientConnectionLost = lambda conn, reason: connector.disconnect()
245 return registered_d 264 return registered_d
246 265
247 def _changePassword(self, new_password, profile_key): 266 def _changePassword(self, new_password, profile_key):
248 client = self.host.getClient(profile_key) 267 client = self.host.getClient(profile_key)
249 return self.changePassword(client, new_password) 268 return self.changePassword(client, new_password)