00001
00002
00003
00004
00005
00006
00007
00008
00009
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> ¶ms) 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> ¶ms) 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)