Skip to content

Commit

Permalink
Make re.match actually check the whole string matches the pattern (#261)
Browse files Browse the repository at this point in the history
And explicitly allow trailing space in RPL_WHOISCHANNELS
  • Loading branch information
progval authored Apr 16, 2024
1 parent 473db1c commit ea66a8f
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 16 deletions.
2 changes: 1 addition & 1 deletion irctest/irc_utils/message_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
unescape_tag_value = MultipleReplacer(dict(map(lambda x: (x[1], x[0]), TAG_ESCAPE)))

# TODO: validate host
tag_key_validator = re.compile(r"\+?(\S+/)?[a-zA-Z0-9-]+")
tag_key_validator = re.compile(r"^\+?(\S+/)?[a-zA-Z0-9-]+$")


def parse_tags(s: str) -> Dict[str, Optional[str]]:
Expand Down
6 changes: 3 additions & 3 deletions irctest/patma.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,15 @@ def match_string(got: Optional[str], expected: Union[str, Operator, None]) -> bo
elif isinstance(expected, _AnyStr) and got is not None:
return True
elif isinstance(expected, StrRe):
if got is None or not re.match(expected.regexp, got):
if got is None or not re.match(expected.regexp + "$", got):
return False
elif isinstance(expected, OptStrRe):
if got is None:
return True
if not re.match(expected.regexp, got):
if not re.match(expected.regexp + "$", got):
return False
elif isinstance(expected, NotStrRe):
if got is None or re.match(expected.regexp, got):
if got is None or re.match(expected.regexp + "$", got):
return False
elif isinstance(expected, InsensitiveStr):
if got is None or got.lower() != expected.string.lower():
Expand Down
5 changes: 3 additions & 2 deletions irctest/server_tests/isupport.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ def testPrefix(self):
return

m = re.match(
r"\((?P<modes>[a-zA-Z]+)\)(?P<prefixes>\S+)", self.server_support["PREFIX"]
r"^\((?P<modes>[a-zA-Z]+)\)(?P<prefixes>\S+)$",
self.server_support["PREFIX"],
)
self.assertTrue(
m,
Expand Down Expand Up @@ -117,5 +118,5 @@ def testTargmax(self):
parts = self.server_support["TARGMAX"].split(",")
for part in parts:
self.assertTrue(
re.match("[A-Z]+:[0-9]*", part), "Invalid TARGMAX key:value: %r", part
re.match("^[A-Z]+:[0-9]*$", part), "Invalid TARGMAX key:value: %r", part
)
27 changes: 18 additions & 9 deletions irctest/server_tests/names.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


class NamesTestCase(cases.BaseServerTestCase):
def _testNames(self, symbol):
def _testNames(self, symbol: bool, allow_trailing_space: bool):
self.connectClient("nick1")
self.sendLine(1, "JOIN #chan")
self.getMessages(1)
Expand All @@ -31,7 +31,10 @@ def _testNames(self, symbol):
"nick1",
*(["="] if symbol else []),
"#chan",
StrRe("(nick2 @nick1|@nick1 nick2)"),
StrRe(
"(nick2 @nick1|@nick1 nick2)"
+ (" ?" if allow_trailing_space else "")
),
],
)

Expand All @@ -44,20 +47,26 @@ def _testNames(self, symbol):
@cases.mark_specifications("RFC1459", deprecated=True)
def testNames1459(self):
"""
https://modern.ircdocs.horse/#names-message
https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.5
https://datatracker.ietf.org/doc/html/rfc2812#section-3.2.5
"""
self._testNames(symbol=False)
self._testNames(symbol=False, allow_trailing_space=True)

@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
@cases.mark_specifications("RFC2812", "Modern")
def testNames2812(self):
"""
https://modern.ircdocs.horse/#names-message
https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.5
https://datatracker.ietf.org/doc/html/rfc2812#section-3.2.5
"""
self._testNames(symbol=True)
self._testNames(symbol=True, allow_trailing_space=True)

@cases.mark_specifications("Modern")
@cases.xfailIfSoftware(
["Bahamut", "irc2"], "Bahamut and irc2 send a trailing space in RPL_NAMREPLY"
)
def testNamesModern(self):
"""
https://modern.ircdocs.horse/#names-message
"""
self._testNames(symbol=True, allow_trailing_space=False)

def _testNamesMultipleChannels(self, symbol):
self.connectClient("nick1")
Expand Down
4 changes: 3 additions & 1 deletion irctest/server_tests/whois.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ def _testWhoisNumerics(self, authenticate, away, oper):
params=[
"nick1",
"nick2",
StrRe("(@#chan1 @#chan2|@#chan2 @#chan1)"),
# trailing space was required by the RFCs, and Modern explicitly
# allows it
StrRe("(@#chan1 @#chan2|@#chan2 @#chan1) ?"),
],
)
elif m.command == RPL_WHOISSPECIAL:
Expand Down

0 comments on commit ea66a8f

Please sign in to comment.