1 /*
2 * Copyright (C) 2004-2020 ZNC, see the NOTICE file for details.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <znc/User.h>
18 #include <znc/IRCNetwork.h>
19
20 using std::vector;
21
22 #define MESSAGE \
23 t_s("Your account has been disabled. Contact your administrator.")
24
25 class CBlockUser : public CModule {
26 public:
MODCONSTRUCTOR(CBlockUser)27 MODCONSTRUCTOR(CBlockUser) {
28 AddHelpCommand();
29 AddCommand("List", "", t_d("List blocked users"),
30 [this](const CString& sLine) { OnListCommand(sLine); });
31 AddCommand("Block", t_d("<user>"), t_d("Block a user"),
32 [this](const CString& sLine) { OnBlockCommand(sLine); });
33 AddCommand("Unblock", t_d("<user>"), t_d("Unblock a user"),
34 [this](const CString& sLine) { OnUnblockCommand(sLine); });
35 }
36
~CBlockUser()37 ~CBlockUser() override {}
38
OnLoad(const CString & sArgs,CString & sMessage)39 bool OnLoad(const CString& sArgs, CString& sMessage) override {
40 VCString vArgs;
41 VCString::iterator it;
42 MCString::iterator it2;
43
44 // Load saved settings
45 for (it2 = BeginNV(); it2 != EndNV(); ++it2) {
46 // Ignore errors
47 Block(it2->first);
48 }
49
50 // Parse arguments, each argument is a user name to block
51 sArgs.Split(" ", vArgs, false);
52
53 for (it = vArgs.begin(); it != vArgs.end(); ++it) {
54 if (!Block(*it)) {
55 sMessage = t_f("Could not block {1}")(*it);
56 return false;
57 }
58 }
59
60 return true;
61 }
62
63 /* If a user is on the blocked list and tries to log in, displays - MESSAGE
64 and stops their log in attempt.*/
OnLoginAttempt(std::shared_ptr<CAuthBase> Auth)65 EModRet OnLoginAttempt(std::shared_ptr<CAuthBase> Auth) override {
66 if (IsBlocked(Auth->GetUsername())) {
67 Auth->RefuseLogin(MESSAGE);
68 return HALT;
69 }
70
71 return CONTINUE;
72 }
73
OnModCommand(const CString & sCommand)74 void OnModCommand(const CString& sCommand) override {
75 if (!GetUser()->IsAdmin()) {
76 PutModule(t_s("Access denied"));
77 } else {
78 HandleCommand(sCommand);
79 }
80 }
81
82 // Displays all blocked users as a list.
OnListCommand(const CString & sCommand)83 void OnListCommand(const CString& sCommand) {
84 if (BeginNV() == EndNV()) {
85 PutModule(t_s("No users are blocked"));
86 return;
87 }
88 PutModule(t_s("Blocked users:"));
89 for (auto it = BeginNV(); it != EndNV(); ++it) {
90 PutModule(it->first);
91 }
92 }
93
94 /* Blocks a user if possible(ie not self, not already blocked).
95 Displays an error message if not possible. */
OnBlockCommand(const CString & sCommand)96 void OnBlockCommand(const CString& sCommand) {
97 CString sUser = sCommand.Token(1, true);
98
99 if (sUser.empty()) {
100 PutModule(t_s("Usage: Block <user>"));
101 return;
102 }
103
104 if (GetUser()->GetUsername().Equals(sUser)) {
105 PutModule(t_s("You can't block yourself"));
106 return;
107 }
108
109 if (Block(sUser))
110 PutModule(t_f("Blocked {1}")(sUser));
111 else
112 PutModule(t_f("Could not block {1} (misspelled?)")(sUser));
113 }
114
115 // Unblocks a user from the blocked list.
OnUnblockCommand(const CString & sCommand)116 void OnUnblockCommand(const CString& sCommand) {
117 CString sUser = sCommand.Token(1, true);
118
119 if (sUser.empty()) {
120 PutModule(t_s("Usage: Unblock <user>"));
121 return;
122 }
123
124 if (DelNV(sUser))
125 PutModule(t_f("Unblocked {1}")(sUser));
126 else
127 PutModule(t_s("This user is not blocked"));
128 }
129
130 // Provides GUI to configure this module by adding a widget to user page in webadmin.
OnEmbeddedWebRequest(CWebSock & WebSock,const CString & sPageName,CTemplate & Tmpl)131 bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName,
132 CTemplate& Tmpl) override {
133 if (sPageName == "webadmin/user" && WebSock.GetSession()->IsAdmin()) {
134 CString sAction = Tmpl["WebadminAction"];
135 if (sAction == "display") {
136 Tmpl["Blocked"] = CString(IsBlocked(Tmpl["Username"]));
137 Tmpl["Self"] = CString(Tmpl["Username"].Equals(
138 WebSock.GetSession()->GetUser()->GetUsername()));
139 return true;
140 }
141 if (sAction == "change" &&
142 WebSock.GetParam("embed_blockuser_presented").ToBool()) {
143 if (Tmpl["Username"].Equals(
144 WebSock.GetSession()->GetUser()->GetUsername()) &&
145 WebSock.GetParam("embed_blockuser_block").ToBool()) {
146 WebSock.GetSession()->AddError(
147 t_s("You can't block yourself"));
148 } else if (WebSock.GetParam("embed_blockuser_block").ToBool()) {
149 if (!WebSock.GetParam("embed_blockuser_old").ToBool()) {
150 if (Block(Tmpl["Username"])) {
151 WebSock.GetSession()->AddSuccess(
152 t_f("Blocked {1}")(Tmpl["Username"]));
153 } else {
154 WebSock.GetSession()->AddError(
155 t_f("Couldn't block {1}")(Tmpl["Username"]));
156 }
157 }
158 } else if (WebSock.GetParam("embed_blockuser_old").ToBool()) {
159 if (DelNV(Tmpl["Username"])) {
160 WebSock.GetSession()->AddSuccess(
161 t_f("Unblocked {1}")(Tmpl["Username"]));
162 } else {
163 WebSock.GetSession()->AddError(
164 t_f("User {1} is not blocked")(Tmpl["Username"]));
165 }
166 }
167 return true;
168 }
169 }
170 return false;
171 }
172
173 private:
174 /* Iterates through all blocked users and returns true if the specified user (sUser)
175 is blocked, else returns false.*/
IsBlocked(const CString & sUser)176 bool IsBlocked(const CString& sUser) {
177 MCString::iterator it;
178 for (it = BeginNV(); it != EndNV(); ++it) {
179 if (sUser == it->first) {
180 return true;
181 }
182 }
183 return false;
184 }
185
Block(const CString & sUser)186 bool Block(const CString& sUser) {
187 CUser* pUser = CZNC::Get().FindUser(sUser);
188
189 if (!pUser) return false;
190
191 // Disconnect all clients
192 vector<CClient*> vpClients = pUser->GetAllClients();
193 vector<CClient*>::iterator it;
194 for (it = vpClients.begin(); it != vpClients.end(); ++it) {
195 (*it)->PutStatusNotice(MESSAGE);
196 (*it)->Close(Csock::CLT_AFTERWRITE);
197 }
198
199 // Disconnect all networks from irc
200 vector<CIRCNetwork*> vNetworks = pUser->GetNetworks();
201 for (vector<CIRCNetwork*>::iterator it2 = vNetworks.begin();
202 it2 != vNetworks.end(); ++it2) {
203 (*it2)->SetIRCConnectEnabled(false);
204 }
205
206 SetNV(pUser->GetUsername(), "");
207 return true;
208 }
209 };
210
211 template <>
TModInfo(CModInfo & Info)212 void TModInfo<CBlockUser>(CModInfo& Info) {
213 Info.SetWikiPage("blockuser");
214 Info.SetHasArgs(true);
215 Info.SetArgsHelpText(
216 Info.t_s("Enter one or more user names. Separate them by spaces."));
217 }
218
219 GLOBALMODULEDEFS(CBlockUser, t_s("Block certain users from logging in."))
220