1
0
mirror of https://github.com/anope/anope.git synced 2026-06-12 18:54:47 +02:00

Rework how nickname protection works.

- Rename the command and module from kill to protect (this command
  hasn't actually killed users in a long time).
- Replace QUICK/IMMED with a duration option.
This commit is contained in:
Sadie Powell
2025-03-08 13:36:41 +00:00
parent b4ab7dadb9
commit 62bfa33464
11 changed files with 337 additions and 336 deletions
+2 -2
View File
@@ -746,8 +746,8 @@ log
* nickserv/getemail nickserv/suspend nickserv/ajoin nickserv/list
*
* nickserv/saset/autoop nickserv/saset/display nickserv/saset/email nickserv/saset/greet
* nickserv/saset/kill nickserv/saset/keepmodes nickserv/saset/language nickserv/saset/message
* nickserv/saset/neverop nickserv/saset/noexpire nickserv/saset/password nickserv/saset/private
* nickserv/saset/keepmodes nickserv/saset/language nickserv/saset/message nickserv/saset/neverop
* nickserv/saset/noexpire nickserv/saset/password nickserv/saset/private nickserv/saset/protect
* nickserv/saset/url
*
* hostserv/set hostserv/del hostserv/list
+35 -27
View File
@@ -126,7 +126,7 @@ module
* This directive is optional, if left blank, the options will default to memo_signon, and
* memo_receive. If you really want no defaults, use "none" by itself as the option.
*/
defaults = "killprotect ns_private hide_email hide_mask memo_signon memo_receive autoop"
defaults = "autoop hide_email hide_mask memo_receive memo_signon ns_private protect"
/*
* The minimum length of time between consecutive uses of NickServ's REGISTER command. This
@@ -171,11 +171,25 @@ module
hidenetsplitquit = no
/*
* If set, is the length of time NickServ's killquick and kill options wait before
* forcing users off of protected nicknames.
* The default period to force users to stop using a protected nickname after.
*
* Defaults to 1 minute.
*/
killquick = 20s
kill = 60s
defaultprotect = 1m
/*
* The minimum period that a user can have a user forced off their protected nickname after.
*
* Defaults to 10 seconds.
*/
minprotect = 10s
/*
* The maximum period that a user can have a user forced off their protected nickname after.
*
* Defaults to 10 minutes.
*/
maxprotect = 10m
/*
* If set, forbids the registration of nicks that contain an existing
@@ -596,28 +610,6 @@ module
command { service = "NickServ"; name = "SET KEEPMODES"; command = "nickserv/set/keepmodes"; }
command { service = "NickServ"; name = "SASET KEEPMODES"; command = "nickserv/saset/keepmodes"; permission = "nickserv/saset/keepmodes"; }
/*
* ns_set_kill
*
* Provides the commands nickserv/set/kill and kickserv/saset/kill.
*
* Used for configuring nickname protection.
*/
module
{
name = "ns_set_kill"
/*
* Allow the use of the IMMED option in the NickServ SET KILL command.
*
* This directive is optional.
*/
#allowkillimmed = yes
}
command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/kill"; }
command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/kill"; permission = "nickserv/saset/kill"; }
/*
* ns_set_language
*
@@ -662,6 +654,22 @@ command { service = "NickServ"; name = "SASET URL"; command = "nickserv/saset/mi
#command { service = "NickServ"; name = "SET TIMEZONE"; command = "nickserv/set/misc"; misc_description = _("Associate a time zone with your account"); }
#command { service = "NickServ"; name = "SASET TIMEZONE"; command = "nickserv/saset/misc"; misc_description = _("Associate a time zone with this account"); permission = "nickserv/saset/timezone"; group = "nickserv/admin"; }
/*
* ns_set_protect
*
* Provides the commands nickserv/set/protect and kickserv/saset/protect.
*
* Used for configuring nickname protection.
*/
module { name = "ns_set_protect" }
command { service = "NickServ"; name = "SET PROTECT"; command = "nickserv/set/protect"; }
command { service = "NickServ"; name = "SASET PROTECT"; command = "nickserv/saset/protect"; permission = "nickserv/saset/kill"; }
# For compatibility with Anope 2.0.
command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/protect"; hide = true; }
command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/protect"; permission = "nickserv/saset/protect"; hide = true; }
/*
* ns_suspend
*
+28 -50
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Anope\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-14 14:57+0000\n"
"PO-Revision-Date: 2024-11-25 01:32+0000\n"
"POT-Creation-Date: 2025-03-08 13:33+0000\n"
"PO-Revision-Date: 2025-03-08 13:33+0000\n"
"Last-Translator: Sadie Powell <sadie@witchery.services>\n"
"Language-Team: English\n"
"Language: en_US\n"
@@ -659,10 +659,10 @@ msgstr ""
msgid "nickname {EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}"
msgstr ""
msgid "nickname {ON | OFF}"
msgid "nickname {ON | delay | OFF}"
msgstr ""
msgid "nickname {ON | QUICK | IMMED | OFF}"
msgid "nickname {ON | OFF}"
msgstr ""
msgid "option (channel | bot) settings"
@@ -3574,9 +3574,6 @@ msgstr ""
msgid "Ignore list:"
msgstr ""
msgid "Immediate protection"
msgstr ""
msgid "Incorrect email address."
msgstr ""
@@ -4739,16 +4736,16 @@ msgstr ""
msgid "Protection"
msgstr ""
#, c-format
msgid "Protection delay must be between %s and %s."
msgstr ""
#, c-format
msgid "Protection is now off for %s."
msgstr ""
#, c-format
msgid "Protection is now on for %s, with a reduced delay."
msgstr ""
#, c-format
msgid "Protection is now on for %s, with no delay."
msgid "Protection is now on after %lu seconds for %s."
msgstr ""
#, c-format
@@ -4761,9 +4758,6 @@ msgid ""
"then enforces the AKILL."
msgstr ""
msgid "Quick protection"
msgstr ""
msgid "RANDOMNEWS {ADD|DEL|LIST} [text|num]"
msgstr ""
@@ -5984,9 +5978,6 @@ msgid ""
"shown to users when they join the channel."
msgstr ""
msgid "The IMMED option is not available on this network."
msgstr ""
#, c-format
msgid ""
"The LEVELS command allows fine control over the meaning of\n"
@@ -6515,44 +6506,28 @@ msgid ""
"information on it using the INFO command.)"
msgstr ""
#, c-format
msgid ""
"Turns automatic protection for the nick on or off. With\n"
"protection on if a user tries to use a nickname from the\n"
"nick's group they will be given some time to change their\n"
"nick after which %s will forcibly change their nick."
msgstr ""
#, c-format
msgid ""
"Turns automatic protection for your account on or off. With\n"
"protection on if another user tries to use a nickname from\n"
"your group they will be given some time to change their nick\n"
"after which %s will forcibly change their nick."
msgstr ""
msgid "Turns chanstats channel statistics ON or OFF for this user."
msgstr ""
msgid "Turns chanstats statistics ON or OFF."
msgstr ""
#, c-format
msgid ""
"Turns the automatic protection option for the nick\n"
"on or off. With protection on, if another user\n"
"tries to take the nick, they will be given one minute to\n"
"change to another nick, after which %s will forcibly change\n"
"their nick.\n"
" \n"
"If you select QUICK, the user will be given only 20 seconds\n"
"to change nicks instead of the usual 60. If you select\n"
"IMMED, the user's nick will be changed immediately without being\n"
"warned first or given a chance to change their nick; please\n"
"do not use this option unless necessary. Also, your\n"
"network's administrators may have disabled this option."
msgstr ""
#, c-format
msgid ""
"Turns the automatic protection option for your nick\n"
"on or off. With protection on, if another user\n"
"tries to take your nick, they will be given one minute to\n"
"change to another nick, after which %s will forcibly change\n"
"their nick.\n"
" \n"
"If you select QUICK, the user will be given only 20 seconds\n"
"to change nicks instead of the usual 60. If you select\n"
"IMMED, the user's nick will be changed immediately without being\n"
"warned first or given a chance to change their nick; please\n"
"do not use this option unless necessary. Also, your\n"
"network's administrators may have disabled this option."
msgstr ""
msgid "Type"
msgstr ""
@@ -7419,3 +7394,6 @@ msgstr ""
msgid "{nick | channel} memo-text"
msgstr ""
msgid "{ON | delay | OFF}"
msgstr ""
+12 -17
View File
@@ -132,7 +132,6 @@ struct ChannelData final
struct UserData final
{
bool kill = false;
Anope::string info_adder;
Anope::string info_message;
time_t info_ts = 0;
@@ -140,6 +139,8 @@ struct UserData final
Anope::string last_quit;
Anope::string last_real_mask;
bool noexpire = false;
bool protect = false;
std::optional<time_t> protectafter;
Anope::string suspend_by;
Anope::string suspend_reason;
time_t suspend_ts = 0;
@@ -1143,22 +1144,9 @@ private:
if (key == "private:autojoin")
return true; // TODO
else if (key == "private:doenforce")
data->kill = true;
data->protect = true;
else if (key == "private:enforcetime")
{
if (!data->kill)
return true; // Don't apply this.
auto kill = Config->GetModule("nickserv").Get<time_t>("kill", "60s");
auto killquick = Config->GetModule("nickserv").Get<time_t>("killquick", "20s");
auto secs = Anope::Convert<time_t>(value, kill);
if (secs >= kill)
nc->Extend<bool>("KILLPROTECT");
else if (secs >= killquick)
nc->Shrink<bool>("KILL_QUICK");
else
nc->Shrink<bool>("KILL_IMMED");
}
data->protectafter = Anope::TryConvert<time_t>(value);
else if (key == "private:freeze:freezer")
data->suspend_by = value;
else if (key == "private:freeze:reason")
@@ -1371,7 +1359,7 @@ private:
ApplyPassword(nc, flags, pass);
// No equivalent: bglmNQrS
ApplyFlags(nc, flags, 'E', "KILLPROTECT");
ApplyFlags(nc, flags, 'E', "PROTECT");
ApplyFlags(nc, flags, 'e', "MEMO_MAIL");
ApplyFlags(nc, flags, 'n', "NEVEROP");
ApplyFlags(nc, flags, 'o', "AUTOOP", false);
@@ -1649,6 +1637,13 @@ public:
}
}
if (data->protect)
{
nc->Extend<bool>("PROTECT");
if (data->protectafter)
nc->Extend("PROTECT_AFTER", data->protectafter.value());
}
if (!data->suspend_reason.empty())
{
SuspendInfo si;
+12 -3
View File
@@ -480,7 +480,10 @@ static void LoadNicks()
READ(read_uint32(&u32, f));
if (u32 & OLD_NI_KILLPROTECT)
nc->Extend<bool>("KILLPROTECT");
{
nc->Extend<bool>("PROTECT");
nc->Extend("PROTECT_AFTER", 60);
}
if (u32 & OLD_NI_MSG)
nc->Extend<bool>("MSG");
if (u32 & OLD_NI_MEMO_HARDMAX)
@@ -498,9 +501,15 @@ static void LoadNicks()
if (u32 & OLD_NI_HIDE_QUIT)
nc->Extend<bool>("HIDE_QUIT");
if (u32 & OLD_NI_KILL_QUICK)
nc->Extend<bool>("KILL_QUICK");
{
nc->Extend<bool>("PROTECT");
nc->Extend("PROTECT_AFTER", 20);
}
if (u32 & OLD_NI_KILL_IMMED)
nc->Extend<bool>("KILL_IMMED");
{
nc->Extend<bool>("PROTECT");
nc->Extend<time_t>("PROTECT_AFTER", 0);
}
if (u32 & OLD_NI_MEMO_MAIL)
nc->Extend<bool>("MEMO_MAIL");
if (u32 & OLD_NI_HIDE_STATUS)
+15 -19
View File
@@ -211,31 +211,27 @@ public:
if (Config->GetModule("nickserv").Get<bool>("nonicknameownership"))
return;
if (!na->nc->HasExt("KILL_IMMED"))
if (na->nc->HasExt("PROTECT"))
{
u->SendMessage(NickServ, NICK_IS_SECURE, NickServ->GetQueryCommand().c_str());
}
if (na->nc->HasExt("KILLPROTECT"))
{
if (na->nc->HasExt("KILL_IMMED"))
auto &block = Config->GetModule(this);
auto protectafter = na->nc->GetExt<time_t>("PROTECT_AFTER");
auto protect = protectafter ? *protectafter : block.Get<time_t>("defaultprotect", "1m");
protect = std::clamp(protect, block.Get<time_t>("minprotect", "10s"), block.Get<time_t>("maxprotect", "10m"));
if (protect)
{
u->SendMessage(NickServ, NICK_IS_SECURE, NickServ->GetQueryCommand().c_str());
u->SendMessage(NickServ, _("If you do not change within %s, I will change your nick."),
Anope::Duration(protect, u->Account()).c_str());
new NickServCollide(this, this, u, na, protect);
}
else
{
u->SendMessage(NickServ, FORCENICKCHANGE_NOW);
this->Collide(u, na);
}
else if (na->nc->HasExt("KILL_QUICK"))
{
time_t killquick = Config->GetModule("nickserv").Get<time_t>("killquick", "20s");
u->SendMessage(NickServ, _("If you do not change within %s, I will change your nick."), Anope::Duration(killquick, u->Account()).c_str());
new NickServCollide(this, this, u, na, killquick);
}
else
{
time_t kill = Config->GetModule("nickserv").Get<time_t>("kill", "60s");
u->SendMessage(NickServ, _("If you do not change within %s, I will change your nick."), Anope::Duration(kill, u->Account()).c_str());
new NickServCollide(this, this, u, na, kill);
}
}
}
void OnUserLogin(User *u) override
-189
View File
@@ -1,189 +0,0 @@
/* NickServ core functions
*
* (C) 2003-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*/
#include "module.h"
class CommandNSSetKill
: public Command
{
public:
CommandNSSetKill(Module *creator, const Anope::string &sname = "nickserv/set/kill", size_t min = 1)
: Command(creator, sname, min, min + 1)
{
this->SetDesc(_("Turn protection on or off"));
this->SetSyntax("{ON | QUICK | IMMED | OFF}");
}
void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
{
if (Anope::ReadOnly)
{
source.Reply(READ_ONLY_MODE);
return;
}
if (Config->GetModule("nickserv").Get<bool>("nonicknameownership"))
{
source.Reply(_("This command may not be used on this network because nickname ownership is disabled."));
return;
}
const NickAlias *na = NickAlias::Find(user);
if (!na)
{
source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
return;
}
NickCore *nc = na->nc;
EventReturn MOD_RESULT;
FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
if (MOD_RESULT == EVENT_STOP)
return;
if (param.equals_ci("ON"))
{
nc->Extend<bool>("KILLPROTECT");
nc->Shrink<bool>("KILL_QUICK");
nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill on for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002."), nc->display.c_str());
}
else if (param.equals_ci("QUICK"))
{
nc->Extend<bool>("KILLPROTECT");
nc->Extend<bool>("KILL_QUICK");
nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill quick for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002, with a reduced delay."), nc->display.c_str());
}
else if (param.equals_ci("IMMED"))
{
if (Config->GetModule(this->owner).Get<bool>("allowkillimmed"))
{
nc->Extend<bool>("KILLPROTECT");
nc->Shrink<bool>("KILL_QUICK");
nc->Extend<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill immed for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002, with no delay."), nc->display.c_str());
}
else
source.Reply(_("The \002IMMED\002 option is not available on this network."));
}
else if (param.equals_ci("OFF"))
{
nc->Shrink<bool>("KILLPROTECT");
nc->Shrink<bool>("KILL_QUICK");
nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable kill for " << nc->display;
source.Reply(_("Protection is now \002off\002 for \002%s\002."), nc->display.c_str());
}
else
this->OnSyntaxError(source, "KILL");
return;
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, source.nc->display, params[0]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Turns the automatic protection option for your nick\n"
"on or off. With protection on, if another user\n"
"tries to take your nick, they will be given one minute to\n"
"change to another nick, after which %s will forcibly change\n"
"their nick.\n"
" \n"
"If you select \002QUICK\002, the user will be given only 20 seconds\n"
"to change nicks instead of the usual 60. If you select\n"
"\002IMMED\002, the user's nick will be changed immediately \037without\037 being\n"
"warned first or given a chance to change their nick; please\n"
"do not use this option unless necessary. Also, your\n"
"network's administrators may have disabled this option."), source.service->nick.c_str());
return true;
}
};
class CommandNSSASetKill final
: public CommandNSSetKill
{
public:
CommandNSSASetKill(Module *creator)
: CommandNSSetKill(creator, "nickserv/saset/kill", 2)
{
this->ClearSyntax();
this->SetSyntax(_("\037nickname\037 {ON | QUICK | IMMED | OFF}"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, params[0], params[1]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Turns the automatic protection option for the nick\n"
"on or off. With protection on, if another user\n"
"tries to take the nick, they will be given one minute to\n"
"change to another nick, after which %s will forcibly change\n"
"their nick.\n"
" \n"
"If you select \002QUICK\002, the user will be given only 20 seconds\n"
"to change nicks instead of the usual 60. If you select\n"
"\002IMMED\002, the user's nick will be changed immediately \037without\037 being\n"
"warned first or given a chance to change their nick; please\n"
"do not use this option unless necessary. Also, your\n"
"network's administrators may have disabled this option."), source.service->nick.c_str());
return true;
}
};
class NSSetKill final
: public Module
{
private:
CommandNSSetKill commandnssetkill;
CommandNSSASetKill commandnssasetkill;
SerializableExtensibleItem<bool> killprotect, kill_quick, kill_immed;
public:
NSSetKill(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandnssetkill(this)
, commandnssasetkill(this)
, killprotect(this, "KILLPROTECT")
, kill_quick(this, "KILL_QUICK")
, kill_immed(this, "KILL_IMMED")
{
}
void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) override
{
if (!show_hidden)
return;
if (kill_immed.HasExt(na->nc))
info.AddOption(_("Immediate protection"));
else if (kill_quick.HasExt(na->nc))
info.AddOption(_("Quick protection"));
else if (killprotect.HasExt(na->nc))
info.AddOption(_("Protection"));
}
};
MODULE_INIT(NSSetKill)
+168
View File
@@ -0,0 +1,168 @@
/* NickServ core functions
*
* (C) 2003-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*/
#include "module.h"
class CommandNSSetProtect
: public Command
{
public:
CommandNSSetProtect(Module *creator, const Anope::string &sname = "nickserv/set/protect", size_t min = 1)
: Command(creator, sname, min, min + 1)
{
this->SetDesc(_("Turn protection on or off"));
this->SetSyntax(_("{ON | \037delay\037 | OFF}"));
}
void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
{
if (Anope::ReadOnly)
{
source.Reply(READ_ONLY_MODE);
return;
}
if (Config->GetModule("nickserv").Get<bool>("nonicknameownership"))
{
source.Reply(_("This command may not be used on this network because nickname ownership is disabled."));
return;
}
const auto *na = NickAlias::Find(user);
if (!na)
{
source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
return;
}
NickCore *nc = na->nc;
EventReturn MOD_RESULT;
FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
if (MOD_RESULT == EVENT_STOP)
return;
if (param.equals_ci("ON"))
{
nc->Extend<bool>("PROTECT");
nc->Shrink<time_t>("PROTECT_AFTER");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable protection for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002."), nc->display.c_str());
}
else if (param.equals_ci("OFF"))
{
nc->Shrink<bool>("PROTECT");
nc->Shrink<time_t>("PROTECT_AFTER");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable protection for " << nc->display;
source.Reply(_("Protection is now \002off\002 for \002%s\002."), nc->display.c_str());
}
else
{
auto iparam = Anope::TryConvert<time_t>(param);
if (!iparam)
{
this->OnSyntaxError(source, "PROTECT");
return;
}
auto &block = Config->GetModule("nickserv");
auto minprotect = block.Get<time_t>("minprotect", "10s");
auto maxprotect = block.Get<time_t>("maxprotect", "10m");
if (*iparam < minprotect || *iparam > maxprotect)
{
source.Reply(_("Protection delay must be between %s and %s."),
Anope::Duration(minprotect, source.GetAccount()).c_str(),
Anope::Duration(maxprotect, source.GetAccount()).c_str());
return;
}
nc->Extend<bool>("PROTECT");
nc->Extend<time_t>("PROTECT_AFTER", *iparam);
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable protection after " << *iparam << " seconds for " << nc->display;
source.Reply(_("Protection is now \002on\002 after \002%lu seconds\002 for \002%s\002."), *iparam, nc->display.c_str());
}
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, source.nc->display, params[0]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Turns automatic protection for your account on or off. With\n"
"protection on if another user tries to use a nickname from\n"
"your group they will be given some time to change their nick\n"
"after which %s will forcibly change their nick."), source.service->nick.c_str());
return true;
}
};
class CommandNSSASetProtect final
: public CommandNSSetProtect
{
public:
CommandNSSASetProtect(Module *creator)
: CommandNSSetProtect(creator, "nickserv/saset/protect", 2)
{
this->ClearSyntax();
this->SetSyntax(_("\037nickname\037 {ON | \037delay\037 | OFF}"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, params[0], params[1]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Turns automatic protection for the nick on or off. With\n"
"protection on if a user tries to use a nickname from the\n"
"nick's group they will be given some time to change their\n"
"nick after which %s will forcibly change their nick."), source.service->nick.c_str());
return true;
}
};
class NSSetProtect final
: public Module
{
private:
CommandNSSetProtect commandnssetprotect;
CommandNSSASetProtect commandnssasetprotect;
SerializableExtensibleItem<bool> protect;
SerializableExtensibleItem<time_t> protectafter;
public:
NSSetProtect(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandnssetprotect(this)
, commandnssasetprotect(this)
, protect(this, "PROTECT")
, protectafter(this, "PROTECT_AFTER")
{
}
void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) override
{
if (!show_hidden)
return;
if (protect.HasExt(na->nc))
info.AddOption(_("Protection"));
}
};
MODULE_INIT(NSSetProtect)
+36 -20
View File
@@ -56,23 +56,38 @@ bool WebCPanel::NickServ::Info::OnRequest(HTTPProvider *server, const Anope::str
na->nc->Shrink<bool>("NS_PRIVATE");
replacements["MESSAGES"] = "Private updated";
}
if (message.post_data["kill"] == "on" && !na->nc->HasExt("KILLPROTECT"))
if (na->nc->HasExt("PROTECT") != !!message.post_data.count("protect"))
{
na->nc->Extend<bool>("KILLPROTECT");
na->nc->Shrink<bool>("KILL_QUICK");
replacements["MESSAGES"] = "Kill updated";
if (!na->nc->HasExt("PROTECT"))
{
na->nc->Shrink<bool>("PROTECT");
na->nc->Shrink<time_t>("PROTECT_AFTER");
}
else
{
na->nc->Extend<bool>("PROTECT");
}
replacements["MESSAGES"] = "Protect updated";
}
else if (message.post_data["kill"] == "quick" && !na->nc->HasExt("KILL_QUICK"))
if (na->nc->HasExt("PROTECT") && message.post_data.count("protect_after") > 0)
{
na->nc->Extend<bool>("KILLPROTECT");
na->nc->Extend<bool>("KILL_QUICK");
replacements["MESSAGES"] = "Kill updated";
}
else if (message.post_data["kill"] == "off" && (!!na->nc->HasExt("KILLPROTECT") || !!na->nc->HasExt("KILL_QUICK")))
{
na->nc->Shrink<bool>("KILLPROTECT");
na->nc->Shrink<bool>("KILL_QUICK");
replacements["MESSAGES"] = "Kill updated";
auto &block = Config->GetModule("nickserv");
auto minprotect = block.Get<time_t>("minprotect", "10s");
auto maxprotect = block.Get<time_t>("maxprotect", "10m");
auto secs = Anope::TryConvert<time_t>(message.post_data["greet"]);
if (!secs)
replacements["ERRORS"] = "Protection after seconds are not valid";
else if (*secs < minprotect || *secs > maxprotect)
{
replacements["ERRORS"] = Anope::printf("Protection delay must be between %ld and %ld seconds.",
minprotect, maxprotect);
}
else
{
na->nc->Extend<time_t>("PROTECT_AFTER", *secs);
replacements["MESSAGES"] = "Protect after updated";
}
}
if (na->nc->HasExt("NS_KEEP_MODES") != !!message.post_data.count("keepmodes"))
{
@@ -113,12 +128,13 @@ bool WebCPanel::NickServ::Info::OnRequest(HTTPProvider *server, const Anope::str
replacements["AUTOOP"];
if (na->nc->HasExt("NS_PRIVATE"))
replacements["PRIVATE"];
if (na->nc->HasExt("KILLPROTECT"))
replacements["KILL_ON"];
if (na->nc->HasExt("KILL_QUICK"))
replacements["KILL_QUICK"];
if (!na->nc->HasExt("KILLPROTECT") && !na->nc->HasExt("KILL_QUICK"))
replacements["KILL_OFF"];
if (na->nc->HasExt("PROTECT"))
{
replacements["PROTECT"];
auto *protectafter = na->nc->GetExt<time_t>("PROTECT_AFTER");
if (protectafter)
replacements["PROTECT_AFTER"] = *protectafter;
}
if (na->nc->HasExt("NS_KEEP_MODES"))
replacements["KEEPMODES"];
if (na->nc->HasExt("MSG"))
@@ -61,14 +61,12 @@
<td><input type="checkbox" name="private" value="on" {IF EXISTS PRIVATE}checked{END IF}></td>
</tr>
<tr>
<td>Kill:</td>
<td>
<select name="kill" class="form-control input-sm">
<option value="on" {IF EXISTS KILL_ON}selected{END IF}>On</option>
<option value="quick" {IF EXISTS KILL_QUICK}selected{END IF}>Quick</option>
<option value="off" {IF EXISTS KILL_OFF}selected{END IF}>Off</option>
</select>
</td>
<td>Protect:</td>
<td><input type="checkbox" name="protect" value="on" {IF EXISTS PROTECT}checked{END IF}></td>
</tr>
<tr>
<td>Protect after:</td>
<td><input name="protect_after" value="{PROTECT_AFTER}" class="form-control input-sm"></td>
</tr>
</tbody>
</table>
+23 -1
View File
@@ -146,7 +146,29 @@ Serializable *NickCore::Unserialize(Serializable *obj, Serialize::Data &data)
b = false;
data["extensible:KILLPROTECT"] >> b;
if (b)
nc->Extend<bool>("KILLPROTECT");
nc->Extend<bool>("PROTECT");
b = false;
data["KILLPROTECT"] >> b;
if (b)
{
nc->Extend<bool>("PROTECT");
nc->Extend("PROTECT_AFTER", Config->GetModule("nickserv").Get<time_t>("kill", "60s"));
}
b = false;
data["KILL_QUICK"] >> b;
if (b)
{
nc->Extend<bool>("PROTECT");
nc->Extend("PROTECT_AFTER", Config->GetModule("nickserv").Get<time_t>("killquick", "20s"));
}
b = false;
data["KILL_IMMED"] >> b;
if (b)
{
nc->Extend<bool>("PROTECT");
nc->Extend("PROTECT_AFTER", 0);
}
/* end compat */
return nc;