[WIP] Add test for CHGHOST using services

Only Insp + Anope for now

TODO: cleanup code
This commit is contained in:
Valentin Lorentz 2022-04-03 20:42:13 +02:00
parent 9a19416731
commit 77c3c10847
4 changed files with 121 additions and 6 deletions

View File

@ -210,9 +210,10 @@ class BaseServerController(_BaseController):
case: irctest.cases.BaseServerTestCase, # type: ignore case: irctest.cases.BaseServerTestCase, # type: ignore
username: str, username: str,
password: Optional[str] = None, password: Optional[str] = None,
**kwargs: Any,
) -> None: ) -> None:
if self.services_controller is not None: if self.services_controller is not None:
self.services_controller.registerUser(case, username, password) self.services_controller.registerUser(case, username, password, **kwargs)
else: else:
raise NotImplementedByController("account registration") raise NotImplementedByController("account registration")
@ -293,7 +294,7 @@ class BaseServicesController(_BaseController):
timeout = time.time() + 5 timeout = time.time() + 5
while True: while True:
c.sendLine(f"PRIVMSG {self.server_controller.nickserv} :HELP") c.sendLine(f"PRIVMSG {self.server_controller.nickserv} :HELP")
msgs = self.getNickServResponse(c) msgs = self.getServiceResponse(c)
for msg in msgs: for msg in msgs:
if msg.command == "401": if msg.command == "401":
# NickServ not available yet # NickServ not available yet
@ -319,7 +320,7 @@ class BaseServicesController(_BaseController):
c.disconnect() c.disconnect()
self.services_up = True self.services_up = True
def getNickServResponse(self, client: Any) -> List[Message]: def getServiceResponse(self, client: Any) -> List[Message]:
"""Wrapper aroung getMessages() that waits longer, because NickServ """Wrapper aroung getMessages() that waits longer, because NickServ
is queried asynchronously.""" is queried asynchronously."""
msgs: List[Message] = [] msgs: List[Message] = []
@ -333,11 +334,14 @@ class BaseServicesController(_BaseController):
case: irctest.cases.BaseServerTestCase, # type: ignore case: irctest.cases.BaseServerTestCase, # type: ignore
username: str, username: str,
password: Optional[str] = None, password: Optional[str] = None,
**kwargs: Any,
) -> None: ) -> None:
if not case.run_services: if not case.run_services:
raise ValueError( raise ValueError(
"Attempted to register a nick, but `run_services` it not True." "Attempted to register a nick, but `run_services` it not True."
) )
if kwargs:
raise NotImplementedByController(", ".join(kwargs))
assert password assert password
client = case.addClient(show_io=True) client = case.addClient(show_io=True)
case.sendLine(client, "NICK " + username) case.sendLine(client, "NICK " + username)
@ -350,7 +354,7 @@ class BaseServicesController(_BaseController):
f"PRIVMSG {self.server_controller.nickserv} " f"PRIVMSG {self.server_controller.nickserv} "
f":REGISTER {password} foo@example.org", f":REGISTER {password} foo@example.org",
) )
msgs = self.getNickServResponse(case.clients[client]) msgs = self.getServiceResponse(case.clients[client])
if self.server_controller.software_name == "inspircd": if self.server_controller.software_name == "inspircd":
assert "900" in {msg.command for msg in msgs}, msgs assert "900" in {msg.command for msg in msgs}, msgs
assert "NOTICE" in {msg.command for msg in msgs}, msgs assert "NOTICE" in {msg.command for msg in msgs}, msgs

View File

@ -1,9 +1,12 @@
import os import os
import shutil import shutil
import subprocess import subprocess
from typing import Type from typing import Any, Optional, Type
from irctest import cases, runner
from irctest.basecontrollers import BaseServicesController, DirectoryBasedController from irctest.basecontrollers import BaseServicesController, DirectoryBasedController
from irctest.client_mock import ClientMock
from irctest.irc_utils.sasl import sasl_plain_blob
TEMPLATE_CONFIG = """ TEMPLATE_CONFIG = """
serverinfo {{ serverinfo {{
@ -30,12 +33,17 @@ networkinfo {{
userlen = 10 userlen = 10
hostlen = 64 hostlen = 64
chanlen = 32 chanlen = 32
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"
}} }}
mail {{ mail {{
usemail = no usemail = no
}} }}
/************************
* NickServ:
*/
service {{ service {{
nick = "NickServ" nick = "NickServ"
user = "services" user = "services"
@ -57,6 +65,29 @@ module {{
}} }}
command {{ service = "NickServ"; name = "REGISTER"; command = "nickserv/register"; }} command {{ service = "NickServ"; name = "REGISTER"; command = "nickserv/register"; }}
/************************
* HostServ:
*/
service {{
nick = "HostServ"
user = "services"
host = "services.host"
gecos = "vHost Service"
}}
module {{
name = "hostserv"
client = "HostServ"
}}
module {{ name = "hs_set" }}
command {{ service = "HostServ"; name = "SET"; command = "hostserv/set"; }}
/************************
* Misc:
*/
options {{ options {{
casemap = "ascii" casemap = "ascii"
readtimeout = 5s readtimeout = 5s
@ -66,7 +97,6 @@ options {{
module {{ name = "m_sasl" }} module {{ name = "m_sasl" }}
module {{ name = "enc_sha256" }} module {{ name = "enc_sha256" }}
module {{ name = "ns_cert" }} module {{ name = "ns_cert" }}
""" """
@ -121,6 +151,39 @@ class AnopeController(BaseServicesController, DirectoryBasedController):
# stderr=subprocess.DEVNULL, # stderr=subprocess.DEVNULL,
) )
def registerUser(
self,
case: cases.BaseServerTestCase, # type: ignore
username: str,
password: Optional[str] = None,
vhost: Optional[str] = None,
**kwargs: Any,
) -> None:
super().registerUser(case, username, password)
if vhost:
if not password:
raise runner.NotImplementedByController(
"vHost for users with no password"
)
c = ClientMock(name="setVhost", show_io=True)
c.connect(self.server_controller.hostname, self.server_controller.port)
c.sendLine("CAP REQ :sasl")
c.sendLine("NICK " + username)
c.sendLine("USER r e g :user")
while c.getMessage(synchronize=False).command != "CAP":
pass
c.sendLine("AUTHENTICATE PLAIN")
while c.getMessage(synchronize=False).command != "AUTHENTICATE":
pass
c.sendLine(sasl_plain_blob(username, password))
c.sendLine("CAP END")
while c.getMessage(synchronize=False).command != "001":
pass
c.getMessages()
c.sendLine(f"PRIVMSG HostServ :SET {username} {vhost}")
self.getServiceResponse(c)
def get_irctest_controller_class() -> Type[AnopeController]: def get_irctest_controller_class() -> Type[AnopeController]:
return AnopeController return AnopeController

View File

@ -61,10 +61,12 @@ TEMPLATE_CONFIG = """
# Protocol: # Protocol:
<module name="botmode"> <module name="botmode">
<module name="cap"> <module name="cap">
<module name="chghost">
<module name="ircv3"> <module name="ircv3">
<module name="ircv3_accounttag"> <module name="ircv3_accounttag">
<module name="ircv3_batch"> <module name="ircv3_batch">
<module name="ircv3_capnotify"> <module name="ircv3_capnotify">
<module name="ircv3_chghost">
<module name="ircv3_ctctags"> <module name="ircv3_ctctags">
<module name="ircv3_echomessage"> <module name="ircv3_echomessage">
<module name="ircv3_invitenotify"> <module name="ircv3_invitenotify">

View File

@ -0,0 +1,46 @@
"""
<http://ircv3.net/specs/extensions/chghost.html>
"""
from irctest import cases
from irctest.irc_utils.sasl import sasl_plain_blob
from irctest.patma import ANYSTR, StrRe
@cases.mark_services
class ChghostServicesTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
def testChghostFromServices(self):
self.connectClient("observer", capabilities=["chghost"], skip_if_cap_nak=True)
self.connectClient("oldclient")
self.controller.registerUser(
self, "vhostuser", "sesame", vhost="vhost.example.com"
)
self.connectClient("vhost-user", capabilities=["sasl"], skip_if_cap_nak=True)
for i in (1, 2, 3):
self.sendLine(i, "JOIN #chan")
self.getMessages(i)
for i in (1, 2, 3):
self.getMessages(i)
self.sendLine(3, "AUTHENTICATE PLAIN")
self.assertMessageMatch(
self.getRegistrationMessage(3),
command="AUTHENTICATE",
params=["+"],
)
self.sendLine(3, sasl_plain_blob("vhostuser", "sesame"))
self.assertMessageMatch(
self.getRegistrationMessage(3),
command="900",
)
self.assertMessageMatch(
self.getMessage(1),
prefix=StrRe("vhost-user!.*@(?!vhost-user.example)"),
command="CHGHOST",
params=[ANYSTR, "vhost.example.com"],
)
self.assertEqual(self.getMessages(2), []) # cycle?