1
0
mirror of https://github.com/hack-chat/main.git synced 2024-03-22 13:20:33 +08:00

normalized

This commit is contained in:
marzavec 2020-09-17 00:44:32 -05:00
parent 6266b1432d
commit 72324050f5
45 changed files with 1873 additions and 241 deletions

14
.editorconfig Normal file
View File

@ -0,0 +1,14 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false

15
.eslintrc.js Normal file
View File

@ -0,0 +1,15 @@
module.exports = {
env: {
browser: true,
commonjs: true,
es2021: true,
},
extends: [
'airbnb-base',
],
parserOptions: {
ecmaVersion: 12,
},
rules: {
},
};

107
.gitattributes vendored Normal file
View File

@ -0,0 +1,107 @@
# From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes
# Handle line endings automatically for files detected as text
# and leave all files detected as binary untouched.
* text=auto
#
# The above will handle all files NOT found below
#
#
## These files are text and should be normalized (Convert crlf => lf)
#
# source code
*.php text
*.css text
*.sass text
*.scss text
*.less text
*.styl text
*.js text eol=lf
*.coffee text
*.json text
*.htm text
*.html text
*.xml text
*.svg text
*.txt text
*.ini text
*.inc text
*.pl text
*.rb text
*.py text
*.scm text
*.sql text
*.sh text
*.bat text
# templates
*.ejs text
*.hbt text
*.jade text
*.haml text
*.hbs text
*.dot text
*.tmpl text
*.phtml text
# server config
.htaccess text
.nginx.conf text
# git config
.gitattributes text
.gitignore text
.gitconfig text
# code analysis config
.jshintrc text
.jscsrc text
.jshintignore text
.csslintrc text
# misc config
*.yaml text
*.yml text
.editorconfig text
# build config
*.npmignore text
*.bowerrc text
# Heroku
Procfile text
.slugignore text
# Documentation
*.md text
LICENSE text
AUTHORS text
#
## These files are binary and should be left untouched
#
# (binary is a macro for -text -diff)
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.mov binary
*.mp4 binary
*.mp3 binary
*.flv binary
*.fla binary
*.swf binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.eot binary
*.woff binary
*.pyc binary
*.pdf binary

1407
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -18,14 +18,20 @@
"clear": "pm2 flush",
"status": "pm2 list",
"refresh": "pm2 flush && pm2 stop pm2.config.js && pm2 delete pm2.config.js",
"postinstall": "cd ./server && npm install && npm run config"
"postinstall": "cd ./server && npm install && npm run config",
"lint": "eslint --ignore-path .gitignore -- ./server ",
"lint:fix": "eslint --ignore-path .gitignore --fix -- ./server "
},
"author": "Marzavec",
"license": "WTFPL",
"dependencies": {
"esm": "^3.2.25",
"http-server": "^0.12.3",
"pm2": "^4.4.1",
"react-icons": "^3.11.0"
"pm2": "^4.4.1"
},
"devDependencies": {
"eslint": "^7.9.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-plugin-import": "^2.22.0"
}
}

View File

@ -6,7 +6,7 @@
*/
// import and initialize the core application
import { CoreApp } from './src/serverLib/CoreApp';
import CoreApp from './src/serverLib/CoreApp';
const coreApp = new CoreApp();
coreApp.init();

View File

@ -5,17 +5,19 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin
if (!UAC.isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
}
// add new trip to config
core.config.mods.push({ trip: data.trip });
core.config.mods.push({ trip: payload.trip });
// find targets current connections
const newMod = server.findSockets({ trip: data.trip });
const newMod = server.findSockets({ trip: payload.trip });
if (newMod.length !== 0) {
for (let i = 0, l = newMod.length; i < l; i += 1) {
// upgrade privilages
@ -33,13 +35,13 @@ export async function run(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: ${payload.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: ${payload.trip}`,
}, { level: UAC.isModerator });
return true;

View File

@ -1,3 +1,7 @@
/* eslint no-unused-vars: 0 */
/* eslint no-restricted-syntax: 0 */
/* eslint guard-for-in: 0 */
/*
Description: Outputs all current channels and their user nicks
*/
@ -5,7 +9,7 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket) {
export async function run({ server, socket }) {
// increase rate limit chance and ignore if not admin
if (!UAC.isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);

View File

@ -5,7 +5,9 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin
if (!UAC.isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
@ -26,8 +28,8 @@ export async function run(core, server, socket, data) {
${loadResult}`;
}
if (typeof data.reason !== 'undefined') {
loadResult += `\nReason: ${data.reason}`;
if (typeof payload.reason !== 'undefined') {
loadResult += `\nReason: ${payload.reason}`;
}
// send results to moderators (which the user using this command is higher than)

View File

@ -5,17 +5,20 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin
if (!UAC.isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
}
// remove trip from config
core.config.mods = core.config.mods.filter((mod) => mod.trip !== data.trip);
// eslint-disable-next-line no-param-reassign
core.config.mods = core.config.mods.filter((mod) => mod.trip !== payload.trip);
// find targets current connections
const targetMod = server.findSockets({ trip: data.trip });
const targetMod = server.findSockets({ trip: payload.trip });
if (targetMod.length !== 0) {
for (let i = 0, l = targetMod.length; i < l; i += 1) {
// downgrade privilages
@ -34,14 +37,14 @@ export async function run(core, server, socket, data) {
server.reply({
cmd: 'info',
text: `Removed mod trip: ${
data.trip
payload.trip
}, remember to run 'saveconfig' to make it permanent`,
}, socket);
// notify all mods
server.broadcast({
cmd: 'info',
text: `Removed mod: ${data.trip}`,
text: `Removed mod: ${payload.trip}`,
}, { level: UAC.isModerator });
return true;

View File

@ -5,7 +5,7 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket) {
export async function run({ core, server, socket }) {
// increase rate limit chance and ignore if not admin
if (!UAC.isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);

View File

@ -5,7 +5,7 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({ server, socket, payload }) {
// increase rate limit chance and ignore if not admin
if (!UAC.isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
@ -14,7 +14,7 @@ export async function run(core, server, socket, data) {
// send text to all channels
server.broadcast({
cmd: 'info',
text: `Server Notice: ${data.text}`,
text: `Server Notice: ${payload.text}`,
}, {});
return true;

View File

@ -1,3 +1,5 @@
/* eslint eqeqeq: 0 */
/*
Description: Allows calling client to change their current nickname
*/
@ -5,7 +7,9 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
if (server.police.frisk(socket.address, 6)) {
return server.reply({
cmd: 'warn', // @todo Remove english and change to numeric id
@ -14,14 +18,14 @@ export async function run(core, server, socket, data) {
}
// verify user data is string
if (typeof data.nick !== 'string') {
if (typeof payload.nick !== 'string') {
return true;
}
const previousNick = socket.nick;
// make sure requested nickname meets standards
const newNick = data.nick.trim();
const newNick = payload.nick.trim();
if (!UAC.verifyNickname(newNick)) {
return server.reply({
cmd: 'warn', // @todo Remove english and change to numeric id
@ -30,7 +34,7 @@ export async function run(core, server, socket, data) {
}
// prevent admin impersonation
// TODO: prevent mod impersonation
// @todo prevent mod impersonation
if (newNick.toLowerCase() === core.config.adminName.toLowerCase()) {
server.police.frisk(socket.address, 4);
@ -50,9 +54,9 @@ export async function run(core, server, socket, data) {
// find any sockets that have the same nickname
const userExists = server.findSockets({
channel: socket.channel,
nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase() &&
nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase()
// Allow them to rename themselves to a different case
targetNick != previousNick,
&& targetNick != previousNick,
});
// return error if found
@ -65,7 +69,7 @@ export async function run(core, server, socket, data) {
}
// build join and leave notices
// TODO: this is a legacy client holdover, name changes in the future will
// @todo this is a legacy client holdover, name changes in the future will
// have thieir own event
const leaveNotice = {
cmd: 'onlineRemove',
@ -90,7 +94,7 @@ export async function run(core, server, socket, data) {
}, { channel: socket.channel });
// commit change to nickname
socket.nick = newNick;
socket.nick = newNick; // eslint-disable-line no-param-reassign
return true;
}
@ -101,7 +105,9 @@ export function initHooks(server) {
}
// hooks chat commands checking for /nick
export function nickCheck(core, server, socket, payload) {
export function nickCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
@ -121,9 +127,14 @@ export function nickCheck(core, server, socket, payload) {
const newNick = input[1].replace(/@/g, '');
this.run(core, server, socket, {
cmd: 'changenick',
nick: newNick,
this.run({
core,
server,
socket,
payload: {
cmd: 'changenick',
nick: newNick,
},
});
return false;

View File

@ -22,9 +22,11 @@ const parseText = (text) => {
};
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// check user input
const text = parseText(data.text);
const text = parseText(payload.text);
if (!text) {
// lets not send objects or empty text, yea?
@ -41,7 +43,7 @@ export async function run(core, server, socket, data) {
}
// build chat payload
const payload = {
const outgoingPayload = {
cmd: 'chat',
nick: socket.nick, /* @legacy */
userid: socket.userid,
@ -51,17 +53,17 @@ export async function run(core, server, socket, data) {
};
if (UAC.isAdmin(socket.level)) {
payload.admin = true;
outgoingPayload.admin = true;
} else if (UAC.isModerator(socket.level)) {
payload.mod = true;
outgoingPayload.mod = true;
}
if (socket.trip) {
payload.trip = socket.trip; /* @legacy */
outgoingPayload.trip = socket.trip; /* @legacy */
}
// broadcast to channel peers
server.broadcast(payload, { channel: socket.channel });
server.broadcast(outgoingPayload, { channel: socket.channel });
// stats are fun
core.stats.increment('messages-sent');
@ -76,7 +78,7 @@ export function initHooks(server) {
}
// checks for miscellaneous '/' based commands
export function commandCheckIn(core, server, socket, payload) {
export function commandCheckIn({ server, socket, payload }) {
if (typeof payload.text !== 'string') {
return false;
}
@ -93,7 +95,7 @@ export function commandCheckIn(core, server, socket, payload) {
return payload;
}
export function finalCmdCheck(core, server, socket, payload) {
export function finalCmdCheck({ server, socket, payload }) {
if (typeof payload.text !== 'string') {
return false;
}
@ -103,7 +105,7 @@ export function finalCmdCheck(core, server, socket, payload) {
}
if (payload.text.startsWith('//')) {
payload.text = payload.text.substr(1);
payload.text = payload.text.substr(1); // eslint-disable-line no-param-reassign
return payload;
}

View File

@ -20,7 +20,7 @@ const parseText = (text) => {
};
// module main
export async function run(core, server, socket, payload) {
export async function run({ server, socket, payload }) {
// check user input
let text = parseText(payload.text);
@ -65,7 +65,9 @@ export function initHooks(server) {
}
// hooks chat commands checking for /me
export function emoteCheck(core, server, socket, payload) {
export function emoteCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
@ -86,9 +88,14 @@ export function emoteCheck(core, server, socket, payload) {
input.splice(0, 1);
const actionText = input.join(' ');
this.run(core, server, socket, {
cmd: 'emote',
text: actionText,
this.run({
core,
server,
socket,
payload: {
cmd: 'emote',
text: actionText,
},
});
return false;

View File

@ -3,7 +3,9 @@
*/
// module main
export async function run(core, server, socket, payload) {
export async function run({
core, server, socket, payload,
}) {
// check for spam
if (server.police.frisk(socket.address, 2)) {
return server.reply({
@ -24,7 +26,9 @@ export async function run(core, server, socket, payload) {
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())}:|`;
const catCommands = core.commands.all(categories[i]).sort((a, b) => a.info.name.localeCompare(b.info.name));
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`;
}
@ -40,6 +44,7 @@ export async function run(core, server, socket, payload) {
reply += `|**Aliases:**|${typeof command.info.aliases !== 'undefined' ? command.info.aliases.join(', ') : 'None'}|\n`;
reply += `|**Category:**|${command.info.category.replace('../src/commands/', '').replace(/^\w/, (c) => c.toUpperCase())}|\n`;
reply += `|**Required Parameters:**|${command.requiredData || 'None'}|\n`;
// eslint-disable-next-line no-useless-escape
reply += `|**Description:**|${command.info.description || '¯\_(ツ)_/¯'}|\n\n`;
reply += `**Usage:** ${command.info.usage || command.info.name}`;
}
@ -60,7 +65,9 @@ export function initHooks(server) {
}
// hooks chat commands checking for /whisper
export function helpCheck(core, server, socket, payload) {
export function helpCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
@ -68,9 +75,14 @@ export function helpCheck(core, server, socket, payload) {
if (payload.text.startsWith('/help')) {
const input = payload.text.substr(1).split(' ', 2);
this.run(core, server, socket, {
cmd: input[0],
command: input[1],
this.run({
core,
server,
socket,
payload: {
cmd: input[0],
command: input[1],
},
});
return false;

View File

@ -8,16 +8,17 @@
* @param {any} channel
* @return {string}
*/
export function getChannel (channel=undefined) {
export function getChannel(channel = undefined) {
if (typeof channel === 'string') {
return channel;
} else {
return Math.random().toString(36).substr(2, 8);
}
return Math.random().toString(36).substr(2, 8);
}
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// check for spam
if (server.police.frisk(socket.address, 2)) {
return server.reply({
@ -27,18 +28,18 @@ export async function run(core, server, socket, data) {
}
// verify user input
if (typeof data.userid !== 'number' || typeof data.channel !== 'string') {
if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') {
return true;
}
// why would you invite yourself?
if (data.userid === socket.userid) {
if (payload.userid === socket.userid) {
return true;
}
// @todo Verify this socket is part of data.channel - multichannel patch
// @todo Verify this socket is part of payload.channel - multichannel patch
// find target user
let targetClient = server.findSockets({ channel: data.channel, userid: data.userid });
let targetClient = server.findSockets({ channel: payload.channel, userid: payload.userid });
if (targetClient.length === 0) {
return server.reply({
@ -50,22 +51,22 @@ export async function run(core, server, socket, data) {
[targetClient] = targetClient;
// generate common channel
const channel = getChannel(data.to);
const channel = getChannel(payload.to);
// build invite
const payload = {
const outgoingPayload = {
cmd: 'invite',
channel: socket.channel,
from: socket.userid,
to: data.userid,
to: payload.userid,
inviteChannel: channel,
};
// send invite notice to target client
server.reply(payload, targetClient);
server.reply(outgoingPayload, targetClient);
// send invite notice to this client
server.reply(payload, socket);
server.reply(outgoingPayload, socket);
// stats are fun
core.stats.increment('invites-sent');
@ -73,7 +74,7 @@ export async function run(core, server, socket, data) {
return true;
}
export const requiredData = [];//['nick'];
export const requiredData = []; // ['nick'];
export const info = {
name: 'invite',
description: 'Sends an invite to the target client with the provided channel, or a random channel.',

View File

@ -1,3 +1,5 @@
/* eslint no-param-reassign: 0 */
/*
Description: Initial entry point, applies `channel` and `nick` to the calling socket
*/
@ -29,7 +31,7 @@ export function parseNickname(core, data) {
return 'Nickname must consist of up to 24 letters, numbers, and underscores';
}
let password = data.pass || false;
const password = data.pass || false;
if (hash(password + core.config.tripSalt) === core.config.adminTrip) {
userInfo.uType = 'admin'; /* @legacy */
@ -43,7 +45,7 @@ export function parseNickname(core, data) {
userInfo.trip = hash(password + core.config.tripSalt);
}
// TODO: disallow moderator impersonation
// @todo disallow moderator impersonation
// for (const mod of core.config.mods) {
core.config.mods.forEach((mod) => {
if (userInfo.trip === mod.trip) {
@ -56,7 +58,9 @@ export function parseNickname(core, data) {
}
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// check for spam
if (server.police.frisk(socket.address, 3)) {
return server.reply({
@ -75,17 +79,17 @@ export async function run(core, server, socket, data) {
}
// check user input
if (typeof data.channel !== 'string' || typeof data.nick !== 'string') {
if (typeof payload.channel !== 'string' || typeof payload.nick !== 'string') {
return true;
}
const channel = data.channel.trim();
const channel = payload.channel.trim();
if (!channel) {
// must join a non-blank channel
return true;
}
const userInfo = this.parseNickname(core, data);
const userInfo = this.parseNickname(core, payload);
if (typeof userInfo === 'string') {
return server.reply({
cmd: 'warn', // @todo Remove english and change to numeric id
@ -95,7 +99,7 @@ export async function run(core, server, socket, data) {
// check if the nickname already exists in the channel
const userExists = server.findSockets({
channel: data.channel,
channel: payload.channel,
nick: (targetNick) => targetNick.toLowerCase() === userInfo.nick.toLowerCase(),
});
@ -108,13 +112,13 @@ export async function run(core, server, socket, data) {
}
// populate final userinfo fields
// @TODO: this could be move into parseNickname, changing the function name to match
// @todo this could be move into parseNickname, changing the function name to match
userInfo.hash = server.getSocketHash(socket);
userInfo.userid = socket.userid;
// @TODO: place this within it's own function allowing import
// @todo place this within it's own function allowing import
// prepare to notify channel peers
const newPeerList = server.findSockets({ channel: data.channel });
const newPeerList = server.findSockets({ channel: payload.channel });
const nicks = []; /* @legacy */
const users = [];
@ -126,7 +130,7 @@ export async function run(core, server, socket, data) {
hash: userInfo.hash,
level: userInfo.level,
userid: userInfo.userid,
channel: data.channel,
channel: payload.channel,
};
// send join announcement and prep online set
@ -141,7 +145,7 @@ export async function run(core, server, socket, data) {
hash: newPeerList[i].hash,
level: newPeerList[i].level,
userid: newPeerList[i].userid,
channel: data.channel,
channel: payload.channel,
isme: false,
});
}
@ -150,7 +154,7 @@ export async function run(core, server, socket, data) {
socket.uType = userInfo.uType; /* @legacy */
socket.nick = userInfo.nick;
socket.trip = userInfo.trip;
socket.channel = data.channel; /* @legacy */
socket.channel = payload.channel; /* @legacy */
socket.hash = userInfo.hash;
socket.level = userInfo.level;
@ -162,7 +166,7 @@ export async function run(core, server, socket, data) {
hash: socket.hash,
level: socket.level,
userid: socket.userid,
channel: data.channel,
channel: payload.channel,
isme: true,
});
@ -179,7 +183,7 @@ export async function run(core, server, socket, data) {
return true;
}
export const requiredData = ['channel', 'nick'];
export const requiredData = []; // ['channel', 'nick'];
export const info = {
name: 'join',
description: 'Place calling socket into target channel with target nick & broadcast event to channel',

View File

@ -21,7 +21,7 @@ const formatTime = (time) => {
};
// module main
export async function run(core, server, socket) {
export async function run({ core, server, socket }) {
// gather connection and channel count
let ips = {};
let channels = {};
@ -63,14 +63,21 @@ export function initHooks(server) {
}
// hooks chat commands checking for /stats
export function 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',
this.run({
core,
server,
socket,
payload: {
cmd: 'morestats',
},
});
return false;

View File

@ -1,9 +1,10 @@
/*
Description: Changes the current channel of the calling socket
@deprecated This module will be removed or replaced
*/
// module main
export async function run(core, server, socket, data) {
export async function run({ server, socket, payload }) {
// check for spam
if (server.police.frisk(socket.address, 6)) {
return server.reply({
@ -13,18 +14,18 @@ export async function run(core, server, socket, data) {
}
// check user input
if (typeof data.channel !== 'string') {
if (typeof payload.channel !== 'string') {
return true;
}
if (data.channel === '') {
if (payload.channel === '') {
return server.reply({
cmd: 'warn', // @todo Remove english and change to numeric id
text: 'Cannot move to an empty channel.',
}, socket);
}
if (data.channel === socket.channel) {
if (payload.channel === socket.channel) {
// they are trying to rejoin the channel
return true;
}
@ -32,7 +33,7 @@ export async function run(core, server, socket, data) {
// check that the nickname isn't already in target channel
const currentNick = socket.nick.toLowerCase();
const userExists = server.findSockets({
channel: data.channel,
channel: payload.channel,
nick: (targetNick) => targetNick.toLowerCase() === currentNick,
});
@ -60,9 +61,9 @@ export async function run(core, server, socket, data) {
}
}
// TODO: import function from join module
// @todo import function from join module
// broadcast join notice to new peers
const newPeerList = server.findSockets({ channel: data.channel });
const newPeerList = server.findSockets({ channel: payload.channel });
const moveAnnouncement = {
cmd: 'onlineAdd',
nick: socket.nick,
@ -85,7 +86,7 @@ export async function run(core, server, socket, data) {
}, socket);
// commit change
socket.channel = data.channel;
socket.channel = payload.channel; // eslint-disable-line no-param-reassign
return true;
}
@ -95,7 +96,9 @@ export function initHooks(server) {
server.registerHook('in', 'chat', this.moveCheck.bind(this), 29);
}
export function moveCheck(core, server, socket, payload) {
export function moveCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
@ -113,9 +116,14 @@ export function moveCheck(core, server, socket, payload) {
return false;
}
this.run(core, server, socket, {
cmd: 'move',
channel: input[1],
this.run({
core,
server,
socket,
payload: {
cmd: 'move',
channel: input[1],
},
});
return false;

View File

@ -1,3 +1,4 @@
/* eslint no-empty-function: 0 */
/*
Description: This module is only in place to supress error notices legacy sources may get
*/

View File

@ -1,3 +1,5 @@
/* eslint no-param-reassign: 0 */
/*
Description: Create a new socket session or restore previous session
*/
@ -5,19 +7,19 @@
// module support functions
const createSessionID = () => {
let sessionID = '';
for( let i = 0, j = 32; i < j; i++) {
for (let i = 0, j = 32; i < j; i += 1) {
sessionID += Math.random().toString(36).substr(2, 9);
}
return sessionID;
}
};
// module main
export async function run(core, server, socket) {
export async function run({ server, socket }) {
// gather connection and channel count
let ips = {};
let channels = {};
// todo: use public channel flag
let publicChanCounts = {
// @todo use public channel flag
const publicChanCounts = {
lounge: 0,
meta: 0,
math: 0,
@ -30,13 +32,13 @@ export async function run(core, server, socket) {
chinese: 0,
};
// todo: code resuage between here and `morestats`, export function
// todo code resuage between here and `morestats`, export function
server.clients.forEach((client) => {
if (client.channel) {
channels[client.channel] = true;
ips[client.address] = true;
if (typeof publicChanCounts[client.channel] !== 'undefined') {
publicChanCounts[client.channel]++;
publicChanCounts[client.channel] += 1;
}
}
});
@ -47,7 +49,7 @@ export async function run(core, server, socket) {
ips = null;
channels = null;
// @todo: restore session
// @todo restore session
socket.sessionID = createSessionID();
socket.hcProtocol = 2;
socket.userid = Math.floor(Math.random() * 9999999999999);
@ -67,5 +69,5 @@ export const info = {
name: 'session',
description: 'Restore previous state by session id or return new session id (currently unavailable)',
usage: `
API: { cmd: 'session', id: '<previous session>' }`
API: { cmd: 'session', id: '<previous session>' }`,
};

View File

@ -3,7 +3,7 @@
*/
// module main
export async function run(core, server, socket) {
export async function run({ core, server, socket }) {
// gather connection and channel count
let ips = {};
let channels = {};

View File

@ -25,7 +25,7 @@ const parseText = (text) => {
};
// module main
export async function run(core, server, socket, payload) {
export async function run({ server, socket, payload }) {
// check user input
const text = parseText(payload.text);
@ -85,7 +85,9 @@ export function initHooks(server) {
}
// hooks chat commands checking for /whisper
export function whisperCheck(core, server, socket, payload) {
export function whisperCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
@ -107,10 +109,15 @@ export function whisperCheck(core, server, socket, payload) {
input.splice(0, 2);
const whisperText = input.join(' ');
this.run(core, server, socket, {
cmd: 'whisper',
nick: target,
text: whisperText,
this.run({
core,
server,
socket,
payload: {
cmd: 'whisper',
nick: target,
text: whisperText,
},
});
return false;
@ -130,10 +137,15 @@ export function whisperCheck(core, server, socket, payload) {
input.splice(0, 1);
const whisperText = input.join(' ');
this.run(core, server, socket, {
cmd: 'whisper',
nick: socket.whisperReply,
text: whisperText,
this.run({
core,
server,
socket,
payload: {
cmd: 'whisper',
nick: socket.whisperReply,
text: whisperText,
},
});
return false;

View File

@ -4,8 +4,8 @@
*/
// module main
export async function run(core, server, socket, data) {
if (data.cmdKey !== server.cmdKey) {
export async function run({ server, socket, payload }) {
if (payload.cmdKey !== server.cmdKey) {
// internal command attempt by client, increase rate limit chance and ignore
return server.police.frisk(socket.address, 20);
}

View File

@ -1,3 +1,5 @@
/* eslint no-param-reassign: 0 */
/*
Description: This module adjusts outgoing data, making it compatible with legacy clients
Dear god this module is horrifying
@ -6,7 +8,7 @@
// import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({ server, socket }) {
return server.police.frisk(socket.address, 20);
}
@ -21,14 +23,14 @@ export function initHooks(server) {
}
// hook incoming join events, if session was not invoked, default proto to 1
export function joinCheck(core, server, socket, payload) {
export function joinCheck({ socket, payload }) {
if (typeof socket.hcProtocol === 'undefined') {
socket.hcProtocol = 1;
const nickArray = payload.nick.split('#', 2);
payload.nick = nickArray[0].trim();
if (nickArray[1] && typeof payload.pass === 'undefined') {
payload.pass = nickArray[1];
payload.pass = nickArray[1]; // eslint-disable-line prefer-destructuring
}
// dunno how this happened on the legacy version
@ -45,9 +47,9 @@ export function joinCheck(core, server, socket, payload) {
}
// if legacy client sent an invite, downgrade request
export function inviteInCheck(core, server, socket, payload) {
export function inviteInCheck({ server, socket, payload }) {
if (socket.hcProtocol === 1) {
let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick });
let targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick });
if (targetClient.length === 0) {
server.reply({
@ -68,7 +70,7 @@ export function inviteInCheck(core, server, socket, payload) {
}
//
export function inviteOutCheck(core, server, socket, payload) {
export function inviteOutCheck({ server, socket, payload }) {
if (socket.hcProtocol === 1) {
payload.cmd = 'info';
if (socket.userid === payload.from) {
@ -89,9 +91,9 @@ export function inviteOutCheck(core, server, socket, payload) {
return payload;
}
export function banCheck(core, server, socket, payload) {
export function banCheck({ server, socket, payload }) {
if (socket.hcProtocol === 1) {
let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick });
let targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick });
if (targetClient.length === 0) {
server.reply({
@ -111,9 +113,9 @@ export function banCheck(core, server, socket, payload) {
return payload;
}
export function dumbCheck(core, server, socket, payload) {
export function dumbCheck({ server, socket, payload }) {
if (socket.hcProtocol === 1) {
let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick });
let targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick });
if (targetClient.length === 0) {
server.reply({
@ -133,15 +135,15 @@ export function dumbCheck(core, server, socket, payload) {
return payload;
}
export function kickCheck(core, server, socket, payload) {
export function kickCheck({ server, socket, payload }) {
if (socket.hcProtocol === 1) {
if (typeof payload.nick !== 'number') {
if (typeof payload.nick !== 'object' && !Array.isArray(data.nick)) {
if (typeof payload.nick !== 'object' && !Array.isArray(payload.nick)) {
return true;
}
}
let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick });
const targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick });
if (targetClient.length === 0) {
return false;

View File

@ -3,8 +3,8 @@
*/
// module main
export async function run(core, server, socket, data) {
if (data.cmdKey !== server.cmdKey) {
export async function run({ server, socket, payload }) {
if (payload.cmdKey !== server.cmdKey) {
// internal command attempt by client, increase rate limit chance and ignore
return server.police.frisk(socket.address, 20);
}
@ -12,7 +12,7 @@ export async function run(core, server, socket, data) {
// send warning to target socket
server.reply({
cmd: 'warn', // @todo Remove english and change to numeric id
text: data.text
text: payload.text,
}, socket);
return true;

View File

@ -1,3 +1,4 @@
/* eslint no-console: 0 */
/*
Description: Adds the target socket's ip to the ratelimiter
*/
@ -5,19 +6,21 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!UAC.isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (typeof data.userid !== 'number') {
if (typeof payload.userid !== 'number') {
return true;
}
// find target user
let badClient = server.findSockets({ channel: socket.channel, userid: data.userid });
let badClient = server.findSockets({ channel: socket.channel, userid: payload.userid });
if (badClient.length === 0) {
return server.reply({
@ -52,8 +55,8 @@ export async function run(core, server, socket, data) {
// notify mods
server.broadcast({
cmd: 'info',
text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${data.channel}, userhash: ${badClient.hash}`,
channel: data.channel,
text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${payload.channel}, userhash: ${badClient.hash}`,
channel: payload.channel,
user: UAC.getUserDetails(badClient),
banner: UAC.getUserDetails(socket),
}, { level: UAC.isModerator });
@ -67,7 +70,7 @@ export async function run(core, server, socket, data) {
return true;
}
//export const requiredData = ['nick'];
// export const requiredData = ['nick'];
export const info = {
name: 'ban',
description: 'Disconnects the target nickname in the same channel as calling socket & adds to ratelimiter',

View File

@ -1,3 +1,6 @@
/* eslint no-param-reassign: 0 */
/* eslint no-multi-assign: 0 */
/*
* Description: Make a user (spammer) dumb (mute)
* Author: simple
@ -13,19 +16,21 @@ export function init(core) {
}
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!UAC.isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (typeof data.userid !== 'number') {
if (typeof payload.userid !== 'number') {
return true;
}
// find target user
let badClient = server.findSockets({ channel: data.channel, userid: data.userid });
let badClient = server.findSockets({ channel: payload.channel, userid: payload.userid });
if (badClient.length === 0) {
return server.reply({
@ -50,14 +55,14 @@ export async function run(core, server, socket, data) {
};
// store allies if needed
if (data.allies && Array.isArray(data.allies)) {
record.allies = data.allies;
if (payload.allies && Array.isArray(payload.allies)) {
record.allies = payload.allies;
}
// notify mods
server.broadcast({
cmd: 'info',
text: `${socket.nick}#${socket.trip} muzzled ${badClient.nick} in ${data.channel}, userhash: ${badClient.hash}`,
text: `${socket.nick}#${socket.trip} muzzled ${badClient.nick} in ${payload.channel}, userhash: ${badClient.hash}`,
}, { level: UAC.isModerator });
return true;
@ -71,7 +76,9 @@ export function initHooks(server) {
}
// hook incoming chat commands, shadow-prevent chat if they are muzzled
export function chatCheck(core, server, socket, payload) {
export function chatCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
@ -116,10 +123,10 @@ export function chatCheck(core, server, socket, payload) {
}
// shadow-prevent all invites from muzzled users
export function inviteCheck(core, server, socket, payload) {
export function inviteCheck({ core, socket, payload }) {
if (core.muzzledHashes[socket.hash]) {
// @todo convert to protocol 2
/*const nickValid = Invite.checkNickname(payload.nick);
/* const nickValid = Invite.checkNickname(payload.nick);
if (nickValid !== null) {
server.reply({
cmd: 'warn', // @todo Remove english and change to numeric id
@ -132,7 +139,7 @@ export function inviteCheck(core, server, socket, payload) {
const channel = Invite.getChannel();
// send fake reply
server.reply(Invite.createSuccessPayload(payload.nick, channel), socket);*/
server.reply(Invite.createSuccessPayload(payload.nick, channel), socket); */
return false;
}
@ -141,7 +148,9 @@ export function inviteCheck(core, server, socket, payload) {
}
// shadow-prevent all whispers from muzzled users
export function whisperCheck(core, server, socket, payload) {
export function whisperCheck({
core, server, socket, payload,
}) {
if (typeof payload.nick !== 'string') {
return false;
}
@ -159,7 +168,8 @@ export function whisperCheck(core, server, socket, payload) {
text: `You whispered to @${targetNick}: ${payload.text}`,
}, socket);
// blanket "spam" protection, may expose the ratelimiting lines from `chat` and use that, TODO: one day #lazydev
// 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;

View File

@ -1,3 +1,5 @@
/* eslint no-console: 0 */
/*
Description: Forces a change on the target(s) socket's channel, then broadcasts event
*/
@ -5,29 +7,31 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!UAC.isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (typeof data.userid !== 'number') {
if (typeof payload.userid !== 'number') {
// @todo create multi-ban ui
if (typeof data.userid !== 'object' && !Array.isArray(data.userid)) {
if (typeof payload.userid !== 'object' && !Array.isArray(payload.userid)) {
return true;
}
}
let destChannel;
if (typeof data.to === 'string' && !!data.to.trim()) {
destChannel = data.to;
if (typeof payload.to === 'string' && !!payload.to.trim()) {
destChannel = payload.to;
} else {
destChannel = Math.random().toString(36).substr(2, 8);
}
// find target user(s)
const badClients = server.findSockets({ channel: data.channel, userid: data.userid });
const badClients = server.findSockets({ channel: payload.channel, userid: payload.userid });
if (badClients.length === 0) {
return server.reply({
@ -76,7 +80,6 @@ export async function run(core, server, socket, data) {
console.log(`${socket.nick} [${socket.trip}] kicked ${kicked[i].nick} in ${socket.channel} to ${destChannel} `);
}
// broadcast client leave event
for (let i = 0, j = kicked.length; i < j; i += 1) {
server.broadcast({

View File

@ -5,23 +5,23 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({ server, socket, payload }) {
// increase rate limit chance and ignore if not admin or mod
if (!UAC.isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (typeof data.nick !== 'string' || typeof data.channel !== 'string') {
if (typeof payload.nick !== 'string' || typeof payload.channel !== 'string') {
return true;
}
if (data.channel === socket.channel) {
if (payload.channel === socket.channel) {
// moving them into the same channel? y u do this?
return true;
}
const badClients = server.findSockets({ channel: socket.channel, nick: data.nick });
const badClients = server.findSockets({ channel: socket.channel, nick: payload.nick });
if (badClients.length === 0) {
return server.reply({
@ -41,7 +41,7 @@ export async function run(core, server, socket, data) {
const currentNick = badClient.nick.toLowerCase();
const userExists = server.findSockets({
channel: data.channel,
channel: payload.channel,
nick: (targetNick) => targetNick.toLowerCase() === currentNick,
});
@ -68,8 +68,8 @@ export async function run(core, server, socket, data) {
}
}
// TODO: import from join module
const newPeerList = server.findSockets({ channel: data.channel });
// @todo import from join module
const newPeerList = server.findSockets({ channel: payload.channel });
const moveAnnouncement = {
cmd: 'onlineAdd',
nick: badClient.nick,
@ -90,12 +90,12 @@ export async function run(core, server, socket, data) {
nicks,
}, badClient);
badClient.channel = data.channel;
badClient.channel = payload.channel;
server.broadcast({
cmd: 'info',
text: `${badClient.nick} was moved into ?${data.channel}`,
}, { channel: data.channel });
text: `${badClient.nick} was moved into ?${payload.channel}`,
}, { channel: payload.channel });
return true;
}

View File

@ -1,3 +1,5 @@
/* eslint no-param-reassign: 0 */
/*
* Description: Pardon a dumb user to be able to speak again
* Author: simple
@ -13,22 +15,24 @@ export function init(core) {
}
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!UAC.isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (typeof data.ip !== 'string' && typeof data.hash !== 'string') {
if (typeof payload.ip !== 'string' && typeof payload.hash !== 'string') {
return server.reply({
cmd: 'warn', // @todo Remove english and change to numeric id
text: "hash:'targethash' or ip:'1.2.3.4' is required",
}, socket);
}
if (typeof data.ip === 'string') {
if (data.ip === '*') {
if (typeof payload.ip === 'string') {
if (payload.ip === '*') {
core.muzzledHashes = {};
return server.broadcast({
@ -36,7 +40,7 @@ export async function run(core, server, socket, data) {
text: `${socket.nick} unmuzzled all users`,
}, { level: UAC.isModerator });
}
} else if (data.hash === '*') {
} else if (payload.hash === '*') {
core.muzzledHashes = {};
return server.broadcast({
@ -47,10 +51,10 @@ export async function run(core, server, socket, data) {
// find target & remove mute status
let target;
if (typeof data.ip === 'string') {
target = server.getSocketHash(data.ip);
if (typeof payload.ip === 'string') {
target = server.getSocketHash(payload.ip);
} else {
target = data.hash;
target = payload.hash;
}
delete core.muzzledHashes[target];

View File

@ -1,3 +1,5 @@
/* eslint no-console: 0 */
/*
Description: Removes a target ip from the ratelimiter
*/
@ -5,14 +7,16 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket, data) {
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!UAC.isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (typeof data.ip !== 'string' && typeof data.hash !== 'string') {
if (typeof payload.ip !== 'string' && typeof payload.hash !== 'string') {
return server.reply({
cmd: 'warn', // @todo Remove english and change to numeric id
text: "hash:'targethash' or ip:'1.2.3.4' is required",
@ -22,12 +26,12 @@ export async function run(core, server, socket, data) {
// find target
let mode;
let target;
if (typeof data.ip === 'string') {
if (typeof payload.ip === 'string') {
mode = 'ip';
target = data.ip;
target = payload.ip;
} else {
mode = 'hash';
target = data.hash;
target = payload.hash;
}
// remove arrest record

View File

@ -1,3 +1,5 @@
/* eslint no-console: 0 */
/*
Description: Clears all bans and ratelimits
*/
@ -5,7 +7,7 @@
import * as UAC from '../utility/UAC/_info';
// module main
export async function run(core, server, socket) {
export async function run({ core, server, socket }) {
// increase rate limit chance and ignore if not admin or mod
if (!UAC.isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);

View File

@ -1,3 +1,9 @@
/* eslint no-bitwise: 0 */
/* eslint global-require: 0 */
/* eslint class-methods-use-this: 0 */
/* eslint no-param-reassign: 0 */
/* eslint no-console: 0 */
import {
start as _start,
get,
@ -8,6 +14,7 @@ import {
* @author Marzavec ( https://github.com/marzavec )
* @version v2.0.0
* @license WTFPL ( http://www.wtfpl.net/txt/copying/ )
* @todo Convert to use the `enquirer` package instead
*/
class SetupWizard {
/**

View File

@ -1,3 +1,5 @@
/* eslint no-console: 0 */
/**
* This script will be run before the package starts asking for the config data,
* used to output a simple guide for the coming questions, or to spam some sexy

View File

@ -1,3 +1,5 @@
/* eslint no-console: 0 */
/**
* This script will be run once all questions have finished and no errors have
* occured. You can congratulate the user on their fine choice in software usage

View File

@ -1,3 +1,6 @@
/* eslint no-undef: 0 */
/* eslint global-require: 0 */
/**
* This object contains Prompt ( https://www.npmjs.com/package/prompt ) style
* questions that the SetupWizard will require an answer to. Questions are asked

View File

@ -1,3 +1,5 @@
/* eslint no-console: 0 */
import {
basename,
join,
@ -98,6 +100,7 @@ class CommandManager {
.replace(new RegExp(sep.replace('\\', '\\\\'), 'g'), '/');
}
// eslint-disable-next-line no-param-reassign
command.info.category = category;
if (this.categories.indexOf(category) === -1) {
@ -126,6 +129,7 @@ class CommandManager {
* @private
* @return {String} Module errors or null if none
*/
// eslint-disable-next-line class-methods-use-this
validateCommand(object) {
if (typeof object !== 'object') { return 'command setup is invalid'; }
if (typeof object.run !== 'function') { return 'run function is missing'; }
@ -253,11 +257,11 @@ class CommandManager {
* @private
* @return {*} Arbitrary module return data
*/
async execute(command, server, socket, data) {
async execute(command, server, socket, payload) {
if (typeof command.requiredData !== 'undefined') {
const missing = [];
for (let i = 0, len = command.requiredData.length; i < len; i += 1) {
if (typeof data[command.requiredData[i]] === 'undefined') { missing.push(command.requiredData[i]); }
if (typeof payload[command.requiredData[i]] === 'undefined') { missing.push(command.requiredData[i]); }
}
if (missing.length > 0) {
@ -278,7 +282,12 @@ class CommandManager {
}
try {
return await command.run(this.core, server, socket, data);
return await command.run({
core: this.core,
server,
socket,
payload,
});
} catch (err) {
const errText = `Failed to execute '${command.info.name}': `;

View File

@ -1,3 +1,5 @@
/* eslint no-console: 0 */
import dateFormat from 'dateformat';
import {
existsSync,

View File

@ -1,3 +1,5 @@
/* eslint no-console: 0 */
import { join } from 'path';
import {
CommandManager,
@ -90,4 +92,4 @@ class CoreApp {
}
}
export { CoreApp };
export { CoreApp as default };

View File

@ -1,3 +1,6 @@
/* eslint global-require: 0 */
/* eslint no-console: 0 */
import {
resolve,
basename as _basename,
@ -57,7 +60,7 @@ class ImportsManager {
let imported;
try {
imported = require(file);
imported = require(file); // eslint-disable-line import/no-dynamic-require
if (!this.imports[dirName]) {
this.imports[dirName] = {};

View File

@ -1,3 +1,6 @@
/* eslint no-bitwise: 0 */
/* eslint no-console: 0 */
import {
Server as WsServer,
OPEN as SocketReady,
@ -189,10 +192,6 @@ class MainServer extends WsServer {
* Issue #1: hard coded `cmd` check
* Issue #2: hard coded `cmd` value checks
*/
if (typeof payload.cmd === 'undefined') {
return;
}
if (typeof payload.cmd !== 'string') {
return;
}
@ -509,7 +508,12 @@ class MainServer extends WsServer {
for (let i = 0, j = hooks.length; i < j; i += 1) {
try {
newPayload = hooks[i].run(this.core, this, socket, newPayload);
newPayload = hooks[i].run({
core: this.core,
server: this,
socket,
payload: newPayload,
});
} catch (err) {
const errText = `Hook failure, '${type}', '${command}': `;
if (this.core.config.logErrDetailed === true) {

View File

@ -77,6 +77,7 @@ class RateLimiter {
return true;
}
// eslint-disable-next-line no-restricted-properties
record.score *= Math.pow(2, -(Date.now() - record.time) / this.halflife);
record.score += deltaScore;
record.time = Date.now();

View File

@ -1,3 +1,5 @@
/* eslint global-require: 0 */
export const CommandManager = require('./CommandManager').default;
export const ConfigManager = require('./ConfigManager').default;
export const ImportsManager = require('./ImportsManager').default;