diff options
Diffstat (limited to 'server/src/commands')
27 files changed, 532 insertions, 492 deletions
diff --git a/server/src/commands/admin/addmod.js b/server/src/commands/admin/addmod.js index 6853a42..26cec40 100644 --- a/server/src/commands/admin/addmod.js +++ b/server/src/commands/admin/addmod.js @@ -3,26 +3,26 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { // increase rate limit chance and ignore if not admin - if (socket.uType != 'admin') { - return server.police.frisk(socket.remoteAddress, 20); + if (socket.uType !== 'admin') { + return server.police.frisk(socket.address, 20); } // add new trip to config core.config.mods.push({ trip: data.trip }); // find targets current connections - let newMod = server.findSockets({ trip: data.trip }); + const newMod = server.findSockets({ trip: data.trip }); if (newMod.length !== 0) { - for (let i = 0, l = newMod.length; i < l; i++) { + for (let i = 0, l = newMod.length; i < l; i += 1) { // upgrade privilages newMod[i].uType = 'mod'; // inform new mod server.send({ cmd: 'info', - text: 'You are now a mod.' + text: 'You are now a mod.', }, newMod[i]); } } @@ -30,21 +30,22 @@ exports.run = async (core, server, socket, data) => { // return success message server.reply({ cmd: 'info', - text: `Added mod trip: ${data.trip}, remember to run 'saveconfig' to make it permanent` + text: `Added mod trip: ${data.trip}, remember to run 'saveconfig' to make it permanent`, }, socket); // notify all mods server.broadcast({ cmd: 'info', - text: `Added mod: ${data.trip}` + text: `Added mod: ${data.trip}`, }, { uType: 'mod' }); -}; -// module meta -exports.requiredData = ['trip']; -exports.info = { + return true; +} + +export const requiredData = ['trip']; +export const info = { name: 'addmod', description: 'Adds target trip to the config as a mod and upgrades the socket type', usage: ` - API: { cmd: 'addmod', trip: '<target trip>' }` + API: { cmd: 'addmod', trip: '<target trip>' }`, }; diff --git a/server/src/commands/admin/listusers.js b/server/src/commands/admin/listusers.js index 5ff350f..0b0199f 100644 --- a/server/src/commands/admin/listusers.js +++ b/server/src/commands/admin/listusers.js @@ -3,46 +3,47 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket) { // increase rate limit chance and ignore if not admin - if (socket.uType != 'admin') { - return server.police.frisk(socket.remoteAddress, 20); + if (socket.uType !== 'admin') { + return server.police.frisk(socket.address, 20); } // find all users currently in a channel - let currentUsers = server.findSockets({ - channel: (channel) => true + const currentUsers = server.findSockets({ + channel: (channel) => true, }); // compile channel and user list - let channels = {}; - for (let i = 0, j = currentUsers.length; i < j; i++) { + const channels = {}; + for (let i = 0, j = currentUsers.length; i < j; i += 1) { if (typeof channels[currentUsers[i].channel] === 'undefined') { channels[currentUsers[i].channel] = []; } - + channels[currentUsers[i].channel].push( - `[${currentUsers[i].trip||'null'}]${currentUsers[i].nick}` + `[${currentUsers[i].trip || 'null'}]${currentUsers[i].nick}`, ); } // build output - let lines = []; - for (let channel in channels) { - lines.push(`?${channel} ${channels[channel].join(", ")}`); + const lines = []; + for (const channel in channels) { + lines.push(`?${channel} ${channels[channel].join(', ')}`); } // send reply server.reply({ cmd: 'info', - text: lines.join("\n") + text: lines.join('\n'), }, socket); -}; -// module meta -exports.info = { + return true; +} + +export const info = { name: 'listusers', description: 'Outputs all current channels and sockets in those channels', usage: ` - API: { cmd: 'listusers' }` + API: { cmd: 'listusers' }`, }; diff --git a/server/src/commands/admin/reload.js b/server/src/commands/admin/reload.js index 588d1c5..206e2ca 100644 --- a/server/src/commands/admin/reload.js +++ b/server/src/commands/admin/reload.js @@ -3,10 +3,10 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { // increase rate limit chance and ignore if not admin - if (socket.uType != 'admin') { - return server.police.frisk(socket.remoteAddress, 20); + if (socket.uType !== 'admin') { + return server.police.frisk(socket.address, 20); } // do command reload and store results @@ -17,7 +17,7 @@ exports.run = async (core, server, socket, data) => { server.loadHooks(); // build reply based on reload results - if (loadResult == '') { + if (loadResult === '') { loadResult = `Reloaded ${core.commands.commands.length} commands, 0 errors`; } else { loadResult = `Reloaded ${core.commands.commands.length} commands, error(s): @@ -31,20 +31,21 @@ exports.run = async (core, server, socket, data) => { // reply with results server.reply({ cmd: 'info', - text: loadResult + text: loadResult, }, socket); // notify mods of reload #transparency server.broadcast({ cmd: 'info', - text: loadResult + text: loadResult, }, { uType: 'mod' }); -}; -// module meta -exports.info = { + return true; +} + +export const info = { name: 'reload', description: '(Re)loads any new commands into memory, outputs errors if any', usage: ` - API: { cmd: 'reload', reason: '<optional reason append>' }` + API: { cmd: 'reload', reason: '<optional reason append>' }`, }; diff --git a/server/src/commands/admin/removemod.js b/server/src/commands/admin/removemod.js index a2d862c..9190dd6 100644 --- a/server/src/commands/admin/removemod.js +++ b/server/src/commands/admin/removemod.js @@ -3,26 +3,26 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { // increase rate limit chance and ignore if not admin - if (socket.uType != 'admin') { - return server.police.frisk(socket.remoteAddress, 20); + if (socket.uType !== 'admin') { + return server.police.frisk(socket.address, 20); } // remove trip from config - core.config.mods = core.config.mods.filter(mod => mod.trip !== data.trip); + core.config.mods = core.config.mods.filter((mod) => mod.trip !== data.trip); // find targets current connections - let targetMod = server.findSockets({ trip: data.trip }); + const targetMod = server.findSockets({ trip: data.trip }); if (targetMod.length !== 0) { - for (let i = 0, l = targetMod.length; i < l; i++) { + for (let i = 0, l = targetMod.length; i < l; i += 1) { // downgrade privilages targetMod[i].uType = 'user'; // inform ex-mod server.send({ cmd: 'info', - text: 'You are now a user.' + text: 'You are now a user.', }, targetMod[i]); } } @@ -32,21 +32,22 @@ exports.run = async (core, server, socket, data) => { cmd: 'info', text: `Removed mod trip: ${ data.trip - }, remember to run 'saveconfig' to make it permanent` + }, remember to run 'saveconfig' to make it permanent`, }, socket); // notify all mods server.broadcast({ cmd: 'info', - text: `Removed mod: ${data.trip}` + text: `Removed mod: ${data.trip}`, }, { uType: 'mod' }); -}; -// module meta -exports.requiredData = ['trip']; -exports.info = { + return true; +} + +export const requiredData = ['trip']; +export const info = { name: 'removemod', description: 'Removes target trip from the config as a mod and downgrades the socket type', usage: ` - API: { cmd: 'removemod', trip: '<target trip>' }` + API: { cmd: 'removemod', trip: '<target trip>' }`, }; diff --git a/server/src/commands/admin/saveconfig.js b/server/src/commands/admin/saveconfig.js index 65fff0e..6c713b4 100644 --- a/server/src/commands/admin/saveconfig.js +++ b/server/src/commands/admin/saveconfig.js @@ -3,37 +3,38 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket) { // increase rate limit chance and ignore if not admin - if (socket.uType != 'admin') { - return server.police.frisk(socket.remoteAddress, 20); + if (socket.uType !== 'admin') { + return server.police.frisk(socket.address, 20); } // attempt save, notify of failure if (!core.configManager.save()) { return server.reply({ cmd: 'warn', - text: 'Failed to save config, check logs.' - }, client); + text: 'Failed to save config, check logs.', + }, socket); } // return success message server.reply({ cmd: 'info', - text: 'Config saved!' + text: 'Config saved!', }, socket); // notify mods #transparency server.broadcast({ cmd: 'info', - text: 'Config saved!' + text: 'Config saved!', }, { uType: 'mod' }); -}; -// module meta -exports.info = { + return true; +} + +export const info = { name: 'saveconfig', description: 'Writes the current config to disk', usage: ` - API: { cmd: 'saveconfig' }` + API: { cmd: 'saveconfig' }`, }; diff --git a/server/src/commands/admin/shout.js b/server/src/commands/admin/shout.js index 821a22a..73b0734 100644 --- a/server/src/commands/admin/shout.js +++ b/server/src/commands/admin/shout.js @@ -3,24 +3,25 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { // increase rate limit chance and ignore if not admin - if (socket.uType != 'admin') { - return server.police.frisk(socket.remoteAddress, 20); + if (socket.uType !== 'admin') { + return server.police.frisk(socket.address, 20); } // send text to all channels server.broadcast({ cmd: 'info', - text: `Server Notice: ${data.text}` + text: `Server Notice: ${data.text}`, }, {}); -}; -// module meta -exports.requiredData = ['text']; -exports.info = { + return true; +} + +export const requiredData = ['text']; +export const info = { name: 'shout', description: 'Displays passed text to every client connected', usage: ` - API: { cmd: 'shout', text: '<shout text>' }` + API: { cmd: 'shout', text: '<shout text>' }`, }; diff --git a/server/src/commands/core/changenick.js b/server/src/commands/core/changenick.js index cb6d1d0..632da83 100644 --- a/server/src/commands/core/changenick.js +++ b/server/src/commands/core/changenick.js @@ -6,43 +6,43 @@ const verifyNickname = (nick) => /^[a-zA-Z0-9_]{1,24}$/.test(nick); // module main -exports.run = async (core, server, socket, data) => { - if (server.police.frisk(socket.remoteAddress, 6)) { +export async function run(core, server, socket, data) { + if (server.police.frisk(socket.address, 6)) { return server.reply({ cmd: 'warn', - text: 'You are changing nicknames too fast. Wait a moment before trying again.' + text: 'You are changing nicknames too fast. Wait a moment before trying again.', }, socket); } // verify user data is string if (typeof data.nick !== 'string') { - return; + return true; } // make sure requested nickname meets standards - let newNick = data.nick.trim(); + const newNick = data.nick.trim(); if (!verifyNickname(newNick)) { return server.reply({ cmd: 'warn', - text: 'Nickname must consist of up to 24 letters, numbers, and underscores' + text: 'Nickname must consist of up to 24 letters, numbers, and underscores', }, socket); } // prevent admin impersonation // TODO: prevent mod impersonation - if (newNick.toLowerCase() == core.config.adminName.toLowerCase()) { - server.police.frisk(socket.remoteAddress, 4); + if (newNick.toLowerCase() === core.config.adminName.toLowerCase()) { + server.police.frisk(socket.address, 4); return server.reply({ cmd: 'warn', - text: 'You are not the admin, liar!' + text: 'You are not the admin, liar!', }, socket); } // find any sockets that have the same nickname - let userExists = server.findSockets({ + const userExists = server.findSockets({ channel: socket.channel, - nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase() + nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase(), }); // return error if found @@ -50,82 +50,83 @@ exports.run = async (core, server, socket, data) => { // That nickname is already in that channel return server.reply({ cmd: 'warn', - text: 'Nickname taken' + text: 'Nickname taken', }, socket); } // build join and leave notices // TODO: this is a legacy client holdover, name changes in the future will // have thieir own event - let leaveNotice = { + const leaveNotice = { cmd: 'onlineRemove', - nick: socket.nick + nick: socket.nick, }; - let joinNotice = { + const joinNotice = { cmd: 'onlineAdd', nick: newNick, trip: socket.trip || 'null', - hash: socket.hash + hash: socket.hash, }; // broadcast remove event and join event with new name, this is to support legacy clients and bots - server.broadcast( leaveNotice, { channel: socket.channel }); - server.broadcast( joinNotice, { channel: socket.channel }); + server.broadcast(leaveNotice, { channel: socket.channel }); + server.broadcast(joinNotice, { channel: socket.channel }); // notify channel that the user has changed their name - server.broadcast( { + server.broadcast({ cmd: 'info', - text: `${socket.nick} is now ${newNick}` + text: `${socket.nick} is now ${newNick}`, }, { channel: socket.channel }); // commit change to nickname socket.nick = newNick; -}; + + return true; +} // module hook functions -exports.initHooks = (server) => { +export function initHooks(server) { server.registerHook('in', 'chat', this.nickCheck, 29); -}; +} // hooks chat commands checking for /nick -exports.nickCheck = (core, server, socket, payload) => { +export function nickCheck(core, server, socket, payload) { if (typeof payload.text !== 'string') { return false; } if (payload.text.startsWith('/nick')) { - let input = payload.text.split(' '); + const input = payload.text.split(' '); // If there is no nickname target parameter if (input[1] === undefined) { server.reply({ cmd: 'warn', - text: 'Refer to `/help nick` for instructions on how to use this command.' + text: 'Refer to `/help nick` for instructions on how to use this command.', }, socket); return false; } - let newNick = input[1].replace(/@/g, ''); + const newNick = input[1].replace(/@/g, ''); this.run(core, server, socket, { cmd: 'changenick', - nick: newNick + nick: newNick, }); return false; } return payload; -}; +} -// module meta -exports.requiredData = ['nick']; -exports.info = { +export const requiredData = ['nick']; +export const info = { name: 'changenick', description: 'This will change your current connections nickname', usage: ` API: { cmd: 'changenick', nick: '<new nickname>' } - Text: /nick <new nickname>` + Text: /nick <new nickname>`, }; diff --git a/server/src/commands/core/chat.js b/server/src/commands/core/chat.js index 7b7e79e..8d0098b 100644 --- a/server/src/commands/core/chat.js +++ b/server/src/commands/core/chat.js @@ -9,43 +9,45 @@ const parseText = (text) => { return false; } + let sanitizedText = text; + // strip newlines from beginning and end - text = text.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); + sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); // replace 3+ newlines with just 2 newlines - text = text.replace(/\n{3,}/g, "\n\n"); + sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n'); - return text; + return sanitizedText; }; // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { // check user input - let text = parseText(data.text); + const text = parseText(data.text); if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.remoteAddress, 13); + return server.police.frisk(socket.address, 13); } // check for spam - let score = text.length / 83 / 4; - if (server.police.frisk(socket.remoteAddress, score)) { + const score = text.length / 83 / 4; + if (server.police.frisk(socket.address, score)) { return server.reply({ cmd: 'warn', - text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.' + text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } // build chat payload - let payload = { + const payload = { cmd: 'chat', nick: socket.nick, - text: text + text, }; - if (socket.uType == 'admin') { + if (socket.uType === 'admin') { payload.admin = true; - } else if (socket.uType == 'mod') { + } else if (socket.uType === 'mod') { payload.mod = true; } @@ -54,20 +56,22 @@ exports.run = async (core, server, socket, data) => { } // broadcast to channel peers - server.broadcast( payload, { channel: socket.channel}); + server.broadcast(payload, { channel: socket.channel }); // stats are fun core.stats.increment('messages-sent'); -}; + + return true; +} // module hook functions -exports.initHooks = (server) => { +export function initHooks(server) { server.registerHook('in', 'chat', this.commandCheckIn, 20); server.registerHook('in', 'chat', this.finalCmdCheck, 254); -}; +} // checks for miscellaneous '/' based commands -exports.commandCheckIn = (core, server, socket, payload) => { +export function commandCheckIn(core, server, socket, payload) { if (typeof payload.text !== 'string') { return false; } @@ -75,16 +79,16 @@ exports.commandCheckIn = (core, server, socket, payload) => { if (payload.text.startsWith('/myhash')) { server.reply({ cmd: 'info', - text: `Your hash: ${socket.hash}` + text: `Your hash: ${socket.hash}`, }, socket); return false; } return payload; -}; +} -exports.finalCmdCheck = (core, server, socket, payload) => { +export function finalCmdCheck(core, server, socket, payload) { if (typeof payload.text !== 'string') { return false; } @@ -97,26 +101,23 @@ exports.finalCmdCheck = (core, server, socket, payload) => { payload.text = payload.text.substr(1); return payload; - } else { - server.reply({ - cmd: 'warn', - text: `Unknown command: ${payload.text}` - }, socket); - - return false; } - return payload; -}; + server.reply({ + cmd: 'warn', + text: `Unknown command: ${payload.text}`, + }, socket); + + return false; +} -// module meta -exports.requiredData = ['text']; -exports.info = { +export const requiredData = ['text']; +export const info = { name: 'chat', description: 'Broadcasts passed `text` field to the calling users channel', usage: ` API: { cmd: 'chat', text: '<text to send>' } Text: Uuuuhm. Just kind type in that little box at the bottom and hit enter.\n Bonus super secret hidden commands: - /myhash` + /myhash`, }; diff --git a/server/src/commands/core/emote.js b/server/src/commands/core/emote.js index b0203cc..f244d74 100644 --- a/server/src/commands/core/emote.js +++ b/server/src/commands/core/emote.js @@ -9,91 +9,94 @@ const parseText = (text) => { return false; } + let sanitizedText = text; + // strip newlines from beginning and end - text = text.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); + sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); // replace 3+ newlines with just 2 newlines - text = text.replace(/\n{3,}/g, "\n\n"); + sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n'); - return text; + return sanitizedText; }; // module main -exports.run = async (core, server, socket, payload) => { +export async function run(core, server, socket, payload) { // check user input - let text = parseText(payload.text); + const text = parseText(payload.text); if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.remoteAddress, 8); + return server.police.frisk(socket.address, 8); } // check for spam - let score = text.length / 83 / 4; - if (server.police.frisk(socket.remoteAddress, score)) { + const score = text.length / 83 / 4; + if (server.police.frisk(socket.address, score)) { return server.reply({ cmd: 'warn', - text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.' + text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } - let newPayload = { + const newPayload = { cmd: 'info', type: 'emote', nick: socket.nick, - text: `@${socket.nick} ${text}` + text: `@${socket.nick} ${text}`, }; if (socket.trip) { newPayload.trip = socket.trip; } // broadcast to channel peers - server.broadcast( newPayload, { channel: socket.channel}); -}; + server.broadcast(newPayload, { channel: socket.channel }); + + return true; +} // module hook functions -exports.initHooks = (server) => { +export function initHooks(server) { server.registerHook('in', 'chat', this.emoteCheck, 30); -}; +} // hooks chat commands checking for /me -exports.emoteCheck = (core, server, socket, payload) => { +export function emoteCheck(core, server, socket, payload) { if (typeof payload.text !== 'string') { return false; } if (payload.text.startsWith('/me ')) { - let input = payload.text.split(' '); + const input = payload.text.split(' '); // If there is no emote target parameter if (input[1] === undefined) { server.reply({ cmd: 'warn', - text: 'Refer to `/help emote` for instructions on how to use this command.' + text: 'Refer to `/help emote` for instructions on how to use this command.', }, socket); return false; } input.splice(0, 1); - let actionText = input.join(' '); + const actionText = input.join(' '); this.run(core, server, socket, { cmd: 'emote', - text: actionText + text: actionText, }); return false; } return payload; -}; +} -// module meta -exports.requiredData = ['text']; -exports.info = { +export const requiredData = ['text']; +export const info = { name: 'emote', description: 'Typical emote / action text', usage: ` API: { cmd: 'emote', text: '<emote/action text>' } - Text: /me <emote/action text>` + Text: /me <emote/action text>`, }; diff --git a/server/src/commands/core/help.js b/server/src/commands/core/help.js index 8eccdb6..25f8844 100644 --- a/server/src/commands/core/help.js +++ b/server/src/commands/core/help.js @@ -3,21 +3,21 @@ */ // module support functions -const stripIndents = require('common-tags').stripIndents; +const { stripIndents } = require('common-tags'); // module main -exports.run = async (core, server, socket, payload) => { +export async function run(core, server, socket, payload) { // check for spam - if (server.police.frisk(socket.remoteAddress, 2)) { + if (server.police.frisk(socket.address, 2)) { return server.reply({ cmd: 'warn', - text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.' + text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } // verify user input if (typeof payload.command !== 'undefined' && typeof payload.command !== 'string') { - return; + return true; } let reply = ''; @@ -27,21 +27,21 @@ exports.run = async (core, server, socket, payload) => { API: {cmd: 'help', command: '<command name>'}`; reply += '\n\n-------------------------------------\n\n'; - let categories = core.commands.categoriesList.sort(); - for (let i = 0, j = categories.length; i < j; i++) { - reply += `${categories[i].replace('../src/commands/', '').replace(/^\w/, c => c.toUpperCase())} Commands:\n`; - let catCommands = core.commands.all(categories[i]).sort((a, b) => a.info.name.localeCompare(b.info.name)); - reply += ` ${catCommands.map(c => `${c.info.name}`).join(', ')}\n\n`; + const categories = core.commands.categoriesList.sort(); + for (let i = 0, j = categories.length; i < j; i += 1) { + reply += `${categories[i].replace('../src/commands/', '').replace(/^\w/, (c) => c.toUpperCase())} Commands:\n`; + const catCommands = core.commands.all(categories[i]).sort((a, b) => a.info.name.localeCompare(b.info.name)); + reply += ` ${catCommands.map((c) => `${c.info.name}`).join(', ')}\n\n`; } } else { - let command = core.commands.get(payload.command); + const command = core.commands.get(payload.command); if (typeof command === 'undefined') { reply = 'Unknown command'; } else { reply = stripIndents`Name: ${command.info.name} Aliases: ${typeof command.info.aliases !== 'undefined' ? command.info.aliases.join(', ') : 'None'} - Category: ${command.info.category.replace('../src/commands/', '').replace(/^\w/, c => c.toUpperCase())} + Category: ${command.info.category.replace('../src/commands/', '').replace(/^\w/, (c) => c.toUpperCase())} Required Parameters: ${command.requiredData || 'None'}\n Description: ${command.info.description || '¯\_(ツ)_/¯'}\n Usage: ${command.info.usage || command.info.name}`; @@ -51,40 +51,41 @@ exports.run = async (core, server, socket, payload) => { // output reply server.reply({ cmd: 'info', - text: reply + text: reply, }, socket); -}; + + return true; +} // module hook functions -exports.initHooks = (server) => { +export function initHooks(server) { server.registerHook('in', 'chat', this.helpCheck, 28); -}; +} // hooks chat commands checking for /whisper -exports.helpCheck = (core, server, socket, payload) => { +export function helpCheck(core, server, socket, payload) { if (typeof payload.text !== 'string') { return false; } if (payload.text.startsWith('/help')) { - let input = payload.text.substr(1).split(' ', 2); + const input = payload.text.substr(1).split(' ', 2); this.run(core, server, socket, { cmd: input[0], - command: input[1] + command: input[1], }); return false; } return payload; -}; +} -// module meta -exports.info = { +export const info = { name: 'help', description: 'Outputs information about the servers current protocol', usage: ` API: { cmd: 'help', command: '<optional command name>' } - Text: /help <optional command name>` + Text: /help <optional command name>`, }; diff --git a/server/src/commands/core/invite.js b/server/src/commands/core/invite.js index 70393b1..1811e8b 100644 --- a/server/src/commands/core/invite.js +++ b/server/src/commands/core/invite.js @@ -6,47 +6,47 @@ const verifyNickname = (nick) => /^[a-zA-Z0-9_]{1,24}$/.test(nick); // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { // check for spam - if (server.police.frisk(socket.remoteAddress, 2)) { + if (server.police.frisk(socket.address, 2)) { return server.reply({ cmd: 'warn', - text: 'You are sending invites too fast. Wait a moment before trying again.' + text: 'You are sending invites too fast. Wait a moment before trying again.', }, socket); } // verify user input if (typeof data.nick !== 'string' || !verifyNickname(data.nick)) { - return; + return true; } // why would you invite yourself? - if (data.nick == socket.nick) { - return; + if (data.nick === socket.nick) { + return true; } // generate common channel - let channel = Math.random().toString(36).substr(2, 8); + const channel = Math.random().toString(36).substr(2, 8); // build and send invite - let payload = { + const payload = { cmd: 'info', type: 'invite', from: socket.nick, invite: channel, - text: `${socket.nick} invited you to ?${channel}` + text: `${socket.nick} invited you to ?${channel}`, }; - let inviteSent = server.broadcast( payload, { + const inviteSent = server.broadcast(payload, { channel: socket.channel, - nick: data.nick + nick: data.nick, }); // server indicates the user was not found if (!inviteSent) { return server.reply({ cmd: 'warn', - text: 'Could not find user in channel' + text: 'Could not find user in channel', }, socket); } @@ -55,18 +55,19 @@ exports.run = async (core, server, socket, data) => { cmd: 'info', type: 'invite', invite: channel, - text: `You invited ${data.nick} to ?${channel}` + text: `You invited ${data.nick} to ?${channel}`, }, socket); // stats are fun core.stats.increment('invites-sent'); -}; -// module meta -exports.requiredData = ['nick']; -exports.info = { + return true; +} + +export const requiredData = ['nick']; +export const info = { name: 'invite', description: 'Generates a unique (more or less) room name and passes it to two clients', usage: ` - API: { cmd: 'invite', nick: '<target nickname>' }` + API: { cmd: 'invite', nick: '<target nickname>' }`, }; diff --git a/server/src/commands/core/join.js b/server/src/commands/core/join.js index 965a8bc..644470e 100644 --- a/server/src/commands/core/join.js +++ b/server/src/commands/core/join.js @@ -6,7 +6,7 @@ const crypto = require('crypto'); const hash = (password) => { - let sha = crypto.createHash('sha256'); + const sha = crypto.createHash('sha256'); sha.update(password); return sha.digest('base64').substr(0, 6); }; @@ -15,15 +15,15 @@ const verifyNickname = (nick) => /^[a-zA-Z0-9_]{1,24}$/.test(nick); // exposed "login" function to allow hooks to verify user join events // returns object containing user info or string if error -exports.parseNickname = (core, data) => { - let userInfo = { +export function parseNickname(core, data) { + const userInfo = { nick: '', uType: 'user', trip: null, }; // seperate nick from password - let nickArray = data.nick.split('#', 2); + const nickArray = data.nick.split('#', 2); userInfo.nick = nickArray[0].trim(); if (!verifyNickname(userInfo.nick)) { @@ -31,90 +31,92 @@ exports.parseNickname = (core, data) => { return 'Nickname must consist of up to 24 letters, numbers, and underscores'; } - let password = nickArray[1]; + const password = nickArray[1]; if (hash(password + core.config.tripSalt) === core.config.adminTrip) { userInfo.uType = 'admin'; userInfo.trip = 'Admin'; - } else if (userInfo.nick.toLowerCase() == core.config.adminName.toLowerCase()) { // they've got the main-admin name while not being an admin + } else if (userInfo.nick.toLowerCase() === core.config.adminName.toLowerCase()) { + // they've got the main-admin name while not being an admin return 'You are not the admin, liar!'; } else if (password) { userInfo.trip = hash(password + core.config.tripSalt); } // TODO: disallow moderator impersonation - for (let mod of core.config.mods) { + // for (const mod of core.config.mods) { + core.config.mods.forEach((mod) => { if (userInfo.trip === mod.trip) { userInfo.uType = 'mod'; } - } + }); return userInfo; -}; +} // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { // check for spam - if (server.police.frisk(socket.remoteAddress, 3)) { + if (server.police.frisk(socket.address, 3)) { return server.reply({ cmd: 'warn', - text: 'You are joining channels too fast. Wait a moment and try again.' + text: 'You are joining channels too fast. Wait a moment and try again.', }, socket); } // calling socket already in a channel if (typeof socket.channel !== 'undefined') { - return; + return true; } // check user input if (typeof data.channel !== 'string' || typeof data.nick !== 'string') { - return; + return true; } - let channel = data.channel.trim(); + const channel = data.channel.trim(); if (!channel) { // must join a non-blank channel - return; + return true; } - let userInfo = this.parseNickname(core, data); + const userInfo = this.parseNickname(core, data); if (typeof userInfo === 'string') { return server.reply({ cmd: 'warn', - text: userInfo + text: userInfo, }, socket); } // check if the nickname already exists in the channel - let userExists = server.findSockets({ + const userExists = server.findSockets({ channel: data.channel, - nick: (targetNick) => targetNick.toLowerCase() === userInfo.nick.toLowerCase() + nick: (targetNick) => targetNick.toLowerCase() === userInfo.nick.toLowerCase(), }); if (userExists.length > 0) { // that nickname is already in that channel return server.reply({ cmd: 'warn', - text: 'Nickname taken' + text: 'Nickname taken', }, socket); } userInfo.userHash = server.getSocketHash(socket); // prepare to notify channel peers - let newPeerList = server.findSockets({ channel: data.channel }); - let nicks = []; + const newPeerList = server.findSockets({ channel: data.channel }); + const nicks = []; - let joinAnnouncement = { + const joinAnnouncement = { cmd: 'onlineAdd', nick: userInfo.nick, trip: userInfo.trip || 'null', - hash: userInfo.userHash + hash: userInfo.userHash, }; // send join announcement and prep online set - for (let i = 0, l = newPeerList.length; i < l; i++) { + for (let i = 0, l = newPeerList.length; i < l; i += 1) { server.reply(joinAnnouncement, newPeerList[i]); nicks.push(newPeerList[i].nick); } @@ -131,18 +133,19 @@ exports.run = async (core, server, socket, data) => { // reply with channel peer list server.reply({ cmd: 'onlineSet', - nicks: nicks + nicks, }, socket); // stats are fun core.stats.increment('users-joined'); -}; -// module meta -exports.requiredData = ['channel', 'nick']; -exports.info = { + return true; +} + +export const requiredData = ['channel', 'nick']; +export const info = { name: 'join', description: 'Place calling socket into target channel with target nick & broadcast event to channel', usage: ` - API: { cmd: 'join', nick: '<your nickname>', channel: '<target channel>' }` + API: { cmd: 'join', nick: '<your nickname>', channel: '<target channel>' }`, }; diff --git a/server/src/commands/core/morestats.js b/server/src/commands/core/morestats.js index a71729c..3cbf8f3 100644 --- a/server/src/commands/core/morestats.js +++ b/server/src/commands/core/morestats.js @@ -3,37 +3,38 @@ */ // module support functions -const stripIndents = require('common-tags').stripIndents; +const { stripIndents } = require('common-tags'); const formatTime = (time) => { let seconds = time[0] + time[1] / 1e9; let minutes = Math.floor(seconds / 60); - seconds = seconds % 60; + seconds %= 60; let hours = Math.floor(minutes / 60); - minutes = minutes % 60; + minutes %= 60; - let days = Math.floor(hours / 24); - hours = hours % 24; + const days = Math.floor(hours / 24); + hours %= 24; return `${days.toFixed(0)}d ${hours.toFixed(0)}h ${minutes.toFixed(0)}m ${seconds.toFixed(0)}s`; }; // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket) { // gather connection and channel count let ips = {}; let channels = {}; - for (let client of server.clients) { + // for (const client of server.clients) { + this.clients.forEach((client) => { if (client.channel) { channels[client.channel] = true; - ips[client.remoteAddress] = true; + ips[client.address] = true; } - } + }); - let uniqueClientCount = Object.keys(ips).length; - let uniqueChannels = Object.keys(channels).length; + const uniqueClientCount = Object.keys(ips).length; + const uniqueChannels = Object.keys(channels).length; ips = null; channels = null; @@ -49,40 +50,39 @@ exports.run = async (core, server, socket, data) => { users-banned: ${(core.stats.get('users-banned') || 0)} users-kicked: ${(core.stats.get('users-kicked') || 0)} stats-requested: ${(core.stats.get('stats-requested') || 0)} - server-uptime: ${formatTime(process.hrtime(core.stats.get('start-time')))}` + server-uptime: ${formatTime(process.hrtime(core.stats.get('start-time')))}`, }, socket); // stats are fun core.stats.increment('stats-requested'); -}; +} // module hook functions -exports.initHooks = (server) => { +export function initHooks(server) { server.registerHook('in', 'chat', this.statsCheck, 26); -}; +} // hooks chat commands checking for /stats -exports.statsCheck = (core, server, socket, payload) => { +export function statsCheck(core, server, socket, payload) { if (typeof payload.text !== 'string') { return false; } if (payload.text.startsWith('/stats')) { this.run(core, server, socket, { - cmd: 'morestats' + cmd: 'morestats', }); return false; } return payload; -}; +} -// module meta -exports.info = { +export const info = { name: 'morestats', description: 'Sends back current server stats to the calling client', usage: ` API: { cmd: 'morestats' } - Text: /stats` + Text: /stats`, }; diff --git a/server/src/commands/core/move.js b/server/src/commands/core/move.js index 8e97a06..7eda88c 100644 --- a/server/src/commands/core/move.js +++ b/server/src/commands/core/move.js @@ -3,67 +3,67 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { // check for spam - if (server.police.frisk(socket.remoteAddress, 6)) { + if (server.police.frisk(socket.address, 6)) { return server.reply({ cmd: 'warn', - text: 'You are changing channels too fast. Wait a moment before trying again.' + text: 'You are changing channels too fast. Wait a moment before trying again.', }, socket); } // check user input if (typeof data.channel !== 'string') { - return; + return true; } if (data.channel === socket.channel) { // they are trying to rejoin the channel - return; + return true; } // check that the nickname isn't already in target channel const currentNick = socket.nick.toLowerCase(); - let userExists = server.findSockets({ + const userExists = server.findSockets({ channel: data.channel, - nick: (targetNick) => targetNick.toLowerCase() === currentNick + nick: (targetNick) => targetNick.toLowerCase() === currentNick, }); if (userExists.length > 0) { // That nickname is already in that channel - return; + return true; } // broadcast leave notice to peers - let peerList = server.findSockets({ channel: socket.channel }); + const peerList = server.findSockets({ channel: socket.channel }); if (peerList.length > 1) { - for (let i = 0, l = peerList.length; i < l; i++) { + for (let i = 0, l = peerList.length; i < l; i += 1) { server.reply({ cmd: 'onlineRemove', - nick: peerList[i].nick + nick: peerList[i].nick, }, socket); - if (socket.nick !== peerList[i].nick){ + if (socket.nick !== peerList[i].nick) { server.reply({ cmd: 'onlineRemove', - nick: socket.nick + nick: socket.nick, }, peerList[i]); } } } // broadcast join notice to new peers - let newPeerList = server.findSockets({ channel: data.channel }); - let moveAnnouncement = { + const newPeerList = server.findSockets({ channel: data.channel }); + const moveAnnouncement = { cmd: 'onlineAdd', nick: socket.nick, trip: socket.trip || 'null', - hash: socket.hash + hash: socket.hash, }; - let nicks = []; + const nicks = []; - for (let i = 0, l = newPeerList.length; i < l; i++) { + for (let i = 0, l = newPeerList.length; i < l; i += 1) { server.reply(moveAnnouncement, newPeerList[i]); nicks.push(newPeerList[i].nick); } @@ -73,18 +73,19 @@ exports.run = async (core, server, socket, data) => { // reply with new user list server.reply({ cmd: 'onlineSet', - nicks: nicks + nicks, }, socket); // commit change socket.channel = data.channel; -}; -// module meta -exports.requiredData = ['channel']; -exports.info = { + return true; +} + +export const requiredData = ['channel']; +export const info = { name: 'move', description: 'This will change your current channel to the new one provided', usage: ` - API: { cmd: 'move', channel: '<target channel>' }` + API: { cmd: 'move', channel: '<target channel>' }`, }; diff --git a/server/src/commands/core/ping.js b/server/src/commands/core/ping.js index 1e710e5..7d8623d 100644 --- a/server/src/commands/core/ping.js +++ b/server/src/commands/core/ping.js @@ -3,12 +3,11 @@ */ // module main -exports.run = async (core, server, socket, data) => { - return; -}; +export async function run() { + +} -// module meta -exports.info = { +export const info = { name: 'ping', - description: 'This module is only in place to supress error notices legacy sources may get' + description: 'This module is only in place to supress error notices legacy sources may get', }; diff --git a/server/src/commands/core/stats.js b/server/src/commands/core/stats.js index ff4b1ef..8badd5b 100644 --- a/server/src/commands/core/stats.js +++ b/server/src/commands/core/stats.js @@ -3,19 +3,20 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket) { // gather connection and channel count let ips = {}; let channels = {}; - for (let client of server.clients) { + // for (const client of server.clients) { + this.clients.forEach((client) => { if (client.channel) { channels[client.channel] = true; - ips[client.remoteAddress] = true; + ips[client.address] = true; } - } + }); - let uniqueClientCount = Object.keys(ips).length; - let uniqueChannels = Object.keys(channels).length; + const uniqueClientCount = Object.keys(ips).length; + const uniqueChannels = Object.keys(channels).length; ips = null; channels = null; @@ -23,17 +24,16 @@ exports.run = async (core, server, socket, data) => { // dispatch info server.reply({ cmd: 'info', - text: `${uniqueClientCount} unique IPs in ${uniqueChannels} channels` + text: `${uniqueClientCount} unique IPs in ${uniqueChannels} channels`, }, socket); // stats are fun core.stats.increment('stats-requested'); -}; +} -// module meta -exports.info = { +export const info = { name: 'stats', description: 'Sends back legacy server stats to the calling client', usage: ` - API: { cmd: 'stats' }` + API: { cmd: 'stats' }`, }; diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index 109889d..1cfa157 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -11,36 +11,38 @@ const parseText = (text) => { return false; } + let sanitizedText = text; + // strip newlines from beginning and end - text = text.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); + sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); // replace 3+ newlines with just 2 newlines - text = text.replace(/\n{3,}/g, "\n\n"); + sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n'); - return text; + return sanitizedText; }; // module main -exports.run = async (core, server, socket, payload) => { +export async function run(core, server, socket, payload) { // check user input - let text = parseText(payload.text); + const text = parseText(payload.text); if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.remoteAddress, 13); + return server.police.frisk(socket.address, 13); } // check for spam - let score = text.length / 83 / 4; - if (server.police.frisk(socket.remoteAddress, score)) { + const score = text.length / 83 / 4; + if (server.police.frisk(socket.address, score)) { return server.reply({ cmd: 'warn', - text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.' + text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } - let targetNick = payload.nick; + const targetNick = payload.nick; if (!verifyNickname(targetNick)) { - return; + return true; } // find target user @@ -49,18 +51,18 @@ exports.run = async (core, server, socket, payload) => { if (targetClient.length === 0) { return server.reply({ cmd: 'warn', - text: 'Could not find user in channel' + text: 'Could not find user in channel', }, socket); } - targetClient = targetClient[0]; + [targetClient] = targetClient; server.reply({ cmd: 'info', type: 'whisper', from: socket.nick, trip: socket.trip || 'null', - text: `${socket.nick} whispered: ${text}` + text: `${socket.nick} whispered: ${text}`, }, targetClient); targetClient.whisperReply = socket.nick; @@ -68,42 +70,44 @@ exports.run = async (core, server, socket, payload) => { server.reply({ cmd: 'info', type: 'whisper', - text: `You whispered to @${targetNick}: ${text}` + text: `You whispered to @${targetNick}: ${text}`, }, socket); -}; + + return true; +} // module hook functions -exports.initHooks = (server) => { +export function initHooks(server) { server.registerHook('in', 'chat', this.whisperCheck, 20); -}; +} // hooks chat commands checking for /whisper -exports.whisperCheck = (core, server, socket, payload) => { +export function whisperCheck(core, server, socket, payload) { if (typeof payload.text !== 'string') { return false; } if (payload.text.startsWith('/whisper')) { - let input = payload.text.split(' '); + const input = payload.text.split(' '); // If there is no nickname target parameter if (input[1] === undefined) { server.reply({ cmd: 'warn', - text: 'Refer to `/help whisper` for instructions on how to use this command.' + text: 'Refer to `/help whisper` for instructions on how to use this command.', }, socket); return false; } - let target = input[1].replace(/@/g, ''); + const target = input[1].replace(/@/g, ''); input.splice(0, 2); - let whisperText = input.join(' '); + const whisperText = input.join(' '); this.run(core, server, socket, { cmd: 'whisper', nick: target, - text: whisperText + text: whisperText, }); return false; @@ -113,35 +117,34 @@ exports.whisperCheck = (core, server, socket, payload) => { if (typeof socket.whisperReply === 'undefined') { server.reply({ cmd: 'warn', - text: 'Cannot reply to nobody' + text: 'Cannot reply to nobody', }, socket); return false; } - let input = payload.text.split(' '); + const input = payload.text.split(' '); input.splice(0, 1); - let whisperText = input.join(' '); + const whisperText = input.join(' '); this.run(core, server, socket, { cmd: 'whisper', nick: socket.whisperReply, - text: whisperText + text: whisperText, }); return false; } return payload; -}; +} -// module meta -exports.requiredData = ['nick', 'text']; -exports.info = { +export const requiredData = ['nick', 'text']; +export const info = { name: 'whisper', description: 'Display text on targets screen that only they can see', usage: ` API: { cmd: 'whisper', nick: '<target name>', text: '<text to whisper>' } Text: /whisper <target name> <text to whisper> - Alt Text: /r <text to whisper, this will auto reply to the last person who whispered to you>` + Alt Text: /r <text to whisper, this will auto reply to the last person who whispered to you>`, }; diff --git a/server/src/commands/internal/disconnect.js b/server/src/commands/internal/disconnect.js index 520f8cb..07a125e 100644 --- a/server/src/commands/internal/disconnect.js +++ b/server/src/commands/internal/disconnect.js @@ -4,28 +4,29 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { if (data.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore - return server.police.frisk(socket.remoteAddress, 20); + return server.police.frisk(socket.address, 20); } // send leave notice to client peers if (socket.channel) { server.broadcast({ cmd: 'onlineRemove', - nick: socket.nick + nick: socket.nick, }, { channel: socket.channel }); } // commit close just in case socket.terminate(); -}; -// module meta -exports.requiredData = ['cmdKey']; -exports.info = { + return true; +} + +export const requiredData = ['cmdKey']; +export const info = { name: 'disconnect', usage: 'Internal Use Only', - description: 'Internally used to relay `onlineRemove` event to clients' + description: 'Internally used to relay `onlineRemove` event to clients', }; diff --git a/server/src/commands/internal/legacylayer.js b/server/src/commands/internal/legacylayer.js index 50f5fd7..c0daa13 100644 --- a/server/src/commands/internal/legacylayer.js +++ b/server/src/commands/internal/legacylayer.js @@ -3,18 +3,19 @@ */ // module main -exports.run = async (core, server, socket, data) => { - return; -}; +export async function run(core, server, socket, data) { + /** + * @todo + */ +} // module hook functions -exports.initHooks = (server) => { +export function initHooks(server) { // module is only a placeholder - //server.registerHook('out', '', this.); -}; + // server.registerHook('out', '', this.); +} -// module meta -exports.info = { +export const info = { name: 'legacylayer', - description: 'This module adjusts outgoing data, making it compatible with legacy clients' + description: 'This module adjusts outgoing data, making it compatible with legacy clients', }; diff --git a/server/src/commands/internal/socketreply.js b/server/src/commands/internal/socketreply.js index 5dadaf6..1ba8df2 100644 --- a/server/src/commands/internal/socketreply.js +++ b/server/src/commands/internal/socketreply.js @@ -3,20 +3,21 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket, data) { if (data.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore - return server.police.frisk(socket.remoteAddress, 20); + return server.police.frisk(socket.address, 20); } // send warning to target socket server.reply({ cmd: 'warn', text: data.text }, socket); -}; -// module meta -exports.requiredData = ['cmdKey', 'text']; -exports.info = { + return true; +} + +export const requiredData = ['cmdKey', 'text']; +export const info = { name: 'socketreply', usage: 'Internal Use Only', - description: 'Internally used to relay warnings to clients' + description: 'Internally used to relay warnings to clients', }; diff --git a/server/src/commands/mod/ban.js b/server/src/commands/mod/ban.js index 9c8eb4f..dd5f01e 100644 --- a/server/src/commands/mod/ban.js +++ b/server/src/commands/mod/ban.js @@ -3,53 +3,53 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(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); + return server.police.frisk(socket.address, 10); } // check user input if (typeof data.nick !== 'string') { - return; + return true; } // find target user - let targetNick = data.nick; + const targetNick = data.nick; let badClient = server.findSockets({ channel: socket.channel, nick: targetNick }); if (badClient.length === 0) { return server.reply({ cmd: 'warn', - text: 'Could not find user in channel' + text: 'Could not find user in channel', }, socket); } - badClient = badClient[0]; + [badClient] = badClient; // i guess banning mods or admins isn't the best idea? if (badClient.uType !== 'user') { return server.reply({ cmd: 'warn', - text: 'Cannot ban other mods, how rude' + text: 'Cannot ban other mods, how rude', }, socket); } // commit arrest record - server.police.arrest(badClient.remoteAddress, badClient.hash); + server.police.arrest(badClient.address, badClient.hash); console.log(`${socket.nick} [${socket.trip}] banned ${targetNick} in ${socket.channel}`); // notify normal users server.broadcast({ cmd: 'info', - text: `Banned ${targetNick}` + text: `Banned ${targetNick}`, }, { channel: socket.channel, uType: 'user' }); // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick} banned ${targetNick} in ${socket.channel}, userhash: ${badClient.hash}` + text: `${socket.nick} banned ${targetNick} in ${socket.channel}, userhash: ${badClient.hash}`, }, { uType: 'mod' }); // force connection closed @@ -57,13 +57,14 @@ exports.run = async (core, server, socket, data) => { // stats are fun core.stats.increment('users-banned'); -}; -// module meta -exports.requiredData = ['nick']; -exports.info = { + return true; +} + +export const requiredData = ['nick']; +export const info = { name: 'ban', description: 'Disconnects the target nickname in the same channel as calling socket & adds to ratelimiter', usage: ` - API: { cmd: 'ban', nick: '<target nickname>' }` + API: { cmd: 'ban', nick: '<target nickname>' }`, }; diff --git a/server/src/commands/mod/dumb.js b/server/src/commands/mod/dumb.js index d5e8fee..644bd4f 100644 --- a/server/src/commands/mod/dumb.js +++ b/server/src/commands/mod/dumb.js @@ -4,22 +4,22 @@ */ // module constructor -exports.init = (core) => { +export function init(core) { if (typeof core.muzzledHashes === 'undefined') { core.muzzledHashes = {}; } -}; +} // module main -exports.run = async (core, server, socket, data) => { +export async function run(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); + return server.police.frisk(socket.address, 10); } // check user input if (typeof data.nick !== 'string') { - return; + return true; } // find target user @@ -28,56 +28,58 @@ exports.run = async (core, server, socket, data) => { if (badClient.length === 0) { return server.reply({ cmd: 'warn', - text: 'Could not find user in channel' + text: 'Could not find user in channel', }, socket); } - badClient = badClient[0]; + [badClient] = badClient; // likely dont need this, muting mods and admins is fine if (badClient.uType !== 'user') { return server.reply({ cmd: 'warn', - text: 'This trick wont work on mods and admin' + text: 'This trick wont work on mods and admin', }, socket); } // store hash in mute list - let record = core.muzzledHashes[badClient.hash] = { - dumb: true - } + const record = core.muzzledHashes[badClient.hash] = { + dumb: true, + }; // store allies if needed - if(data.allies && Array.isArray(data.allies)){ - record.allies = data.allies; + if (data.allies && Array.isArray(data.allies)) { + record.allies = data.allies; } // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick} muzzled ${data.nick} in ${socket.channel}, userhash: ${badClient.hash}` + text: `${socket.nick} muzzled ${data.nick} in ${socket.channel}, userhash: ${badClient.hash}`, }, { uType: 'mod' }); -}; + + return true; +} // module hook functions -exports.initHooks = (server) => { +export function initHooks(server) { server.registerHook('in', 'chat', this.chatCheck, 25); server.registerHook('in', 'invite', this.inviteCheck, 25); // 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) => { +export function chatCheck(core, server, socket, payload) { if (typeof payload.text !== 'string') { return false; } - if(core.muzzledHashes[socket.hash]){ + if (core.muzzledHashes[socket.hash]) { // build fake chat payload - mutedPayload = { + const mutedPayload = { cmd: 'chat', nick: socket.nick, - text: payload.text + text: payload.text, }; if (socket.trip) { @@ -85,50 +87,59 @@ exports.chatCheck = (core, server, socket, payload) => { } // broadcast to any duplicate connections in channel - server.broadcast( mutedPayload, { channel: socket.channel, hash: socket.hash }); + 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 }); + 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); + /** + * Blanket "spam" protection. + * May expose the ratelimiting lines from `chat` and use that + * @todo one day #lazydev + */ + server.police.frisk(socket.address, 9); return false; } return payload; -}; +} // shadow-prevent all invites from muzzled users -exports.inviteCheck = (core, server, socket, payload) => { +export function inviteCheck(core, server, socket, payload) { if (typeof payload.nick !== 'string') { return false; } - if(core.muzzledHashes[socket.hash]){ + if (core.muzzledHashes[socket.hash]) { // generate common channel - let channel = Math.random().toString(36).substr(2, 8); + const channel = Math.random().toString(36).substr(2, 8); // send fake reply server.reply({ cmd: 'info', - text: `You invited ${payload.nick} to ?${channel}` + text: `You invited ${payload.nick} to ?${channel}`, }, socket); return false; } return payload; -}; +} -// module meta -exports.requiredData = ['nick']; -exports.info = { +export const requiredData = ['nick']; +export const info = { name: 'dumb', description: 'Globally shadow mute a connection. Optional allies array will see muted messages.', usage: ` - API: { cmd: 'dumb', nick: '<target nick>', allies: ['<optional nick array>', ...] }` + API: { cmd: 'dumb', nick: '<target nick>', allies: ['<optional nick array>', ...] }`, }; -exports.info.aliases = ['muzzle', 'mute']; +info.aliases = ['muzzle', 'mute']; diff --git a/server/src/commands/mod/kick.js b/server/src/commands/mod/kick.js index f3bc7ca..cb01d5c 100644 --- a/server/src/commands/mod/kick.js +++ b/server/src/commands/mod/kick.js @@ -3,37 +3,37 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(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); + return server.police.frisk(socket.address, 10); } // check user input if (typeof data.nick !== 'string') { if (typeof data.nick !== 'object' && !Array.isArray(data.nick)) { - return; + return true; } } // find target user(s) - let badClients = server.findSockets({ channel: socket.channel, nick: data.nick }); + const badClients = server.findSockets({ channel: socket.channel, nick: data.nick }); if (badClients.length === 0) { return server.reply({ cmd: 'warn', - text: 'Could not find user(s) in channel' + text: 'Could not find user(s) in channel', }, socket); } // check if found targets are kickable, commit kick let newChannel = ''; - let kicked = []; - for (let i = 0, j = badClients.length; i < j; i++) { + const kicked = []; + for (let i = 0, j = badClients.length; i < j; i += 1) { if (badClients[i].uType !== 'user') { server.reply({ cmd: 'warn', - text: 'Cannot kick other mods, how rude' + text: 'Cannot kick other mods, how rude', }, socket); } else { newChannel = Math.random().toString(36).substr(2, 8); @@ -42,7 +42,7 @@ exports.run = async (core, server, socket, data) => { // inform mods with where they were sent server.broadcast({ cmd: 'info', - text: `${badClients[i].nick} was banished to ?${newChannel}` + text: `${badClients[i].nick} was banished to ?${newChannel}`, }, { channel: socket.channel, uType: 'mod' }); kicked.push(badClients[i].nick); @@ -51,32 +51,33 @@ exports.run = async (core, server, socket, data) => { } if (kicked.length === 0) { - return; + return true; } // broadcast client leave event - for (let i = 0, j = kicked.length; i < j; i++) { + for (let i = 0, j = kicked.length; i < j; i += 1) { server.broadcast({ cmd: 'onlineRemove', - nick: kicked[i] + nick: kicked[i], }, { channel: socket.channel }); } // publicly broadcast kick event server.broadcast({ cmd: 'info', - text: `Kicked ${kicked.join(', ')}` + text: `Kicked ${kicked.join(', ')}`, }, { channel: socket.channel, uType: 'user' }); // stats are fun core.stats.increment('users-kicked', kicked.length); -}; -// module meta -exports.requiredData = ['nick']; -exports.info = { + return true; +} + +export const requiredData = ['nick']; +export const info = { name: 'kick', description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings', usage: ` - API: { cmd: 'kick', nick: '<target nick>' }` + API: { cmd: 'kick', nick: '<target nick>' }`, }; diff --git a/server/src/commands/mod/moveuser.js b/server/src/commands/mod/moveuser.js index c7fc4bf..b55c207 100644 --- a/server/src/commands/mod/moveuser.js +++ b/server/src/commands/mod/moveuser.js @@ -3,79 +3,79 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(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); + return server.police.frisk(socket.address, 10); } // check user input if (typeof data.nick !== 'string' || typeof data.channel !== 'string') { - return; + return true; } if (data.channel === socket.channel) { // moving them into the same channel? y u do this? - return; + return true; } - let badClients = server.findSockets({ channel: socket.channel, nick: data.nick }); + const 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' + text: 'Could not find user in channel', }, socket); } - let badClient = badClients[0]; + const badClient = badClients[0]; if (badClient.uType !== 'user') { return server.reply({ cmd: 'warn', - text: 'Cannot move other mods, how rude' + text: 'Cannot move other mods, how rude', }, socket); } const currentNick = badClient.nick.toLowerCase(); - let userExists = server.findSockets({ + const userExists = server.findSockets({ channel: data.channel, - nick: (targetNick) => targetNick.toLowerCase() === currentNick + nick: (targetNick) => targetNick.toLowerCase() === currentNick, }); if (userExists.length > 0) { // That nickname is already in that channel - return; + return true; } - let peerList = server.findSockets({ channel: socket.channel }); + const peerList = server.findSockets({ channel: socket.channel }); if (peerList.length > 1) { - for (let i = 0, l = peerList.length; i < l; i++) { + for (let i = 0, l = peerList.length; i < l; i += 1) { server.reply({ cmd: 'onlineRemove', - nick: peerList[i].nick + nick: peerList[i].nick, }, badClient); - if (badClient.nick !== peerList[i].nick){ + if (badClient.nick !== peerList[i].nick) { server.reply({ cmd: 'onlineRemove', - nick: badClient.nick + nick: badClient.nick, }, peerList[i]); } } } - let newPeerList = server.findSockets({ channel: data.channel }); - let moveAnnouncement = { + const newPeerList = server.findSockets({ channel: data.channel }); + const moveAnnouncement = { cmd: 'onlineAdd', nick: badClient.nick, trip: badClient.trip || 'null', - hash: server.getSocketHash(badClient) + hash: server.getSocketHash(badClient), }; - let nicks = []; + const nicks = []; - for (let i = 0, l = newPeerList.length; i < l; i++) { + for (let i = 0, l = newPeerList.length; i < l; i += 1) { server.reply(moveAnnouncement, newPeerList[i]); nicks.push(newPeerList[i].nick); } @@ -84,22 +84,23 @@ exports.run = async (core, server, socket, data) => { server.reply({ cmd: 'onlineSet', - nicks: nicks + nicks, }, badClient); badClient.channel = data.channel; - server.broadcast( { + server.broadcast({ cmd: 'info', - text: `${badClient.nick} was moved into ?${data.channel}` + text: `${badClient.nick} was moved into ?${data.channel}`, }, { channel: data.channel }); -}; -// module meta -exports.requiredData = ['nick', 'channel']; -exports.info = { + return true; +} + +export const requiredData = ['nick', 'channel']; +export const info = { name: 'moveuser', description: 'This will move the target user nick into another channel', usage: ` - API: { cmd: 'moveuser', nick: '<target nick>', channel: '<new channel>' }` + 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 23fc4de..5514545 100644 --- a/server/src/commands/mod/speak.js +++ b/server/src/commands/mod/speak.js @@ -3,32 +3,32 @@ * Author: simple */ - // module constructor - exports.init = (core) => { - if (typeof core.muzzledHashes === 'undefined') { - core.muzzledHashes = {}; - } - }; +// module constructor +export function init(core) { + if (typeof core.muzzledHashes === 'undefined') { + core.muzzledHashes = {}; + } +} // module main -exports.run = async (core, server, socket, data) => { +export async function run(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); + return server.police.frisk(socket.address, 10); } // check user input if (typeof data.ip !== 'string' && typeof data.hash !== 'string') { return server.reply({ cmd: 'warn', - text: "hash:'targethash' or ip:'1.2.3.4' is required" + text: "hash:'targethash' or ip:'1.2.3.4' is required", }, socket); } // find target & remove mute status let target; if (typeof data.ip === 'string') { - target = getSocketHash(data.ip); + target = server.getSocketHash(data.ip); } else { target = data.hash; } @@ -38,15 +38,16 @@ exports.run = async (core, server, socket, data) => { // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick} unmuzzled : ${target}` + text: `${socket.nick} unmuzzled : ${target}`, }, { uType: 'mod' }); -}; -// module meta -exports.info = { + return true; +} + +export const info = { name: 'speak', description: 'Pardon a dumb user to be able to speak again', usage: ` - API: { cmd: 'speak', ip/hash: '<target ip or hash' }` + API: { cmd: 'speak', ip/hash: '<target ip or hash' }`, }; -exports.info.aliases = ['unmuzzle', 'unmute']; +info.aliases = ['unmuzzle', 'unmute']; diff --git a/server/src/commands/mod/unban.js b/server/src/commands/mod/unban.js index 6744d9d..0d1e469 100644 --- a/server/src/commands/mod/unban.js +++ b/server/src/commands/mod/unban.js @@ -3,22 +3,23 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(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); + return server.police.frisk(socket.address, 10); } // check user input if (typeof data.ip !== 'string' && typeof data.hash !== 'string') { return server.reply({ cmd: 'warn', - text: "hash:'targethash' or ip:'1.2.3.4' is required" + text: "hash:'targethash' or ip:'1.2.3.4' is required", }, socket); } // find target - let mode, target; + let mode; let + target; if (typeof data.ip === 'string') { mode = 'ip'; target = data.ip; @@ -39,23 +40,24 @@ exports.run = async (core, server, socket, data) => { // reply with success server.reply({ cmd: 'info', - text: `Unbanned ${target}` + text: `Unbanned ${target}`, }, socket); // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick} unbanned: ${target}` + text: `${socket.nick} unbanned: ${target}`, }, { uType: 'mod' }); // stats are fun core.stats.decrement('users-banned'); -}; -// module meta -exports.info = { + return true; +} + +export const info = { name: 'unban', description: 'Removes target ip from the ratelimiter', usage: ` - API: { cmd: 'unban', ip/hash: '<target ip or hash>' }` + 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 index c285b80..49eeee5 100644 --- a/server/src/commands/mod/unbanall.js +++ b/server/src/commands/mod/unbanall.js @@ -3,34 +3,35 @@ */ // module main -exports.run = async (core, server, socket, data) => { +export async function run(core, server, socket) { // increase rate limit chance and ignore if not admin or mod if (socket.uType === 'user') { - return server.police.frisk(socket.remoteAddress, 10); + return server.police.frisk(socket.address, 10); } // remove arrest records - server.police.records = {}; + server.police.clear(); console.log(`${socket.nick} [${socket.trip}] unbanned all`); // reply with success server.reply({ cmd: 'info', - text: `Unbanned all ip addresses` + text: 'Unbanned all ip addresses', }, socket); // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick} unbanned all ip addresses` + text: `${socket.nick} unbanned all ip addresses`, }, { uType: 'mod' }); -}; -// module meta -exports.info = { + return true; +} + +export const info = { name: 'unbanall', description: 'Clears all banned ip addresses', usage: ` - API: { cmd: 'unbanall' }` + API: { cmd: 'unbanall' }`, }; |