diff options
-rw-r--r-- | .gitlab-ci.yml | 25 | ||||
-rw-r--r-- | itests/test_pep.py | 9 | ||||
-rw-r--r-- | slixmpp/jid.py | 8 | ||||
-rw-r--r-- | slixmpp/plugins/xep_0030/disco.py | 1 | ||||
-rw-r--r-- | slixmpp/plugins/xep_0045/muc.py | 2 | ||||
-rw-r--r-- | slixmpp/plugins/xep_0045/stanza.py | 9 | ||||
-rw-r--r-- | slixmpp/plugins/xep_0047/stream.py | 2 | ||||
-rw-r--r-- | slixmpp/plugins/xep_0425/moderation.py | 1 | ||||
-rw-r--r-- | slixmpp/xmlstream/handler/waiter.py | 2 | ||||
-rw-r--r-- | slixmpp/xmlstream/xmlstream.py | 38 |
10 files changed, 82 insertions, 15 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 48c6be9a..69bd7b7a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,6 +23,29 @@ test: - pip3 install emoji aiohttp - ./run_tests.py +test-3.10: + stage: test + tags: + - docker + image: python:3.10 + script: + - apt update + - apt install -y python3 python3-pip cython3 gpg + - pip3 install emoji aiohttp + - ./run_tests.py + +test-3.11: + stage: test + tags: + - docker + image: python:3.11-rc + allow_failure: true + script: + - apt update + - apt install -y python3 python3-pip cython3 gpg + - pip3 install emoji aiohttp + - ./run_tests.py + test_integration: stage: test tags: @@ -42,6 +65,6 @@ trigger_poezio: stage: trigger tags: - docker - image: appropriate/curl:latest + image: curlimages/curl:7.79.1 script: - curl --request POST -F token="$SLIXMPP_TRIGGER_TOKEN" -F ref=master https://lab.louiz.org/api/v4/projects/18/trigger/pipeline diff --git a/itests/test_pep.py b/itests/test_pep.py index a674a348..382c22b6 100644 --- a/itests/test_pep.py +++ b/itests/test_pep.py @@ -34,7 +34,14 @@ class TestPEP(SlixIntegration): """Check we can get and set public PEP data""" stanza = Mystanza() stanza['test'] = str(uuid4().hex) - await self.clients[0]['xep_0222'].store(stanza, id='toto') + try: + await self.clients[0]['xep_0060'].delete_node( + self.clients[0].boundjid.bare, + node=stanza.namespace, + ) + except: + pass + await self.clients[0]['xep_0222'].store(stanza, node=stanza.namespace, id='toto') fetched = await self.clients[0]['xep_0222'].retrieve( stanza.namespace, ) diff --git a/slixmpp/jid.py b/slixmpp/jid.py index adde95a4..d02f98a3 100644 --- a/slixmpp/jid.py +++ b/slixmpp/jid.py @@ -133,15 +133,15 @@ def _validate_domain(domain: str): try: domain = idna(domain) except StringprepError: - raise InvalidJID('idna validation failed') + raise InvalidJID(f'idna validation failed: {domain}') if ':' in domain: - raise InvalidJID('Domain containing a port') + raise InvalidJID(f'Domain containing a port: {domain}') for label in domain.split('.'): if not label: - raise InvalidJID('Domain containing too many dots') + raise InvalidJID(f'Domain containing too many dots: {domain}') if '-' in (label[0], label[-1]): - raise InvalidJID('Domain started or ended with -') + raise InvalidJID(f'Domain starting or ending with -: {domain}') if not domain: raise InvalidJID('Domain must not be 0 bytes') diff --git a/slixmpp/plugins/xep_0030/disco.py b/slixmpp/plugins/xep_0030/disco.py index 0fa09927..37d453aa 100644 --- a/slixmpp/plugins/xep_0030/disco.py +++ b/slixmpp/plugins/xep_0030/disco.py @@ -326,7 +326,6 @@ class XEP_0030(BasePlugin): info_futures, _ = await asyncio.wait( infos, timeout=timeout, - loop=self.xmpp.loop ) self.domain_infos[domain] = [ diff --git a/slixmpp/plugins/xep_0045/muc.py b/slixmpp/plugins/xep_0045/muc.py index 21f5c896..52988d44 100644 --- a/slixmpp/plugins/xep_0045/muc.py +++ b/slixmpp/plugins/xep_0045/muc.py @@ -35,6 +35,7 @@ from slixmpp.plugins.xep_0045 import stanza from slixmpp.plugins.xep_0045.stanza import ( MUCInvite, MUCDecline, + MUCDestroy, MUCPresence, MUCJoin, MUCMessage, @@ -88,6 +89,7 @@ class XEP_0045(BasePlugin): register_stanza_plugin(MUCMessage, MUCStatus) register_stanza_plugin(MUCPresence, MUCStatus) register_stanza_plugin(Presence, MUCPresence) + register_stanza_plugin(MUCPresence, MUCDestroy) register_stanza_plugin(Presence, MUCJoin) register_stanza_plugin(MUCJoin, MUCHistory) register_stanza_plugin(Message, MUCMessage) diff --git a/slixmpp/plugins/xep_0045/stanza.py b/slixmpp/plugins/xep_0045/stanza.py index 428dbce7..6c3d2244 100644 --- a/slixmpp/plugins/xep_0045/stanza.py +++ b/slixmpp/plugins/xep_0045/stanza.py @@ -235,6 +235,7 @@ class MUCOwnerQuery(ElementBase): class MUCOwnerDestroy(ElementBase): name = 'destroy' plugin_attrib = 'destroy' + namespace = NS_OWNER interfaces = {'reason', 'jid'} sub_interfaces = {'reason'} @@ -288,3 +289,11 @@ class MUCActor(ElementBase): if jid: return JID(jid) return jid + + +class MUCDestroy(ElementBase): + name = 'destroy' + plugin_attrib = 'destroy' + namespace = NS_USER + interfaces = {'reason', 'jid'} + sub_interfaces = {'reason'} diff --git a/slixmpp/plugins/xep_0047/stream.py b/slixmpp/plugins/xep_0047/stream.py index f020ea68..0cda5dd9 100644 --- a/slixmpp/plugins/xep_0047/stream.py +++ b/slixmpp/plugins/xep_0047/stream.py @@ -115,7 +115,7 @@ class IBBytestream(object): self.xmpp.add_event_handler('ibb_stream_end', on_close) self.xmpp.add_event_handler('ibb_stream_data', on_data) try: - await asyncio.wait_for(end_future, timeout, loop=self.xmpp.loop) + await asyncio.wait_for(end_future, timeout) except asyncio.TimeoutError: raise IqTimeout(result) finally: diff --git a/slixmpp/plugins/xep_0425/moderation.py b/slixmpp/plugins/xep_0425/moderation.py index 053e18f6..3c1308fc 100644 --- a/slixmpp/plugins/xep_0425/moderation.py +++ b/slixmpp/plugins/xep_0425/moderation.py @@ -44,4 +44,5 @@ class XEP_0425(BasePlugin): iq = self.xmpp.make_iq_set(ito=room.bare, ifrom=ifrom) iq['apply_to']['id'] = id iq['apply_to']['moderate']['reason'] = reason + iq['apply_to']['moderate'].enable('retract') await iq.send(**iqkwargs) diff --git a/slixmpp/xmlstream/handler/waiter.py b/slixmpp/xmlstream/handler/waiter.py index dde49754..599004b5 100644 --- a/slixmpp/xmlstream/handler/waiter.py +++ b/slixmpp/xmlstream/handler/waiter.py @@ -80,7 +80,7 @@ class Waiter(BaseHandler): try: await wait_for( - self._event.wait(), timeout, loop=stream.loop + self._event.wait(), timeout, ) except TimeoutError: log.warning("Timed out waiting for %s", self.name) diff --git a/slixmpp/xmlstream/xmlstream.py b/slixmpp/xmlstream/xmlstream.py index 30f99071..82611bfd 100644 --- a/slixmpp/xmlstream/xmlstream.py +++ b/slixmpp/xmlstream/xmlstream.py @@ -15,6 +15,7 @@ from typing import ( Coroutine, Callable, Iterator, + Iterable, List, Optional, Set, @@ -46,6 +47,7 @@ from asyncio import ( iscoroutinefunction, wait, ) +from pathlib import Path from slixmpp.types import FilterString from slixmpp.xmlstream.tostring import tostring @@ -74,6 +76,15 @@ class NotConnectedError(Exception): """ +class InvalidCABundle(Exception): + """ + Exception raised when the CA Bundle file hasn't been found. + """ + + def __init__(self, path: Optional[Path]): + self.path = path + + _T = TypeVar('_T', str, ElementBase, StanzaBase) @@ -161,7 +172,7 @@ class XMLStream(asyncio.BaseProtocol): #: #: On Mac OS X, certificates in the system keyring will #: be consulted, even if they are not in the provided file. - ca_certs: Optional[str] + ca_certs: Optional[Union[Path, Iterable[Path]]] #: Path to a file containing a client certificate to use for #: authenticating via SASL EXTERNAL. If set, there must also @@ -449,7 +460,7 @@ class XMLStream(asyncio.BaseProtocol): if self._connect_loop_wait > 0: self.event('reconnect_delay', self._connect_loop_wait) - await asyncio.sleep(self._connect_loop_wait, loop=self.loop) + await asyncio.sleep(self._connect_loop_wait) record = await self._pick_dns_answer(self.default_domain) if record is not None: @@ -504,10 +515,10 @@ class XMLStream(asyncio.BaseProtocol): else: self.loop.run_until_complete(self.disconnected) else: - tasks: List[Future] = [asyncio.sleep(timeout, loop=self.loop)] + tasks: List[Future] = [asyncio.sleep(timeout)] if not forever: tasks.append(self.disconnected) - self.loop.run_until_complete(asyncio.wait(tasks, loop=self.loop)) + self.loop.run_until_complete(asyncio.wait(tasks)) def init_parser(self) -> None: """init the XML parser. The parser must always be reset for each new @@ -715,7 +726,7 @@ class XMLStream(asyncio.BaseProtocol): log.debug("reconnecting...") async def handler(event: Any) -> None: # We yield here to allow synchronous handlers to work first - await asyncio.sleep(0, loop=self.loop) + await asyncio.sleep(0) self.connect() self.add_event_handler('disconnected', handler, disposable=True) self.disconnect(wait, reason) @@ -759,8 +770,23 @@ class XMLStream(asyncio.BaseProtocol): log.debug('Loaded cert file %s and key file %s', self.certfile, self.keyfile) if self.ca_certs is not None: + ca_cert: Optional[Path] = None + # XXX: Compat before d733c54518. + if isinstance(self.ca_certs, str): + self.ca_certs = Path(self.ca_certs) + if isinstance(self.ca_certs, Path): + if self.ca_certs.is_file(): + ca_cert = self.ca_certs + else: + for bundle in self.ca_certs: + if bundle.is_file(): + ca_cert = bundle + break + if ca_cert is None: + raise InvalidCABundle(ca_cert) + self.ssl_context.verify_mode = ssl.CERT_REQUIRED - self.ssl_context.load_verify_locations(cafile=self.ca_certs) + self.ssl_context.load_verify_locations(cafile=ca_cert) return self.ssl_context |