From 538b2cf035b844ccb56bb9800c817518be7d7dee Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Tue, 24 Feb 2026 15:36:48 +0000 Subject: [PATCH] Refactor the logic in ns_cert. --- language/anope.en_US.po | 8 +- modules/nickserv/ns_cert.cpp | 156 ++++++++++++++++++----------------- 2 files changed, 86 insertions(+), 78 deletions(-) diff --git a/language/anope.en_US.po b/language/anope.en_US.po index 686120ef6..a5fdc8df0 100644 --- a/language/anope.en_US.po +++ b/language/anope.en_US.po @@ -16,8 +16,8 @@ msgid "" msgstr "" "Project-Id-Version: Anope\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-02-22 17:02+0000\n" -"PO-Revision-Date: 2026-02-22 17:03+0000\n" +"POT-Creation-Date: 2026-02-24 15:34+0000\n" +"PO-Revision-Date: 2026-02-24 15:34+0000\n" "Last-Translator: Sadie Powell \n" "Language-Team: English\n" "Language: en_US\n" @@ -1306,10 +1306,10 @@ msgstr "" msgid "ADD [+expiry] mask limit reason" msgstr "" -msgid "ADD [nickname] channel [key]" +msgid "ADD [nickname fingerprint]" msgstr "" -msgid "ADD [nickname] [fingerprint]" +msgid "ADD [nickname] channel [key]" msgstr "" msgid "ADD [+expiry] mask reason" diff --git a/modules/nickserv/ns_cert.cpp b/modules/nickserv/ns_cert.cpp index 72b045a28..c52eb8c56 100644 --- a/modules/nickserv/ns_cert.cpp +++ b/modules/nickserv/ns_cert.cpp @@ -288,10 +288,17 @@ class CommandNSCert final : public Command { private: - void DoAdd(CommandSource &source, NickCore *nc, Anope::string certfp) + void DoAdd(CommandSource &source, const std::vector ¶ms) { - auto *cl = nc->Require(NICKSERV_CERT_EXT); + auto *nc = FindTarget(source, params.size() == 3 ? params[1] : "", true); + if (!nc) + return; + const auto certfp = FindFingerprint(source, params, nc, false); + if (certfp.empty()) + return; + + auto *cl = nc->Require(NICKSERV_CERT_EXT); const auto max = Config->GetModule(this->owner).Get("max", "5"); if (cl->GetCertCount() >= max) { @@ -300,19 +307,6 @@ private: return; } - if (source.GetAccount() == nc) - { - User *u = source.GetUser(); - - if (!u || u->fingerprint.empty()) - { - source.Reply(_("You are not using a client certificate.")); - return; - } - - certfp = u->fingerprint; - } - if (cl->FindCert(certfp)) { source.Reply(_("Fingerprint \002%s\002 already present on %s's certificate list."), certfp.c_str(), nc->display.c_str()); @@ -333,23 +327,17 @@ private: source.Reply(_("\002%s\002 added to %s's certificate list."), certfp.c_str(), nc->display.c_str()); } - void DoDel(CommandSource &source, NickCore *nc, Anope::string certfp) + void DoDel(CommandSource &source, const std::vector ¶ms) { - auto *cl = nc->Require(NICKSERV_CERT_EXT); - - if (certfp.empty()) - { - User *u = source.GetUser(); - if (u) - certfp = u->fingerprint; - } - - if (certfp.empty()) - { - this->OnSyntaxError(source, "DEL"); + auto *nc = FindTarget(source, params.size() == 3 ? params[1] : "", true); + if (!nc) return; - } + const auto certfp = FindFingerprint(source, params, nc, true); + if (certfp.empty()) + return; + + auto *cl = nc->Require(NICKSERV_CERT_EXT); if (!cl->FindCert(certfp)) { source.Reply(_("\002%s\002 not found on %s's certificate list."), certfp.c_str(), nc->display.c_str()); @@ -362,10 +350,13 @@ private: source.Reply(_("\002%s\002 deleted from %s's certificate list."), certfp.c_str(), nc->display.c_str()); } - static void DoList(CommandSource &source, const NickCore *nc, bool full) + void DoList(CommandSource &source, const std::vector ¶ms, bool full) { - auto *cl = nc->GetExt(NICKSERV_CERT_EXT); + auto *nc = FindTarget(source, params.size() > 1 ? params[1] : "", false); + if (!nc) + return; + auto *cl = nc->GetExt(NICKSERV_CERT_EXT); if (!cl || !cl->GetCertCount()) { source.Reply(_("%s's certificate list is empty."), nc->display.c_str()); @@ -383,7 +374,6 @@ private: ? _("\002{fingerprint}\002 -- created by {creator} at {created}") : _("\002{fingerprint}\002 -- created by {creator} at {created} ({description})"); }); - } else { @@ -419,11 +409,66 @@ private: list.SendTo(source); } + Anope::string FindFingerprint(CommandSource &source, const std::vector ¶ms, const NickCore *nc, bool del) + { + if (source.GetAccount() != nc || del) + { + if (params.size() > 1) + return params.back(); + + this->OnSyntaxError(source, params[0]); + return ""; + } + + auto *u = source.GetUser(); + if (u && !u->fingerprint.empty()) + return u->fingerprint; + + source.Reply(_("You are not using a client certificate.")); + return ""; + } + + NickCore *FindTarget(CommandSource &source, const Anope::string &nick, bool modify) + { + if (!nick.empty()) + { + const auto *na = NickAlias::Find(nick); + if (!na) + { + source.Reply(NICK_X_NOT_REGISTERED, nick.c_str()); + return nullptr; + } + + NickCore *nc = na->nc; + if (nc != source.GetAccount() && !source.HasPriv("nickserv/cert")) + { + source.Reply(ACCESS_DENIED); + return nullptr; + } + + if (modify) + { + if (nc->HasExt("NS_SUSPENDED")) + { + source.Reply(NICK_X_SUSPENDED, nc->display.c_str()); + return nullptr; + } + if (Config->GetModule("nickserv").Get("secureadmins", "yes") && source.GetAccount() != nc && nc->IsServicesOper()) + { + source.Reply(_("You may view but not modify the certificate list of other Services Operators.")); + return nullptr; + } + } + return nc; + } + return source.nc; + } + public: CommandNSCert(Module *creator) : Command(creator, "nickserv/cert", 1, 3) { this->SetDesc(_("Modify the nickname client certificate list")); - this->SetSyntax(_("ADD [\037nickname\037] [\037fingerprint\037]")); + this->SetSyntax(_("ADD [\037nickname\037 \037fingerprint\037]")); this->SetSyntax(_("DEL [\037nickname\037] \037fingerprint\037")); this->SetSyntax(_("LIST [\037nickname\037]")); this->SetSyntax(_("VIEW [\037nickname\037]")); @@ -432,53 +477,16 @@ public: void Execute(CommandSource &source, const std::vector ¶ms) override { const Anope::string &cmd = params[0]; - Anope::string nick, certfp; - - if (cmd.equals_ci("LIST") || cmd.equals_ci("VIEW")) - nick = params.size() > 1 ? params[1] : ""; - else - { - nick = params.size() == 3 ? params[1] : ""; - certfp = params.size() > 1 ? params[params.size() - 1] : ""; - } - - NickCore *nc; - if (!nick.empty()) - { - const NickAlias *na = NickAlias::Find(nick); - if (na == NULL) - { - source.Reply(NICK_X_NOT_REGISTERED, nick.c_str()); - return; - } - else if (na->nc != source.GetAccount() && !source.HasPriv("nickserv/cert")) - { - source.Reply(ACCESS_DENIED); - return; - } - else if (Config->GetModule("nickserv").Get("secureadmins", "yes") && source.GetAccount() != na->nc && na->nc->IsServicesOper() && !cmd.equals_ci("LIST")) - { - source.Reply(_("You may view but not modify the certificate list of other Services Operators.")); - return; - } - - nc = na->nc; - } - else - nc = source.nc; - if (cmd.equals_ci("LIST")) - return this->DoList(source, nc, false); + return this->DoList(source, params, false); if (cmd.equals_ci("VIEW")) - return this->DoList(source, nc, true); - else if (nc->HasExt("NS_SUSPENDED")) - source.Reply(NICK_X_SUSPENDED, nc->display.c_str()); + return this->DoList(source, params, true); else if (Anope::ReadOnly) source.Reply(READ_ONLY_MODE); else if (cmd.equals_ci("ADD")) - return this->DoAdd(source, nc, certfp); + return this->DoAdd(source, params); else if (cmd.equals_ci("DEL")) - return this->DoDel(source, nc, certfp); + return this->DoDel(source, params); else this->OnSyntaxError(source, ""); }