anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
ns_recover.cpp (8536B)
1 /* NickServ core functions 2 * 3 * (C) 2003-2022 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 #include "modules/ns_cert.h" 14 15 static ServiceReference<NickServService> nickserv("NickServService", "NickServ"); 16 17 typedef std::map<Anope::string, ChannelStatus> NSRecoverInfo; 18 19 class NSRecoverSvsnick 20 { 21 public: 22 Reference<User> from; 23 Anope::string to; 24 }; 25 26 class NSRecoverRequest : public IdentifyRequest 27 { 28 CommandSource source; 29 Command *cmd; 30 Anope::string user; 31 32 public: 33 NSRecoverRequest(Module *o, CommandSource &src, Command *c, const Anope::string &nick, const Anope::string &pass) : IdentifyRequest(o, nick, pass), source(src), cmd(c), user(nick) { } 34 35 void OnSuccess() anope_override 36 { 37 User *u = User::Find(user, true); 38 if (!source.GetUser() || !source.service) 39 return; 40 41 NickAlias *na = NickAlias::Find(user); 42 if (!na) 43 return; 44 45 Log(LOG_COMMAND, source, cmd) << "for " << na->nick; 46 47 /* Nick is being held by us, release it */ 48 if (na->HasExt("HELD")) 49 { 50 nickserv->Release(na); 51 source.Reply(_("Service's hold on \002%s\002 has been released."), na->nick.c_str()); 52 } 53 else if (!u) 54 { 55 source.Reply(_("No one is using your nick, and services are not holding it.")); 56 } 57 // If the user being recovered is identified for the account of the nick then the user is the 58 // same person that is executing the command, so kill them off (old GHOST command). 59 else if (u->Account() == na->nc) 60 { 61 if (!source.GetAccount() && na->nc->HasExt("NS_SECURE")) 62 { 63 source.GetUser()->Login(u->Account()); 64 Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << u->Account()->display; 65 } 66 67 if (Config->GetModule("ns_recover")->Get<bool>("restoreonrecover")) 68 { 69 if (!u->chans.empty()) 70 { 71 NSRecoverInfo *ei = source.GetUser()->Extend<NSRecoverInfo>("recover"); 72 for (User::ChanUserList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it) 73 (*ei)[it->first->name] = it->second->status; 74 } 75 } 76 77 u->SendMessage(source.service, _("This nickname has been recovered by %s. If you did not do\n" 78 "this then %s may have your password, and you should change it."), 79 source.GetNick().c_str(), source.GetNick().c_str()); 80 81 Anope::string buf = source.command.upper() + " command used by " + source.GetNick(); 82 u->Kill(*source.service, buf); 83 84 source.Reply(_("Ghost with your nick has been killed.")); 85 86 if (IRCD->CanSVSNick) 87 IRCD->SendForceNickChange(source.GetUser(), GetAccount(), Anope::CurTime); 88 } 89 /* User is not identified or not identified to the same account as the person using this command */ 90 else 91 { 92 if (!source.GetAccount() && na->nc->HasExt("NS_SECURE")) 93 { 94 source.GetUser()->Login(na->nc); // Identify the user using the command if they arent identified 95 Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << na->nick << " (" << na->nc->display << ")"; 96 source.Reply(_("You have been logged in as \002%s\002."), na->nc->display.c_str()); 97 } 98 99 u->SendMessage(source.service, _("This nickname has been recovered by %s."), source.GetNick().c_str()); 100 101 if (IRCD->CanSVSNick) 102 { 103 NSRecoverSvsnick *svs = u->Extend<NSRecoverSvsnick>("svsnick"); 104 svs->from = source.GetUser(); 105 svs->to = u->nick; 106 } 107 108 if (nickserv) 109 nickserv->Collide(u, na); 110 111 if (IRCD->CanSVSNick) 112 { 113 /* If we can svsnick then release our hold and svsnick the user using the command */ 114 if (nickserv) 115 nickserv->Release(na); 116 117 source.Reply(_("You have regained control of \002%s\002."), u->nick.c_str()); 118 } 119 else 120 { 121 source.Reply(_("The user with your nick has been removed. Use this command again\n" 122 "to release services's hold on your nick.")); 123 } 124 } 125 } 126 127 void OnFail() anope_override 128 { 129 if (NickAlias::Find(GetAccount()) != NULL) 130 { 131 source.Reply(ACCESS_DENIED); 132 if (!GetPassword().empty()) 133 { 134 Log(LOG_COMMAND, source, cmd) << "with an invalid password for " << GetAccount(); 135 if (source.GetUser()) 136 source.GetUser()->BadPassword(); 137 } 138 } 139 else 140 source.Reply(NICK_X_NOT_REGISTERED, GetAccount().c_str()); 141 } 142 }; 143 144 class CommandNSRecover : public Command 145 { 146 public: 147 CommandNSRecover(Module *creator) : Command(creator, "nickserv/recover", 1, 2) 148 { 149 this->SetDesc(_("Regains control of your nick")); 150 this->SetSyntax(_("\037nickname\037 [\037password\037]")); 151 this->AllowUnregistered(true); 152 } 153 154 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 155 { 156 const Anope::string &nick = params[0]; 157 const Anope::string &pass = params.size() > 1 ? params[1] : ""; 158 159 User *user = User::Find(nick, true); 160 161 if (user && source.GetUser() == user) 162 { 163 source.Reply(_("You can't %s yourself!"), source.command.lower().c_str()); 164 return; 165 } 166 167 const NickAlias *na = NickAlias::Find(nick); 168 169 if (!na) 170 { 171 source.Reply(NICK_X_NOT_REGISTERED, nick.c_str()); 172 return; 173 } 174 else if (na->nc->HasExt("NS_SUSPENDED")) 175 { 176 source.Reply(NICK_X_SUSPENDED, na->nick.c_str()); 177 return; 178 } 179 180 bool ok = false; 181 if (source.GetAccount() == na->nc) 182 ok = true; 183 else if (!na->nc->HasExt("NS_SECURE") && source.GetUser() && na->nc->IsOnAccess(source.GetUser())) 184 ok = true; 185 186 NSCertList *cl = na->nc->GetExt<NSCertList>("certificates"); 187 if (source.GetUser() && !source.GetUser()->fingerprint.empty() && cl && cl->FindCert(source.GetUser()->fingerprint)) 188 ok = true; 189 190 if (source.HasPriv("nickserv/recover")) 191 ok = true; 192 193 if (ok == false && !pass.empty()) 194 { 195 NSRecoverRequest *req = new NSRecoverRequest(owner, source, this, na->nick, pass); 196 FOREACH_MOD(OnCheckAuthentication, (source.GetUser(), req)); 197 req->Dispatch(); 198 } 199 else 200 { 201 NSRecoverRequest req(owner, source, this, na->nick, pass); 202 203 if (ok) 204 req.OnSuccess(); 205 else 206 req.OnFail(); 207 } 208 } 209 210 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 211 { 212 this->SendSyntax(source); 213 source.Reply(" "); 214 source.Reply(_("Recovers your nick from another user or from services.\n" 215 "If services are currently holding your nick, the hold\n" 216 "will be released. If another user is holding your nick\n" 217 "and is identified they will be killed (similar to the old\n" 218 "GHOST command). If they are not identified they will be\n" 219 "forced off of the nick.")); 220 return true; 221 } 222 }; 223 224 class NSRecover : public Module 225 { 226 CommandNSRecover commandnsrecover; 227 PrimitiveExtensibleItem<NSRecoverInfo> recover; 228 PrimitiveExtensibleItem<NSRecoverSvsnick> svsnick; 229 230 public: 231 NSRecover(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), 232 commandnsrecover(this), recover(this, "recover"), svsnick(this, "svsnick") 233 { 234 235 if (Config->GetModule("nickserv")->Get<bool>("nonicknameownership")) 236 throw ModuleException(modname + " can not be used with options:nonicknameownership enabled"); 237 238 } 239 240 void OnUserNickChange(User *u, const Anope::string &oldnick) anope_override 241 { 242 if (Config->GetModule(this)->Get<bool>("restoreonrecover")) 243 { 244 NSRecoverInfo *ei = recover.Get(u); 245 BotInfo *NickServ = Config->GetClient("NickServ"); 246 247 if (ei != NULL && NickServ != NULL) 248 for (NSRecoverInfo::iterator it = ei->begin(), it_end = ei->end(); it != it_end;) 249 { 250 Channel *c = Channel::Find(it->first); 251 const Anope::string &cname = it->first; 252 ++it; 253 254 /* User might already be on the channel */ 255 if (u->FindChannel(c)) 256 this->OnJoinChannel(u, c); 257 else if (IRCD->CanSVSJoin) 258 IRCD->SendSVSJoin(NickServ, u, cname, ""); 259 } 260 } 261 262 NSRecoverSvsnick *svs = svsnick.Get(u); 263 if (svs) 264 { 265 if (svs->from) 266 { 267 // svsnick from to to 268 IRCD->SendForceNickChange(svs->from, svs->to, Anope::CurTime); 269 } 270 271 svsnick.Unset(u); 272 } 273 } 274 275 void OnJoinChannel(User *u, Channel *c) anope_override 276 { 277 if (Config->GetModule(this)->Get<bool>("restoreonrecover")) 278 { 279 NSRecoverInfo *ei = recover.Get(u); 280 281 if (ei != NULL) 282 { 283 NSRecoverInfo::iterator it = ei->find(c->name); 284 if (it != ei->end()) 285 { 286 for (size_t i = 0; i < it->second.Modes().length(); ++i) 287 c->SetMode(c->ci->WhoSends(), ModeManager::FindChannelModeByChar(it->second.Modes()[i]), u->GetUID()); 288 289 ei->erase(it); 290 if (ei->empty()) 291 recover.Unset(u); 292 } 293 } 294 } 295 } 296 }; 297 298 MODULE_INIT(NSRecover)