comparison sat/plugins/plugin_xep_0077.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 8018cf9aa55b
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 xep-0077 4 # SAT plugin for managing xep-0077
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
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, check_certificate=True): 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(_("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.check_certificate = check_certificate
68 tls_init.required = False 68 tls_init.required = False
69 tls_init.check_certificate = self.check_certificate 69 tls_init.check_certificate = self.check_certificate
70 xs.initializers.append(tls_init) 70 xs.initializers.append(tls_init)
71 71
72 def register(self, xmlstream): 72 def register(self, xmlstream):
73 log.debug(_(u"Stream started with {server}, now registering" 73 log.debug(_("Stream started with {server}, now registering"
74 .format(server=self.jid.host))) 74 .format(server=self.jid.host)))
75 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)
76 d = iq.send(self.jid.host).addCallbacks(self.registrationCb, self.registrationEb) 76 d = iq.send(self.jid.host).addCallbacks(self.registrationCb, self.registrationEb)
77 d.chainDeferred(self.registered) 77 d.chainDeferred(self.registered)
78 78
79 def registrationCb(self, answer): 79 def registrationCb(self, answer):
80 log.debug(_(u"Registration answer: {}").format(answer.toXml())) 80 log.debug(_("Registration answer: {}").format(answer.toXml()))
81 self.xmlstream.sendFooter() 81 self.xmlstream.sendFooter()
82 82
83 def registrationEb(self, failure_): 83 def registrationEb(self, failure_):
84 log.info(_("Registration failure: {}").format(unicode(failure_.value))) 84 log.info(_("Registration failure: {}").format(str(failure_.value)))
85 self.xmlstream.sendFooter() 85 self.xmlstream.sendFooter()
86 raise failure_ 86 raise failure_
87 87
88 88
89 class ServerRegister(xmlstream.XmlStreamFactory): 89 class ServerRegister(xmlstream.XmlStreamFactory):
95 def clientConnectionLost(self, connector, reason): 95 def clientConnectionLost(self, connector, reason):
96 connector.disconnect() 96 connector.disconnect()
97 97
98 def _disconnected(self, reason): 98 def _disconnected(self, reason):
99 if not self.authenticator.registered.called: 99 if not self.authenticator.registered.called:
100 err = jabber_error.StreamError(u"Server unexpectedly closed the connection") 100 err = jabber_error.StreamError("Server unexpectedly closed the connection")
101 try: 101 try:
102 if reason.value.args[0][0][2] == "certificate verify failed": 102 if reason.value.args[0][0][2] == "certificate verify failed":
103 err = exceptions.InvalidCertificate() 103 err = exceptions.InvalidCertificate()
104 except (IndexError, TypeError): 104 except (IndexError, TypeError):
105 pass 105 pass
114 "inBandRegister", 114 "inBandRegister",
115 ".plugin", 115 ".plugin",
116 in_sign="ss", 116 in_sign="ss",
117 out_sign="", 117 out_sign="",
118 method=self._inBandRegister, 118 method=self._inBandRegister,
119 async=True, 119 async_=True,
120 ) 120 )
121 host.bridge.addMethod( 121 host.bridge.addMethod(
122 "inBandAccountNew", 122 "inBandAccountNew",
123 ".plugin", 123 ".plugin",
124 in_sign="ssssi", 124 in_sign="ssssi",
125 out_sign="", 125 out_sign="",
126 method=self._registerNewAccount, 126 method=self._registerNewAccount,
127 async=True, 127 async_=True,
128 ) 128 )
129 host.bridge.addMethod( 129 host.bridge.addMethod(
130 "inBandUnregister", 130 "inBandUnregister",
131 ".plugin", 131 ".plugin",
132 in_sign="ss", 132 in_sign="ss",
133 out_sign="", 133 out_sign="",
134 method=self._unregister, 134 method=self._unregister,
135 async=True, 135 async_=True,
136 ) 136 )
137 host.bridge.addMethod( 137 host.bridge.addMethod(
138 "inBandPasswordChange", 138 "inBandPasswordChange",
139 ".plugin", 139 ".plugin",
140 in_sign="ss", 140 in_sign="ss",
141 out_sign="", 141 out_sign="",
142 method=self._changePassword, 142 method=self._changePassword,
143 async=True, 143 async_=True,
144 ) 144 )
145 145
146 @staticmethod 146 @staticmethod
147 def buildRegisterIQ(xmlstream_, jid_, password, email=None): 147 def buildRegisterIQ(xmlstream_, jid_, password, email=None):
148 iq_elt = xmlstream.IQ(xmlstream_, "set") 148 iq_elt = xmlstream.IQ(xmlstream_, "set")
158 return iq_elt 158 return iq_elt
159 159
160 def _regCb(self, answer, client, post_treat_cb): 160 def _regCb(self, answer, client, post_treat_cb):
161 """Called after the first get IQ""" 161 """Called after the first get IQ"""
162 try: 162 try:
163 query_elt = answer.elements(NS_REG, "query").next() 163 query_elt = next(answer.elements(NS_REG, "query"))
164 except StopIteration: 164 except StopIteration:
165 raise exceptions.DataError("Can't find expected query element") 165 raise exceptions.DataError("Can't find expected query element")
166 166
167 try: 167 try:
168 x_elem = query_elt.elements(data_form.NS_X_DATA, "x").next() 168 x_elem = next(query_elt.elements(data_form.NS_X_DATA, "x"))
169 except StopIteration: 169 except StopIteration:
170 # XXX: it seems we have an old service which doesn't manage data forms 170 # XXX: it seems we have an old service which doesn't manage data forms
171 log.warning(_("Can't find data form")) 171 log.warning(_("Can't find data form"))
172 raise exceptions.DataError( 172 raise exceptions.DataError(
173 _("This gateway can't be managed by SàT, sorry :(") 173 _("This gateway can't be managed by SàT, sorry :(")
192 ) 192 )
193 return xml_tools.dataForm2XMLUI(form, submit_reg_id) 193 return xml_tools.dataForm2XMLUI(form, submit_reg_id)
194 194
195 def _regEb(self, failure, client): 195 def _regEb(self, failure, client):
196 """Called when something is wrong with registration""" 196 """Called when something is wrong with registration"""
197 log.info(_("Registration failure: %s") % unicode(failure.value)) 197 log.info(_("Registration failure: %s") % str(failure.value))
198 raise failure 198 raise failure
199 199
200 def _regSuccess(self, answer, client, post_treat_cb): 200 def _regSuccess(self, answer, client, post_treat_cb):
201 log.debug(_(u"registration answer: %s") % answer.toXml()) 201 log.debug(_("registration answer: %s") % answer.toXml())
202 if post_treat_cb is not None: 202 if post_treat_cb is not None:
203 post_treat_cb(jid.JID(answer["from"]), client.profile) 203 post_treat_cb(jid.JID(answer["from"]), client.profile)
204 return {} 204 return {}
205 205
206 def _regFailure(self, failure, client): 206 def _regFailure(self, failure, client):
207 log.info(_(u"Registration failure: %s") % unicode(failure.value)) 207 log.info(_("Registration failure: %s") % str(failure.value))
208 if failure.value.condition == "conflict": 208 if failure.value.condition == "conflict":
209 raise exceptions.ConflictError( 209 raise exceptions.ConflictError(
210 _("Username already exists, please choose an other one") 210 _("Username already exists, please choose an other one")
211 ) 211 )
212 raise failure 212 raise failure
219 219
220 @param to_jid(jid.JID): jid of the service to register to 220 @param to_jid(jid.JID): jid of the service to register to
221 """ 221 """
222 # FIXME: this post_treat_cb arguments seems wrong, check it 222 # FIXME: this post_treat_cb arguments seems wrong, check it
223 client = self.host.getClient(profile_key) 223 client = self.host.getClient(profile_key)
224 log.debug(_(u"Asking registration for {}").format(to_jid.full())) 224 log.debug(_("Asking registration for {}").format(to_jid.full()))
225 reg_request = client.IQ(u"get") 225 reg_request = client.IQ("get")
226 reg_request["from"] = client.jid.full() 226 reg_request["from"] = client.jid.full()
227 reg_request["to"] = to_jid.full() 227 reg_request["to"] = to_jid.full()
228 reg_request.addElement("query", NS_REG) 228 reg_request.addElement("query", NS_REG)
229 d = reg_request.send(to_jid.full()).addCallbacks( 229 d = reg_request.send(to_jid.full()).addCallbacks(
230 self._regCb, 230 self._regCb,
243 if port: 243 if port:
244 kwargs["port"] = port 244 kwargs["port"] = port
245 return self.registerNewAccount(jid.JID(jid_), password, **kwargs) 245 return self.registerNewAccount(jid.JID(jid_), password, **kwargs)
246 246
247 def registerNewAccount( 247 def registerNewAccount(
248 self, jid_, password, email=None, host=u"127.0.0.1", port=C.XMPP_C2S_PORT 248 self, jid_, password, email=None, host="127.0.0.1", port=C.XMPP_C2S_PORT
249 ): 249 ):
250 """register a new account on a XMPP server 250 """register a new account on a XMPP server
251 251
252 @param jid_(jid.JID): request jid to register 252 @param jid_(jid.JID): request jid to register
253 @param password(unicode): password of the account 253 @param password(unicode): password of the account
254 @param email(unicode): email of the account 254 @param email(unicode): email of the account
255 @param host(unicode): host of the server to register to 255 @param host(unicode): host of the server to register to
256 @param port(int): port of the server to register to 256 @param port(int): port of the server to register to
257 """ 257 """
258 check_certificate = host != u"127.0.0.1" 258 check_certificate = host != "127.0.0.1"
259 authenticator = RegisteringAuthenticator( 259 authenticator = RegisteringAuthenticator(
260 jid_, password, email, check_certificate=check_certificate) 260 jid_, password, email, check_certificate=check_certificate)
261 registered_d = authenticator.registered 261 registered_d = authenticator.registered
262 server_register = ServerRegister(authenticator) 262 server_register = ServerRegister(authenticator)
263 reactor.connectTCP(host, port, server_register) 263 reactor.connectTCP(host, port, server_register)
288 DELETE THE XMPP ACCOUNT WITHOUT WARNING 288 DELETE THE XMPP ACCOUNT WITHOUT WARNING
289 @param to_jid(jid.JID): jid of the service or server 289 @param to_jid(jid.JID): jid of the service or server
290 """ 290 """
291 iq_elt = client.IQ() 291 iq_elt = client.IQ()
292 iq_elt["to"] = to_jid.full() 292 iq_elt["to"] = to_jid.full()
293 query_elt = iq_elt.addElement((NS_REG, u"query")) 293 query_elt = iq_elt.addElement((NS_REG, "query"))
294 query_elt.addElement(u"remove") 294 query_elt.addElement("remove")
295 return iq_elt.send() 295 return iq_elt.send()