comparison sat/core/patches.py @ 3044:691283719bb2

core (patches): updated TLS patches: - updated patches to handle TLS after implementation in Twisted 19.7.0. A patch is still needed for Wokkel. - minimum required version of Twisted is now 19.7.0
author Goffi <goffi@goffi.org>
date Tue, 01 Oct 2019 22:49:10 +0200
parents ab2696e34d29
children 524856bd7b19
comparison
equal deleted inserted replaced
3043:3df611adb598 3044:691283719bb2
1 import copy 1 import copy
2 from twisted.words.protocols.jabber import xmlstream, sasl, client as tclient, jid 2 from twisted.words.protocols.jabber import xmlstream, sasl, client as tclient, jid
3 from twisted.internet import ssl
4 from wokkel import client 3 from wokkel import client
5 from sat.core.constants import Const as C 4 from sat.core.constants import Const as C
6 from sat.core.log import getLogger 5 from sat.core.log import getLogger
7 6
8 log = getLogger(__name__) 7 log = getLogger(__name__)
9 8
10 """This module apply monkey patches to Twisted and Wokkel 9 """This module applies monkey patches to Twisted and Wokkel
11 First part handle certificate validation during XMPP connectionand are temporary 10 First part handle certificate validation during XMPP connectionand are temporary
12 (until merged upstream). 11 (until merged upstream).
13 Second part add a trigger point to send and onElement method of XmlStream 12 Second part add a trigger point to send and onElement method of XmlStream
14 """ 13 """
15 14
16 15
17 ## certificate validation patches 16 ## certificate validation patches
18 17
19 class TLSInitiatingInitializer(xmlstream.TLSInitiatingInitializer):
20 check_certificate = True
21
22 def onProceed(self, obj):
23 self.xmlstream.removeObserver('/failure', self.onFailure)
24 trustRoot = ssl.platformTrust() if self.check_certificate else None
25 ctx = ssl.CertificateOptions(trustRoot=trustRoot)
26 self.xmlstream.transport.startTLS(ctx)
27 self.xmlstream.reset()
28 self.xmlstream.sendHeader()
29 self._deferred.callback(xmlstream.Reset)
30
31 18
32 class XMPPClient(client.XMPPClient): 19 class XMPPClient(client.XMPPClient):
33 20
34 def __init__(self, jid, password, host=None, port=5222, 21 def __init__(self, jid, password, host=None, port=5222,
35 check_certificate=True): 22 tls_required=True, configurationForTLS=None):
36 self.jid = jid 23 self.jid = jid
37 self.domain = jid.host.encode('idna') 24 self.domain = jid.host.encode('idna')
38 self.host = host 25 self.host = host
39 self.port = port 26 self.port = port
40 27
41 factory = HybridClientFactory( 28 factory = HybridClientFactory(
42 jid, password, check_certificate=check_certificate) 29 jid, password, tls_required=tls_required,
30 configurationForTLS=configurationForTLS)
43 31
44 client.StreamManager.__init__(self, factory) 32 client.StreamManager.__init__(self, factory)
45 33
46 34
47 def HybridClientFactory(jid, password, check_certificate=True): 35 def HybridClientFactory(jid, password, tls_required=True, configurationForTLS=None):
48 a = HybridAuthenticator(jid, password, check_certificate) 36 a = HybridAuthenticator(jid, password, tls_required, configurationForTLS)
49 37
50 return xmlstream.XmlStreamFactory(a) 38 return xmlstream.XmlStreamFactory(a)
51 39
52 40
53 class HybridAuthenticator(client.HybridAuthenticator): 41 class HybridAuthenticator(client.HybridAuthenticator):
54 res_binding = True 42 res_binding = True
55 43
56 def __init__(self, jid, password, check_certificate): 44 def __init__(self, jid, password, tls_required=True, configurationForTLS=None):
57 xmlstream.ConnectAuthenticator.__init__(self, jid.host) 45 xmlstream.ConnectAuthenticator.__init__(self, jid.host)
58 self.jid = jid 46 self.jid = jid
59 self.password = password 47 self.password = password
60 self.check_certificate = check_certificate 48 self.tls_required = tls_required
49 self.configurationForTLS = configurationForTLS
61 50
62 def associateWithStream(self, xs): 51 def associateWithStream(self, xs):
63 xmlstream.ConnectAuthenticator.associateWithStream(self, xs) 52 xmlstream.ConnectAuthenticator.associateWithStream(self, xs)
64 53
65 tlsInit = xmlstream.TLSInitiatingInitializer(xs) 54 tlsInit = xmlstream.TLSInitiatingInitializer(
66 tlsInit.check_certificate = self.check_certificate 55 xs, required=self.tls_required, configurationForTLS=self.configurationForTLS)
67 xs.initializers = [client.client.CheckVersionInitializer(xs), 56 xs.initializers = [client.client.CheckVersionInitializer(xs),
68 tlsInit, 57 tlsInit,
69 CheckAuthInitializer(xs, self.res_binding)] 58 CheckAuthInitializer(xs, self.res_binding)]
70 59
71 60
82 self._onElementHooks = [] 71 self._onElementHooks = []
83 self._sendHooks = [] 72 self._sendHooks = []
84 73
85 def addHook(self, hook_type, callback): 74 def addHook(self, hook_type, callback):
86 """Add a send or receive hook""" 75 """Add a send or receive hook"""
87 conflict_msg = ("Hook conflict: can't add {hook_type} hook {callback}" 76 conflict_msg = f"Hook conflict: can't add {hook_type} hook {callback}"
88 .format(hook_type=hook_type, callback=callback))
89 if hook_type == C.STREAM_HOOK_RECEIVE: 77 if hook_type == C.STREAM_HOOK_RECEIVE:
90 if callback not in self._onElementHooks: 78 if callback not in self._onElementHooks:
91 self._onElementHooks.append(callback) 79 self._onElementHooks.append(callback)
92 else: 80 else:
93 log.warning(conflict_msg) 81 log.warning(conflict_msg)
95 if callback not in self._sendHooks: 83 if callback not in self._sendHooks:
96 self._sendHooks.append(callback) 84 self._sendHooks.append(callback)
97 else: 85 else:
98 log.warning(conflict_msg) 86 log.warning(conflict_msg)
99 else: 87 else:
100 raise ValueError("Invalid hook type: {hook_type}" 88 raise ValueError(f"Invalid hook type: {hook_type}")
101 .format(hook_type=hook_type))
102 89
103 def onElement(self, element): 90 def onElement(self, element):
104 for hook in self._onElementHooks: 91 for hook in self._onElementHooks:
105 hook(element) 92 hook(element)
106 xmlstream.XmlStream.onElement(self, element) 93 xmlstream.XmlStream.onElement(self, element)
159 jid.__internJIDs[jidstring] = j 146 jid.__internJIDs[jidstring] = j
160 return copy.copy(j) 147 return copy.copy(j)
161 148
162 149
163 def apply(): 150 def apply():
164 # FIXME: certificate validation is now implemented in Twisted trunk, to be removed 151 # certificate validation
165 # # certificate validation 152 client.XMPPClient = XMPPClient
166 # xmlstream.TLSInitiatingInitializer = TLSInitiatingInitializer
167 # client.XMPPClient = XMPPClient
168 # XmlStream triggers 153 # XmlStream triggers
169 xmlstream.XmlStreamFactory.protocol = XmlStream 154 xmlstream.XmlStreamFactory.protocol = XmlStream
170 # jid fix 155 # jid fix
171 jid.internJID = internJID 156 jid.internJID = internJID