diff --git a/data/nickserv.example.conf b/data/nickserv.example.conf index e71cab983..4aaaffe57 100644 --- a/data/nickserv.example.conf +++ b/data/nickserv.example.conf @@ -113,6 +113,7 @@ module * - memo_signon: Notify user if they have a new memo when they sign into the nick * - memo_receive: Notify user if they have a new memo as soon as it's received * - memo_mail: Notify user if they have a new memo by mail + * - autologin: User will be automatically logged in when they connect with a known SSL cert. * - autoop: User will be automatically opped in channels they enter and have access to * - neverop: User can not be added to access lists * - msg: Messages will be sent as PRIVMSGs instead of NOTICEs @@ -123,7 +124,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 = "autoop hide_email hide_mask memo_receive memo_signon ns_private protect" + defaults = "autologin 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 diff --git a/docs/CHANGES.md b/docs/CHANGES.md index d71d0e711..54d20f613 100644 --- a/docs/CHANGES.md +++ b/docs/CHANGES.md @@ -4,6 +4,8 @@ ### Breaking Changes +* Automatic login using a known SSL fingerprint now requires the `AUTOLOGIN` option to be set on accounts. Users can enable it on existing accounts with `/NS SET AUTOLOGIN ON`. + * Conan 2 is now used for packaging dependencies on Windows. If you are building from source you will need to upgrade Conan. * Non-breaking spaces in translatable messages now use 0x1B instead of 0x1A due to recent msgfmt releases treating 0x1A as an EOF character. If you have an out of tree translation you will need to update it. diff --git a/language/anope.en_US.po b/language/anope.en_US.po index 9017e3ce6..40b5aac4c 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-14 15:15+0000\n" -"PO-Revision-Date: 2026-02-14 15:15+0000\n" +"POT-Creation-Date: 2026-02-22 16:58+0000\n" +"PO-Revision-Date: 2026-02-22 16:58+0000\n" "Last-Translator: Sadie Powell \n" "Language-Team: English\n" "Language: en_US\n" @@ -1141,6 +1141,14 @@ msgstr "" msgid "%s will not send you any notification of memos." msgstr "" +#, c-format +msgid "%s will now be automatically logged in when they connect using a known SSL certificate." +msgstr "" + +#, c-format +msgid "%s will now not be automatically logged in when they connect using a known SSL certificate." +msgstr "" + #, c-format msgid "%s will now notify you of memos when they are sent to you." msgstr "" @@ -1780,9 +1788,6 @@ msgstr "" msgid "Associate a greet message with your nickname" msgstr "" -msgid "Associate an email address with the channel" -msgstr "" - msgid "Associate an email address with your nickname" msgstr "" @@ -5035,6 +5040,10 @@ msgstr "" msgid "Sets whether the given nickname can be added to a channel access list." msgstr "" +#, c-format +msgid "Sets whether the given nickname should automatically be logged in when they connect using a known SSL certificate. You can configure their SSL certificate using the %s command." +msgstr "" + #, c-format msgid "Sets whether the given nickname will be given its status modes in channels automatically. Set to ON to allow %s to set status modes on the given nickname automatically when it is entering channels. Note that depending on channel settings some modes may not get set automatically." msgstr "" @@ -5045,6 +5054,13 @@ msgstr "" msgid "Sets whether you can be added to a channel access list." msgstr "" +msgid "Sets whether you should automatically be logged in when you connect using a known SSL certificate." +msgstr "" + +#, c-format +msgid "Sets whether you should automatically be logged in when you connect using a known SSL certificate. You can configure your SSL certificate using the %s command." +msgstr "" + #, c-format msgid "Sets whether you will be given your channel status modes automatically. Set to ON to allow %s to set status modes on you automatically when entering channels. Note that depending on channel settings some modes may not get set automatically." msgstr "" diff --git a/modules/nickserv/ns_cert.cpp b/modules/nickserv/ns_cert.cpp index 112b766f9..387c62508 100644 --- a/modules/nickserv/ns_cert.cpp +++ b/modules/nickserv/ns_cert.cpp @@ -388,10 +388,114 @@ public: } }; +class CommandNSSetAutologin + : public Command +{ +public: + CommandNSSetAutologin(Module *creator, const Anope::string &sname = "nickserv/set/autologin", size_t min = 1) + : Command(creator, sname, min, min + 1) + { + this->SetDesc(_("Sets whether you should automatically be logged in when you connect using a known SSL certificate.")); + this->SetSyntax("{ON | OFF}"); + } + + void Run(CommandSource &source, const Anope::string &user, const Anope::string ¶m) + { + if (Anope::ReadOnly) + { + source.Reply(READ_ONLY_MODE); + return; + } + + const NickAlias *na = NickAlias::Find(user); + if (na == NULL) + { + 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")) + { + Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable autologin for " << na->nc->display; + nc->Extend("AUTOLOGIN"); + source.Reply(_("%s will now be automatically logged in when they connect using a known SSL certificate."), nc->display.c_str()); + } + else if (param.equals_ci("OFF")) + { + Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable autologin for " << na->nc->display; + nc->Shrink("AUTOLOGIN"); + source.Reply(_("%s will now not be automatically logged in when they connect using a known SSL certificate."), nc->display.c_str()); + } + else + this->OnSyntaxError(source, "AUTOLOGIN"); + } + + void Execute(CommandSource &source, const std::vector ¶ms) override + { + this->Run(source, source.nc->display, params[0]); + } + + bool OnHelp(CommandSource &source, const Anope::string &) override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply( + _( + "Sets whether you should automatically be logged in when you connect using a known " + "SSL certificate. You can configure your SSL certificate using the \002%s\002 " + "command." + ), + source.service->GetQueryCommand("nickserv/cert").c_str() + ); + return true; + } +}; + +class CommandNSSASetAutologin final + : public CommandNSSetAutologin +{ +public: + CommandNSSASetAutologin(Module *creator) + : CommandNSSetAutologin(creator, "nickserv/saset/autologin", 2) + { + this->ClearSyntax(); + this->SetSyntax(_("\037nickname\037 {ON | OFF}")); + } + + void Execute(CommandSource &source, const std::vector ¶ms) override + { + this->Run(source, params[0], params[1]); + } + + bool OnHelp(CommandSource &source, const Anope::string &) override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply( + _( + "Sets whether the given nickname should automatically be logged in when they " + "connect using a known SSL certificate. You can configure their SSL certificate " + "using the \002%s\002 command." + ), + source.service->GetQueryCommand("nickserv/cert").c_str() + ); + return true; + } +}; + class NSCert final : public Module { +private: CommandNSCert commandnscert; + CommandNSSetAutologin commandnssetautologin; + CommandNSSASetAutologin commandnssasetautologin; NSCertListImpl::ExtensibleItem certs; CertServiceImpl cs; @@ -400,6 +504,9 @@ class NSCert final if (!nc || nc->HasExt("NS_SUSPENDED")) return false; // Account suspended. + if (!nc->HasExt("AUTOLOGIN")) + return false; // Autologin disabled. + const auto maxlogins = Config->GetModule("ns_identify").Get("maxlogins"); if (maxlogins && nc->users.size() >= maxlogins) { @@ -416,6 +523,8 @@ public: NSCert(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR) , commandnscert(this) + , commandnssetautologin(this) + , commandnssasetautologin(this) , certs(this, NICKSERV_CERT_EXT) , cs(this) {