# HG changeset patch # User Goffi # Date 1556434513 -7200 # Node ID 69e4716d626896387e86f561737ba765f08df251 # Parent 4cd7545c4ebb4e1bd86d5ef253a79b153f5bbd07 plugins (jingle) file transfer: use initial "from" attribute as local jid instead of client.jid: while client.jid is fine in a client context, for components it's not the right jid to use: it is the jid of the component itself while the file transfer/jingle session entity may be established with this jid + a local part (e.g. if client is files.example.net, session may be established with louise@files.example.net, in which case "from" is louise@files.example.net, while client.jid will be files.example.net). As a consequence, using client.jid was causing trouble with components. This patch fixes it for jingle and plugins linked to file transfer by keeping a "local_jid" variable in the session, where the jid from the original "from" attribute is used. diff -r 4cd7545c4ebb -r 69e4716d6268 sat/plugins/plugin_xep_0047.py --- a/sat/plugins/plugin_xep_0047.py Sun Apr 28 08:55:13 2019 +0200 +++ b/sat/plugins/plugin_xep_0047.py Sun Apr 28 08:55:13 2019 +0200 @@ -131,10 +131,11 @@ """ return self._createSession(*args, **kwargs)[DEFER_KEY] - def _createSession(self, client, stream_object, to_jid, sid): + def _createSession(self, client, stream_object, local_jid, to_jid, sid): """Called when a bytestream is imminent @param stream_object(IConsumer): stream object where data will be written + @param local_jid(jid.JID): same as [startStream] @param to_jid(jid.JId): jid of the other peer @param sid(unicode): session id @return (dict): session data @@ -144,6 +145,7 @@ session_data = client.xep_0047_current_stream[sid] = { "id": sid, DEFER_KEY: defer.Deferred(), + "local_jid": local_jid, "to": to_jid, "stream_object": stream_object, "seq": -1, @@ -285,15 +287,19 @@ self._killSession(sid, client, error_condition) client.send(iq_elt) - def startStream(self, client, stream_object, to_jid, sid, block_size=None): + def startStream(self, client, stream_object, local_jid, to_jid, sid, block_size=None): """Launch the stream workflow @param stream_object(ifaces.IStreamProducer): stream object to send + @param local_jid(jid.JID): jid to use as local jid + This is needed for client which can be addressed with a different jid than + client.jid if a local part is used (e.g. piotr@file.example.net where + client.jid would be file.example.net) @param to_jid(jid.JID): JID of the recipient @param sid(unicode): Stream session id @param block_size(int, None): size of the block (or None for default) """ - session_data = self._createSession(client, stream_object, to_jid, sid) + session_data = self._createSession(client, stream_object, local_jid, to_jid, sid) if block_size is None: block_size = XEP_0047.BLOCK_SIZE @@ -301,6 +307,7 @@ session_data["block_size"] = block_size iq_elt = client.IQ() + iq_elt["from"] = local_jid.full() iq_elt["to"] = to_jid.full() open_elt = iq_elt.addElement((NS_IBB, "open")) open_elt["block-size"] = str(block_size) @@ -323,6 +330,7 @@ buffer_ = session_data["stream_object"].read(session_data["block_size"]) if buffer_: next_iq_elt = client.IQ() + next_iq_elt["from"] = session_data["local_jid"].full() next_iq_elt["to"] = session_data["to"].full() data_elt = next_iq_elt.addElement((NS_IBB, "data")) seq = session_data["seq"] = (session_data["seq"] + 1) % 65535 @@ -350,6 +358,7 @@ @param failure_reason(unicode, None): reason of the failure, or None if steam was successful """ iq_elt = client.IQ() + iq_elt["from"] = session_data["local_jid"].full() iq_elt["to"] = session_data["to"].full() close_elt = iq_elt.addElement((NS_IBB, "close")) close_elt["sid"] = session_data["id"] diff -r 4cd7545c4ebb -r 69e4716d6268 sat/plugins/plugin_xep_0065.py --- a/sat/plugins/plugin_xep_0065.py Sun Apr 28 08:55:13 2019 +0200 +++ b/sat/plugins/plugin_xep_0065.py Sun Apr 28 08:55:13 2019 +0200 @@ -273,7 +273,7 @@ raise exceptions.InternalError(u"Unknown {} type !".format(self.type)) return 2 ** 16 * multiplier + self._local_priority - def activate(self, sid, peer_jid, client): + def activate(self, client, sid, peer_jid, local_jid): """Activate the proxy candidate Send activation request as explained in XEP-0065 ยง 6.3.5 @@ -284,6 +284,7 @@ """ assert self.type == XEP_0065.TYPE_PROXY iq_elt = client.IQ() + iq_elt["from"] = local_jid.full() iq_elt["to"] = self.jid.full() query_elt = iq_elt.addElement((NS_BS, "query")) query_elt["sid"] = sid @@ -801,20 +802,22 @@ return self._server_factory @defer.inlineCallbacks - def getProxy(self, client): + def getProxy(self, client, local_jid): """Return the proxy available for this profile cache is used between clients using the same server + @param local_jid(jid.JID): same as for [getCandidates] @return ((D)(ProxyInfos, None)): Found proxy infos, or None if not acceptable proxy is found + @raise exceptions.NotFound: no Proxy found """ def notFound(server): log.info(u"No proxy found on this server") self._cache_proxies[server] = None - defer.returnValue(None) + raise exceptions.NotFound - server = client.jid.host + server = client.host if client.is_component else client.jid.host try: defer.returnValue(self._cache_proxies[server]) except KeyError: @@ -826,6 +829,7 @@ except (defer.CancelledError, StopIteration, KeyError): notFound(server) iq_elt = client.IQ("get") + iq_elt["from"] = local_jid.full() iq_elt["to"] = proxy.full() iq_elt.addElement((NS_BS, "query")) @@ -885,14 +889,21 @@ defer.returnValue((local_port, self._external_port, local_ips, external_ip)) @defer.inlineCallbacks - def getCandidates(self, client): + def getCandidates(self, client, local_jid): """Return a list of our stream candidates + @param local_jid(jid.JID): jid to use as local jid + This is needed for client which can be addressed with a different jid than + client.jid if a local part is used (e.g. piotr@file.example.net where + client.jid would be file.example.net) @return (D(list[Candidate])): list of candidates, ordered by priority """ server_factory = yield self.getSocks5ServerFactory() local_port, ext_port, local_ips, external_ip = yield self._getNetworkData(client) - proxy = yield self.getProxy(client) + try: + proxy = yield self.getProxy(client, local_jid) + except exceptions.NotFound: + proxy = None # its time to gather the candidates candidates = [] @@ -907,7 +918,7 @@ local_port, XEP_0065.TYPE_DIRECT, PRIORITY_BEST_DIRECT, - client.jid, + local_jid, priority_local=True, factory=server_factory, ) @@ -919,7 +930,7 @@ local_port, XEP_0065.TYPE_DIRECT, PRIORITY_DIRECT, - client.jid, + local_jid, priority_local=True, factory=server_factory, ) @@ -933,7 +944,7 @@ ext_port, XEP_0065.TYPE_ASSISTED, PRIORITY_ASSISTED, - client.jid, + local_jid, priority_local=True, factory=server_factory, ) @@ -1134,24 +1145,26 @@ return failure_ - def startStream(self, client, stream_object, to_jid, sid): + def startStream(self, client, stream_object, local_jid, to_jid, sid): """Launch the stream workflow @param streamProducer: stream_object to use + @param local_jid(jid.JID): same as for [getCandidates] @param to_jid: JID of the recipient @param sid: Stream session id @param successCb: method to call when stream successfuly finished @param failureCb: method to call when something goes wrong @return (D): Deferred fired when session is finished """ - session_data = self._createSession(client, stream_object, to_jid, sid, True) + session_data = self._createSession( + client, stream_object, local_jid, to_jid, sid, True) session_data[client] = client def gotCandidates(candidates): session_data["candidates"] = candidates iq_elt = client.IQ() - iq_elt["from"] = client.jid.full() + iq_elt["from"] = local_jid.full() iq_elt["to"] = to_jid.full() query_elt = iq_elt.addElement((NS_BS, "query")) query_elt["mode"] = "tcp" @@ -1165,13 +1178,13 @@ log.debug(u"Candidate proposed: {}".format(candidate)) d = iq_elt.send() - args = [session_data, client] + args = [client, session_data, local_jid] d.addCallbacks(self._IQNegotiationCb, self._IQNegotiationEb, args, None, args) - self.getCandidates(client).addCallback(gotCandidates) + self.getCandidates(client, local_jid).addCallback(gotCandidates) return session_data[DEFER_KEY] - def _IQNegotiationCb(self, iq_elt, session_data, client): + def _IQNegotiationCb(self, iq_elt, client, session_data, local_jid): """Called when the result of open iq is received @param session_data(dict): data of the session @@ -1204,7 +1217,7 @@ d = self.connectCandidate(client, candidate, session_data["hash"]) d.addCallback( lambda __: candidate.activate( - session_data["id"], session_data["peer_jid"], client + client, session_data["id"], session_data["peer_jid"], local_jid ) ) d.addErrback(self._activationEb) @@ -1216,7 +1229,7 @@ def _activationEb(self, failure): log.warning(u"Proxy activation error: {}".format(failure.value)) - def _IQNegotiationEb(self, stanza_err, session_data, client): + def _IQNegotiationEb(self, stanza_err, client, session_data, local_jid): log.warning(u"Socks5 transfer failed: {}".format(stanza_err.value)) # FIXME: must clean session @@ -1227,10 +1240,12 @@ """ return self._createSession(*args, **kwargs)[DEFER_KEY] - def _createSession(self, client, stream_object, to_jid, sid, requester=False): + def _createSession(self, client, stream_object, local_jid, to_jid, sid, + requester=False): """Called when a bytestream is imminent - @param stream_object(iface.IStreamProducer): File object where data will be written + @param stream_object(iface.IStreamProducer): File object where data will be + written @param to_jid(jid.JId): jid of the other peer @param sid(unicode): session id @param initiator(bool): if True, this session is create by initiator @@ -1239,10 +1254,10 @@ if sid in client.xep_0065_sid_session: raise exceptions.ConflictError(u"A session with this id already exists !") if requester: - session_hash = getSessionHash(client.jid, to_jid, sid) + session_hash = getSessionHash(local_jid, to_jid, sid) session_data = self._registerHash(client, session_hash, stream_object) else: - session_hash = getSessionHash(to_jid, client.jid, sid) + session_hash = getSessionHash(to_jid, local_jid, sid) session_d = defer.Deferred() session_d.addBoth(self.killSession, session_hash, sid, client) session_data = client._s5b_sessions[session_hash] = { @@ -1255,6 +1270,7 @@ session_data.update( { "id": sid, + "local_jid": local_jid, "peer_jid": to_jid, "stream_object": stream_object, "hash": session_hash, diff -r 4cd7545c4ebb -r 69e4716d6268 sat/plugins/plugin_xep_0096.py --- a/sat/plugins/plugin_xep_0096.py Sun Apr 28 08:55:13 2019 +0200 +++ b/sat/plugins/plugin_xep_0096.py Sun Apr 28 08:55:13 2019 +0200 @@ -239,7 +239,7 @@ # file_obj = self._getFileObject(dest_path, can_range) # range_offset = file_obj.tell() d = data["stream_plugin"].createSession( - client, data["stream_object"], data["peer_jid"], data["si_id"] + client, data["stream_object"], client.jid, data["peer_jid"], data["si_id"] ) d.addCallback(self._transferCb, client, data) d.addErrback(self._transferEb, client, data) @@ -357,7 +357,8 @@ stream_object = stream.FileStreamObject( self.host, client, filepath, uid=sid, size=size ) - d = plugin.startStream(client, stream_object, jid.JID(iq_elt["from"]), sid) + d = plugin.startStream(client, stream_object, client.jid, + jid.JID(iq_elt["from"]), sid) d.addCallback(self._sendCb, client, sid, stream_object) d.addErrback(self._sendEb, client, sid, stream_object) diff -r 4cd7545c4ebb -r 69e4716d6268 sat/plugins/plugin_xep_0166.py --- a/sat/plugins/plugin_xep_0166.py Sun Apr 28 08:55:13 2019 +0200 +++ b/sat/plugins/plugin_xep_0166.py Sun Apr 28 08:55:13 2019 +0200 @@ -121,7 +121,7 @@ def _buildJingleElt(self, client, session, action): iq_elt = client.IQ("set") - iq_elt["from"] = client.jid.full() + iq_elt["from"] = session['local_jid'].full() iq_elt["to"] = session["peer_jid"].full() jingle_elt = iq_elt.addElement("jingle", NS_JINGLE) jingle_elt["sid"] = session["id"] @@ -353,7 +353,8 @@ @return D(unicode): jingle session id """ assert contents # there must be at least one content - if peer_jid == client.jid: + if (peer_jid == client.jid + or client.is_component and peer_jid.host == client.jid.host): raise ValueError(_(u"You can't do a jingle session with yourself")) initiator = client.jid sid = unicode(uuid.uuid4()) @@ -363,6 +364,7 @@ "state": STATE_PENDING, "initiator": initiator, "role": XEP_0166.ROLE_INITIATOR, + "local_jid": client.jid, "peer_jid": peer_jid, "started": time.time(), "contents": {}, @@ -538,6 +540,9 @@ "state": STATE_PENDING, "initiator": peer_jid, "role": XEP_0166.ROLE_RESPONDER, + # we store local_jid using request['to'] because for a component the jid + # used may not be client.jid (if a local part is used). + "local_jid": jid.JID(request['to']), "peer_jid": peer_jid, "started": time.time(), } @@ -832,7 +837,7 @@ iq_elt, jingle_elt = self._buildJingleElt( client, session, XEP_0166.A_SESSION_ACCEPT ) - jingle_elt["responder"] = client.jid.full() + jingle_elt["responder"] = session['local_jid'].full() # contents diff -r 4cd7545c4ebb -r 69e4716d6268 sat/plugins/plugin_xep_0234.py --- a/sat/plugins/plugin_xep_0234.py Sun Apr 28 08:55:13 2019 +0200 +++ b/sat/plugins/plugin_xep_0234.py Sun Apr 28 08:55:13 2019 +0200 @@ -106,21 +106,9 @@ # generic methods - def buildFileElement( - self, - name, - file_hash=None, - hash_algo=None, - size=None, - mime_type=None, - desc=None, - modified=None, - transfer_range=None, - path=None, - namespace=None, - file_elt=None, - **kwargs - ): + def buildFileElement(self, name, file_hash=None, hash_algo=None, size=None, + mime_type=None, desc=None, modified=None, transfer_range=None, path=None, + namespace=None, file_elt=None, **kwargs): """Generate a element with available metadata @param file_hash(unicode, None): hash of the file diff -r 4cd7545c4ebb -r 69e4716d6268 sat/plugins/plugin_xep_0260.py --- a/sat/plugins/plugin_xep_0260.py Sun Apr 28 08:55:13 2019 +0200 +++ b/sat/plugins/plugin_xep_0260.py Sun Apr 28 08:55:13 2019 +0200 @@ -140,13 +140,14 @@ transport_data = content_data["transport_data"] sid = transport_data["sid"] = unicode(uuid.uuid4()) session_hash = transport_data["session_hash"] = self._s5b.getSessionHash( - client.jid, session["peer_jid"], sid + session[u"local_jid"], session["peer_jid"], sid ) transport_data["peer_session_hash"] = self._s5b.getSessionHash( - session["peer_jid"], client.jid, sid + session["peer_jid"], session[u"local_jid"], sid ) # requester and target are inversed for peer candidates transport_data["stream_d"] = self._s5b.registerHash(client, session_hash, None) - candidates = transport_data["candidates"] = yield self._s5b.getCandidates(client) + candidates = transport_data["candidates"] = yield self._s5b.getCandidates( + client, session["local_jid"]) mode = "tcp" # XXX: we only manage tcp for now transport_elt = self._buildCandidates( session, candidates, sid, session_hash, client, mode @@ -249,7 +250,7 @@ log.debug( u"Candidates have same priority, we select the one choosed by initiator" ) - if session["initiator"] == client.jid: + if session["initiator"] == session[u"local_jid"]: choosed_candidate = best_candidate else: choosed_candidate = peer_best_candidate @@ -425,12 +426,12 @@ assert "peer_candidates" not in transport_data sid = transport_data["sid"] = transport_elt["sid"] session_hash = transport_data["session_hash"] = self._s5b.getSessionHash( - client.jid, session["peer_jid"], sid + session["local_jid"], session["peer_jid"], sid ) peer_session_hash = transport_data[ "peer_session_hash" ] = self._s5b.getSessionHash( - session["peer_jid"], client.jid, sid + session["peer_jid"], session["local_jid"], sid ) # requester and target are inversed for peer candidates peer_candidates = transport_data["peer_candidates"] = self._parseCandidates( transport_elt @@ -444,7 +445,7 @@ d.addCallback( self._foundPeerCandidate, session, transport_data, content_name, client ) - candidates = yield self._s5b.getCandidates(client) + candidates = yield self._s5b.getCandidates(client, session["local_jid"]) # we remove duplicate candidates candidates = [ candidate for candidate in candidates if candidate not in peer_candidates diff -r 4cd7545c4ebb -r 69e4716d6268 sat/plugins/plugin_xep_0261.py --- a/sat/plugins/plugin_xep_0261.py Sun Apr 28 08:55:13 2019 +0200 +++ b/sat/plugins/plugin_xep_0261.py Sun Apr 28 08:55:13 2019 +0200 @@ -84,17 +84,19 @@ elif action in (self._j.A_SESSION_INITIATE, self._j.A_TRANSPORT_REPLACE): transport_data["sid"] = transport_elt["sid"] elif action in (self._j.A_START, self._j.A_PREPARE_RESPONDER): + local_jid = session["local_jid"] peer_jid = session["peer_jid"] sid = transport_data["sid"] stream_object = content_data["stream_object"] if action == self._j.A_START: block_size = transport_data["block_size"] d = self._ibb.startStream( - client, stream_object, peer_jid, sid, block_size + client, stream_object, local_jid, peer_jid, sid, block_size ) d.chainDeferred(content_data["finished_d"]) else: - d = self._ibb.createSession(client, stream_object, peer_jid, sid) + d = self._ibb.createSession( + client, stream_object, local_jid, peer_jid, sid) d.chainDeferred(content_data["finished_d"]) else: log.warning(u"FIXME: unmanaged action {}".format(action))