ns_resetpass.cpp

Go to the documentation of this file.
00001 /* NickServ core functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 
00016 static bool SendResetEmail(User *u, const NickAlias *na, const BotInfo *bi);
00017 
00018 class CommandNSResetPass : public Command
00019 {
00020  public:
00021         CommandNSResetPass(Module *creator) : Command(creator, "nickserv/resetpass", 1, 1)
00022         {
00023                 this->SetDesc(_("Helps you reset lost passwords"));
00024                 this->SetSyntax(_("\037nickname\037"));
00025                 this->AllowUnregistered(true);
00026         }
00027 
00028         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00029         {
00030                 const NickAlias *na;
00031 
00032                 if (Config->RestrictMail && !source.HasCommand("nickserv/resetpass"))
00033                         source.Reply(ACCESS_DENIED);
00034                 else if (!(na = NickAlias::Find(params[0])))
00035                         source.Reply(NICK_X_NOT_REGISTERED, params[0].c_str());
00036                 else
00037                 {
00038                         if (SendResetEmail(source.GetUser(), na, source.service))
00039                         {
00040                                 Log(LOG_COMMAND, source, this) << "for " << na->nick << " (group: " << na->nc->display << ")";
00041                                 source.Reply(_("Password reset email for \002%s\002 has been sent."), na->nick.c_str());
00042                         }
00043                 }
00044 
00045                 return;
00046         }
00047 
00048         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00049         {
00050                 this->SendSyntax(source);
00051                 source.Reply(" ");
00052                 source.Reply(_("Sends a passcode to the nickname with instructions on how to\n"
00053                                 "reset their password."));
00054                 return true;
00055         }
00056 };
00057 
00058 struct ResetInfo : ExtensibleItem
00059 {
00060         Anope::string code;
00061         time_t time;
00062 };
00063 
00064 class NSResetPass : public Module
00065 {
00066         CommandNSResetPass commandnsresetpass;
00067 
00068  public:
00069         NSResetPass(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00070                 commandnsresetpass(this)
00071         {
00072                 this->SetAuthor("Anope");
00073 
00074                 if (!Config->UseMail)
00075                         throw ModuleException("Not using mail.");
00076 
00077 
00078                 ModuleManager::Attach(I_OnPreCommand, this);
00079         }
00080 
00081         ~NSResetPass()
00082         {
00083                 for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it)
00084                         it->second->Shrink("ns_resetpass");
00085         }
00086 
00087         EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) anope_override
00088         {
00089                 if (command->name == "nickserv/confirm" && params.size() > 1)
00090                 {
00091                         NickAlias *na = NickAlias::Find(params[0]);
00092 
00093                         ResetInfo *ri = na ? na->nc->GetExt<ResetInfo *>("ns_resetpass") : NULL;
00094                         if (na && ri)
00095                         {
00096                                 NickCore *nc = na->nc;
00097                                 const Anope::string &passcode = params[1];
00098                                 if (ri->time < Anope::CurTime - 3600)
00099                                 {
00100                                         nc->Shrink("ns_resetpass");
00101                                         source.Reply(_("Your password reset request has expired."));
00102                                 }
00103                                 else if (passcode.equals_cs(ri->code))
00104                                 {
00105                                         nc->Shrink("ns_resetpass");
00106 
00107                                         Log(LOG_COMMAND, source, &commandnsresetpass) << "confirmed RESETPASS to forcefully identify as " << na->nick;
00108 
00109                                         nc->Shrink("UNCONFIRMED");
00110 
00111                                         if (source.GetUser())
00112                                         {
00113                                                 source.GetUser()->Identify(na);
00114                                                 source.Reply(_("You are now identified for your nick. Change your password now."));
00115                                         }
00116                                 }
00117                                 else
00118                                         return EVENT_CONTINUE;
00119 
00120                                 return EVENT_STOP;
00121                         }
00122                 }
00123 
00124                 return EVENT_CONTINUE;
00125         }
00126 };
00127 
00128 static bool SendResetEmail(User *u, const NickAlias *na, const BotInfo *bi)
00129 {
00130         int min = 1, max = 62;
00131         int chars[] = {
00132                 ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
00133                 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
00134                 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
00135                 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
00136                 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
00137         };
00138 
00139         Anope::string passcode;
00140         int idx;
00141         for (idx = 0; idx < 20; ++idx)
00142                 passcode += chars[1 + static_cast<int>((static_cast<float>(max - min)) * static_cast<uint16_t>(rand()) / 65536.0) + min];
00143 
00144         Anope::string subject = Language::Translate(na->nc, Config->MailResetSubject.c_str());
00145         Anope::string message = Language::Translate(na->nc, Config->MailResetMessage.c_str());
00146 
00147         subject = subject.replace_all_cs("%n", na->nick);
00148         subject = subject.replace_all_cs("%N", Config->NetworkName);
00149         subject = subject.replace_all_cs("%c", passcode);
00150 
00151         message = message.replace_all_cs("%n", na->nick);
00152         message = message.replace_all_cs("%N", Config->NetworkName);
00153         message = message.replace_all_cs("%c", passcode);
00154 
00155         ResetInfo *ri = new ResetInfo;
00156         ri->code = passcode;
00157         ri->time = Anope::CurTime;
00158         NickCore *nc = na->nc;
00159         nc->Extend("ns_resetpass", ri);
00160 
00161         return Mail::Send(u, nc, bi, subject, message);
00162 }
00163 
00164 MODULE_INIT(NSResetPass)