From 93c2488fbce884222a06eb71b9b0e57272a44147 Mon Sep 17 00:00:00 2001 From: Jimmie Hogklint Date: Sat, 14 Dec 2019 23:42:44 +0100 Subject: [PATCH 1/4] Handle ConnectionResetError when sending PING --- pydle/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydle/client.py b/pydle/client.py index 66176aa..74a21a2 100644 --- a/pydle/client.py +++ b/pydle/client.py @@ -372,7 +372,7 @@ async def handle_forever(self): try: await self.rawmsg("PING", self.server_tag) data = await self.connection.recv(timeout=self.READ_TIMEOUT) - except asyncio.TimeoutError: + except (asyncio.TimeoutError, ConnectionResetError) as e: data = None if not data: From 95aae28e5b6705061b5b4ee8c8ecc567d90036fb Mon Sep 17 00:00:00 2001 From: Joshua Salzedo Date: Sun, 22 Dec 2019 16:19:02 -0800 Subject: [PATCH 2/4] Handle IRCv3 tag escape sequences fixes #123 --- pydle/features/ircv3/tags.py | 29 ++++++++++++++++++++++++++++- tests/test_ircv3.py | 24 ++++++++++++++++++++++++ tox.ini | 1 + 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tests/test_ircv3.py diff --git a/pydle/features/ircv3/tags.py b/pydle/features/ircv3/tags.py index 46be61a..934ca5e 100644 --- a/pydle/features/ircv3/tags.py +++ b/pydle/features/ircv3/tags.py @@ -3,14 +3,24 @@ import pydle.client import pydle.protocol from pydle.features import rfc1459 +import re TAG_INDICATOR = '@' TAG_SEPARATOR = ';' TAG_VALUE_SEPARATOR = '=' TAGGED_MESSAGE_LENGTH_LIMIT = 1024 +TAG_CONVERSIONS = { + r"\:": ';', + r"\s": ' ', + r"\\": '\\', + r"\r": '\r', + r"\n": '\n' +} + class TaggedMessage(rfc1459.RFC1459Message): + def __init__(self, tags=None, **kw): super().__init__(**kw) self._kw['tags'] = tags @@ -53,6 +63,20 @@ def parse(cls, line, encoding=pydle.protocol.DEFAULT_ENCODING): else: tag = raw_tag value = True + # Parse escape sequences since IRC escapes != python escapes + + # convert known escapes first + for escape, replacement in TAG_CONVERSIONS.items(): + value = value.replace(escape, replacement) + + # convert other escape sequences based on the spec + pattern =re.compile(r"(\\[\s\S])+") + for match in pattern.finditer(value): + escape = match.group() + value = value.replace(escape, escape[1]) + + + # Finally: add constructed tag to the output object. tags[tag] = value # Parse rest of message. @@ -77,7 +101,10 @@ def construct(self, force=False): message = TAG_INDICATOR + TAG_SEPARATOR.join(raw_tags) + ' ' + message if len(message) > TAGGED_MESSAGE_LENGTH_LIMIT and not force: - raise protocol.ProtocolViolation('The constructed message is too long. ({len} > {maxlen})'.format(len=len(message), maxlen=TAGGED_MESSAGE_LENGTH_LIMIT), message=message) + raise protocol.ProtocolViolation( + 'The constructed message is too long. ({len} > {maxlen})'.format(len=len(message), + maxlen=TAGGED_MESSAGE_LENGTH_LIMIT), + message=message) return message diff --git a/tests/test_ircv3.py b/tests/test_ircv3.py new file mode 100644 index 0000000..ca883f2 --- /dev/null +++ b/tests/test_ircv3.py @@ -0,0 +1,24 @@ +import pytest + +from pydle.features import ircv3 + +pytestmark = pytest.mark.new_test + + +@pytest.mark.parametrize( + "payload, expected", + [ + ( + rb"@+example=raw+:=,escaped\:\s\\ :irc.example.com NOTICE #channel :Message", + {"+example": """raw+:=,escaped; \\"""} + ), + ( + rb"@+example=\foo\bar :irc.example.com NOTICE #channel :Message", + {"+example": "foobar"} + ), + ] +) +def test_tagged_message_escape_sequences(payload, expected): + message = ircv3.tags.TaggedMessage.parse(payload) + + assert message.tags == expected diff --git a/tox.ini b/tox.ini index 3ae6c91..11dec10 100644 --- a/tox.ini +++ b/tox.ini @@ -15,3 +15,4 @@ markers = slow: may take several seconds or more to complete. meta: tests the test suite itself. real: tests pydle against a real server. Requires PYDLE_TESTS_REAL_HOST and PYDLE_TESTS_REAL_PORT environment variables. + new_test: new tests \ No newline at end of file From 7ce00dd1c201984c8646cefb92f1cac167fb3075 Mon Sep 17 00:00:00 2001 From: Joshua Salzedo Date: Sun, 22 Dec 2019 16:21:52 -0800 Subject: [PATCH 3/4] \n at EOL, fix pytestmark boilerplate --- tests/test_ircv3.py | 6 +++--- tox.ini | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_ircv3.py b/tests/test_ircv3.py index ca883f2..f99410f 100644 --- a/tests/test_ircv3.py +++ b/tests/test_ircv3.py @@ -2,7 +2,7 @@ from pydle.features import ircv3 -pytestmark = pytest.mark.new_test +pytestmark = pytest.mark.unit @pytest.mark.parametrize( @@ -13,8 +13,8 @@ {"+example": """raw+:=,escaped; \\"""} ), ( - rb"@+example=\foo\bar :irc.example.com NOTICE #channel :Message", - {"+example": "foobar"} + rb"@+example=\foo\bar :irc.example.com NOTICE #channel :Message", + {"+example": "foobar"} ), ] ) diff --git a/tox.ini b/tox.ini index 11dec10..5bd18aa 100644 --- a/tox.ini +++ b/tox.ini @@ -15,4 +15,4 @@ markers = slow: may take several seconds or more to complete. meta: tests the test suite itself. real: tests pydle against a real server. Requires PYDLE_TESTS_REAL_HOST and PYDLE_TESTS_REAL_PORT environment variables. - new_test: new tests \ No newline at end of file + unit: unit tests From beccbdd04a3e44e22ac16173b1b456cd6f4e1553 Mon Sep 17 00:00:00 2001 From: Joshua Salzedo Date: Mon, 3 Feb 2020 20:25:18 -0800 Subject: [PATCH 4/4] #134 ignore strictly invalid null nickname --- pydle/features/rfc1459/client.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pydle/features/rfc1459/client.py b/pydle/features/rfc1459/client.py index 077692e..f83957f 100644 --- a/pydle/features/rfc1459/client.py +++ b/pydle/features/rfc1459/client.py @@ -923,6 +923,9 @@ async def on_raw_353(self, message): safe_entry = entry.lstrip(''.join(self._nickname_prefixes.keys())) # Parse entry and update database. nick, metadata = self._parse_user(safe_entry) + if not nick: + # nonsense nickname + continue self._sync_user(nick, metadata) # Get prefixes.