Files
znc/test/integration/tests/modules.cpp
T
Alhuda Khan a9ec2fb9a4 bouncedcc: connect to the bounce port via localhost in the test
The bounce listener binds to the IRC socket's local address. With the
inttest unix sockets that is "localhost" on Linux, which Csocket
resolves to ::1, so connecting to 127.0.0.1 never reached it.
2026-10-24 11:57:02 +05:30

1253 lines
46 KiB
C++

/*
* Copyright (C) 2004-2026 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "znctest.h"
#include <QSslSocket>
#include <QTcpServer>
using testing::HasSubstr;
using testing::Not;
namespace znc_inttest {
namespace {
TEST_F(ZNCTest, NotifyConnectModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod notify_connect");
client.ReadUntil("Loaded module");
auto client2 = ConnectClient();
client2.Write("PASS :hunter2");
client2.Write("NICK nick");
client2.Write("USER user/test x x :x");
client.ReadUntil("NOTICE nick :*** user attached from ");
auto client3 = ConnectClient();
client3.Write("PASS :hunter2");
client3.Write("NICK nick");
client3.Write("USER user@identifier/test x x :x");
client.ReadUntil(
"NOTICE nick :*** user@identifier attached from ");
client2.ReadUntil(
"NOTICE nick :*** user@identifier attached from ");
client2.Write("QUIT");
client.ReadUntil("NOTICE nick :*** user detached from ");
client3.Close();
client.ReadUntil(
"NOTICE nick :*** user@identifier detached from ");
}
TEST_F(ZNCTest, ClientNotifyModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod clientnotify");
client.ReadUntil("Loaded module");
auto check_not_sent = [](Socket& client, QString wrongAnswer) {
QString result = QString::fromUtf8(client.ReadRemainder());
QRegularExpression expr(wrongAnswer);
QRegularExpressionMatch match = expr.match(result);
EXPECT_FALSE(match.hasMatch())
<< "Got an answer from the ClientNotifyModule even though we didnt "
"want one with the given configuration: "
<< wrongAnswer.toStdString() << result.toStdString();
};
auto client2 = LoginClient();
client.ReadUntilRe(R"(:Another client \((localhost)?\) authenticated as your user. Use the 'ListClients' command to see all 2 clients.)");
auto client3 = LoginClient();
client.ReadUntilRe(R"(:Another client \((localhost)?\) authenticated as your user. Use the 'ListClients' command to see all 3 clients.)");
// disable notifications for every message
client.Write("PRIVMSG *clientnotify :NewOnly on");
// check that we do not ge a notification after connecting from a know ip
auto client4 = LoginClient();
check_not_sent(client, ":Another client (.*) authenticated as your user. Use the 'ListClients' command to see all 4 clients.");
// choose to notify only on new client ids
client.Write("PRIVMSG *clientnotify :NotifyOnNewID on");
auto client5 = LoginClient("identifier123");
client.ReadUntilRe(R"(:Another client \((localhost)? / identifier123\) authenticated as your user. Use the 'ListClients' command to see all 5 clients.)");
auto client6 = LoginClient("identifier123");
check_not_sent(client, ":Another client (.* / identifier123) authenticated as your user. Use the 'ListClients' command to see all 6 clients.");
auto client7 = LoginClient("not_identifier123");
client.ReadUntilRe(R"(:Another client \((localhost)? / not_identifier123\) authenticated as your user. Use the 'ListClients' command to see all 7 clients.)");
// choose to notify from both clientids and new IPs
client.Write("PRIVMSG *clientnotify :NotifyOnNewIP on");
auto client8 = LoginClient();
check_not_sent(client, ":Another client (.* / identifier123) authenticated as your user. Use the 'ListClients' command to see all 8 clients.");
auto client9 = LoginClient("definitely_not_identifier123");
client.ReadUntilRe(R"(:Another client \((localhost)? / definitely_not_identifier123\) authenticated as your user. Use the 'ListClients' command to see all 9 clients.)");
}
TEST_F(ZNCTest, ShellModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod shell");
client.Write("PRIVMSG *shell :echo blahblah");
client.ReadUntil("PRIVMSG nick :blahblah");
client.ReadUntil("PRIVMSG nick :znc$");
}
TEST_F(ZNCTest, WatchModule) {
// TODO test options
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod watch");
client.ReadUntil("Loaded module");
client.Write("PRIVMSG *watch :add *");
client.ReadUntil("Adding entry:");
client.Write("PRIVMSG *watch :add * *spaces *word1 word2*");
client.ReadUntil("Adding entry:");
ircd.Write(":server 001 nick :Hello");
ircd.Write(":nick JOIN :#znc");
// OnChanCTCPMessage / OnChanActionMessage
ircd.Write(":n!i@h PRIVMSG #znc :\001ACTION foo\001");
client.ReadUntil(
":$*!watch@znc.in PRIVMSG nick :* CTCP: n [ACTION foo] to [#znc]");
// OnChanNoticeMessage
ircd.Write(":n!i@h NOTICE #znc :Channel notice");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :-n:#znc- Channel notice");
// OnChanTextMessage
ircd.Write(":n!i@h PRIVMSG #znc :SOMETHING word1 word2 SOMETHING");
client.ReadUntil(
":*spaces!watch@znc.in PRIVMSG nick :<n:#znc> SOMETHING word1 word2 "
"SOMETHING");
// OnPrivCTCPMessage / OnPrivActionMessage
ircd.Write(":n!i@h PRIVMSG nick :\001ACTION foo\001");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :* CTCP: n [ACTION foo]");
// OnPrivCTCPReplyMessage
ircd.Write(":n!i@h NOTICE nick :\001VERSION znc 1.0\001");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :* CTCP: n reply [VERSION znc 1.0]");
// OnPrivNoticeMessage
ircd.Write(":n!i@h NOTICE nick :Private notice");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :-n- Private notice");
// OnPrivTextMessage
ircd.Write(":n!i@h PRIVMSG nick :Hello there");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :<n> Hello there");
// OnJoinMessage
ircd.Write(":join!i@h JOIN :#znc");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :* join (i@h) joins #znc");
// OnKickMessage
ircd.Write(":kick!i@h JOIN :#znc");
ircd.Write(":n!i@h KICK #znc kick :Test Kick");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :* n kicked kick from #znc because "
"[Test Kick]");
// OnNickMessage
ircd.Write(":someone!i@h JOIN :#znc");
ircd.Write(":someone!i@h NICK :newname");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :* someone is now known as newname");
// OnPartMessage
ircd.Write(":part!i@h JOIN :#znc");
ircd.Write(":part!i@h PART #znc :Leaving");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :* part (i@h) parts #znc(Leaving)");
// OnQuitMessage
ircd.Write(":quit!i@h JOIN :#znc");
ircd.Write(":quit!i@h QUIT :Goodbye");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :* Quits: quit (i@h) (Goodbye)");
// OnRawMode
ircd.Write(":n!i@h MODE #znc +o op");
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :* n sets mode: +o op on #znc");
}
TEST_F(ZNCTest, CryptModule) {
#ifndef HAVE_LIBSSL
GTEST_SKIP() << "SSL is disabled";
#endif
QFile conf(m_dir.path() + "/configs/znc.conf");
ASSERT_TRUE(conf.open(QIODevice::Append | QIODevice::Text));
QTextStream(&conf) << "ServerThrottle = 1\n";
auto znc = Run();
auto ircd1 = ConnectIRCd();
auto client1 = LoginClient();
client1.Write("znc loadmod controlpanel");
client1.Write("PRIVMSG *controlpanel :CloneUser user user2");
client1.ReadUntil("User user2 added!");
client1.Write("PRIVMSG *controlpanel :Set Nick user2 nick2");
client1.Write("znc loadmod crypt");
client1.ReadUntil("Loaded module");
auto ircd2 = ConnectIRCd();
auto client2 = ConnectClient();
client2.Write("PASS user2:hunter2");
client2.Write("NICK nick2");
client2.Write("USER user2/test x x :x");
client2.Write("znc loadmod crypt");
client2.ReadUntil("Loaded module");
client1.Write("PRIVMSG *crypt :keyx nick2");
client1.ReadUntil("Sent my DH1080 public key to nick2");
QByteArray pub1("");
ircd1.ReadUntilAndGet("NOTICE nick2 :DH1080_INIT ", pub1);
ircd2.Write(":user!user@user/test " + pub1);
client2.ReadUntil("Received DH1080 public key from user");
client2.ReadUntil("Key for user successfully set.");
QByteArray pub2("");
ircd2.ReadUntilAndGet("NOTICE user :DH1080_FINISH ", pub2);
ircd1.Write(":nick2!user2@user2/test " + pub2);
client1.ReadUntil("Key for nick2 successfully set.");
client1.Write("PRIVMSG *crypt :listkeys");
QByteArray key1("");
client1.ReadUntilAndGet("\002nick2\017: ", key1);
client2.Write("PRIVMSG *crypt :listkeys");
QByteArray key2("");
client2.ReadUntilAndGet("\002user\017: ", key2);
ASSERT_EQ(key1.mid(9), key2.mid(8));
// OnPrivTextMessage
client1.Write("CAP REQ :echo-message");
client1.Write("PRIVMSG .nick2 :Hello");
QByteArray secretmsg;
ircd1.ReadUntilAndGet("PRIVMSG nick2 :+OK ", secretmsg);
ircd2.Write(":user!user@user/test " + secretmsg);
client2.ReadUntil("Hello");
client1.ReadUntil(secretmsg); // by echo-message
client1.Write("PRIVMSG *crypt :SetNickPrefix .");
client1.ReadUntil("Setting Nick Prefix to .");
client2.Write("PRIVMSG *crypt :SetNickPrefix .");
client2.ReadUntil("Setting Nick Prefix to .");
// OnPrivNoticeMessage
client1.Write("NOTICE .nick2 :secret notice");
QByteArray noticeMsg;
ircd1.ReadUntilAndGet("NOTICE nick2 :+OK ", noticeMsg);
ircd2.Write(":user!user@user/test " + noticeMsg);
QByteArray noticeLine;
client2.ReadUntilAndGet("NOTICE nick2 :", noticeLine);
QByteArray noticemessage = noticeLine.mid(noticeLine.lastIndexOf(':') + 1);
EXPECT_EQ(noticemessage, "secret notice");
// OnUserActionMessage
client1.Write("PRIVMSG .nick2 :\001ACTION waves\001");
QByteArray actionMsg;
ircd1.ReadUntilAndGet("PRIVMSG nick2 :\001ACTION +OK ", actionMsg);
ircd2.Write(":user!user@user/test " + actionMsg);
QByteArray actionLine;
client2.ReadUntilAndGet("PRIVMSG nick2 :", actionLine);
QByteArray actionMessage = actionLine.mid(actionLine.lastIndexOf(':') + 1);
EXPECT_EQ(actionMessage, "\001ACTION waves\001");
client1.Write("JOIN #test");
client2.Write("JOIN #test");
QByteArray chanKey = "channelKey123";
client1.Write(QByteArray("PRIVMSG *crypt :SetKey #test ") + chanKey);
client1.ReadUntil(QByteArray("Set encryption key for [#test] to [") +
chanKey + "]");
client2.Write(QByteArray("PRIVMSG *crypt :SetKey #test ") + chanKey);
client2.ReadUntil(QByteArray("Set encryption key for [#test] to [") +
chanKey + "]");
// OnChanTextMessage
client1.Write("PRIVMSG #test :channel secret");
QByteArray chanMsg;
ircd1.ReadUntilAndGet("PRIVMSG #test :+OK ", chanMsg);
ircd2.Write(":user!user@user/test " + chanMsg);
client2.ReadUntil("channel secret");
// OnChanNoticeMessage
client1.Write("NOTICE #test :chan notice");
QByteArray chanNoticeMsg;
ircd1.ReadUntilAndGet("NOTICE #test :+OK ", chanNoticeMsg);
ircd2.Write(":user!user@user/test " + chanNoticeMsg);
client2.ReadUntil("chan notice");
// OnChanActionMessage
client1.Write("PRIVMSG #test :\001ACTION dances\001");
QByteArray chanActionMsg;
ircd1.ReadUntilAndGet("PRIVMSG #test :\001ACTION +OK ", chanActionMsg);
ircd2.Write(":user!user@user/test " + chanActionMsg);
client2.ReadUntil("dances");
// OnUserTopicMessage / OnNumericMessage
client1.Write("TOPIC #test :new chan topic");
QByteArray chanTopicEncrypted;
ircd1.ReadUntilAndGet("TOPIC #test :+OK ", chanTopicEncrypted);
chanTopicEncrypted = "+OK " + chanTopicEncrypted.mid(
chanTopicEncrypted.lastIndexOf(' ') + 1);
ircd2.Write(":ircd2 332 nick2 #test :" + chanTopicEncrypted);
client2.ReadUntil("new chan topic");
// OnTopicMessage
ircd2.Write(":user!user@user/test TOPIC #test :" + chanTopicEncrypted);
QByteArray topicLine;
client2.ReadUntilAndGet("TOPIC #test :", topicLine);
}
TEST_F(ZNCTest, AutoAttachModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
InstallModule("testmod.cpp", R"(
#include <znc/Client.h>
#include <znc/Modules.h>
class TestModule : public CModule {
public:
MODCONSTRUCTOR(TestModule) {}
EModRet OnChanBufferPlayMessage(CMessage& Message) override {
PutIRC("TEST " + Message.GetClient()->GetNickMask());
return CONTINUE;
}
};
MODULEDEFS(TestModule, "Test")
)");
client.Write("znc loadmod testmod");
client.Write("PRIVMSG *controlpanel :Set AutoClearChanBuffer $me no");
client.Write("znc loadmod autoattach");
client.Write("PRIVMSG *autoattach :Add * * *");
client.ReadUntil("Added to list");
ircd.Write(":server 001 nick :Hello");
ircd.Write(":nick JOIN :#znc");
ircd.Write(":server 353 nick #znc :nick");
ircd.Write(":server 366 nick #znc :End of /NAMES list");
// OnChanTextMessage
ircd.Write(":foo PRIVMSG #znc :hi");
client.ReadUntil(":foo PRIVMSG");
client.Write("detach #znc");
client.ReadUntil("Detached");
ircd.Write(":foo PRIVMSG #znc :hello");
ircd.ReadUntil("TEST");
client.ReadUntil("hello");
// OnChanActionMessage
ircd.Write(":foo PRIVMSG #znc :hi");
client.ReadUntil(":foo PRIVMSG");
client.Write("detach #znc");
client.ReadUntil("Detached");
ircd.Write(":foo PRIVMSG #znc :\001ACTION hello\001");
ircd.ReadUntil("TEST");
client.ReadUntil("\001ACTION hello\001");
// OnChanNoticeMessage
ircd.Write(":foo NOTICE #znc :hi");
client.ReadUntil(":foo NOTICE");
client.Write("detach #znc");
client.ReadUntil("Detached");
ircd.Write(":foo NOTICE #znc :hello NOTICE");
ircd.ReadUntil("TEST");
client.ReadUntil("hello NOTICE");
}
TEST_F(ZNCTest, KeepNickModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod keepnick");
client.ReadUntil("Loaded module");
ircd.ReadUntil("NICK user");
ircd.Write(":server 433 * nick :Nickname is already in use.");
ircd.ReadUntil("NICK user_");
ircd.Write(":server 001 user_ :Hello");
client.ReadUntil("Connected!");
ircd.ReadUntil("NICK user");
ircd.Write(":server 435 user_ user #error :Nope :-P");
client.ReadUntil(
":*keepnick!keepnick@znc.in PRIVMSG user_ "
":Unable to obtain nick user: Nope :-P, #error");
client.Write("PRIVMSG *keepnick :state");
client.ReadUntil("Currently disabled");
client.Write("NICK user_");
ircd.ReadUntil("NICK user_");
client.Write("JOIN #test");
ircd.ReadUntil("JOIN #test");
ircd.Write(":server 353 nick = #test :user_ user");
ircd.Write(":server 366 nick #test :End of /NAMES list");
client.Write("PRIVMSG *keepnick :enable");
client.ReadUntil("Trying to get");
// OnQuitMessage
ircd.Write(":user QUIT :Leaving");
ircd.ReadUntil("NICK user");
// OnNickMessage
client.Write("NICK test");
ircd.ReadUntil("NICK test");
ircd.Write(":user!ident@host JOIN #test");
client.ReadUntil("JOIN");
ircd.Write(":user!ident@host NICK user2");
ircd.ReadUntil("NICK user");
}
TEST_F(ZNCTest, ModuleCSRFOverride) {
// TODO: Qt 6.8 introduced QNetworkRequest::FullLocalServerNameAttribute to
// let it connect to unix socket
int port = PickPortNumber();
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write(QStringLiteral("znc addport %1 all all").arg(port).toUtf8());
client.Write("znc loadmod samplewebapi");
client.ReadUntil("Loaded module");
auto request = QNetworkRequest(
QUrl(QStringLiteral("http://127.0.0.1:%1/mods/global/samplewebapi/")
.arg(port)));
auto reply =
HttpPost(request, {{"text", "ipsum"}})->readAll().toStdString();
EXPECT_THAT(reply, HasSubstr("ipsum"));
}
class SaslModuleTest : public ZNCTest,
public testing::WithParamInterface<
std::pair<int, std::vector<std::string>>> {
public:
static std::string Prefix() {
std::string s;
for (int i = 0; i < 33; ++i) s += "YWFh";
s += "YQBh";
for (int i = 0; i < 33; ++i) s += "YWFh";
s += "AGJi";
for (int i = 0; i < 31; ++i) s += "YmJi";
EXPECT_EQ(s.length(), 396);
return s;
}
protected:
int PassLen() { return std::get<0>(GetParam()); }
void ExpectPlainAuth(Socket& ircd) {
for (const auto& str : std::get<1>(GetParam())) {
QByteArray line;
ircd.ReadUntilAndGet("AUTHENTICATE ", line);
ASSERT_EQ(line.toStdString(), "AUTHENTICATE " + str);
}
ASSERT_EQ(ircd.ReadRemainder().indexOf("AUTHENTICATE"), -1);
}
};
TEST_P(SaslModuleTest, Test) {
QFile conf(m_dir.path() + "/configs/znc.conf");
ASSERT_TRUE(conf.open(QIODevice::Append | QIODevice::Text));
QTextStream(&conf) << "ServerThrottle = 1\n";
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod sasl");
QByteArray sUser(100, 'a');
QByteArray sPass(PassLen(), 'b');
client.Write("PRIVMSG *sasl :set " + sUser + " " + sPass);
client.Write("znc jump");
ircd = ConnectIRCd();
ircd.ReadUntil("CAP LS");
ircd.Write("CAP * LS :away-notify sasl");
ircd.ReadUntil("CAP REQ :away-notify sasl");
ircd.Write("CAP * ACK :away-notify sasl");
ircd.ReadUntil("AUTHENTICATE EXTERNAL");
ircd.Write(":server 904 *");
ircd.ReadUntil("AUTHENTICATE PLAIN");
ircd.Write("AUTHENTICATE +");
ExpectPlainAuth(ircd);
ircd.Write(":server 903 user :Logged in");
ircd.ReadUntil("CAP END");
}
INSTANTIATE_TEST_CASE_P(SaslInst, SaslModuleTest,
testing::Values(
std::pair<int, std::vector<std::string>>{
95, {SaslModuleTest::Prefix()}},
std::pair<int, std::vector<std::string>>{
96, {SaslModuleTest::Prefix() + "Yg==", "+"}},
std::pair<int, std::vector<std::string>>{
97, {SaslModuleTest::Prefix() + "YmI=", "+"}},
std::pair<int, std::vector<std::string>>{
98, {SaslModuleTest::Prefix() + "YmJi", "+"}},
std::pair<int, std::vector<std::string>>{
99,
{SaslModuleTest::Prefix() + "YmJi", "Yg=="}}));
TEST_F(ZNCTest, SaslMechsNotInit) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod sasl");
client.Write("PRIVMSG *sasl :set * *");
client.ReadUntil("Password has been set");
ircd.Write("AUTHENTICATE +");
ircd.Write("PING foo");
ircd.ReadUntil("PONG foo");
}
TEST_F(ZNCTest, SaslRequire) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod sasl");
client.Write("PRIVMSG *sasl :set * *");
client.Write("PRIVMSG *sasl :requireauth yes");
client.ReadUntil("Password has been set");
client.Write("znc jump");
ircd = ConnectIRCd();
ircd.ReadUntil("CAP LS");
ircd.Write(":server 001 nick :Hello");
ircd.ReadUntil("QUIT :SASL not available");
auto ircd2 = ConnectIRCd();
}
TEST_F(ZNCTest, SaslAuthPlainImapAuth) {
auto znc = Run();
auto ircd = ConnectIRCd();
QTcpServer imap;
ASSERT_TRUE(imap.listen(QHostAddress::LocalHost)) << imap.errorString().toStdString();
auto client = LoginClient();
client.Write(
QStringLiteral("znc loadmod imapauth 127.0.0.1 %1 %@mail.test.com")
.arg(imap.serverPort())
.toUtf8());
client.ReadUntil("Loaded");
auto client2 = ConnectClient();
client2.Write("NICK foo");
client2.Write("CAP REQ :sasl");
client2.Write("USER bar");
client2.Write("AUTHENTICATE PLAIN");
client2.Write("AUTHENTICATE " + QByteArrayLiteral("\0user@phone/net\0hunter3").toBase64());
client2.ReadUntil("ACK :sasl");
ASSERT_TRUE(imap.waitForNewConnection(30000 /* msec */));
auto imapsock = WrapIO(imap.nextPendingConnection());
imapsock.Write("* OK IMAP4rev1 Service Ready");
imapsock.ReadUntil("AUTH LOGIN user@mail.test.com hunter3");
imapsock.Write("AUTH OK");
client2.ReadUntil(":irc.znc.in 903 foo :SASL authentication successful");
}
TEST_F(ZNCTest, SaslAuthExternal) {
#ifndef HAVE_LIBSSL
GTEST_SKIP() << "SSL is disabled";
#endif
int port = PickPortNumber();
auto znc = Run();
auto ircd = ConnectIRCd();
ircd.Write(":server 001 nick :Hello");
auto client = LoginClient();
client.Write(QStringLiteral("znc addport +%1 all all").arg(port).toUtf8());
client.ReadUntil(":Port added");
client.Write("znc loadmod certauth");
client.ReadUntil("Loaded");
client.Close();
QSslSocket sock;
// Could generate a new one for the test, but this one is good enough
sock.setLocalCertificate(m_dir.path() + "/znc.pem");
sock.setPrivateKey(m_dir.path() + "/znc.pem");
sock.setPeerVerifyMode(QSslSocket::VerifyNone);
sock.connectToHostEncrypted("127.0.0.1", port);
ASSERT_TRUE(sock.waitForConnected()) << sock.errorString().toStdString();
ASSERT_TRUE(sock.waitForEncrypted()) << sock.errorString().toStdString();
auto client2 = WrapIO(&sock);
client2.Write("PASS :hunter2");
client2.Write("NICK nick");
client2.Write("USER user/test x x :x");
client2.Write("privmsg *certauth add");
client2.ReadUntil("added");
auto Reconnect = [&] {
client2.Close();
ASSERT_TRUE(sock.state() == QAbstractSocket::UnconnectedState || sock.waitForDisconnected())
<< sock.errorString().toStdString();
sock.connectToHostEncrypted("127.0.0.1", port);
ASSERT_TRUE(sock.waitForConnected())
<< sock.errorString().toStdString();
ASSERT_TRUE(sock.waitForEncrypted())
<< sock.errorString().toStdString();
client2.Write("CAP REQ sasl");
client2.Write("NICK nick");
client2.Write("USER u x x :x");
client2.ReadUntil("ACK :sasl");
client2.Write("AUTHENTICATE EXTERNAL");
client2.ReadUntil("AUTHENTICATE +");
};
Reconnect();
ircd.Write(":friend PRIVMSG nick :hello");
client2.Write("AUTHENTICATE +");
client2.ReadUntil(
":irc.znc.in 900 nick nick!user@127.0.0.1 user :You are now logged in "
"as user");
client2.ReadUntil(":irc.znc.in 903 nick :SASL authentication successful");
client2.Write("CAP END");
// '[' comes from lack of server-time
client2.ReadUntil(":friend PRIVMSG nick :[");
Reconnect();
client2.Write("AUTHENTICATE " + QByteArrayLiteral("user/te").toBase64());
client2.ReadUntil(
":irc.znc.in 900 nick nick!user@127.0.0.1 user :You are now logged in "
"as user");
client2.ReadUntil(":irc.znc.in 903 nick :SASL authentication successful");
client2.Write("CAP END");
client2.ReadUntil(
":*status!status@znc.in PRIVMSG nick :Network te doesn't exist.");
Reconnect();
client2.Write("AUTHENTICATE " + QByteArrayLiteral("moo").toBase64());
client2.ReadUntil(
":irc.znc.in 904 nick :The specified user doesn't have this key");
client = LoginClient();
client.Write("privmsg *certauth :del 1");
client.ReadUntil("Removed");
Reconnect();
client2.Write("AUTHENTICATE +");
client2.ReadUntil(
":irc.znc.in 904 nick :Client cert not recognized");
// Wrong mechanism
auto client3 = ConnectClient();
client3.Write("CAP LS 302");
client3.Write("NICK nick");
client3.ReadUntil(" sasl=EXTERNAL,PLAIN ");
client3.Write("CAP REQ :sasl");
client3.ReadUntil("ACK :sasl");
client3.Write("AUTHENTICATE FOO");
client3.ReadUntil(":irc.znc.in 908 nick EXTERNAL,PLAIN :are available SASL mechanisms");
client3.ReadUntil(
":irc.znc.in 904 nick :SASL authentication failed");
}
TEST_F(ZNCTest, StripControlsModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod stripcontrols");
client.ReadUntil("Loaded module");
ircd.Write(":server 001 nick :Hello");
client.Write(":nick JOIN #test");
ircd.ReadUntil("JOIN #test");
// OnChanCTCPMessage
ircd.Write(":user!id@host PRIVMSG #test :\001\002bold\002 \003\034red\003 test\001");
client.ReadUntil(":user!id@host PRIVMSG #test :\001bold red test\001");
// OnChanNoticeMessage
ircd.Write(":user!id@host NOTICE #test :\002bold\002 \003\034red\003 test");
client.ReadUntil(":user!id@host NOTICE #test :bold red test");
// OnChanTextMessage
ircd.Write(":user!id@host PRIVMSG #test :\002bold\002 \003\034red\003 test");
client.ReadUntil(":user!id@host PRIVMSG #test :bold red test");
// OnPrivCTCPMessage
ircd.Write(":user!id@host PRIVMSG nick :\001\002bold\002 \003\034red\003 test\001");
client.ReadUntil(":user!id@host PRIVMSG nick :\001bold red test\001");
// OnPrivNoticeMessage
ircd.Write(":user!id@host NOTICE nick :\002bold\002 \003\034red\003 test");
client.ReadUntil(":user!id@host NOTICE nick :bold red test");
// OnPrivTextMessage
ircd.Write(":user!id@host PRIVMSG nick :\002bold\002 \003\034red\003 test");
client.ReadUntil(":user!id@host PRIVMSG nick :bold red test");
// OnTopicMessage
ircd.Write(":user!id@host TOPIC #test :\002bold\002 \003\034red\003 test");
client.ReadUntil(":user!id@host TOPIC #test :bold red test");
// OnNumericMessage
// Topic from joining channel.
ircd.Write("332 nick #test :\002bold\002 \003\034red\003 test");
client.ReadUntil("332 nick #test :bold red test");
// Topic from /list
//ircd.Write("321 nick Channel :Users Name]");
ircd.Write("322 nick #test 42 :\002bold\002 \003\034red\003 test");
client.ReadUntil("322 nick #test 42 :bold red test");
}
TEST_F(ZNCTest, AutoReplyModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod autoreply I'm currently away");
client.ReadUntil("Loaded module");
// Set for 1 second instead of waiting 15 seconds.
client.Write("PRIVMSG *simple_away :SetTimer 1");
client.ReadUntil("1 second");
ircd.Write(":server 001 nick :Hello");
client.Write("QUIT :Going away");
client.Close();
ircd.ReadUntil("AWAY :Auto away");
ircd.Write(":testuser!test@host PRIVMSG nick :Hello there");
ircd.ReadUntil("NOTICE testuser :I'm currently away");
ircd.Write(":testuser!test@host PRIVMSG nick :Another message");
ircd.Write(":otheruser!other@host PRIVMSG nick :Hi nick");
ircd.ReadUntil("NOTICE otheruser :I'm currently away");
auto client2 = LoginClient();
ircd.Write(":thirduser!third@host PRIVMSG nick :Are you there?");
}
TEST_F(ZNCTest, BounceDCCModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod bouncedcc");
client.ReadUntil("Loaded module");
ircd.Write(":server 001 nick :Hello");
// OnUserCTCPMessage
client.Write("PRIVMSG friend :\001DCC CHAT chat 3232235521 12345\001");
QByteArray line;
ircd.ReadUntilAndGet("PRIVMSG friend :\001DCC CHAT chat", line);
EXPECT_THAT(line.toStdString(), Not(HasSubstr("3232235521 12345")));
// OnPrivCTCPMessage
ircd.Write(":friend!user@host PRIVMSG nick :\001DCC CHAT chat 3232235521 54321\001");
QByteArray line2;
client.ReadUntilAndGet(":friend!user@host PRIVMSG nick :\001DCC CHAT chat", line2);
EXPECT_THAT(line2.toStdString(), Not(HasSubstr("3232235521 54321")));
// Only the user's own clients may connect to that bounce port. The test
// client is on a unix socket, so a TCP connection from anywhere is refused.
// The listener binds to the IRC socket's local address, which for a unix
// socket is "localhost" on Linux and may resolve to ::1 only.
QByteArray bouncePort = line2.mid(line2.lastIndexOf(' ') + 1);
bouncePort.chop(1); // trailing \001
QTcpSocket outsider;
outsider.connectToHost("localhost", bouncePort.toUShort());
ASSERT_TRUE(outsider.waitForConnected());
client.ReadUntil("Refused connection from");
// Peer must not be able to make ZNC connect to its own loopback
ircd.Write(":friend!user@host PRIVMSG nick :\001DCC CHAT chat 2130706433 6379\001");
client.ReadUntil("refused: bad address 2130706433");
ircd.Write(":friend!user@host PRIVMSG nick :\001DCC SEND f 2852039166 80 1\001");
client.ReadUntil("refused: bad address 2852039166");
ircd.Write(":friend!user@host PRIVMSG nick :\001DCC CHAT chat 6425673729 22\001");
client.ReadUntil("refused: bad address 6425673729");
}
TEST_F(ZNCTest, ChanSaverModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
ircd.Write(":server 001 nick :Hello");
client.ReadUntil("001");
client.Write("PRIVMSG *controlpanel :GetChan InConfig $me $network #test");
client.ReadUntil("No channels matching [#test] found");
client.Write("JOIN #test");
ircd.ReadUntil("JOIN #test");
ircd.Write(":nick JOIN #test");
ircd.Write(":server 353 nick #test :nick");
ircd.Write(":server 366 nick #test :End of /NAMES list.");
client.ReadUntil(":nick JOIN #test");
client.Write("PRIVMSG *controlpanel :GetChan InConfig $me $network #test");
client.ReadUntil("InConfig = true");
client.Write("PART #test");
ircd.ReadUntil("PART #test");
ircd.Write(":nick PART #test");
client.ReadUntil(":nick PART #test");
client.Write("PRIVMSG *controlpanel :GetChan InConfig $me $network #test");
client.ReadUntil("No channels matching [#test] found");
}
TEST_F(ZNCTest, ClearBufferOnMsgModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod clearbufferonmsg");
client.ReadUntil("Loaded module");
ircd.Write(":server 001 nick :Hello");
ircd.Write(":nick JOIN :#test");
ircd.Write(":server 353 nick = #test :nick someone");
ircd.Write(":server 366 nick #test :End of /NAMES list");
client.ReadUntil("End of /NAMES");
// OnUserTextMessage
ircd.Write(":someone!user@host PRIVMSG #test :testing - OnUserTextMessage");
client.ReadUntil("testing - OnUserTextMessage");
client.Write("PRIVMSG #test :test");
ircd.ReadUntil("PRIVMSG");
client.Write("DETACH #test");
client.ReadUntil("Detached");
client.Write("ATTACH #test");
client.ReadUntil("End of /NAMES list");
QByteArray remainder = client.ReadRemainder();
EXPECT_THAT(remainder, Not(HasSubstr("OnUserTextMessage")))
<< "OnUserTextMessage failed to clear buffer";
// OnUserActionMessage
ircd.Write(":someone!user@host PRIVMSG #test :testing - OnUserActionMessage");
client.ReadUntil("testing - OnUserActionMessage");
client.Write("PRIVMSG #test :\001ACTION testing\001");
ircd.ReadUntil("PRIVMSG");
client.Write("DETACH #test");
client.ReadUntil("Detached");
client.Write("ATTACH #test");
client.ReadUntil("End of /NAMES list");
remainder = client.ReadRemainder();
EXPECT_THAT(remainder, Not(HasSubstr("OnUserActionMessage")))
<< "OnUserActionMessage failed to clear buffer";
// OnUserCTCPMessage
ircd.Write(":someone!user@host PRIVMSG #test :testing - OnUserCTCPMessage");
client.ReadUntil("testing - OnUserCTCPMessage");
client.Write("PRIVMSG #test :\001VERSION\001");
ircd.ReadUntil("PRIVMSG");
client.Write("DETACH #test");
client.ReadUntil("Detached");
client.Write("ATTACH #test");
client.ReadUntil("End of /NAMES list");
remainder = client.ReadRemainder();
EXPECT_THAT(remainder, Not(HasSubstr("OnUserCTCPMessage")))
<< "OnUserCTCPMessage failed to clear buffer";
// OnUserNoticeMessage
ircd.Write(":someone!user@host PRIVMSG #test :testing - OnUserNoticeMessage");
client.ReadUntil("testing - OnUserNoticeMessage");
client.Write("NOTICE #test :testing");
ircd.ReadUntil("NOTICE");
client.Write("DETACH #test");
client.ReadUntil("Detached");
client.Write("ATTACH #test");
client.ReadUntil("End of /NAMES list");
remainder = client.ReadRemainder();
EXPECT_THAT(remainder, Not(HasSubstr("OnUserNoticeMessage")))
<< "OnUserNoticeMessage failed to clear buffer";
// OnUserPartMessage
ircd.Write(":someone!user@host PRIVMSG #test :testing - OnUserPartMessage");
client.ReadUntil("testing - OnUserPartMessage");
client.Write("PART #test :testing");
ircd.ReadUntil("PART");
client.Write("JOIN #test");
ircd.ReadUntil("JOIN");
ircd.Write(":server 353 nick = #test :nick someone");
ircd.Write(":server 366 nick #test :End of /NAMES list");
client.ReadUntil("End of /NAMES");
client.Write("DETACH #test");
client.ReadUntil("Detached");
client.Write("ATTACH #test");
client.ReadUntil("End of /NAMES list");
remainder = client.ReadRemainder();
EXPECT_THAT(remainder, Not(HasSubstr("OnUserPartMessage")))
<< "OnUserPartMessage failed to clear buffer";
// OnUserTopicMessage
ircd.Write(":someone!user@host PRIVMSG #test :testing - OnUserTopicMessage");
client.ReadUntil("testing - OnUserTopicMessage");
client.Write("TOPIC #test :testing");
ircd.ReadUntil("TOPIC");
client.Write("DETACH #test");
client.ReadUntil("Detached");
client.Write("ATTACH #test");
client.ReadUntil("End of /NAMES list");
remainder = client.ReadRemainder();
EXPECT_THAT(remainder, Not(HasSubstr("OnUserTopicMessage")))
<< "OnUserTopicMessage failed to clear buffer";
// OnUserQuitMessage
client.Write("znc unloadmod clearbufferonmsg");
client.ReadUntil("unloaded");
// quit is set as false by default
client.Write("znc loadmod clearbufferonmsg quit");
client.ReadUntil("Loaded module");
ircd.Write(":other!user@host PRIVMSG #test :buffered message");
client.ReadUntil("buffered message");
client.Write("QUIT :bye");
client.Close();
auto client2 = LoginClient();
client2.ReadUntil("001");
client2.Write("JOIN #test");
ASSERT_THAT(client2.ReadRemainder().toStdString(),
Not(HasSubstr("buffered message")));
}
TEST_F(ZNCTest, CtcpFloodModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod ctcpflood");
client.ReadUntil("Loaded module");
ircd.Write(":server 001 nick :Hello");
ircd.Write(":nick JOIN :#test");
ircd.Write(":server 353 nick = #test :nick someone");
ircd.Write(":server 366 nick #test :End of /NAMES list");
// OnChanCTCPMessage
ircd.Write(":someone!user@host PRIVMSG #test :\001message1\001");
ircd.Write(":someone!user@host PRIVMSG #test :\001message2\001");
ircd.Write(":someone!user@host PRIVMSG #test :\001message3\001");
ircd.Write(":someone!user@host PRIVMSG #test :\001message4\001");
ircd.Write(":someone!user@host PRIVMSG #test :\001message5\001");
ircd.Write(":someone!user@host PRIVMSG #test :\001message6\001");
ircd.Write(":someone!user@host PRIVMSG #test :\001message7\001");
client.ReadUntil("Limit reached by");
// Unload to reset timer.
client.Write("znc unloadmod ctcpflood");
client.ReadUntil("unloaded");
client.Write("znc loadmod ctcpflood");
client.ReadUntil("Loaded module");
// OnPrivCTCPMessage
ircd.Write(":query!user@host PRIVMSG nick :\001message1\001");
ircd.Write(":query!user@host PRIVMSG nick :\001message2\001");
ircd.Write(":query!user@host PRIVMSG nick :\001message3\001");
ircd.Write(":query!user@host PRIVMSG nick :\001message4\001");
ircd.Write(":query!user@host PRIVMSG nick :\001message5\001");
ircd.Write(":query!user@host PRIVMSG nick :\001message6\001");
ircd.Write(":query!user@host PRIVMSG nick :\001message7\001");
client.ReadUntil("Limit reached by");
}
TEST_F(ZNCTest, FloodDetachModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod flooddetach");
client.ReadUntil("Loaded module");
ircd.Write(":server 001 nick :Hello");
auto JoinChan = [&](const QString& sChan) {
ircd.Write((":nick JOIN :" + sChan).toUtf8());
ircd.Write((":server 353 nick = " + sChan + " :nick someone").toUtf8());
ircd.Write(
(":server 366 nick " + sChan + " :End of /NAMES list").toUtf8());
client.ReadUntil("End of /NAMES");
};
// Just use 10 for everything.
// OnChanMessage
JoinChan("#test-privmsg");
for (int i = 1; i <= 10; i++) {
ircd.Write((":someone!user@host PRIVMSG #test-privmsg :message" +
QString::number(i))
.toUtf8());
}
client.ReadUntil("Channel #test-privmsg was flooded");
// OnNickMessage
JoinChan("#test-nick");
QString sNick = "someone";
for (int i = 1; i <= 10; i++) {
QString sNewNick = "someone" + QString::number(i + 1);
ircd.Write((":" + sNick + "!user@host NICK " + sNewNick).toUtf8());
sNick = sNewNick;
}
client.ReadUntil("Channel #test-nick was flooded");
// OnTopicMessage
JoinChan("#test-topic");
for (int i = 1; i <= 10; i++) {
ircd.Write(
(":someone!user@host TOPIC #test-topic :TOPIC" + QString::number(i))
.toUtf8());
}
client.ReadUntil("Channel #test-topic was flooded");
// OnNoticeMessage
JoinChan("#test-notice");
for (int i = 1; i <= 10; i++) {
ircd.Write((":someone!user@host NOTICE #test-notice :notice" +
QString::number(i))
.toUtf8());
}
client.ReadUntil("Channel #test-notice was flooded");
// OnChanActionMessage / OnChanCTCPMessage
JoinChan("#test-ctcp");
for (int i = 1; i <= 10; i++) {
ircd.Write((":someone!user@host PRIVMSG #test-ctcp :\001"
"ACTION action" +
QString::number(i) + "\001")
.toUtf8());
}
client.ReadUntil("Channel #test-ctcp was flooded");
}
TEST_F(ZNCTest, KickRejoinModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod kickrejoin");
client.ReadUntil("Loaded module");
ircd.Write(":server 001 nick :Hello");
ircd.Write(":nick JOIN :#test");
ircd.Write(":server 353 nick = #test :nick @foobar");
ircd.Write(":server 366 nick #test :End of /NAMES list");
ircd.Write(":foobar!user@host KICK #test nick :Kicked!");
ircd.ReadUntil("JOIN #test");
}
TEST_F(ZNCTest, NickServModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod nickserv");
client.ReadUntil("Loaded module");
client.Write("PRIVMSG *nickserv :set hunter2");
client.ReadUntil("Password set");
ircd.Write(":server 001 nick :Hello");
// OnPrivNoticeMessage
ircd.Write(
":NickServ!services@network NOTICE nick :This nickname is registered. "
"Please choose a different nickname, or identify via /msg NickServ "
"identify <password>.");
ircd.ReadUntil("NICKSERV IDENTIFY hunter2");
// OnPrivTextMessage
ircd.Write(
":NickServ!services@network PRIVMSG nick :This nickname is registered. "
"Please choose a different nickname, or identify via /msg NickServ "
"identify <password>.");
ircd.ReadUntil("NICKSERV IDENTIFY hunter2");
}
TEST_F(ZNCTest, StickyChanModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod stickychan");
client.ReadUntil("Loaded module");
client.Write("PRIVMSG *stickychan :stick #sticky");
client.ReadUntil("Stuck #sticky");
ircd.Write("001 nick Welcome");
ircd.Write(":nick JOIN :#sticky");
client.ReadUntil("JOIN :#sticky");
client.Write("PART #sticky :leaving");
ASSERT_THAT(ircd.ReadRemainder(), Not(HasSubstr("PART")));
client.Write("PRIVMSG *controlpanel :GetChan InConfig $me $network #sticky");
client.ReadUntil("InConfig = true");
}
TEST_F(ZNCTest, AwayStoreModule) {
#ifndef HAVE_LIBSSL
GTEST_SKIP() << "SSL is disabled";
#endif
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod awaystore testpass");
client.ReadUntil("Loaded module");
ircd.Write(":server 001 nick :Hello");
client.ReadUntil("001");
client.Write("PRIVMSG *awaystore :timer");
client.ReadUntil("Current timer setting");
client.Write("PRIVMSG *awaystore :settimer 1");
client.ReadUntil("Timer set to 1");
client.Write("PRIVMSG *awaystore :away Test reason");
client.ReadUntil("You have been marked as away");
ircd.ReadUntil("AWAY :Test reason");
ircd.Write(":TestUser!test@host PRIVMSG nick :Normal message");
client.ReadUntil(":TestUser!test@host PRIVMSG nick :Normal message");
// Test for #815 - awaystore replay does not work
ircd.Write(":TestUser!test@host PRIVMSG nick :AAA:BBB:CCC");
client.ReadUntil(":TestUser!test@host PRIVMSG nick :AAA:BBB:CCC");
ircd.Write(":TestUser!test@host PRIVMSG nick :\001ACTION does something\001");
client.ReadUntil(":TestUser!test@host PRIVMSG nick :\001ACTION does something\001");
// Test for #267 - AwayStore IPv6 parsing issue
ircd.Write(":IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789 PRIVMSG nick :Normal message");
client.ReadUntil(":IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789 PRIVMSG nick :Normal message");
ircd.Write(":IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789 PRIVMSG nick :AAA:BBB:CCC");
client.ReadUntil(":IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789 PRIVMSG nick :AAA:BBB:CCC");
ircd.Write(":IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789 PRIVMSG nick :\001ACTION does something\001");
client.ReadUntil(":IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789 PRIVMSG nick :\001ACTION does something\001");
client.Write("PRIVMSG *awaystore :messages");
client.ReadUntil("TestUser!test@host Normal message");
client.ReadUntil("TestUser!test@host AAA:BBB:CCC");
client.ReadUntil("TestUser!test@host * does something");
client.ReadUntil("IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789 Normal message");
client.ReadUntil("IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789 AAA:BBB:CCC");
client.ReadUntil("IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789 * does something");
client.Write("PRIVMSG *awaystore :show");
client.ReadUntil("IPv6!test@2001:db8:1234:5678:abcd:ef01:2345:6789");
client.ReadUntil("Normal message");
client.ReadUntil("AAA:BBB:CCC");
client.ReadUntil("* does something");
client.ReadUntil("TestUser!test@host");
client.ReadUntil("Normal message");
client.ReadUntil("AAA:BBB:CCC");
client.ReadUntil("* does something");
client.ReadUntil("#--- End of messages");
client.Write("PRIVMSG *awaystore :delete 0");
client.ReadUntil("Message erased");
client.Write("PRIVMSG *awaystore :back");
client.ReadUntil("Welcome back!");
ircd.ReadUntil("away");
client.Write("PRIVMSG *awaystore :replay");
client.ReadUntil(":TestUser!test@host PRIVMSG nick :AAA:BBB:CCC");
client.ReadUntil(":TestUser!test@host PRIVMSG nick :* does something");
client.Write("PRIVMSG *awaystore :save");
client.ReadUntil("Messages saved to disk");
client.Write("PRIVMSG *awaystore :delete all");
client.ReadUntil("Deleted 5 messages");
client.Write("PRIVMSG *awaystore :save");
client.ReadUntil("Messages saved to disk");
client.Write("PRIVMSG *status :unloadmod awaystore");
client.ReadUntil("unloaded");
// Begin 'pass' bug not using CBlowfish::MD5()
client.Write("znc loadmod awaystore testpass");
client.ReadUntil("Loaded module");
client.Write("PRIVMSG *awaystore :away Not here");
client.ReadUntil("You have been marked as away");
ircd.Write(":TestUser!test@host PRIVMSG nick :should survive");
client.ReadUntil(":TestUser!test@host PRIVMSG nick :should survive");
client.Write("PRIVMSG *awaystore :pass newpass");
client.ReadUntil("Password updated to [newpass]");
client.Write("PRIVMSG *awaystore :save");
client.ReadUntil("Messages saved to disk");
client.Write("znc unloadmod awaystore");
client.ReadUntil("unloaded");
client.Write("znc loadmod awaystore newpass");
client.ReadUntil("Loaded module");
client.Write("znc unloadmod awaystore");
client.ReadUntil("unloaded");
// End 'pass' bug test
// Begin 'away' not updating bug test
client.Write("znc loadmod awaystore newpass");
client.ReadUntil("Loaded module");
client.Write("PRIVMSG *awaystore :away first reason");
client.ReadUntil("You have been marked as away");
ircd.ReadUntil("AWAY :first reason");
client.Write("PRIVMSG *awaystore :away second reason");
client.ReadUntil("You have been marked as away");
ircd.ReadUntil("AWAY :second reason");
// End 'away' bug test
}
// https://github.com/znc/znc/issues/1910
TEST_F(ZNCTest, ListSocketsModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod listsockets");
client.ReadUntil("Loaded module");
client.Write("PRIVMSG *listsockets :list");
int year = QDate::currentDate().year();
ASSERT_THAT(client.ReadRemainder().toStdString(),
AnyOf(HasSubstr(std::to_string(year - 1) + "-"),
HasSubstr(std::to_string(year) + "-"),
HasSubstr(std::to_string(year + 1) + "-")));
}
} // namespace
} // namespace znc_inttest