mirror of
https://github.com/znc/znc.git
synced 2026-08-07 09:22:55 +02:00
Merge branch 'notify'
This commit is contained in:
+83
-16
@@ -14,22 +14,28 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <znc/znc.h>
|
||||
#include <znc/User.h>
|
||||
#include <znc/znc.h>
|
||||
|
||||
using std::set;
|
||||
|
||||
class CClientNotifyMod : public CModule {
|
||||
protected:
|
||||
CString m_sMethod;
|
||||
|
||||
bool m_bNewOnly{};
|
||||
bool m_bOnDisconnect{};
|
||||
bool m_bNotifyOnNewIP{};
|
||||
bool m_bNotifyOnNewClientID{};
|
||||
|
||||
set<CString> m_sClientsSeen;
|
||||
set<CString> m_sClientsSeenIP;
|
||||
set<CString> m_sClientsSeenID;
|
||||
|
||||
void SaveSettings() {
|
||||
SetNV("method", m_sMethod);
|
||||
SetNV("newonly", m_bNewOnly ? "1" : "0");
|
||||
SetNV("notifyonnewip", m_bNotifyOnNewIP ? "1" : "0");
|
||||
SetNV("notifyonnewclientid", m_bNotifyOnNewClientID ? "1" : "0");
|
||||
SetNV("ondisconnect", m_bOnDisconnect ? "1" : "0");
|
||||
}
|
||||
|
||||
@@ -48,8 +54,16 @@ class CClientNotifyMod : public CModule {
|
||||
t_d("Sets the notify method"),
|
||||
[=](const CString& sLine) { OnMethodCommand(sLine); });
|
||||
AddCommand("NewOnly", t_d("<on|off>"),
|
||||
t_d("Turns notifications for unseen IP addresses on or off"),
|
||||
t_d("Turns notifications for unseen connections on or off"),
|
||||
[=](const CString& sLine) { OnNewOnlyCommand(sLine); });
|
||||
AddCommand("NotifyOnNewIP", t_d("<on|off>"),
|
||||
t_d("Specifies whether you want to be notified about new "
|
||||
"connections with new IPs"),
|
||||
[=](const CString& sLine) { OnNotifyOnNewIP(sLine); });
|
||||
AddCommand("NotifyOnNewID", t_d("<on|off>"),
|
||||
t_d("Specifies whether you want to be notified about new "
|
||||
"connections with new client IDs"),
|
||||
[=](const CString& sLine) { OnNotifyOnNewID(sLine); });
|
||||
AddCommand(
|
||||
"OnDisconnect", t_d("<on|off>"),
|
||||
t_d("Turns notifications for clients disconnecting on or off"),
|
||||
@@ -68,6 +82,8 @@ class CClientNotifyMod : public CModule {
|
||||
|
||||
// default = off for these:
|
||||
|
||||
m_bNotifyOnNewIP = (GetNV("notifyonnewip") == "1");
|
||||
m_bNotifyOnNewClientID = (GetNV("notifyonnewclientid") == "1");
|
||||
m_bNewOnly = (GetNV("newonly") == "1");
|
||||
m_bOnDisconnect = (GetNV("ondisconnect") == "1");
|
||||
|
||||
@@ -76,18 +92,41 @@ class CClientNotifyMod : public CModule {
|
||||
|
||||
void OnClientLogin() override {
|
||||
CString sRemoteIP = GetClient()->GetRemoteIP();
|
||||
if (!m_bNewOnly ||
|
||||
m_sClientsSeen.find(sRemoteIP) == m_sClientsSeen.end()) {
|
||||
SendNotification(t_p("<This message is impossible for 1 client>",
|
||||
"Another client authenticated as your user. "
|
||||
"Use the 'ListClients' command to see all {1} "
|
||||
"clients.",
|
||||
GetUser()->GetAllClients().size())(
|
||||
GetUser()->GetAllClients().size()));
|
||||
CString sRemoteClientID = GetClient()->GetIdentifier();
|
||||
|
||||
// the set<> will automatically disregard duplicates:
|
||||
m_sClientsSeen.insert(sRemoteIP);
|
||||
CString sClientNameMessage{sRemoteIP};
|
||||
if (m_bNotifyOnNewClientID && sRemoteClientID != "") {
|
||||
sClientNameMessage += " / " + sRemoteClientID;
|
||||
}
|
||||
|
||||
auto sendLoginNotification = [&]() {
|
||||
SendNotification(
|
||||
t_p("<This message is impossible for 1 client>",
|
||||
"Another client ({1}) authenticated as your user. "
|
||||
"Use the 'ListClients' command to see all {2} "
|
||||
"clients.",
|
||||
GetUser()->GetAllClients().size())(
|
||||
sClientNameMessage, GetUser()->GetAllClients().size()));
|
||||
};
|
||||
|
||||
if (m_bNewOnly) {
|
||||
// see if we actually got a new client
|
||||
// TODO: replace setName.find(...) == setName.end() with
|
||||
// !setName.contains() once ZNC uses C++20
|
||||
if ((m_bNotifyOnNewIP && (m_sClientsSeenIP.find(sRemoteIP) ==
|
||||
m_sClientsSeenIP.end())) ||
|
||||
(m_bNotifyOnNewClientID &&
|
||||
(m_sClientsSeenID.find(sRemoteClientID) ==
|
||||
m_sClientsSeenID.end()))) {
|
||||
sendLoginNotification();
|
||||
}
|
||||
} else {
|
||||
sendLoginNotification();
|
||||
}
|
||||
|
||||
// the set<> will automatically disregard duplicates:
|
||||
m_sClientsSeenIP.insert(sRemoteIP);
|
||||
m_sClientsSeenID.insert(sRemoteClientID);
|
||||
}
|
||||
|
||||
void OnClientDisconnect() override {
|
||||
@@ -127,6 +166,32 @@ class CClientNotifyMod : public CModule {
|
||||
PutModule(t_s("Saved."));
|
||||
}
|
||||
|
||||
void OnNotifyOnNewIP(const CString& sCommand) {
|
||||
const CString sArg = sCommand.Token(1, true).AsLower();
|
||||
|
||||
if (sArg.empty()) {
|
||||
PutModule(t_s("Usage: NotifyOnNewIP <on|off>"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_bNotifyOnNewIP = sArg.ToBool();
|
||||
SaveSettings();
|
||||
PutModule(t_s("Saved."));
|
||||
}
|
||||
|
||||
void OnNotifyOnNewID(const CString& sCommand) {
|
||||
const CString sArg = sCommand.Token(1, true).AsLower();
|
||||
|
||||
if (sArg.empty()) {
|
||||
PutModule(t_s("Usage: NotifyOnNewID <on|off>"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_bNotifyOnNewClientID = sArg.ToBool();
|
||||
SaveSettings();
|
||||
PutModule(t_s("Saved."));
|
||||
}
|
||||
|
||||
void OnDisconnectCommand(const CString& sCommand) {
|
||||
const CString sArg = sCommand.Token(1, true).AsLower();
|
||||
|
||||
@@ -142,9 +207,11 @@ class CClientNotifyMod : public CModule {
|
||||
|
||||
void OnShowCommand(const CString& sLine) {
|
||||
PutModule(
|
||||
t_f("Current settings: Method: {1}, for unseen IP addresses only: "
|
||||
"{2}, notify on disconnecting clients: {3}")(
|
||||
m_sMethod, m_bNewOnly, m_bOnDisconnect));
|
||||
t_f("Current settings: Method: {1}, for unseen only: {2}, notify"
|
||||
"for unseen IPs: {3}, notify for unseen IDs: {4}, notify on"
|
||||
"disconnecting clients: {5}")(
|
||||
m_sMethod, m_bNewOnly, m_bNotifyOnNewIP, m_bNotifyOnNewClientID,
|
||||
m_bOnDisconnect));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -72,11 +72,15 @@ Socket ZNCTest::ConnectClient() {
|
||||
return WrapIO(&sock);
|
||||
}
|
||||
|
||||
Socket ZNCTest::LoginClient() {
|
||||
Socket ZNCTest::LoginClient(QString identifier) {
|
||||
auto client = ConnectClient();
|
||||
client.Write("PASS :hunter2");
|
||||
client.Write("NICK nick");
|
||||
client.Write("USER user/test x x :x");
|
||||
if ( identifier.length() == 0 ) {
|
||||
client.Write("USER user/test x x :x");
|
||||
} else {
|
||||
client.Write("USER user@" + identifier.toUtf8() + "/test x x :x");
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class ZNCTest : public testing::Test {
|
||||
|
||||
Socket ConnectIRCd();
|
||||
Socket ConnectClient();
|
||||
Socket LoginClient();
|
||||
Socket LoginClient(QString identifier = "");
|
||||
|
||||
std::unique_ptr<Process> Run();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "znctest.h"
|
||||
|
||||
using testing::HasSubstr;
|
||||
using testing::Not;
|
||||
|
||||
namespace znc_inttest {
|
||||
namespace {
|
||||
@@ -54,6 +55,50 @@ TEST_F(ZNCTest, NotifyConnectModule) {
|
||||
"NOTICE nick :*** user@identifier detached from 127.0.0.1");
|
||||
}
|
||||
|
||||
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, std::string wrongAnswer){
|
||||
auto result = QString{client.ReadRemainder()}.toStdString();
|
||||
EXPECT_THAT(result, Not(HasSubstr((wrongAnswer)))) << "Got an answer from the ClientNotifyModule even though we didnt want one with the given configuration";
|
||||
};
|
||||
|
||||
auto client2 = LoginClient();
|
||||
client.ReadUntil(":Another client (127.0.0.1) authenticated as your user. Use the 'ListClients' command to see all 2 clients.");
|
||||
auto client3 = LoginClient();
|
||||
client.ReadUntil(":Another client (127.0.0.1) 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 (127.0.0.1) 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.ReadUntil(":Another client (127.0.0.1 / identifier123) authenticated as your user. Use the 'ListClients' command to see all 5 clients.");
|
||||
auto client6 = LoginClient("identifier123");
|
||||
check_not_sent(client, ":Another client (127.0.0.1 / identifier123) authenticated as your user. Use the 'ListClients' command to see all 6 clients.");
|
||||
|
||||
auto client7 = LoginClient("not_identifier123");
|
||||
client.ReadUntil(":Another client (127.0.0.1 / 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 (127.0.0.1 / identifier123) authenticated as your user. Use the 'ListClients' command to see all 8 clients.");
|
||||
auto client9 = LoginClient("definitely_not_identifier123");
|
||||
client.ReadUntil(":Another client (127.0.0.1 / 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();
|
||||
|
||||
Reference in New Issue
Block a user