1 var Logger
= require("./logger");
2 var Server
= require("./server");
3 var db
= require("./database");
4 var util
= require("./utilities");
5 import { v4 as uuidv4
} from 'uuid';
7 function eventUsername(user
) {
8 return user
.getName() + "@" + user
.realip
;
11 function handleAnnounce(user
, data
) {
12 var sv
= Server
.getServer();
21 Logger
.eventlog
.log("[acp] " + eventUsername(user
) + " opened announcement `" +
25 function handleAnnounceClear(user
) {
26 Server
.getServer().announce(null);
27 Logger
.eventlog
.log("[acp] " + eventUsername(user
) + " cleared announcement");
30 function handleGlobalBan(user
, data
) {
31 const globalBanDB
= db
.getGlobalBanDB();
32 globalBanDB
.addGlobalIPBan(data
.ip
, data
.note
).then(() => {
33 Logger
.eventlog
.log("[acp] " + eventUsername(user
) + " global banned " + data
.ip
);
34 return globalBanDB
.listGlobalBans().then(bans
=> {
35 // Why is it called reason in the DB and note in the socket frame?
37 const mappedBans
= bans
.map(ban
=> {
38 return { ip
: ban
.ip
, note
: ban
.reason
};
40 user
.socket
.emit("acp-gbanlist", mappedBans
);
43 user
.socket
.emit("errMessage", {
49 function handleGlobalBanDelete(user
, data
) {
50 const globalBanDB
= db
.getGlobalBanDB();
51 globalBanDB
.removeGlobalIPBan(data
.ip
).then(() => {
52 Logger
.eventlog
.log("[acp] " + eventUsername(user
) + " un-global banned " +
54 return globalBanDB
.listGlobalBans().then(bans
=> {
55 // Why is it called reason in the DB and note in the socket frame?
57 const mappedBans
= bans
.map(ban
=> {
58 return { ip
: ban
.ip
, note
: ban
.reason
};
60 user
.socket
.emit("acp-gbanlist", mappedBans
);
63 user
.socket
.emit("errMessage", {
69 function handleListUsers(user
, data
) {
70 var value
= data
.value
;
71 var field
= data
.field
;
72 value
= (typeof value
!== 'string') ? '' : value
;
73 field
= (typeof field
!== 'string') ? 'name' : field
;
75 var fields
= ["id", "name", "global_rank", "email", "ip", "time"];
77 if(!fields
.includes(field
)){
78 user
.socket
.emit("errMessage", {
79 msg
: `The field "${field}" doesn't exist or isn't searchable.`
84 db
.users
.search(field
, value
, fields
, function (err
, users
) {
86 user
.socket
.emit("errMessage", {
91 user
.socket
.emit("acp-list-users", users
);
95 function handleSetRank(user
, data
) {
98 if (typeof name
!== "string" || typeof rank
!== "number") {
102 if (rank
>= user
.global_rank
) {
103 user
.socket
.emit("errMessage", {
104 msg
: "You are not permitted to promote others to equal or higher rank than " +
110 db
.users
.getGlobalRank(name
, function (err
, oldrank
) {
112 user
.socket
.emit("errMessage", {
118 if (oldrank
>= user
.global_rank
) {
119 user
.socket
.emit("errMessage", {
120 msg
: "You are not permitted to change the rank of users who rank " +
126 db
.users
.setGlobalRank(name
, rank
, function (err
) {
128 user
.socket
.emit("errMessage", {
132 Logger
.eventlog
.log("[acp] " + eventUsername(user
) + " set " + name
+
133 "'s global_rank to " + rank
);
134 user
.socket
.emit("acp-set-rank", data
);
140 function handleResetPassword(user
, data
, ack
) {
141 var name
= data
.name
;
142 var email
= data
.email
;
143 if (typeof name
!== "string" || typeof email
!== "string") {
147 db
.users
.getGlobalRank(name
, function (err
, rank
) {
148 if (rank
>= user
.global_rank
) {
149 user
.socket
.emit("errMessage", {
150 msg
: "You don't have permission to reset the password for " + name
155 var hash
= util
.sha1(util
.randomSalt(64));
156 var expire
= Date
.now() + 86400000;
157 db
.addPasswordReset({
165 ack
&& ack({ error
: err
});
169 Logger
.eventlog
.log("[acp] " + eventUsername(user
) + " initialized a " +
170 "password recovery for " + name
);
172 ack
&& ack({ hash
});
177 function handleListChannels(user
, data
) {
178 var field
= data
.field
;
179 var value
= data
.value
;
180 if (typeof field
!== "string" || typeof value
!== "string") {
185 if (field
=== "owner") {
186 dbfunc
= db
.channels
.searchOwner
;
188 dbfunc
= db
.channels
.search
;
191 dbfunc(value
, function (err
, rows
) {
193 user
.socket
.emit("errMessage", {
199 user
.socket
.emit("acp-list-channels", rows
);
203 function handleDeleteChannel(user
, data
) {
204 var name
= data
.name
;
205 if (typeof data
.name
!== "string") {
209 var sv
= Server
.getServer();
210 if (sv
.isChannelLoaded(name
)) {
211 sv
.getChannel(name
).users
.forEach(function (u
) {
212 u
.kick("Channel shutting down");
216 db
.channels
.drop(name
, function (err
) {
217 Logger
.eventlog
.log("[acp] " + eventUsername(user
) + " deleted channel " + name
);
219 user
.socket
.emit("errMessage", {
223 user
.socket
.emit("acp-delete-channel", {
230 function handleListActiveChannels(user
) {
231 user
.socket
.emit("acp-list-activechannels", Server
.getServer().packChannelList(false, true));
234 function handleForceUnload(user
, data
) {
235 var name
= data
.name
;
236 if (typeof name
!== "string") {
240 var sv
= Server
.getServer();
241 if (!sv
.isChannelLoaded(name
)) {
245 var chan
= sv
.getChannel(name
);
246 var users
= Array
.prototype.slice
.call(chan
.users
);
248 users
.forEach(function (u
) {
249 u
.kick("Channel shutting down");
252 Logger
.eventlog
.log("[acp] " + eventUsername(user
) + " forced unload of " + name
);
255 function init(user
) {
257 s
.on("acp-announce", handleAnnounce
.bind(this, user
));
258 s
.on("acp-announce-clear", handleAnnounceClear
.bind(this, user
));
259 s
.on("acp-gban", handleGlobalBan
.bind(this, user
));
260 s
.on("acp-gban-delete", handleGlobalBanDelete
.bind(this, user
));
261 s
.on("acp-list-users", handleListUsers
.bind(this, user
));
262 s
.on("acp-set-rank", handleSetRank
.bind(this, user
));
263 s
.on("acp-reset-password", handleResetPassword
.bind(this, user
));
264 s
.on("acp-list-channels", handleListChannels
.bind(this, user
));
265 s
.on("acp-delete-channel", handleDeleteChannel
.bind(this, user
));
266 s
.on("acp-list-activechannels", handleListActiveChannels
.bind(this, user
));
267 s
.on("acp-force-unload", handleForceUnload
.bind(this, user
));
269 const globalBanDB
= db
.getGlobalBanDB();
270 globalBanDB
.listGlobalBans().then(bans
=> {
271 // Why is it called reason in the DB and note in the socket frame?
273 const mappedBans
= bans
.map(ban
=> {
274 return { ip
: ban
.ip
, note
: ban
.reason
};
276 user
.socket
.emit("acp-gbanlist", mappedBans
);
278 user
.socket
.emit("errMessage", {
282 Logger
.eventlog
.log("[acp] Initialized ACP for " + eventUsername(user
));
285 module
.exports
.init
= init
;