00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "module.h"
00015
00016 static bool SendRegmail(User *u, const NickAlias *na, const BotInfo *bi);
00017
00018 class CommandNSConfirm : public Command
00019 {
00020 public:
00021 CommandNSConfirm(Module *creator) : Command(creator, "nickserv/confirm", 1, 2)
00022 {
00023 this->SetDesc(_("Confirm a passcode"));
00024 this->SetSyntax(_("\037passcode\037"));
00025 this->AllowUnregistered(true);
00026 }
00027
00028 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
00029 {
00030 const Anope::string &passcode = params[0];
00031
00032 if (source.nc && !source.nc->HasExt("UNCONFIRMED") && source.HasPriv("nickserv/confirm"))
00033 {
00034 NickAlias *na = NickAlias::Find(passcode);
00035 if (na == NULL)
00036 source.Reply(NICK_X_NOT_REGISTERED, passcode.c_str());
00037 else if (na->nc->HasExt("UNCONFIRMED") == false)
00038 source.Reply(_("Nick \002%s\002 is already confirmed."), na->nick.c_str());
00039 else
00040 {
00041 na->nc->Shrink("UNCONFIRMED");
00042 Log(LOG_ADMIN, source, this) << "to confirm nick " << na->nick << " (" << na->nc->display << ")";
00043 source.Reply(_("Nick \002%s\002 has been confirmed."), na->nick.c_str());
00044 }
00045 }
00046 else if (source.nc)
00047 {
00048 Anope::string *code = source.nc->GetExt<ExtensibleItemClass<Anope::string> *>("ns_register_passcode");
00049 if (code != NULL && *code == passcode)
00050 {
00051 NickCore *nc = source.nc;
00052 nc->Shrink("ns_register_passcode");
00053 Log(LOG_COMMAND, source, this) << "to confirm their email";
00054 source.Reply(_("Your email address of \002%s\002 has been confirmed."), source.nc->email.c_str());
00055 nc->Shrink("UNCONFIRMED");
00056
00057 if (source.GetUser())
00058 {
00059 IRCD->SendLogin(source.GetUser());
00060 const NickAlias *na = NickAlias::Find(source.GetNick());
00061 if (!Config->NoNicknameOwnership && na != NULL && na->nc == source.GetAccount() && na->nc->HasExt("UNCONFIRMED") == false)
00062 source.GetUser()->SetMode(NickServ, "REGISTERED");
00063 }
00064 }
00065 else
00066 source.Reply(_("Invalid passcode."));
00067 }
00068 else
00069 source.Reply(_("Invalid passcode."));
00070
00071 return;
00072 }
00073
00074 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00075 {
00076 this->SendSyntax(source);
00077 source.Reply(" ");
00078 source.Reply(_("This command is used by several commands as a way to confirm\n"
00079 "changes made to your account.\n"
00080 " \n"
00081 "This is most commonly used to confirm your email address once\n"
00082 "you register or change it.\n"
00083 " \n"
00084 "This is also used after the RESETPASS command has been used to\n"
00085 "force identify you to your nick so you may change your password."));
00086 if (source.HasPriv("nickserv/confirm"))
00087 source.Reply(_("Additionally, Services Operators with the \037nickserv/confirm\037 permission can\n"
00088 "replace \037passcode\037 with a users nick to force validate them."));
00089 return true;
00090 }
00091
00092 void OnSyntaxError(CommandSource &source, const Anope::string &subcommand) anope_override
00093 {
00094 source.Reply(NICK_CONFIRM_INVALID);
00095 }
00096 };
00097
00098 class CommandNSRegister : public Command
00099 {
00100 public:
00101 CommandNSRegister(Module *creator) : Command(creator, "nickserv/register", 1, 2)
00102 {
00103 this->SetDesc(_("Register a nickname"));
00104 if (Config->NSForceEmail)
00105 this->SetSyntax(_("\037password\037 \037email\037"));
00106 else
00107 this->SetSyntax(_("\037password\037 \037[email]\037"));
00108 this->AllowUnregistered(true);
00109 }
00110
00111 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
00112 {
00113 NickAlias *na;
00114 size_t prefixlen = Config->NSGuestNickPrefix.length();
00115 User *u = source.GetUser();
00116 Anope::string u_nick = source.GetNick();
00117 size_t nicklen = u_nick.length();
00118 Anope::string pass = params[0];
00119 Anope::string email = params.size() > 1 ? params[1] : "";
00120
00121 if (Anope::ReadOnly)
00122 {
00123 source.Reply(_("Sorry, nickname registration is temporarily disabled."));
00124 return;
00125 }
00126
00127 if (Config->NSRegistration.equals_ci("disable"))
00128 {
00129 source.Reply(_("Registration is currently disabled."));
00130 return;
00131 }
00132
00133 if (u && !u->HasMode("OPER") && Config->NickRegDelay && Anope::CurTime - u->timestamp < Config->NickRegDelay)
00134 {
00135 source.Reply(_("You must have been using this nick for at least %d seconds to register."), Config->NickRegDelay);
00136 return;
00137 }
00138
00139
00140
00141
00142
00143
00144 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)
00145 {
00146 source.Reply(NICK_CANNOT_BE_REGISTERED, u_nick.c_str());
00147 return;
00148 }
00149
00150 if (!IRCD->IsNickValid(u_nick))
00151 {
00152 source.Reply(NICK_CANNOT_BE_REGISTERED, u_nick.c_str());
00153 return;
00154 }
00155
00156 if (Config->RestrictOperNicks)
00157 for (unsigned i = 0; i < Config->Opers.size(); ++i)
00158 {
00159 Oper *o = Config->Opers[i];
00160
00161 if (!source.IsOper() && u_nick.find_ci(o->name) != Anope::string::npos)
00162 {
00163 source.Reply(NICK_CANNOT_BE_REGISTERED, u_nick.c_str());
00164 return;
00165 }
00166 }
00167
00168 if (Config->NSForceEmail && email.empty())
00169 this->OnSyntaxError(source, "");
00170 else if (u && Anope::CurTime < u->lastnickreg + Config->NSRegDelay)
00171 source.Reply(_("Please wait %d seconds before using the REGISTER command again."), (u->lastnickreg + Config->NSRegDelay) - Anope::CurTime);
00172 else if ((na = NickAlias::Find(u_nick)))
00173 source.Reply(NICK_ALREADY_REGISTERED, u_nick.c_str());
00174 else if (pass.equals_ci(u_nick) || (Config->StrictPasswords && pass.length() < 5))
00175 source.Reply(MORE_OBSCURE_PASSWORD);
00176 else if (pass.length() > Config->PassLen)
00177 source.Reply(PASSWORD_TOO_LONG);
00178 else if (!email.empty() && !Mail::Validate(email))
00179 source.Reply(MAIL_X_INVALID, email.c_str());
00180 else
00181 {
00182 NickCore *nc = new NickCore(u_nick);
00183 na = new NickAlias(u_nick, nc);
00184 Anope::Encrypt(pass, nc->pass);
00185 if (!email.empty())
00186 nc->email = email;
00187
00188 if (u)
00189 {
00190 na->last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost();
00191 na->last_realname = u->realname;
00192
00193 u->Login(nc);
00194
00195 if (Config->NSAddAccessOnReg)
00196 nc->AddAccess(u->Mask());
00197 }
00198
00199 Log(LOG_COMMAND, source, this) << "to register " << na->nick << " (email: " << (!na->nc->email.empty() ? na->nc->email : "none") << ")";
00200
00201 FOREACH_MOD(I_OnNickRegister, OnNickRegister(na));
00202
00203 if (Config->NSAddAccessOnReg)
00204 source.Reply(_("Nickname \002%s\002 registered under your user@host-mask: %s"), u_nick.c_str(), na->nc->GetAccess(0).c_str());
00205 else
00206 source.Reply(_("Nickname \002%s\002 registered."), u_nick.c_str());
00207
00208 Anope::string tmp_pass;
00209 if (Anope::Decrypt(na->nc->pass, tmp_pass) == 1)
00210 source.Reply(_("Your password is \002%s\002 - remember this for later use."), tmp_pass.c_str());
00211
00212 if (Config->NSRegistration.equals_ci("admin"))
00213 {
00214 nc->ExtendMetadata("UNCONFIRMED");
00215 source.Reply(_("All new accounts must be validated by an administrator. Please wait for your registration to be confirmed."));
00216 }
00217 else if (Config->NSRegistration.equals_ci("mail"))
00218 {
00219 nc->ExtendMetadata("UNCONFIRMED");
00220 if (SendRegmail(u, na, source.service))
00221 {
00222 source.Reply(_("A passcode has been sent to %s, please type \002%s%s CONFIRM <passcode>\002 to confirm your email address."), email.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str());
00223 source.Reply(_("If you do not confirm your email address within %s your account will expire."), Anope::Duration(Config->NSUnconfirmedExpire).c_str());
00224 }
00225 }
00226 else if (Config->NSRegistration.equals_ci("none"))
00227 {
00228 if (u)
00229 {
00230 IRCD->SendLogin(u);
00231 if (!Config->NoNicknameOwnership && na->nc == u->Account() && na->nc->HasExt("UNCONFIRMED") == false)
00232 u->SetMode(NickServ, "REGISTERED");
00233 }
00234 }
00235
00236 if (u)
00237 u->lastnickreg = Anope::CurTime;
00238 }
00239 }
00240
00241 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00242 {
00243 this->SendSyntax(source);
00244 source.Reply(" ");
00245 source.Reply(_("Registers your nickname in the %s database. Once\n"
00246 "your nick is registered, you can use the \002SET\002 and \002ACCESS\002\n"
00247 "commands to configure your nick's settings as you like\n"
00248 "them. Make sure you remember the password you use when\n"
00249 "registering - you'll need it to make changes to your nick\n"
00250 "later. (Note that \002case matters!\002 \037ANOPE\037, \037Anope\037, and\n"
00251 "\037anope\037 are all different passwords!)\n"
00252 " \n"
00253 "Guidelines on choosing passwords:\n"
00254 " \n"
00255 "Passwords should not be easily guessable. For example,\n"
00256 "using your real name as a password is a bad idea. Using\n"
00257 "your nickname as a password is a much worse idea ;) and,\n"
00258 "in fact, %s will not allow it. Also, short\n"
00259 "passwords are vulnerable to trial-and-error searches, so\n"
00260 "you should choose a password at least 5 characters long.\n"
00261 "Finally, the space character cannot be used in passwords."),
00262 Config->NickServ.c_str(), Config->NickServ.c_str());
00263
00264 if (!Config->NSForceEmail)
00265 {
00266 source.Reply(" ");
00267 source.Reply(_("The \037email\037 parameter is optional and will set the email\n"
00268 "for your nick immediately.\n"
00269 "Your privacy is respected; this e-mail won't be given to\n"
00270 "any third-party person. You may also wish to \002SET HIDE\002 it\n"
00271 "after registering if it isn't the default setting already."));
00272 }
00273
00274 source.Reply(" ");
00275 source.Reply(_("This command also creates a new group for your nickname,\n"
00276 "that will allow you to register other nicks later sharing\n"
00277 "the same configuration, the same set of memos and the\n"
00278 "same channel privileges."));
00279 return true;
00280 }
00281 };
00282
00283 class CommandNSResend : public Command
00284 {
00285 public:
00286 CommandNSResend(Module *creator) : Command(creator, "nickserv/resend", 0, 0)
00287 {
00288 this->SetSyntax("");
00289 }
00290
00291 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
00292 {
00293 if (!Config->NSRegistration.equals_ci("mail"))
00294 return;
00295
00296 const NickAlias *na = NickAlias::Find(source.GetNick());
00297
00298 if (na == NULL)
00299 source.Reply(NICK_NOT_REGISTERED);
00300 else if (na->nc != source.GetAccount() || source.nc->HasExt("UNCONFIRMED") == false)
00301 source.Reply(_("Your account is already confirmed."));
00302 else
00303 {
00304 if (Anope::CurTime < source.nc->lastmail + Config->NSResendDelay)
00305 source.Reply(_("Cannot send mail now; please retry a little later."));
00306 else if (SendRegmail(source.GetUser(), na, source.service))
00307 {
00308 na->nc->lastmail = Anope::CurTime;
00309 source.Reply(_("Your passcode has been re-sent to %s."), na->nc->email.c_str());
00310 Log(LOG_COMMAND, source, this) << "to resend registration verification code";
00311 }
00312 else
00313 Log(this->owner) << "Unable to resend registration verification code for " << source.GetNick();
00314 }
00315
00316 return;
00317 }
00318
00319 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00320 {
00321 if (!Config->NSRegistration.equals_ci("mail"))
00322 return false;
00323
00324 this->SendSyntax(source);
00325 source.Reply(" ");
00326 source.Reply(_("This command will re-send the auth code (also called passcode)\n"
00327 "to the e-mail address of the nickname in the database."));
00328 return true;
00329 }
00330
00331 void OnServHelp(CommandSource &source) anope_override
00332 {
00333 if (Config->NSRegistration.equals_ci("mail"))
00334 Command::OnServHelp(source);
00335 }
00336 };
00337
00338 class NSRegister : public Module
00339 {
00340 CommandNSRegister commandnsregister;
00341 CommandNSConfirm commandnsconfirm;
00342 CommandNSResend commandnsrsend;
00343
00344 public:
00345 NSRegister(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00346 commandnsregister(this), commandnsconfirm(this), commandnsrsend(this)
00347 {
00348 this->SetAuthor("Anope");
00349
00350 if (Config->NSRegistration.equals_ci("disable"))
00351 throw ModuleException("Module will not load with nickserv:registration disabled.");
00352 }
00353 };
00354
00355 static bool SendRegmail(User *u, const NickAlias *na, const BotInfo *bi)
00356 {
00357 NickCore *nc = na->nc;
00358
00359 Anope::string *code = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("ns_register_passcode");
00360 Anope::string codebuf;
00361 if (code == NULL)
00362 {
00363 int chars[] = {
00364 ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
00365 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
00366 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
00367 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
00368 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
00369 };
00370 int idx, min = 1, max = 62;
00371 for (idx = 0; idx < 9; ++idx)
00372 codebuf += chars[1 + static_cast<int>((static_cast<float>(max - min)) * static_cast<uint16_t>(rand()) / 65536.0) + min];
00373 nc->Extend("ns_register_passcode", new ExtensibleItemClass<Anope::string>(codebuf));
00374 }
00375 else
00376 codebuf = *code;
00377
00378 Anope::string subject = Language::Translate(na->nc, Config->MailRegistrationSubject.c_str());
00379 Anope::string message = Language::Translate(na->nc, Config->MailRegistrationMessage.c_str());
00380
00381 subject = subject.replace_all_cs("%n", na->nick);
00382 subject = subject.replace_all_cs("%N", Config->NetworkName);
00383 subject = subject.replace_all_cs("%c", codebuf);
00384
00385 message = message.replace_all_cs("%n", na->nick);
00386 message = message.replace_all_cs("%N", Config->NetworkName);
00387 message = message.replace_all_cs("%c", codebuf);
00388
00389 return Mail::Send(u, nc, bi, subject, message);
00390 }
00391
00392 MODULE_INIT(NSRegister)