aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/commands/mod
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--server/src/commands/mod/ban.js22
-rw-r--r--server/src/commands/mod/dumb.js98
-rw-r--r--server/src/commands/mod/kick.js18
-rw-r--r--server/src/commands/mod/moveuser.js105
-rw-r--r--server/src/commands/mod/speak.js27
-rw-r--r--server/src/commands/mod/unban.js17
-rw-r--r--server/src/commands/mod/unbanall.js36
7 files changed, 264 insertions, 59 deletions
diff --git a/server/src/commands/mod/ban.js b/server/src/commands/mod/ban.js
index 721ad27..8236136 100644
--- a/server/src/commands/mod/ban.js
+++ b/server/src/commands/mod/ban.js
@@ -2,12 +2,11 @@
Description: Adds the target socket's ip to the ratelimiter
*/
+// module main
exports.run = async (core, server, socket, data) => {
// increase rate limit chance and ignore if not admin or mod
- if (socket.uType == 'user') {
- server._police.frisk(socket.remoteAddress, 10);
-
- return;
+ if (socket.uType === 'user') {
+ return server._police.frisk(socket.remoteAddress, 10);
}
// check user input
@@ -20,24 +19,20 @@ exports.run = async (core, server, socket, data) => {
let badClient = server.findSockets({ channel: socket.channel, nick: targetNick });
if (badClient.length === 0) {
- server.reply({
+ return server.reply({
cmd: 'warn',
text: 'Could not find user in channel'
}, socket);
-
- return;
}
badClient = badClient[0];
// i guess banning mods or admins isn't the best idea?
if (badClient.uType !== 'user') {
- server.reply({
+ return server.reply({
cmd: 'warn',
text: 'Cannot ban other mods, how rude'
}, socket);
-
- return;
}
// commit arrest record
@@ -64,10 +59,11 @@ exports.run = async (core, server, socket, data) => {
core.managers.stats.increment('users-banned');
};
+// module meta
exports.requiredData = ['nick'];
-
exports.info = {
name: 'ban',
- usage: 'ban {nick}',
- description: 'Disconnects the target nickname in the same channel as calling socket & adds to ratelimiter'
+ description: 'Disconnects the target nickname in the same channel as calling socket & adds to ratelimiter',
+ usage: `
+ API: { cmd: 'ban', nick: '<target nickname>' }`
};
diff --git a/server/src/commands/mod/dumb.js b/server/src/commands/mod/dumb.js
index 675ecd6..ecb4e0d 100644
--- a/server/src/commands/mod/dumb.js
+++ b/server/src/commands/mod/dumb.js
@@ -1,18 +1,20 @@
/*
- * Description: Make a user (spammer) dumb
+ * Description: Make a user (spammer) dumb (mute)
* Author: simple
*/
+// module constructor
exports.init = (core) => {
+ if (typeof core.muzzledHashes === 'undefined') {
core.muzzledHashes = {};
-}
+ }
+};
+// module main
exports.run = async (core, server, socket, data) => {
// increase rate limit chance and ignore if not admin or mod
- if (socket.uType == 'user') {
- server._police.frisk(socket.remoteAddress, 10);
-
- return;
+ if (socket.uType === 'user') {
+ return server._police.frisk(socket.remoteAddress, 10);
}
// check user input
@@ -24,29 +26,25 @@ exports.run = async (core, server, socket, data) => {
let badClient = server.findSockets({ channel: socket.channel, nick: data.nick });
if (badClient.length === 0) {
- server.reply({
+ return server.reply({
cmd: 'warn',
text: 'Could not find user in channel'
}, socket);
-
- return;
}
badClient = badClient[0];
// likely dont need this, muting mods and admins is fine
if (badClient.uType !== 'user') {
- server.reply({
+ return server.reply({
cmd: 'warn',
text: 'This trick wont work on mods and admin'
}, socket);
-
- return;
}
// store hash in mute list
let record = core.muzzledHashes[badClient.hash] = {
- dumb:true
+ dumb: true
}
// store allies if needed
@@ -59,12 +57,78 @@ exports.run = async (core, server, socket, data) => {
cmd: 'info',
text: `${socket.nick} muzzled ${data.nick} in ${socket.channel}, userhash: ${badClient.hash}`
}, { uType: 'mod' });
-}
+};
-exports.requiredData = ['nick'];
+// module hook functions
+exports.initHooks = (server) => {
+ server.registerHook('in', 'chat', this.chatCheck);
+ server.registerHook('in', 'invite', this.inviteCheck);
+ // TODO: add whisper hook, need hook priorities todo finished first
+};
+
+// hook incoming chat commands, shadow-prevent chat if they are muzzled
+exports.chatCheck = (core, server, socket, payload) => {
+ if (typeof payload.text !== 'string') {
+ return false;
+ }
+
+ if(core.muzzledHashes[socket.hash]){
+ // build fake chat payload
+ mutedPayload = {
+ cmd: 'chat',
+ nick: socket.nick,
+ text: payload.text
+ };
+
+ if (socket.trip) {
+ mutedPayload.trip = socket.trip;
+ }
+
+ // broadcast to any duplicate connections in channel
+ server.broadcast( mutedPayload, { channel: socket.channel, hash: socket.hash });
+ // broadcast to allies, if any
+ if(core.muzzledHashes[socket.hash].allies){
+ server.broadcast( mutedPayload, { channel: socket.channel, nick: core.muzzledHashes[socket.hash].allies });
+ }
+
+ // blanket "spam" protection, may expose the ratelimiting lines from `chat` and use that, TODO: one day #lazydev
+ server._police.frisk(socket.remoteAddress, 9);
+
+ return false;
+ }
+
+ return payload;
+};
+
+// shadow-prevent all invites from muzzled users
+exports.inviteCheck = (core, server, socket, payload) => {
+ if (typeof payload.nick !== 'string') {
+ return false;
+ }
+
+ if(core.muzzledHashes[socket.hash]){
+ // generate common channel
+ let channel = Math.random().toString(36).substr(2, 8);
+
+ // send fake reply
+ server.reply({
+ cmd: 'info',
+ text: `You invited ${payload.nick} to ?${channel}`
+ }, socket);
+
+ return false;
+ }
+
+ return payload;
+};
+
+// module meta
+exports.requiredData = ['nick'];
exports.info = {
name: 'dumb',
- usage: 'dumb {nick} [allies...]',
- description: 'Globally shadow mute a connection. Optional allies array will see muted messages.'
+ description: 'Globally shadow mute a connection. Optional allies array will see muted messages.',
+ usage: `
+ API: { cmd: 'dumb', nick: '<target nick>', allies: ['<optional nick array>', ...] }`
};
+exports.info.aliases = ['muzzle', 'mute'];
diff --git a/server/src/commands/mod/kick.js b/server/src/commands/mod/kick.js
index 75c0d40..0e8ee0a 100644
--- a/server/src/commands/mod/kick.js
+++ b/server/src/commands/mod/kick.js
@@ -2,12 +2,11 @@
Description: Forces a change on the target(s) socket's channel, then broadcasts event
*/
+// module main
exports.run = async (core, server, socket, data) => {
// increase rate limit chance and ignore if not admin or mod
- if (socket.uType == 'user') {
- server._police.frisk(socket.remoteAddress, 10);
-
- return;
+ if (socket.uType === 'user') {
+ return server._police.frisk(socket.remoteAddress, 10);
}
// check user input
@@ -21,12 +20,10 @@ exports.run = async (core, server, socket, data) => {
let badClients = server.findSockets({ channel: socket.channel, nick: data.nick });
if (badClients.length === 0) {
- server.reply({
+ return server.reply({
cmd: 'warn',
text: 'Could not find user(s) in channel'
}, socket);
-
- return;
}
// check if found targets are kickable, commit kick
@@ -75,10 +72,11 @@ exports.run = async (core, server, socket, data) => {
core.managers.stats.increment('users-kicked', kicked.length);
};
+// module meta
exports.requiredData = ['nick'];
-
exports.info = {
name: 'kick',
- usage: 'kick {nick}',
- description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings'
+ description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings',
+ usage: `
+ API: { cmd: 'kick', nick: '<target nick>' }`
};
diff --git a/server/src/commands/mod/moveuser.js b/server/src/commands/mod/moveuser.js
new file mode 100644
index 0000000..e4f6c22
--- /dev/null
+++ b/server/src/commands/mod/moveuser.js
@@ -0,0 +1,105 @@
+/*
+ Description: Removes the target socket from the current channel and forces a join event in another
+*/
+
+// module main
+exports.run = async (core, server, socket, data) => {
+ // increase rate limit chance and ignore if not admin or mod
+ if (socket.uType === 'user') {
+ return server._police.frisk(socket.remoteAddress, 10);
+ }
+
+ // check user input
+ if (typeof data.nick !== 'string' || typeof data.channel !== 'string') {
+ return;
+ }
+
+ if (data.channel === socket.channel) {
+ // moving them into the same channel? y u do this?
+ return;
+ }
+
+ let badClients = server.findSockets({ channel: socket.channel, nick: data.nick });
+
+ if (badClients.length === 0) {
+ return server.reply({
+ cmd: 'warn',
+ text: 'Could not find user in channel'
+ }, socket);
+ }
+
+ let badClient = badClients[0];
+
+ if (badClient.uType !== 'user') {
+ return server.reply({
+ cmd: 'warn',
+ text: 'Cannot move other mods, how rude'
+ }, socket);
+ }
+
+ const currentNick = badClient.nick.toLowerCase();
+ let userExists = server.findSockets({
+ channel: data.channel,
+ nick: (targetNick) => targetNick.toLowerCase() === currentNick
+ });
+
+ if (userExists.length > 0) {
+ // That nickname is already in that channel
+ return;
+ }
+
+ let peerList = server.findSockets({ channel: socket.channel });
+
+ if (peerList.length > 1) {
+ for (let i = 0, l = peerList.length; i < l; i++) {
+ server.reply({
+ cmd: 'onlineRemove',
+ nick: peerList[i].nick
+ }, badClient);
+
+ if (badClient.nick !== peerList[i].nick){
+ server.reply({
+ cmd: 'onlineRemove',
+ nick: badClient.nick
+ }, peerList[i]);
+ }
+ }
+ }
+
+ let newPeerList = server.findSockets({ channel: data.channel });
+ let moveAnnouncement = {
+ cmd: 'onlineAdd',
+ nick: badClient.nick,
+ trip: badClient.trip || 'null',
+ hash: server.getSocketHash(badClient)
+ };
+ let nicks = [];
+
+ for (let i = 0, l = newPeerList.length; i < l; i++) {
+ server.reply(moveAnnouncement, newPeerList[i]);
+ nicks.push(newPeerList[i].nick);
+ }
+
+ nicks.push(badClient.nick);
+
+ server.reply({
+ cmd: 'onlineSet',
+ nicks: nicks
+ }, badClient);
+
+ badClient.channel = data.channel;
+
+ server.broadcast( {
+ cmd: 'info',
+ text: `${badClient.nick} was moved into ?${data.channel}`
+ }, { channel: data.channel });
+};
+
+// module meta
+exports.requiredData = ['nick', 'channel'];
+exports.info = {
+ name: 'moveuser',
+ description: 'This will move the target user nick into another channel',
+ usage: `
+ API: { cmd: 'moveuser', nick: '<target nick>', channel: '<new channel>' }`
+};
diff --git a/server/src/commands/mod/speak.js b/server/src/commands/mod/speak.js
index 454ca94..e2a3ef7 100644
--- a/server/src/commands/mod/speak.js
+++ b/server/src/commands/mod/speak.js
@@ -3,22 +3,26 @@
* Author: simple
*/
+ // module constructor
+ exports.init = (core) => {
+ if (typeof core.muzzledHashes === 'undefined') {
+ core.muzzledHashes = {};
+ }
+ };
+
+// module main
exports.run = async (core, server, socket, data) => {
// increase rate limit chance and ignore if not admin or mod
- if (socket.uType == 'user') {
- server._police.frisk(socket.remoteAddress, 10);
-
- return;
+ if (socket.uType === 'user') {
+ return server._police.frisk(socket.remoteAddress, 10);
}
// check user input
if (typeof data.ip !== 'string' && typeof data.hash !== 'string') {
- server.reply({
+ return server.reply({
cmd: 'warn',
text: "hash:'targethash' or ip:'1.2.3.4' is required"
}, socket);
-
- return;
}
// find target & remove mute status
@@ -36,10 +40,13 @@ exports.run = async (core, server, socket, data) => {
cmd: 'info',
text: `${socket.nick} unmuzzled : ${target}`
}, { uType: 'mod' });
-}
+};
+// module meta
exports.info = {
name: 'speak',
- usage: 'speak {[ip || hash]}',
- description: 'Pardon a dumb user to be able to speak again'
+ description: 'Pardon a dumb user to be able to speak again',
+ usage: `
+ API: { cmd: 'speak', ip/hash: '<target ip or hash' }`
};
+exports.info.aliases = ['unmuzzle', 'unmute'];
diff --git a/server/src/commands/mod/unban.js b/server/src/commands/mod/unban.js
index 9115dbd..0cd8ca7 100644
--- a/server/src/commands/mod/unban.js
+++ b/server/src/commands/mod/unban.js
@@ -2,22 +2,19 @@
Description: Removes a target ip from the ratelimiter
*/
+// module main
exports.run = async (core, server, socket, data) => {
// increase rate limit chance and ignore if not admin or mod
- if (socket.uType == 'user') {
- server._police.frisk(socket.remoteAddress, 10);
-
- return;
+ if (socket.uType === 'user') {
+ return server._police.frisk(socket.remoteAddress, 10);
}
// check user input
if (typeof data.ip !== 'string' && typeof data.hash !== 'string') {
- server.reply({
+ return server.reply({
cmd: 'warn',
text: "hash:'targethash' or ip:'1.2.3.4' is required"
}, socket);
-
- return;
}
// find target
@@ -55,8 +52,10 @@ exports.run = async (core, server, socket, data) => {
core.managers.stats.decrement('users-banned');
};
+// module meta
exports.info = {
name: 'unban',
- usage: 'unban {[ip || hash]}',
- description: 'Removes target ip from the ratelimiter'
+ description: 'Removes target ip from the ratelimiter',
+ usage: `
+ API: { cmd: 'unban', ip/hash: '<target ip or hash>' }`
};
diff --git a/server/src/commands/mod/unbanall.js b/server/src/commands/mod/unbanall.js
new file mode 100644
index 0000000..a9cf682
--- /dev/null
+++ b/server/src/commands/mod/unbanall.js
@@ -0,0 +1,36 @@
+/*
+ Description: Clears all bans and ratelimits
+*/
+
+// module main
+exports.run = async (core, server, socket, data) => {
+ // increase rate limit chance and ignore if not admin or mod
+ if (socket.uType === 'user') {
+ return server._police.frisk(socket.remoteAddress, 10);
+ }
+
+ // remove arrest records
+ server._police._records = {};
+
+ console.log(`${socket.nick} [${socket.trip}] unbanned all`);
+
+ // reply with success
+ server.reply({
+ cmd: 'info',
+ text: `Unbanned all ip addresses`
+ }, socket);
+
+ // notify mods
+ server.broadcast({
+ cmd: 'info',
+ text: `${socket.nick} unbanned all ip addresses`
+ }, { uType: 'mod' });
+};
+
+// module meta
+exports.info = {
+ name: 'unbanall',
+ description: 'Clears all banned ip addresses',
+ usage: `
+ API: { cmd: 'unbanall' }`
+};