diff --git a/.github/workflows/test-stable.yml b/.github/workflows/test-stable.yml index 024115a9..67334e42 100644 --- a/.github/workflows/test-stable.yml +++ b/.github/workflows/test-stable.yml @@ -233,7 +233,7 @@ jobs: uses: actions/checkout@v3 with: path: ngircd - ref: rel-26.1 + ref: 0714466af88d71d6c395629cd7fb624b099507d4 repository: ngircd/ngircd - name: Build ngircd run: | diff --git a/irctest/server_tests/chmodes/key.py b/irctest/server_tests/chmodes/key.py index fd4c008e..26d60da5 100644 --- a/irctest/server_tests/chmodes/key.py +++ b/irctest/server_tests/chmodes/key.py @@ -44,8 +44,8 @@ def testKeyNormal(self): @pytest.mark.parametrize( "key", - ["passphrase with spaces", "long" * 100, ""], - ids=["spaces", "long", "empty"], + ["passphrase with spaces", "long" * 100, "", " "], + ids=["spaces", "long", "empty", "only-space"], ) @cases.mark_specifications("RFC2812", "Modern") def testKeyValidation(self, key): @@ -84,6 +84,8 @@ def testKeyValidation(self, key): "ngIRCd does not validate channel keys: " "https://github.com/ngircd/ngircd/issues/290" ) + if key == " " and self.controller.software_name == "irc2": + pytest.xfail("irc2 rewrites non-empty keys that contain only spaces") self.connectClient("bar") self.joinChannel(1, "#chan") diff --git a/irctest/server_tests/connection_registration.py b/irctest/server_tests/connection_registration.py index 7399cb9c..a3d50384 100644 --- a/irctest/server_tests/connection_registration.py +++ b/irctest/server_tests/connection_registration.py @@ -5,6 +5,8 @@ TODO: cross-reference Modern and RFC 2812 too """ +import time + from irctest import cases from irctest.client_mock import ConnectionClosed from irctest.numerics import ERR_NEEDMOREPARAMS, ERR_PASSWDMISMATCH @@ -133,7 +135,7 @@ def testNickCollision(self): self.assertNotEqual( m.command, "001", - "Received 001 after registering with the nick of a " "registered user.", + "Received 001 after registering with the nick of a registered user.", ) def testEarlyNickCollision(self): @@ -206,3 +208,58 @@ def testEmptyRealname(self): command=ERR_NEEDMOREPARAMS, params=[StrRe(r"(\*|foo)"), "USER", ANYSTR], ) + + def testNonutf8Realname(self): + self.addClient() + self.sendLine(1, "NICK foo") + line = b"USER username * * :i\xe8rc\xe9\r\n" + print("1 -> S (repr): " + repr(line)) + self.clients[1].conn.sendall(line) + for _ in range(10): + time.sleep(1) + d = self.clients[1].conn.recv(10000) + self.assertTrue(d, "Server closed connection") + print("S -> 1 (repr): " + repr(d)) + if b" 001 " in d: + break + if b"ERROR " in d or b" FAIL " in d: + # Rejected; nothing more to test. + return + for line in d.split(b"\r\n"): + if line.startswith(b"PING "): + line = line.replace(b"PING", b"PONG") + b"\r\n" + print("1 -> S (repr): " + repr(line)) + self.clients[1].conn.sendall(line) + else: + self.assertTrue(False, "stuck waiting") + self.sendLine(1, "WHOIS foo") + time.sleep(3) # for ngIRCd + d = self.clients[1].conn.recv(10000) + print("S -> 1 (repr): " + repr(d)) + self.assertIn(b"username", d) + + def testNonutf8Username(self): + self.addClient() + self.sendLine(1, "NICK foo") + self.sendLine(1, "USER 😊😊😊😊😊😊😊😊😊😊 * * :realname") + for _ in range(10): + time.sleep(1) + d = self.clients[1].conn.recv(10000) + self.assertTrue(d, "Server closed connection") + print("S -> 1 (repr): " + repr(d)) + if b" 001 " in d: + break + if b" 468" in d or b"ERROR " in d: + # Rejected; nothing more to test. + return + for line in d.split(b"\r\n"): + if line.startswith(b"PING "): + line = line.replace(b"PING", b"PONG") + b"\r\n" + print("1 -> S (repr): " + repr(line)) + self.clients[1].conn.sendall(line) + else: + self.assertTrue(False, "stuck waiting") + self.sendLine(1, "WHOIS foo") + d = self.clients[1].conn.recv(10000) + print("S -> 1 (repr): " + repr(d)) + self.assertIn(b"realname", d) diff --git a/irctest/server_tests/messages.py b/irctest/server_tests/messages.py index 441446df..c0f4ec0a 100644 --- a/irctest/server_tests/messages.py +++ b/irctest/server_tests/messages.py @@ -53,6 +53,28 @@ def testPrivmsgNonexistentUser(self): # ERR_NOSUCHNICK: 401 :No such nick self.assertMessageMatch(msg, command="401", params=["foo", "bar", ANYSTR]) + @cases.mark_specifications("RFC1459", "RFC2812", "Modern") + @cases.xfailIfSoftware( + ["irc2"], + "replies with ERR_NEEDMOREPARAMS instead of ERR_NOTEXTTOSEND", + ) + def testEmptyPrivmsg(self): + self.connectClient("foo") + self.sendLine(1, "JOIN #chan") + self.getMessages(1) # synchronize + self.connectClient("bar") + self.sendLine(2, "JOIN #chan") + self.getMessages(2) # synchronize + self.getMessages(1) # synchronize + self.sendLine(1, "PRIVMSG #chan :") + + self.assertMessageMatch( + self.getMessage(1), + command="412", # ERR_NOTEXTTOSEND + params=["foo", ANYSTR], + ) + self.assertEqual(self.getMessages(2), []) + class NoticeTestCase(cases.BaseServerTestCase): @cases.mark_specifications("RFC1459", "RFC2812") diff --git a/irctest/server_tests/utf8.py b/irctest/server_tests/utf8.py index bb5e77da..12ac1298 100644 --- a/irctest/server_tests/utf8.py +++ b/irctest/server_tests/utf8.py @@ -46,3 +46,38 @@ def testUtf8Validation(self): if m.command in ("FAIL", "WARN"): self.assertMessageMatch(m, params=["PRIVMSG", "INVALID_UTF8", ANYSTR]) + + def testNonutf8Realname(self): + self.connectClient("foo") + if "UTF8ONLY" not in self.server_support: + raise runner.IsupportTokenNotSupported("UTF8ONLY") + + self.addClient() + self.sendLine(2, "NICK foo") + self.clients[2].conn.sendall(b"USER username * * :i\xe8rc\xe9\r\n") + + d = self.clients[2].conn.recv(1024) + if b" FAIL " in d or b" 468 " in d: # ERR_INVALIDUSERNAME + return # nothing more to test + self.assertIn(b" 001 ", d) + + self.sendLine(2, "WHOIS foo") + self.getMessages(2) + + def testNonutf8Username(self): + self.connectClient("foo") + if "UTF8ONLY" not in self.server_support: + raise runner.IsupportTokenNotSupported("UTF8ONLY") + + self.addClient() + self.sendLine(2, "NICK foo") + self.sendLine(2, "USER 😊😊😊😊😊😊😊😊😊😊 * * :realname") + m = self.getRegistrationMessage(2) + if m.command in ("FAIL", "468"): # ERR_INVALIDUSERNAME + return # nothing more to test + self.assertMessageMatch( + m, + command="001", + ) + self.sendLine(2, "WHOIS foo") + self.getMessages(2) diff --git a/workflows.yml b/workflows.yml index 8c187dad..1033a19f 100644 --- a/workflows.yml +++ b/workflows.yml @@ -235,7 +235,7 @@ software: name: ngircd repository: ngircd/ngircd refs: - stable: rel-26.1 + stable: 0714466af88d71d6c395629cd7fb624b099507d4 # two years ahead of rel-26.1 release: null devel: master devel_release: null