Skip to content

Commit

Permalink
Add various validation tests (#221)
Browse files Browse the repository at this point in the history
* Add various validation tests

* skip UTF8ONLY tests on servers that don't support it

* Fixes for Ergo

* Fixes for Nefarious and ircu2

* xfail for irc2 and workaround for ngIRCd

* Bump ngIRCd to the ERR_NOTEXTTOSEND fix
  • Loading branch information
progval authored Sep 18, 2023
1 parent 04d0c80 commit 3692f2d
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-stable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down
6 changes: 4 additions & 2 deletions irctest/server_tests/chmodes/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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")
Expand Down
59 changes: 58 additions & 1 deletion irctest/server_tests/connection_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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)
22 changes: 22 additions & 0 deletions irctest/server_tests/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,28 @@ def testPrivmsgNonexistentUser(self):
# ERR_NOSUCHNICK: 401 <sender> <recipient> :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")
Expand Down
35 changes: 35 additions & 0 deletions irctest/server_tests/utf8.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 1 addition & 1 deletion workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 3692f2d

Please sign in to comment.