comparison libervia/backend/plugins/plugin_xep_0065.py @ 4270:0d7bb4df2343

Reformatted code base using black.
author Goffi <goffi@goffi.org>
date Wed, 19 Jun 2024 18:44:57 +0200
parents b86912d3fd33
children
comparison
equal deleted inserted replaced
4269:64a85ce8be70 4270:0d7bb4df2343
94 NS_BS = "http://jabber.org/protocol/bytestreams" 94 NS_BS = "http://jabber.org/protocol/bytestreams"
95 BS_REQUEST = IQ_SET + '/query[@xmlns="' + NS_BS + '"]' 95 BS_REQUEST = IQ_SET + '/query[@xmlns="' + NS_BS + '"]'
96 TIMER_KEY = "timer" 96 TIMER_KEY = "timer"
97 DEFER_KEY = "finished" # key of the deferred used to track session end 97 DEFER_KEY = "finished" # key of the deferred used to track session end
98 SERVER_STARTING_PORT = ( 98 SERVER_STARTING_PORT = (
99 0 99 0 # starting number for server port search (0 to ask automatic attribution)
100 ) # starting number for server port search (0 to ask automatic attribution) 100 )
101 101
102 # priorities are candidates local priorities, must be a int between 0 and 65535 102 # priorities are candidates local priorities, must be a int between 0 and 65535
103 PRIORITY_BEST_DIRECT = 10000 103 PRIORITY_BEST_DIRECT = 10000
104 PRIORITY_DIRECT = 5000 104 PRIORITY_DIRECT = 5000
105 PRIORITY_ASSISTED = 1000 105 PRIORITY_ASSISTED = 1000
167 167
168 ProxyInfos = namedtuple("ProxyInfos", ["host", "jid", "port"]) 168 ProxyInfos = namedtuple("ProxyInfos", ["host", "jid", "port"])
169 169
170 170
171 class Candidate(object): 171 class Candidate(object):
172 def __init__(self, host, port, type_, priority, jid_, id_=None, priority_local=False, 172 def __init__(
173 factory=None,): 173 self,
174 host,
175 port,
176 type_,
177 priority,
178 jid_,
179 id_=None,
180 priority_local=False,
181 factory=None,
182 ):
174 """ 183 """
175 @param host(unicode): host IP or domain 184 @param host(unicode): host IP or domain
176 @param port(int): port 185 @param port(int): port
177 @param type_(unicode): stream type (one of XEP_0065.TYPE_*) 186 @param type_(unicode): stream type (one of XEP_0065.TYPE_*)
178 @param priority(int): priority 187 @param priority(int): priority
245 multiplier = 110 254 multiplier = 110
246 elif self.type == XEP_0065.TYPE_PROXY: 255 elif self.type == XEP_0065.TYPE_PROXY:
247 multiplier = 10 256 multiplier = 10
248 else: 257 else:
249 raise exceptions.InternalError("Unknown {} type !".format(self.type)) 258 raise exceptions.InternalError("Unknown {} type !".format(self.type))
250 return 2 ** 16 * multiplier + self._local_priority 259 return 2**16 * multiplier + self._local_priority
251 260
252 def activate(self, client, sid, peer_jid, local_jid): 261 def activate(self, client, sid, peer_jid, local_jid):
253 """Activate the proxy candidate 262 """Activate the proxy candidate
254 263
255 Send activation request as explained in XEP-0065 § 6.3.5 264 Send activation request as explained in XEP-0065 § 6.3.5
287 (sid + requester_jid.full() + target_jid.full()).encode("utf-8") 296 (sid + requester_jid.full() + target_jid.full()).encode("utf-8")
288 ).hexdigest() 297 ).hexdigest()
289 298
290 299
291 class SOCKSv5(protocol.Protocol): 300 class SOCKSv5(protocol.Protocol):
292 CHUNK_SIZE = 2 ** 16 301 CHUNK_SIZE = 2**16
293 302
294 def __init__(self, session_hash=None): 303 def __init__(self, session_hash=None):
295 """ 304 """
296 @param session_hash(str): hash of the session 305 @param session_hash(str): hash of the session
297 must only be used in client mode 306 must only be used in client mode
375 384
376 def _parse_user_pass(self): 385 def _parse_user_pass(self):
377 try: 386 try:
378 # Parse out data 387 # Parse out data
379 ver, ulen = struct.unpack("BB", self.buf[:2]) 388 ver, ulen = struct.unpack("BB", self.buf[:2])
380 uname, = struct.unpack("%ds" % ulen, self.buf[2 : ulen + 2]) 389 (uname,) = struct.unpack("%ds" % ulen, self.buf[2 : ulen + 2])
381 plen, = struct.unpack("B", self.buf[ulen + 2]) 390 (plen,) = struct.unpack("B", self.buf[ulen + 2])
382 password, = struct.unpack("%ds" % plen, self.buf[ulen + 3 : ulen + 3 + plen]) 391 (password,) = struct.unpack(
392 "%ds" % plen, self.buf[ulen + 3 : ulen + 3 + plen]
393 )
383 # Trim off fron of the buffer 394 # Trim off fron of the buffer
384 self.buf = self.buf[3 + ulen + plen :] 395 self.buf = self.buf[3 + ulen + plen :]
385 # Fire event to authenticate user 396 # Fire event to authenticate user
386 if self.authenticate_user_pass(uname, password): 397 if self.authenticate_user_pass(uname, password):
387 # Signal success 398 # Signal success
441 except struct.error: 452 except struct.error:
442 # The buffer is probably not complete, we need to wait more 453 # The buffer is probably not complete, we need to wait more
443 return None 454 return None
444 455
445 def _make_request(self): 456 def _make_request(self):
446 hash_ = self._session_hash.encode('utf-8') 457 hash_ = self._session_hash.encode("utf-8")
447 request = struct.pack( 458 request = struct.pack(
448 "!5B%dsH" % len(hash_), 459 "!5B%dsH" % len(hash_),
449 SOCKS5_VER, 460 SOCKS5_VER,
450 CMD_CONNECT, 461 CMD_CONNECT,
451 0, 462 0,
499 if self.state == STATE_CLIENT_INITIAL: 510 if self.state == STATE_CLIENT_INITIAL:
500 self._start_negotiation() 511 self._start_negotiation()
501 512
502 def connect_requested(self, addr, port): 513 def connect_requested(self, addr, port):
503 # Check that this session is expected 514 # Check that this session is expected
504 if not self.factory.add_to_session(addr.decode('utf-8'), self): 515 if not self.factory.add_to_session(addr.decode("utf-8"), self):
505 log.warning( 516 log.warning(
506 "Unexpected connection request received from {host}".format( 517 "Unexpected connection request received from {host}".format(
507 host=self.transport.getPeer().host 518 host=self.transport.getPeer().host
508 ) 519 )
509 ) 520 )
510 self.send_error_reply(REPLY_CONN_REFUSED) 521 self.send_error_reply(REPLY_CONN_REFUSED)
511 return 522 return
512 self._session_hash = addr.decode('utf-8') 523 self._session_hash = addr.decode("utf-8")
513 self.connect_completed(addr, 0) 524 self.connect_completed(addr, 0)
514 525
515 def start_transfer(self, chunk_size): 526 def start_transfer(self, chunk_size):
516 """Callback called when the result iq is received 527 """Callback called when the result iq is received
517 528
722 def __init__(self, host): 733 def __init__(self, host):
723 log.info(_("Plugin XEP_0065 initialization")) 734 log.info(_("Plugin XEP_0065 initialization"))
724 self.host = host 735 self.host = host
725 736
726 # session data 737 # session data
727 self.hash_clients_map = {} # key: hash of the transfer session, value: session data 738 self.hash_clients_map = (
739 {}
740 ) # key: hash of the transfer session, value: session data
728 self._cache_proxies = {} # key: server jid, value: proxy data 741 self._cache_proxies = {} # key: server jid, value: proxy data
729 742
730 # misc data 743 # misc data
731 self._server_factory = None 744 self._server_factory = None
732 self._external_port = None 745 self._external_port = None
877 client.jid if a local part is used (e.g. piotr@file.example.net where 890 client.jid if a local part is used (e.g. piotr@file.example.net where
878 client.jid would be file.example.net) 891 client.jid would be file.example.net)
879 @return (D(list[Candidate])): list of candidates, ordered by priority 892 @return (D(list[Candidate])): list of candidates, ordered by priority
880 """ 893 """
881 server_factory = self.get_socks_5_server_factory() 894 server_factory = self.get_socks_5_server_factory()
882 local_port, ext_port, local_ips, external_ip = await self._get_network_data(client) 895 local_port, ext_port, local_ips, external_ip = await self._get_network_data(
896 client
897 )
883 try: 898 try:
884 proxy = await self.get_proxy(client, local_jid) 899 proxy = await self.get_proxy(client, local_jid)
885 except exceptions.NotFound: 900 except exceptions.NotFound:
886 proxy = None 901 proxy = None
887 902
1018 d.addErrback(connection_eb, client, candidate) 1033 d.addErrback(connection_eb, client, candidate)
1019 defers_list.append(d) 1034 defers_list.append(d)
1020 1035
1021 return defers_list 1036 return defers_list
1022 1037
1023 def get_best_candidate(self, client, candidates, session_hash, peer_session_hash=None): 1038 def get_best_candidate(
1039 self, client, candidates, session_hash, peer_session_hash=None
1040 ):
1024 """Get best candidate (according to priority) which can connect 1041 """Get best candidate (according to priority) which can connect
1025 1042
1026 @param candidates(iterable[Candidate]): candidates to test 1043 @param candidates(iterable[Candidate]): candidates to test
1027 @param session_hash(unicode): hash of the session 1044 @param session_hash(unicode): hash of the session
1028 hash is the same as hostname computed in XEP-0065 § 5.3.2 #1 1045 hash is the same as hostname computed in XEP-0065 § 5.3.2 #1
1135 @param successCb: method to call when stream successfuly finished 1152 @param successCb: method to call when stream successfuly finished
1136 @param failureCb: method to call when something goes wrong 1153 @param failureCb: method to call when something goes wrong
1137 @return (D): Deferred fired when session is finished 1154 @return (D): Deferred fired when session is finished
1138 """ 1155 """
1139 session_data = self._create_session( 1156 session_data = self._create_session(
1140 client, stream_object, local_jid, to_jid, sid, True) 1157 client, stream_object, local_jid, to_jid, sid, True
1158 )
1141 1159
1142 session_data[client] = client 1160 session_data[client] = client
1143 1161
1144 def got_candidates(candidates): 1162 def got_candidates(candidates):
1145 session_data["candidates"] = candidates 1163 session_data["candidates"] = candidates
1157 streamhost["jid"] = candidate.jid.full() 1175 streamhost["jid"] = candidate.jid.full()
1158 log.debug("Candidate proposed: {}".format(candidate)) 1176 log.debug("Candidate proposed: {}".format(candidate))
1159 1177
1160 d = iq_elt.send() 1178 d = iq_elt.send()
1161 args = [client, session_data, local_jid] 1179 args = [client, session_data, local_jid]
1162 d.addCallbacks(self._iq_negotiation_cb, self._iq_negotiation_eb, args, None, args) 1180 d.addCallbacks(
1163 1181 self._iq_negotiation_cb, self._iq_negotiation_eb, args, None, args
1164 defer.ensureDeferred(self.get_candidates(client, local_jid)).addCallback(got_candidates) 1182 )
1183
1184 defer.ensureDeferred(self.get_candidates(client, local_jid)).addCallback(
1185 got_candidates
1186 )
1165 return session_data[DEFER_KEY] 1187 return session_data[DEFER_KEY]
1166 1188
1167 def _iq_negotiation_cb(self, iq_elt, client, session_data, local_jid): 1189 def _iq_negotiation_cb(self, iq_elt, client, session_data, local_jid):
1168 """Called when the result of open iq is received 1190 """Called when the result of open iq is received
1169 1191
1179 # FIXME: must clean session 1201 # FIXME: must clean session
1180 return 1202 return
1181 1203
1182 streamhost_jid = jid.JID(streamhost_used_elt["jid"]) 1204 streamhost_jid = jid.JID(streamhost_used_elt["jid"])
1183 try: 1205 try:
1184 candidate = next(( 1206 candidate = next(
1185 c for c in session_data["candidates"] if c.jid == streamhost_jid 1207 (c for c in session_data["candidates"] if c.jid == streamhost_jid)
1186 )) 1208 )
1187 except StopIteration: 1209 except StopIteration:
1188 log.warning( 1210 log.warning(
1189 "Candidate [{jid}] is unknown !".format(jid=streamhost_jid.full()) 1211 "Candidate [{jid}] is unknown !".format(jid=streamhost_jid.full())
1190 ) 1212 )
1191 return 1213 return
1218 1240
1219 session deferred is fired when transfer is finished 1241 session deferred is fired when transfer is finished
1220 """ 1242 """
1221 return self._create_session(*args, **kwargs)[DEFER_KEY] 1243 return self._create_session(*args, **kwargs)[DEFER_KEY]
1222 1244
1223 def _create_session(self, client, stream_object, local_jid, to_jid, sid, 1245 def _create_session(
1224 requester=False): 1246 self, client, stream_object, local_jid, to_jid, sid, requester=False
1247 ):
1225 """Called when a bytestream is imminent 1248 """Called when a bytestream is imminent
1226 1249
1227 @param stream_object(iface.IStreamProducer): File object where data will be 1250 @param stream_object(iface.IStreamProducer): File object where data will be
1228 written 1251 written
1229 @param to_jid(jid.JId): jid of the other peer 1252 @param to_jid(jid.JId): jid of the other peer