Mercurial > libervia-backend
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 |