Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0047.py @ 3028:ab2696e34d29
Python 3 port:
/!\ this is a huge commit
/!\ starting from this commit, SàT is needs Python 3.6+
/!\ SàT maybe be instable or some feature may not work anymore, this will improve with time
This patch port backend, bridge and frontends to Python 3.
Roughly this has been done this way:
- 2to3 tools has been applied (with python 3.7)
- all references to python2 have been replaced with python3 (notably shebangs)
- fixed files not handled by 2to3 (notably the shell script)
- several manual fixes
- fixed issues reported by Python 3 that where not handled in Python 2
- replaced "async" with "async_" when needed (it's a reserved word from Python 3.7)
- replaced zope's "implements" with @implementer decorator
- temporary hack to handle data pickled in database, as str or bytes may be returned,
to be checked later
- fixed hash comparison for password
- removed some code which is not needed anymore with Python 3
- deactivated some code which needs to be checked (notably certificate validation)
- tested with jp, fixed reported issues until some basic commands worked
- ported Primitivus (after porting dependencies like urwid satext)
- more manual fixes
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 13 Aug 2019 19:08:41 +0200 |
parents | 69e4716d6268 |
children | 9d0df638c8b4 |
comparison
equal
deleted
inserted
replaced
3027:ff5bcb12ae60 | 3028:ab2696e34d29 |
---|---|
1 #!/usr/bin/env python2 | 1 #!/usr/bin/env python3 |
2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
3 | 3 |
4 # SAT plugin for managing gateways (xep-0047) | 4 # SAT plugin for managing gateways (xep-0047) |
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) | 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) |
6 | 6 |
30 from twisted.internet import defer | 30 from twisted.internet import defer |
31 from twisted.python import failure | 31 from twisted.python import failure |
32 | 32 |
33 from wokkel import disco, iwokkel | 33 from wokkel import disco, iwokkel |
34 | 34 |
35 from zope.interface import implements | 35 from zope.interface import implementer |
36 | 36 |
37 import base64 | 37 import base64 |
38 | 38 |
39 try: | 39 try: |
40 from twisted.words.protocols.xmlstream import XMPPHandler | 40 from twisted.words.protocols.xmlstream import XMPPHandler |
82 | 82 |
83 @param sid(unicode): session id of client.xep_0047_current_stream | 83 @param sid(unicode): session id of client.xep_0047_current_stream |
84 @param client: %(doc_client)s | 84 @param client: %(doc_client)s |
85 """ | 85 """ |
86 log.info( | 86 log.info( |
87 u"In-Band Bytestream: TimeOut reached for id {sid} [{profile}]".format( | 87 "In-Band Bytestream: TimeOut reached for id {sid} [{profile}]".format( |
88 sid=sid, profile=client.profile | 88 sid=sid, profile=client.profile |
89 ) | 89 ) |
90 ) | 90 ) |
91 self._killSession(sid, client, "TIMEOUT") | 91 self._killSession(sid, client, "TIMEOUT") |
92 | 92 |
99 else, will be used to call failure_cb | 99 else, will be used to call failure_cb |
100 """ | 100 """ |
101 try: | 101 try: |
102 session = client.xep_0047_current_stream[sid] | 102 session = client.xep_0047_current_stream[sid] |
103 except KeyError: | 103 except KeyError: |
104 log.warning(u"kill id called on a non existant id") | 104 log.warning("kill id called on a non existant id") |
105 return | 105 return |
106 | 106 |
107 try: | 107 try: |
108 observer_cb = session["observer_cb"] | 108 observer_cb = session["observer_cb"] |
109 except KeyError: | 109 except KeyError: |
139 @param to_jid(jid.JId): jid of the other peer | 139 @param to_jid(jid.JId): jid of the other peer |
140 @param sid(unicode): session id | 140 @param sid(unicode): session id |
141 @return (dict): session data | 141 @return (dict): session data |
142 """ | 142 """ |
143 if sid in client.xep_0047_current_stream: | 143 if sid in client.xep_0047_current_stream: |
144 raise exceptions.ConflictError(u"A session with this id already exists !") | 144 raise exceptions.ConflictError("A session with this id already exists !") |
145 session_data = client.xep_0047_current_stream[sid] = { | 145 session_data = client.xep_0047_current_stream[sid] = { |
146 "id": sid, | 146 "id": sid, |
147 DEFER_KEY: defer.Deferred(), | 147 DEFER_KEY: defer.Deferred(), |
148 "local_jid": local_jid, | 148 "local_jid": local_jid, |
149 "to": to_jid, | 149 "to": to_jid, |
157 def _onIBBOpen(self, iq_elt, client): | 157 def _onIBBOpen(self, iq_elt, client): |
158 """"Called when an IBB <open> element is received | 158 """"Called when an IBB <open> element is received |
159 | 159 |
160 @param iq_elt(domish.Element): the whole <iq> stanza | 160 @param iq_elt(domish.Element): the whole <iq> stanza |
161 """ | 161 """ |
162 log.debug(_(u"IBB stream opening")) | 162 log.debug(_("IBB stream opening")) |
163 iq_elt.handled = True | 163 iq_elt.handled = True |
164 open_elt = iq_elt.elements(NS_IBB, "open").next() | 164 open_elt = next(iq_elt.elements(NS_IBB, "open")) |
165 block_size = open_elt.getAttribute("block-size") | 165 block_size = open_elt.getAttribute("block-size") |
166 sid = open_elt.getAttribute("sid") | 166 sid = open_elt.getAttribute("sid") |
167 stanza = open_elt.getAttribute("stanza", "iq") | 167 stanza = open_elt.getAttribute("stanza", "iq") |
168 if not sid or not block_size or int(block_size) > 65535: | 168 if not sid or not block_size or int(block_size) > 65535: |
169 return self._sendError("not-acceptable", sid or None, iq_elt, client) | 169 return self._sendError("not-acceptable", sid or None, iq_elt, client) |
170 if not sid in client.xep_0047_current_stream: | 170 if not sid in client.xep_0047_current_stream: |
171 log.warning(_(u"Ignoring unexpected IBB transfer: %s" % sid)) | 171 log.warning(_("Ignoring unexpected IBB transfer: %s" % sid)) |
172 return self._sendError("not-acceptable", sid or None, iq_elt, client) | 172 return self._sendError("not-acceptable", sid or None, iq_elt, client) |
173 session_data = client.xep_0047_current_stream[sid] | 173 session_data = client.xep_0047_current_stream[sid] |
174 if session_data["to"] != jid.JID(iq_elt["from"]): | 174 if session_data["to"] != jid.JID(iq_elt["from"]): |
175 log.warning( | 175 log.warning( |
176 _("sended jid inconsistency (man in the middle attack attempt ?)") | 176 _("sended jid inconsistency (man in the middle attack attempt ?)") |
202 | 202 |
203 @param iq_elt(domish.Element): the whole <iq> stanza | 203 @param iq_elt(domish.Element): the whole <iq> stanza |
204 """ | 204 """ |
205 iq_elt.handled = True | 205 iq_elt.handled = True |
206 log.debug(_("IBB stream closing")) | 206 log.debug(_("IBB stream closing")) |
207 close_elt = iq_elt.elements(NS_IBB, "close").next() | 207 close_elt = next(iq_elt.elements(NS_IBB, "close")) |
208 # XXX: this observer is only triggered on valid sid, so we don't need to check it | 208 # XXX: this observer is only triggered on valid sid, so we don't need to check it |
209 sid = close_elt["sid"] | 209 sid = close_elt["sid"] |
210 | 210 |
211 iq_result_elt = xmlstream.toResponse(iq_elt, "result") | 211 iq_result_elt = xmlstream.toResponse(iq_elt, "result") |
212 client.send(iq_result_elt) | 212 client.send(iq_result_elt) |
217 | 217 |
218 Manage the data elelement (check validity and write to the stream_object) | 218 Manage the data elelement (check validity and write to the stream_object) |
219 @param element(domish.Element): <iq> or <message> stanza | 219 @param element(domish.Element): <iq> or <message> stanza |
220 """ | 220 """ |
221 element.handled = True | 221 element.handled = True |
222 data_elt = element.elements(NS_IBB, "data").next() | 222 data_elt = next(element.elements(NS_IBB, "data")) |
223 sid = data_elt["sid"] | 223 sid = data_elt["sid"] |
224 | 224 |
225 try: | 225 try: |
226 session_data = client.xep_0047_current_stream[sid] | 226 session_data = client.xep_0047_current_stream[sid] |
227 except KeyError: | 227 except KeyError: |
228 log.warning(_(u"Received data for an unknown session id")) | 228 log.warning(_("Received data for an unknown session id")) |
229 return self._sendError("item-not-found", None, element, client) | 229 return self._sendError("item-not-found", None, element, client) |
230 | 230 |
231 from_jid = session_data["to"] | 231 from_jid = session_data["to"] |
232 stream_object = session_data["stream_object"] | 232 stream_object = session_data["stream_object"] |
233 | 233 |
234 if from_jid.full() != element["from"]: | 234 if from_jid.full() != element["from"]: |
235 log.warning( | 235 log.warning( |
236 _( | 236 _( |
237 u"sended jid inconsistency (man in the middle attack attempt ?)\ninitial={initial}\ngiven={given}" | 237 "sended jid inconsistency (man in the middle attack attempt ?)\ninitial={initial}\ngiven={given}" |
238 ).format(initial=from_jid, given=element["from"]) | 238 ).format(initial=from_jid, given=element["from"]) |
239 ) | 239 ) |
240 if element.name == "iq": | 240 if element.name == "iq": |
241 self._sendError("not-acceptable", sid, element, client) | 241 self._sendError("not-acceptable", sid, element, client) |
242 return | 242 return |
243 | 243 |
244 session_data["seq"] = (session_data["seq"] + 1) % 65535 | 244 session_data["seq"] = (session_data["seq"] + 1) % 65535 |
245 if int(data_elt.getAttribute("seq", -1)) != session_data["seq"]: | 245 if int(data_elt.getAttribute("seq", -1)) != session_data["seq"]: |
246 log.warning(_(u"Sequence error")) | 246 log.warning(_("Sequence error")) |
247 if element.name == "iq": | 247 if element.name == "iq": |
248 reason = "not-acceptable" | 248 reason = "not-acceptable" |
249 self._sendError(reason, sid, element, client) | 249 self._sendError(reason, sid, element, client) |
250 self.terminateStream(session_data, client, reason) | 250 self.terminateStream(session_data, client, reason) |
251 return | 251 return |
256 # we can now decode the data | 256 # we can now decode the data |
257 try: | 257 try: |
258 stream_object.write(base64.b64decode(str(data_elt))) | 258 stream_object.write(base64.b64decode(str(data_elt))) |
259 except TypeError: | 259 except TypeError: |
260 # The base64 data is invalid | 260 # The base64 data is invalid |
261 log.warning(_(u"Invalid base64 data")) | 261 log.warning(_("Invalid base64 data")) |
262 if element.name == "iq": | 262 if element.name == "iq": |
263 self._sendError("not-acceptable", sid, element, client) | 263 self._sendError("not-acceptable", sid, element, client) |
264 self.terminateStream(session_data, client, reason) | 264 self.terminateStream(session_data, client, reason) |
265 return | 265 return |
266 | 266 |
277 @param iq_elt(domish.Element): full <iq> stanza | 277 @param iq_elt(domish.Element): full <iq> stanza |
278 @param client: %(doc_client)s | 278 @param client: %(doc_client)s |
279 """ | 279 """ |
280 iq_elt = error.StanzaError(error_condition).toResponse(iq_elt) | 280 iq_elt = error.StanzaError(error_condition).toResponse(iq_elt) |
281 log.warning( | 281 log.warning( |
282 u"Error while managing in-band bytestream session, cancelling: {}".format( | 282 "Error while managing in-band bytestream session, cancelling: {}".format( |
283 error_condition | 283 error_condition |
284 ) | 284 ) |
285 ) | 285 ) |
286 if sid is not None: | 286 if sid is not None: |
287 self._killSession(sid, client, error_condition) | 287 self._killSession(sid, client, error_condition) |
332 next_iq_elt = client.IQ() | 332 next_iq_elt = client.IQ() |
333 next_iq_elt["from"] = session_data["local_jid"].full() | 333 next_iq_elt["from"] = session_data["local_jid"].full() |
334 next_iq_elt["to"] = session_data["to"].full() | 334 next_iq_elt["to"] = session_data["to"].full() |
335 data_elt = next_iq_elt.addElement((NS_IBB, "data")) | 335 data_elt = next_iq_elt.addElement((NS_IBB, "data")) |
336 seq = session_data["seq"] = (session_data["seq"] + 1) % 65535 | 336 seq = session_data["seq"] = (session_data["seq"] + 1) % 65535 |
337 data_elt["seq"] = unicode(seq) | 337 data_elt["seq"] = str(seq) |
338 data_elt["sid"] = session_data["id"] | 338 data_elt["sid"] = session_data["id"] |
339 data_elt.addContent(base64.b64encode(buffer_)) | 339 data_elt.addContent(base64.b64encode(buffer_)) |
340 args = [session_data, client] | 340 args = [session_data, client] |
341 d = next_iq_elt.send() | 341 d = next_iq_elt.send() |
342 d.addCallbacks(self._IQDataStreamCb, self._IQDataStreamEb, args, None, args) | 342 d.addCallbacks(self._IQDataStreamCb, self._IQDataStreamEb, args, None, args) |
343 else: | 343 else: |
344 self.terminateStream(session_data, client) | 344 self.terminateStream(session_data, client) |
345 | 345 |
346 def _IQDataStreamEb(self, failure, session_data, client): | 346 def _IQDataStreamEb(self, failure, session_data, client): |
347 if failure.check(error.StanzaError): | 347 if failure.check(error.StanzaError): |
348 log.warning(u"IBB transfer failed: {}".format(failure.value)) | 348 log.warning("IBB transfer failed: {}".format(failure.value)) |
349 else: | 349 else: |
350 log.error(u"IBB transfer failed: {}".format(failure.value)) | 350 log.error("IBB transfer failed: {}".format(failure.value)) |
351 self.terminateStream(session_data, client, "IQ_ERROR") | 351 self.terminateStream(session_data, client, "IQ_ERROR") |
352 | 352 |
353 def terminateStream(self, session_data, client, failure_reason=None): | 353 def terminateStream(self, session_data, client, failure_reason=None): |
354 """Terminate the stream session | 354 """Terminate the stream session |
355 | 355 |
364 close_elt["sid"] = session_data["id"] | 364 close_elt["sid"] = session_data["id"] |
365 iq_elt.send() | 365 iq_elt.send() |
366 self._killSession(session_data["id"], client, failure_reason) | 366 self._killSession(session_data["id"], client, failure_reason) |
367 | 367 |
368 | 368 |
369 @implementer(iwokkel.IDisco) | |
369 class XEP_0047_handler(XMPPHandler): | 370 class XEP_0047_handler(XMPPHandler): |
370 implements(iwokkel.IDisco) | |
371 | 371 |
372 def __init__(self, parent): | 372 def __init__(self, parent): |
373 self.plugin_parent = parent | 373 self.plugin_parent = parent |
374 | 374 |
375 def connectionInitialized(self): | 375 def connectionInitialized(self): |