Anope IRC Services  Version 2.0
ns_register.cpp
Go to the documentation of this file.
1 /* NickServ core functions
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  */
11 
12 #include "module.h"
13 
14 static bool SendRegmail(User *u, const NickAlias *na, BotInfo *bi);
15 
16 class CommandNSConfirm : public Command
17 {
18  public:
19  CommandNSConfirm(Module *creator) : Command(creator, "nickserv/confirm", 1, 2)
20  {
21  this->SetDesc(_("Confirm a passcode"));
22  this->SetSyntax(_("\037passcode\037"));
23  this->AllowUnregistered(true);
24  }
25 
26  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
27  {
28  const Anope::string &passcode = params[0];
29 
30  if (source.nc && !source.nc->HasExt("UNCONFIRMED") && source.HasPriv("nickserv/confirm"))
31  {
32  NickAlias *na = NickAlias::Find(passcode);
33  if (na == NULL)
34  source.Reply(NICK_X_NOT_REGISTERED, passcode.c_str());
35  else if (na->nc->HasExt("UNCONFIRMED") == false)
36  source.Reply(_("Nick \002%s\002 is already confirmed."), na->nick.c_str());
37  else
38  {
39  na->nc->Shrink<bool>("UNCONFIRMED");
40  Log(LOG_ADMIN, source, this) << "to confirm nick " << na->nick << " (" << na->nc->display << ")";
41  source.Reply(_("Nick \002%s\002 has been confirmed."), na->nick.c_str());
42  }
43  }
44  else if (source.nc)
45  {
46  Anope::string *code = source.nc->GetExt<Anope::string>("passcode");
47  if (code != NULL && *code == passcode)
48  {
49  NickCore *nc = source.nc;
50  nc->Shrink<Anope::string>("passcode");
51  Log(LOG_COMMAND, source, this) << "to confirm their email";
52  source.Reply(_("Your email address of \002%s\002 has been confirmed."), source.nc->email.c_str());
53  nc->Shrink<bool>("UNCONFIRMED");
54 
55  if (source.GetUser())
56  {
57  NickAlias *na = NickAlias::Find(source.GetNick());
58  if (na)
59  {
60  IRCD->SendLogin(source.GetUser(), na);
61  if (!Config->GetModule("nickserv")->Get<bool>("nonicknameownership") && na->nc == source.GetAccount() && !na->nc->HasExt("UNCONFIRMED"))
62  source.GetUser()->SetMode(source.service, "REGISTERED");
63  }
64  }
65  }
66  else
67  source.Reply(_("Invalid passcode."));
68  }
69  else
70  source.Reply(_("Invalid passcode."));
71 
72  return;
73  }
74 
75  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
76  {
77  this->SendSyntax(source);
78  source.Reply(" ");
79  source.Reply(_("This command is used by several commands as a way to confirm\n"
80  "changes made to your account.\n"
81  " \n"
82  "This is most commonly used to confirm your email address once\n"
83  "you register or change it.\n"
84  " \n"
85  "This is also used after the RESETPASS command has been used to\n"
86  "force identify you to your nick so you may change your password."));
87  if (source.HasPriv("nickserv/confirm"))
88  source.Reply(_("Additionally, Services Operators with the \037nickserv/confirm\037 permission can\n"
89  "replace \037passcode\037 with a users nick to force validate them."));
90  return true;
91  }
92 
93  void OnSyntaxError(CommandSource &source, const Anope::string &subcommand) anope_override
94  {
95  source.Reply(NICK_CONFIRM_INVALID);
96  }
97 };
98 
99 class CommandNSRegister : public Command
100 {
101  public:
102  CommandNSRegister(Module *creator) : Command(creator, "nickserv/register", 1, 2)
103  {
104  this->SetDesc(_("Register a nickname"));
105  if (Config->GetModule("nickserv")->Get<bool>("forceemail", "yes"))
106  this->SetSyntax(_("\037password\037 \037email\037"));
107  else
108  this->SetSyntax(_("\037password\037 \037[email]\037"));
109  this->AllowUnregistered(true);
110  }
111 
112  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
113  {
114  User *u = source.GetUser();
115  Anope::string u_nick = source.GetNick();
116  size_t nicklen = u_nick.length();
117  Anope::string pass = params[0];
118  Anope::string email = params.size() > 1 ? params[1] : "";
119  const Anope::string &nsregister = Config->GetModule(this->owner)->Get<const Anope::string>("registration");
120 
121  if (Anope::ReadOnly)
122  {
123  source.Reply(_("Sorry, nickname registration is temporarily disabled."));
124  return;
125  }
126 
127  if (nsregister.equals_ci("disable"))
128  {
129  source.Reply(_("Registration is currently disabled."));
130  return;
131  }
132 
133  time_t nickregdelay = Config->GetModule(this->owner)->Get<time_t>("nickregdelay");
134  time_t reg_delay = Config->GetModule("nickserv")->Get<time_t>("regdelay");
135  if (u && !u->HasMode("OPER") && nickregdelay && Anope::CurTime - u->timestamp < nickregdelay)
136  {
137  source.Reply(_("You must have been using this nick for at least %d seconds to register."), nickregdelay);
138  return;
139  }
140 
141  /* Prevent "Guest" nicks from being registered. -TheShadow */
142 
143  /* Guest nick can now have a series of between 1 and 7 digits.
144  * --lara
145  */
146  const Anope::string &guestnick = Config->GetModule("nickserv")->Get<const Anope::string>("guestnickprefix", "Guest");
147  if (nicklen <= guestnick.length() + 7 && nicklen >= guestnick.length() + 1 && !u_nick.find_ci(guestnick) && u_nick.substr(guestnick.length()).find_first_not_of("1234567890") == Anope::string::npos)
148  {
149  source.Reply(NICK_CANNOT_BE_REGISTERED, u_nick.c_str());
150  return;
151  }
152 
153  if (!IRCD->IsNickValid(u_nick))
154  {
155  source.Reply(NICK_CANNOT_BE_REGISTERED, u_nick.c_str());
156  return;
157  }
158 
159  if (Config->GetModule("nickserv")->Get<bool>("restrictopernicks"))
160  for (unsigned i = 0; i < Oper::opers.size(); ++i)
161  {
162  Oper *o = Oper::opers[i];
163 
164  if (!source.IsOper() && u_nick.find_ci(o->name) != Anope::string::npos)
165  {
166  source.Reply(NICK_CANNOT_BE_REGISTERED, u_nick.c_str());
167  return;
168  }
169  }
170 
171  if (Config->GetModule("nickserv")->Get<bool>("forceemail", "yes") && email.empty())
172  this->OnSyntaxError(source, "");
173  else if (u && Anope::CurTime < u->lastnickreg + reg_delay)
174  source.Reply(_("Please wait %d seconds before using the REGISTER command again."), (u->lastnickreg + reg_delay) - Anope::CurTime);
175  else if (NickAlias::Find(u_nick) != NULL)
176  source.Reply(NICK_ALREADY_REGISTERED, u_nick.c_str());
177  else if (pass.equals_ci(u_nick) || (Config->GetBlock("options")->Get<bool>("strictpasswords") && pass.length() < 5))
178  source.Reply(MORE_OBSCURE_PASSWORD);
179  else if (pass.length() > Config->GetModule("nickserv")->Get<unsigned>("passlen", "32"))
180  source.Reply(PASSWORD_TOO_LONG);
181  else if (!email.empty() && !Mail::Validate(email))
182  source.Reply(MAIL_X_INVALID, email.c_str());
183  else
184  {
185  NickCore *nc = new NickCore(u_nick);
186  NickAlias *na = new NickAlias(u_nick, nc);
187  Anope::Encrypt(pass, nc->pass);
188  if (!email.empty())
189  nc->email = email;
190 
191  if (u)
192  {
193  na->last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost();
194  na->last_realname = u->realname;
195  }
196  else
197  na->last_realname = source.GetNick();
198 
199  Log(LOG_COMMAND, source, this) << "to register " << na->nick << " (email: " << (!na->nc->email.empty() ? na->nc->email : "none") << ")";
200 
201  FOREACH_MOD(OnNickRegister, (source.GetUser(), na, pass));
202 
203  if (na->nc->GetAccessCount())
204  source.Reply(_("Nickname \002%s\002 registered under your user@host-mask: %s"), u_nick.c_str(), na->nc->GetAccess(0).c_str());
205  else
206  source.Reply(_("Nickname \002%s\002 registered."), u_nick.c_str());
207 
208  Anope::string tmp_pass;
209  if (Anope::Decrypt(na->nc->pass, tmp_pass) == 1)
210  source.Reply(_("Your password is \002%s\002 - remember this for later use."), tmp_pass.c_str());
211 
212  if (nsregister.equals_ci("admin"))
213  {
214  nc->Extend<bool>("UNCONFIRMED");
215  // User::Identify() called below will notify the user that their registration is pending
216  }
217  else if (nsregister.equals_ci("mail"))
218  {
219  if (!email.empty())
220  {
221  nc->Extend<bool>("UNCONFIRMED");
222  SendRegmail(NULL, na, source.service);
223  }
224  }
225 
226  if (u)
227  {
228  u->Identify(na);
230  }
231  }
232  }
233 
234  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
235  {
236  this->SendSyntax(source);
237  source.Reply(" ");
238  source.Reply(_("Registers your nickname in the %s database. Once\n"
239  "your nick is registered, you can use the \002SET\002 and \002ACCESS\002\n"
240  "commands to configure your nick's settings as you like\n"
241  "them. Make sure you remember the password you use when\n"
242  "registering - you'll need it to make changes to your nick\n"
243  "later. (Note that \002case matters!\002 \037ANOPE\037, \037Anope\037, and\n"
244  "\037anope\037 are all different passwords!)\n"
245  " \n"
246  "Guidelines on choosing passwords:\n"
247  " \n"
248  "Passwords should not be easily guessable. For example,\n"
249  "using your real name as a password is a bad idea. Using\n"
250  "your nickname as a password is a much worse idea ;) and,\n"
251  "in fact, %s will not allow it. Also, short\n"
252  "passwords are vulnerable to trial-and-error searches, so\n"
253  "you should choose a password at least 5 characters long.\n"
254  "Finally, the space character cannot be used in passwords."),
255  source.service->nick.c_str(), source.service->nick.c_str());
256 
257  if (!Config->GetModule("nickserv")->Get<bool>("forceemail", "yes"))
258  {
259  source.Reply(" ");
260  source.Reply(_("The \037email\037 parameter is optional and will set the email\n"
261  "for your nick immediately.\n"
262  "Your privacy is respected; this e-mail won't be given to\n"
263  "any third-party person. You may also wish to \002SET HIDE\002 it\n"
264  "after registering if it isn't the default setting already."));
265  }
266 
267  source.Reply(" ");
268  source.Reply(_("This command also creates a new group for your nickname,\n"
269  "that will allow you to register other nicks later sharing\n"
270  "the same configuration, the same set of memos and the\n"
271  "same channel privileges."));
272  return true;
273  }
274 };
275 
276 class CommandNSResend : public Command
277 {
278  public:
279  CommandNSResend(Module *creator) : Command(creator, "nickserv/resend", 0, 0)
280  {
281  this->SetDesc(_("Resend registration confirmation email"));
282  }
283 
284  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
285  {
286  if (!Config->GetModule(this->owner)->Get<const Anope::string>("registration").equals_ci("mail"))
287  {
288  source.Reply(ACCESS_DENIED);
289  return;
290  }
291 
292  const NickAlias *na = NickAlias::Find(source.GetNick());
293 
294  if (na == NULL)
295  source.Reply(NICK_NOT_REGISTERED);
296  else if (na->nc != source.GetAccount() || !source.nc->HasExt("UNCONFIRMED"))
297  source.Reply(_("Your account is already confirmed."));
298  else
299  {
300  if (Anope::CurTime < source.nc->lastmail + Config->GetModule(this->owner)->Get<time_t>("resenddelay"))
301  source.Reply(_("Cannot send mail now; please retry a little later."));
302  else if (SendRegmail(source.GetUser(), na, source.service))
303  {
304  na->nc->lastmail = Anope::CurTime;
305  source.Reply(_("Your passcode has been re-sent to %s."), na->nc->email.c_str());
306  Log(LOG_COMMAND, source, this) << "to resend registration verification code";
307  }
308  else
309  Log(this->owner) << "Unable to resend registration verification code for " << source.GetNick();
310  }
311 
312  return;
313  }
314 
315  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
316  {
317  if (!Config->GetModule(this->owner)->Get<const Anope::string>("registration").equals_ci("mail"))
318  return false;
319 
320  this->SendSyntax(source);
321  source.Reply(" ");
322  source.Reply(_("This command will resend you the registration confirmation email."));
323  return true;
324  }
325 
327  {
328  if (Config->GetModule(this->owner)->Get<const Anope::string>("registration").equals_ci("mail"))
329  Command::OnServHelp(source);
330  }
331 };
332 
333 class NSRegister : public Module
334 {
338 
341 
342  public:
343  NSRegister(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
344  commandnsregister(this), commandnsconfirm(this), commandnsrsend(this), unconfirmed(this, "UNCONFIRMED"),
345  passcode(this, "passcode")
346  {
347  if (Config->GetModule(this)->Get<const Anope::string>("registration").equals_ci("disable"))
348  throw ModuleException("Module " + this->name + " will not load with registration disabled.");
349  }
350 
352  {
353  BotInfo *NickServ;
354  if (unconfirmed.HasExt(u->Account()) && (NickServ = Config->GetClient("NickServ")))
355  {
356  const Anope::string &nsregister = Config->GetModule(this)->Get<const Anope::string>("registration");
357  if (nsregister.equals_ci("admin"))
358  u->SendMessage(NickServ, _("All new accounts must be validated by an administrator. Please wait for your registration to be confirmed."));
359  else
360  u->SendMessage(NickServ, _("Your email address is not confirmed. To confirm it, follow the instructions that were emailed to you."));
361  const NickAlias *this_na = NickAlias::Find(u->Account()->display);
362  time_t time_registered = Anope::CurTime - this_na->time_registered;
363  time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d");
364  if (unconfirmed_expire > time_registered)
365  u->SendMessage(NickServ, _("Your account will expire, if not confirmed, in %s."), Anope::Duration(unconfirmed_expire - time_registered, u->Account()).c_str());
366  }
367  }
368 
369  void OnPreNickExpire(NickAlias *na, bool &expire) anope_override
370  {
371  if (unconfirmed.HasExt(na->nc))
372  {
373  time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d");
374  if (unconfirmed_expire && Anope::CurTime - na->time_registered >= unconfirmed_expire)
375  expire = true;
376  }
377  }
378 };
379 
380 static bool SendRegmail(User *u, const NickAlias *na, BotInfo *bi)
381 {
382  NickCore *nc = na->nc;
383 
384  Anope::string *code = na->nc->GetExt<Anope::string>("passcode");
385  if (code == NULL)
386  {
387  code = na->nc->Extend<Anope::string>("passcode");
388  *code = Anope::Random(9);
389  }
390 
391  Anope::string subject = Language::Translate(na->nc, Config->GetBlock("mail")->Get<const Anope::string>("registration_subject").c_str()),
392  message = Language::Translate(na->nc, Config->GetBlock("mail")->Get<const Anope::string>("registration_message").c_str());
393 
394  subject = subject.replace_all_cs("%n", na->nick);
395  subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname"));
396  subject = subject.replace_all_cs("%c", *code);
397 
398  message = message.replace_all_cs("%n", na->nick);
399  message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname"));
400  message = message.replace_all_cs("%c", *code);
401 
402  return Mail::Send(u, nc, bi, subject, message);
403 }
404 
Serialize::Reference< NickCore > nc
Definition: account.h:47
Definition: bots.h:24
bool HasMode(const Anope::string &name) const
Definition: users.cpp:513
CoreExport bool ReadOnly
Definition: main.cpp:28
static NickAlias * Find(const Anope::string &nick)
Definition: nickalias.cpp:121
void OnServHelp(CommandSource &source) anope_override
Anope::string name
Definition: modules.h:221
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
const Anope::string & GetIdent() const
Definition: users.cpp:264
#define NICK_ALREADY_REGISTERED
Definition: language.h:98
Definition: opertype.h:18
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
Definition: ns_register.cpp:26
Anope::string nick
Definition: account.h:37
#define ACCESS_DENIED
Definition: language.h:73
Anope::string last_usermask
Definition: account.h:41
SerializableExtensibleItem< bool > unconfirmed
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
Definition: ns_register.cpp:75
void OnPreNickExpire(NickAlias *na, bool &expire) anope_override
Definition: users.h:34
T * Extend(const Anope::string &name, const T &what)
Definition: extensible.h:224
#define NICK_X_NOT_REGISTERED
Definition: language.h:79
void OnNickIdentify(User *u) anope_override
Anope::string name
Definition: opertype.h:21
void SetDesc(const Anope::string &d)
Definition: command.cpp:130
bool equals_ci(const char *_str) const
Definition: anope.h:78
CoreExport time_t CurTime
Definition: main.cpp:41
Anope::string pass
Definition: account.h:115
static bool SendRegmail(User *u, const NickAlias *na, BotInfo *bi)
#define FOREACH_MOD(ename, args)
Definition: modules.h:62
#define NICK_CONFIRM_INVALID
Definition: language.h:100
CommandNSConfirm commandnsconfirm
size_type find_ci(const string &_str, size_type pos=0) const
Definition: anope.h:194
void Identify(NickAlias *na)
Definition: users.cpp:355
time_t lastnickreg
Definition: users.h:92
string substr(size_type pos=0, size_type n=npos) const
Definition: anope.h:277
time_t timestamp
Definition: users.h:81
CoreExport bool Decrypt(const Anope::string &src, Anope::string &dest)
Definition: misc.cpp:518
static std::vector< Oper * > opers
Definition: opertype.h:35
#define MAIL_X_INVALID
Definition: language.h:87
size_type length() const
Definition: anope.h:131
Definition: Config.cs:26
void Shrink(const Anope::string &name)
Definition: extensible.h:253
CoreExport bool Validate(const Anope::string &email)
Definition: mail.cpp:115
virtual void OnSyntaxError(CommandSource &source, const Anope::string &subcommand)
Definition: command.cpp:191
static const size_type npos
Definition: anope.h:44
CommandNSRegister commandnsregister
string replace_all_cs(const string &_orig, const string &_repl) const
Definition: anope.h:229
const Anope::string & GetDisplayedHost() const
Definition: users.cpp:203
time_t time_registered
Definition: account.h:44
#define MORE_OBSCURE_PASSWORD
Definition: language.h:74
virtual bool IsNickValid(const Anope::string &)
Definition: protocol.cpp:349
CoreExport bool Send(User *from, NickCore *to, BotInfo *service, const Anope::string &subject, const Anope::string &message)
Definition: mail.cpp:54
#define anope_override
Definition: services.h:56
bool empty() const
Definition: anope.h:126
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
CoreExport IRCDProto * IRCD
Definition: protocol.cpp:23
#define MODULE_INIT(x)
Definition: modules.h:45
CoreExport const char * Translate(const char *string)
Definition: language.cpp:59
CoreExport Anope::string Random(size_t len)
Definition: misc.cpp:754
bool AllowUnregistered() const
Definition: command.cpp:159
void SetSyntax(const Anope::string &s)
Definition: command.cpp:140
Anope::string realname
Definition: users.h:71
virtual void SendLogin(User *u, NickAlias *na)=0
virtual void OnServHelp(CommandSource &source)
Definition: command.cpp:184
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
CommandNSResend commandnsrsend
void SendSyntax(CommandSource &)
Definition: command.cpp:145
Anope::string last_realname
Definition: account.h:39
#define PASSWORD_TOO_LONG
Definition: language.h:77
CoreExport void Encrypt(const Anope::string &src, Anope::string &dest)
Definition: misc.cpp:511
const char * c_str() const
Definition: anope.h:117
CommandNSConfirm(Module *creator)
Definition: ns_register.cpp:19
Definition: logger.h:53
CoreExport Anope::string Duration(time_t seconds, const NickCore *nc=NULL)
Definition: misc.cpp:315
#define NICK_NOT_REGISTERED
Definition: language.h:78
CommandNSResend(Module *creator)
NSRegister(const Anope::string &modname, const Anope::string &creator)
void OnSyntaxError(CommandSource &source, const Anope::string &subcommand) anope_override
Definition: ns_register.cpp:93
bool HasExt(const Extensible *obj) const
Definition: extensible.h:111
CommandNSRegister(Module *creator)
Anope::string email
Definition: account.h:116
SerializableExtensibleItem< Anope::string > passcode
#define NICK_CANNOT_BE_REGISTERED
Definition: language.h:97
#define _(x)
Definition: services.h:50
Module * owner
Definition: service.h:84