summaryrefslogtreecommitdiff
path: root/modules/commands/ns_register.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/commands/ns_register.cpp')
-rw-r--r--modules/commands/ns_register.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp
new file mode 100644
index 000000000..552551994
--- /dev/null
+++ b/modules/commands/ns_register.cpp
@@ -0,0 +1,355 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2011 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"
+
+static bool SendRegmail(User *u, NickAlias *na, BotInfo *bi);
+
+class CommandNSConfirm : public Command
+{
+ public:
+ CommandNSConfirm(Module *creator) : Command(creator, "nickserv/confirm", 1, 2)
+ {
+ this->SetFlag(CFLAG_ALLOW_UNREGISTERED);
+ this->SetDesc(_("Confirm an auth code"));
+ this->SetSyntax(_("\037passcode\037"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params)
+ {
+ User *u = source.u;
+ const Anope::string &passcode = params[0];
+
+ if (u->Account() && u->HasPriv("nickserv/confirm"))
+ {
+ NickAlias *na = findnick(passcode);
+ if (na == NULL)
+ source.Reply(NICK_X_NOT_REGISTERED, passcode.c_str());
+ else if (na->nc->HasFlag(NI_UNCONFIRMED) == false)
+ source.Reply(_("Nick \002%s\002 is already confirmed."), na->nick.c_str());
+ else
+ {
+ na->nc->UnsetFlag(NI_UNCONFIRMED);
+ Log(LOG_ADMIN, u, this) << "to confirm nick " << na->nick << " (" << na->nc->display << ")";
+ source.Reply(_("Nick \002%s\002 has been confirmed."), na->nick.c_str());
+ }
+ }
+ else if (u->Account())
+ {
+ Anope::string code;
+ if (u->Account()->GetExtRegular<Anope::string>("ns_register_passcode", code) && code == passcode)
+ {
+ u->Account()->Shrink("ns_register_passcode");
+ Log(LOG_COMMAND, u, this) << "to confirm their email";
+ source.Reply(_("Your email address of \002%s\002 has been confirmed."), u->Account()->email.c_str());
+ u->Account()->UnsetFlag(NI_UNCONFIRMED);
+ ircdproto->SendAccountLogin(u, u->Account());
+ NickAlias *na = findnick(u->nick);
+ if (na && na->nc == u->Account())
+ u->SetMode(findbot(Config->NickServ), UMODE_REGISTERED);
+ }
+ else
+ source.Reply(_("Invalid passcode."));
+ }
+ else
+ source.Reply(_("Invalid passcode."));
+
+ return;
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &subcommand)
+ {
+ User *u = source.u;
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("This command is used by several commands as a way to confirm\n"
+ "changes made to your account.\n"
+ " \n"
+ "This is most commonly used to confirm your email address once\n"
+ "you register or change it.\n"
+ " \n"
+ "This is also used after the RESETPASS command has been used to\n"
+ "force identify you to your nick so you may change your password."));
+ if (u->Account() && u->HasPriv("nickserv/confirm"))
+ source.Reply(_("Additionally, Services Operators with the \037nickserv/confirm\037 permission can\n"
+ "replace \037passcode\037 with a users nick to force validate them."));
+ return true;
+ }
+
+ void OnSyntaxError(CommandSource &source, const Anope::string &subcommand)
+ {
+ source.Reply(NICK_CONFIRM_INVALID);
+ }
+};
+
+class CommandNSRegister : public Command
+{
+ public:
+ CommandNSRegister(Module *creator) : Command(creator, "nickserv/register", 1, 2)
+ {
+ this->SetFlag(CFLAG_ALLOW_UNREGISTERED);
+ this->SetDesc(_("Register a nickname"));
+ if (Config->NSForceEmail)
+ this->SetSyntax(_("\037password\037 \037email\037"));
+ else
+ this->SetSyntax(_("\037password\037 \037[email]\037"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params)
+ {
+ User *u = source.u;
+ NickAlias *na;
+ size_t prefixlen = Config->NSGuestNickPrefix.length();
+ size_t nicklen = u->nick.length();
+ Anope::string pass = params[0];
+ Anope::string email = params.size() > 1 ? params[1] : "";
+
+ if (readonly)
+ {
+ source.Reply(_("Sorry, nickname registration is temporarily disabled."));
+ return;
+ }
+
+ if (!u->HasMode(UMODE_OPER) && Config->NickRegDelay && Anope::CurTime - u->my_signon < Config->NickRegDelay)
+ {
+ source.Reply(_("You must have been using this nick for at least %d seconds to register."), Config->NickRegDelay);
+ return;
+ }
+
+ /* Prevent "Guest" nicks from being registered. -TheShadow */
+
+ /* Guest nick can now have a series of between 1 and 7 digits.
+ * --lara
+ */
+ if (nicklen <= prefixlen + 7 && nicklen >= prefixlen + 1 && !u->nick.find_ci(Config->NSGuestNickPrefix) && u->nick.substr(prefixlen).find_first_not_of("1234567890") == Anope::string::npos)
+ {
+ source.Reply(NICK_CANNOT_BE_REGISTERED, u->nick.c_str());
+ return;
+ }
+
+ if (Config->RestrictOperNicks)
+ for (unsigned i = 0; i < Config->Opers.size(); ++i)
+ {
+ Oper *o = Config->Opers[i];
+
+ if (!u->HasMode(UMODE_OPER) && u->nick.find_ci(o->name) != Anope::string::npos)
+ {
+ source.Reply(NICK_CANNOT_BE_REGISTERED, u->nick.c_str());
+ return;
+ }
+ }
+
+ if (Config->NSForceEmail && email.empty())
+ this->OnSyntaxError(source, "");
+ else if (Anope::CurTime < u->lastnickreg + Config->NSRegDelay)
+ source.Reply(_("Please wait %d seconds before using the REGISTER command again."), (u->lastnickreg + Config->NSRegDelay) - Anope::CurTime);
+ else if ((na = findnick(u->nick)))
+ source.Reply(NICK_ALREADY_REGISTERED, u->nick.c_str());
+ else if (pass.equals_ci(u->nick) || (Config->StrictPasswords && pass.length() < 5))
+ source.Reply(MORE_OBSCURE_PASSWORD);
+ else if (pass.length() > Config->PassLen)
+ source.Reply(PASSWORD_TOO_LONG);
+ else if (!email.empty() && !MailValidate(email))
+ source.Reply(MAIL_X_INVALID, email.c_str());
+ else
+ {
+ na = new NickAlias(u->nick, new NickCore(u->nick));
+ enc_encrypt(pass, na->nc->pass);
+ if (!email.empty())
+ na->nc->email = email;
+
+ Anope::string last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost();
+ na->last_usermask = last_usermask;
+ na->last_realname = u->realname;
+ if (Config->NSAddAccessOnReg)
+ na->nc->AddAccess(create_mask(u));
+
+ u->Login(na->nc);
+
+ Log(LOG_COMMAND, u, this) << "to register " << na->nick << " (email: " << (!na->nc->email.empty() ? na->nc->email : "none") << ")";
+
+ FOREACH_MOD(I_OnNickRegister, OnNickRegister(na));
+
+ if (Config->NSAddAccessOnReg)
+ source.Reply(_("Nickname \002%s\002 registered under your account: %s"), u->nick.c_str(), na->nc->GetAccess(0).c_str());
+ else
+ source.Reply(_("Nickname \002%s\002 registered."), u->nick.c_str());
+
+ Anope::string tmp_pass;
+ if (enc_decrypt(na->nc->pass, tmp_pass) == 1)
+ source.Reply(_("Your password is \002%s\002 - remember this for later use."), tmp_pass.c_str());
+
+ if (Config->NSEmailReg)
+ {
+ na->nc->SetFlag(NI_UNCONFIRMED);
+ if (SendRegmail(u, na, source.owner))
+ {
+ source.Reply(_("A passcode has been sent to %s, please type %s%s confirm <passcode> to confirm your email address."), email.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str());
+ source.Reply(_("If you do not confirm your email address within %s your account will expire."), duration(Config->NSUnconfirmedExpire).c_str());
+ }
+ }
+ else
+ ircdproto->SendAccountLogin(u, u->Account());
+ ircdproto->SetAutoIdentificationToken(u);
+
+ u->lastnickreg = Anope::CurTime;
+ }
+
+ return;
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &subcommand)
+ {
+ this->SendSyntax(source);
+ source.Reply("\n");
+ source.Reply(_("Registers your nickname in the %s database. Once\n"
+ "your nick is registered, you can use the \002SET\002 and \002ACCESS\002\n"
+ "commands to configure your nick's settings as you like\n"
+ "them. Make sure you remember the password you use when\n"
+ "registering - you'll need it to make changes to your nick\n"
+ "later. (Note that \002case matters!\002 \037ANOPE\037, \037Anope\037, and \n"
+ "\037anope\037 are all different passwords!)\n"
+ " \n"
+ "Guidelines on choosing passwords:\n"
+ " \n"
+ "Passwords should not be easily guessable. For example,\n"
+ "using your real name as a password is a bad idea. Using\n"
+ "your nickname as a password is a much worse idea ;) and,\n"
+ "in fact, %s will not allow it. Also, short\n"
+ "passwords are vulnerable to trial-and-error searches, so\n"
+ "you should choose a password at least 5 characters long.\n"
+ "Finally, the space character cannot be used in passwords.\n"),
+ Config->NickServ.c_str(), Config->NickServ.c_str());
+
+ if (!Config->NSForceEmail)
+ source.Reply(_(" \n"
+ "The parameter \037email\037 is optional and will set the email\n"
+ "for your nick immediately.\n"
+ "Your privacy is respected; this e-mail won't be given to\n"
+ "any third-party person.\n"
+ " \n"));
+
+ source.Reply(_("This command also creates a new group for your nickname,\n"
+ "that will allow you to register other nicks later sharing\n"
+ "the same configuration, the same set of memos and the\n"
+ "same channel privileges."));
+ return true;
+ }
+};
+
+class CommandNSResend : public Command
+{
+ public:
+ CommandNSResend(Module *creator) : Command(creator, "nickserv/resend", 0, 0)
+ {
+ this->SetSyntax("");
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params)
+ {
+ if (!Config->NSEmailReg)
+ return;
+
+ User *u = source.u;
+ NickAlias *na = findnick(u->nick);
+
+ if (na == NULL)
+ source.Reply(NICK_NOT_REGISTERED);
+ else if (na->nc != u->Account() || u->Account()->HasFlag(NI_UNCONFIRMED) == false)
+ source.Reply(_("Your account is already confirmed."));
+ else
+ {
+ if (Anope::CurTime < u->Account()->lastmail + Config->NSResendDelay)
+ source.Reply(_("Cannot send mail now; please retry a little later."));
+ else if (!SendRegmail(u, na, source.owner))
+ {
+ na->nc->lastmail = Anope::CurTime;
+ source.Reply(_("Your passcode has been re-sent to %s."), na->nc->email.c_str());
+ Log(LOG_COMMAND, u, this) << "to resend registration verification code";
+ }
+ else
+ Log() << "Unable to resend registration verification code for " << u->nick;
+ }
+
+ return;
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &subcommand)
+ {
+ if (!Config->NSEmailReg)
+ return false;
+
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("This command will re-send the auth code (also called passcode)\n"
+ "to the e-mail address of the user whom is performing it."));
+ return true;
+ }
+
+ void OnServHelp(CommandSource &source)
+ {
+ if (Config->NSEmailReg)
+ source.Reply(" %-14s %s", this->name.c_str(),_("Resend the registration passcode"));
+ }
+};
+
+class NSRegister : public Module
+{
+ CommandNSRegister commandnsregister;
+ CommandNSConfirm commandnsconfirm;
+ CommandNSResend commandnsrsend;
+
+ public:
+ NSRegister(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
+ commandnsregister(this), commandnsconfirm(this), commandnsrsend(this)
+ {
+ this->SetAuthor("Anope");
+
+ ModuleManager::RegisterService(&commandnsregister);
+ ModuleManager::RegisterService(&commandnsconfirm);
+ ModuleManager::RegisterService(&commandnsrsend);
+ }
+};
+
+static bool SendRegmail(User *u, NickAlias *na, BotInfo *bi)
+{
+ Anope::string code;
+ if (na->nc->GetExtRegular<Anope::string>("ns_register_passcode", code) == false)
+ {
+ int chars[] = {
+ ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
+ 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
+ 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
+ };
+ int idx, min = 1, max = 62;
+ for (idx = 0; idx < 9; ++idx)
+ code += chars[1 + static_cast<int>((static_cast<float>(max - min)) * getrandom16() / 65536.0) + min];
+ na->nc->Extend("ns_register_passcode", new ExtensibleItemRegular<Anope::string>(code));
+ }
+
+ Anope::string subject = Anope::printf(_("Nickname Registration (%s)"), na->nick.c_str());
+ Anope::string message = Anope::printf(_("Hi,\n"
+ " \n"
+ "You have requested to register the nickname %s on %s.\n"
+ "Please type \" %s%s confirm %s \" to complete registration.\n"
+ " \n"
+ "If you don't know why this mail was sent to you, please ignore it silently.\n"
+ " \n"
+ "%s administrators."), na->nick.c_str(), Config->NetworkName.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str(), code.c_str(), Config->NetworkName.c_str());
+
+ return Mail(u, na->nc, bi, subject, message);
+}
+
+MODULE_INIT(NSRegister)